1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platformNet.h"
- #include "core/strings/stringFunctions.h"
- #if defined (TORQUE_OS_WIN)
- #define TORQUE_USE_WINSOCK
- #include <errno.h>
- #include <winsock.h>
- #ifndef EINPROGRESS
- #define EINPROGRESS WSAEINPROGRESS
- #endif // EINPROGRESS
- #define ioctl ioctlsocket
- typedef S32 socklen_t;
- #elif defined ( TORQUE_OS_MAC )
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/poll.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include <sys/ioctl.h>
- typedef sockaddr_in SOCKADDR_IN;
- typedef sockaddr * PSOCKADDR;
- typedef sockaddr SOCKADDR;
- typedef in_addr IN_ADDR;
- #define INVALID_SOCKET -1
- #define SOCKET_ERROR -1
- #define closesocket close
- #elif defined TORQUE_OS_LINUX
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/poll.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include <sys/ioctl.h>
- typedef sockaddr_in SOCKADDR_IN;
- typedef sockaddr * PSOCKADDR;
- typedef sockaddr SOCKADDR;
- typedef in_addr IN_ADDR;
- #define INVALID_SOCKET -1
- #define SOCKET_ERROR -1
- #define closesocket close
- #elif defined( TORQUE_OS_XENON )
- #include <Xtl.h>
- #include <string>
- #define TORQUE_USE_WINSOCK
- #define EINPROGRESS WSAEINPROGRESS
- #define ioctl ioctlsocket
- typedef S32 socklen_t;
- DWORD _getLastErrorAndClear()
- {
- DWORD err = WSAGetLastError();
- WSASetLastError( 0 );
- return err;
- }
- #else
- #endif
- #if defined(TORQUE_USE_WINSOCK)
- static const char* strerror_wsa( S32 code )
- {
- switch( code )
- {
- #define E( name ) case name: return #name;
- E( WSANOTINITIALISED );
- E( WSAENETDOWN );
- E( WSAEADDRINUSE );
- E( WSAEINPROGRESS );
- E( WSAEALREADY );
- E( WSAEADDRNOTAVAIL );
- E( WSAEAFNOSUPPORT );
- E( WSAEFAULT );
- E( WSAEINVAL );
- E( WSAEISCONN );
- E( WSAENETUNREACH );
- E( WSAEHOSTUNREACH );
- E( WSAENOBUFS );
- E( WSAENOTSOCK );
- E( WSAETIMEDOUT );
- E( WSAEWOULDBLOCK );
- E( WSAEACCES );
- #undef E
- default:
- return "Unknown";
- }
- }
- #endif
- #include "core/util/tVector.h"
- #include "platform/platformNetAsync.h"
- #include "console/console.h"
- #include "core/util/journal/process.h"
- #include "core/util/journal/journal.h"
- static Net::Error getLastError();
- static S32 defaultPort = 28000;
- static S32 netPort = 0;
- static NetSocket udpSocket = InvalidSocket;
- ConnectionNotifyEvent Net::smConnectionNotify;
- ConnectionAcceptedEvent Net::smConnectionAccept;
- ConnectionReceiveEvent Net::smConnectionReceive;
- PacketReceiveEvent Net::smPacketReceive;
- // local enum for socket states for polled sockets
- enum SocketState
- {
- InvalidState,
- Connected,
- ConnectionPending,
- Listening,
- NameLookupRequired
- };
- // the Socket structure helps us keep track of the
- // above states
- struct Socket
- {
- Socket()
- {
- fd = InvalidSocket;
- state = InvalidState;
- remoteAddr[0] = 0;
- remotePort = -1;
- }
- NetSocket fd;
- S32 state;
- char remoteAddr[256];
- S32 remotePort;
- };
- // list of polled sockets
- static Vector<Socket*> gPolledSockets( __FILE__, __LINE__ );
- static Socket* addPolledSocket(NetSocket& fd, S32 state,
- char* remoteAddr = NULL, S32 port = -1)
- {
- Socket* sock = new Socket();
- sock->fd = fd;
- sock->state = state;
- if (remoteAddr)
- dStrcpy(sock->remoteAddr, remoteAddr);
- if (port != -1)
- sock->remotePort = port;
- gPolledSockets.push_back(sock);
- return sock;
- }
- enum {
- MaxConnections = 1024,
- };
- bool netSocketWaitForWritable(NetSocket fd, S32 timeoutMs)
- {
- fd_set writefds;
- timeval timeout;
- FD_ZERO(&writefds);
- FD_SET( fd, &writefds );
- timeout.tv_sec = timeoutMs / 1000;
- timeout.tv_usec = ( timeoutMs % 1000 ) * 1000;
- if( select(fd + 1, NULL, &writefds, NULL, &timeout) > 0 )
- return true;
- return false;
- }
- static S32 initCount = 0;
- bool Net::init()
- {
- #if defined(TORQUE_USE_WINSOCK)
- if(!initCount)
- {
- #ifdef TORQUE_OS_XENON
- // Configure startup parameters
- XNetStartupParams xnsp;
- memset( &xnsp, 0, sizeof( xnsp ) );
- xnsp.cfgSizeOfStruct = sizeof( XNetStartupParams );
- #ifndef TORQUE_DISABLE_PC_CONNECTIVITY
- xnsp.cfgFlags = XNET_STARTUP_BYPASS_SECURITY;
- Con::warnf("XNET_STARTUP_BYPASS_SECURITY enabled! This build can talk to PCs!");
- #endif
- AssertISV( !XNetStartup( &xnsp ), "Net::init - failed to init XNet" );
- #endif
- WSADATA stWSAData;
- AssertISV( !WSAStartup( 0x0101, &stWSAData ), "Net::init - failed to init WinSock!" );
- //logprintf("Winsock initialization %s", success ? "succeeded." : "failed!");
- }
- #endif
- initCount++;
- Process::notify(&Net::process, PROCESS_NET_ORDER);
- return(true);
- }
- void Net::shutdown()
- {
- Process::remove(&Net::process);
- while (gPolledSockets.size() > 0)
- closeConnectTo(gPolledSockets[0]->fd);
- closePort();
- initCount--;
- #if defined(TORQUE_USE_WINSOCK)
- if(!initCount)
- {
- WSACleanup();
- #ifdef TORQUE_OS_XENON
- XNetCleanup();
- #endif
- }
- #endif
- }
- Net::Error getLastError()
- {
- #if defined(TORQUE_USE_WINSOCK)
- S32 err = WSAGetLastError();
- switch(err)
- {
- case 0:
- return Net::NoError;
- case WSAEWOULDBLOCK:
- return Net::WouldBlock;
- default:
- return Net::UnknownError;
- }
- #else
- if (errno == EAGAIN)
- return Net::WouldBlock;
- if (errno == 0)
- return Net::NoError;
- return Net::UnknownError;
- #endif
- }
- static void netToIPSocketAddress(const NetAddress *address, struct sockaddr_in *sockAddr)
- {
- dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
- sockAddr->sin_family = AF_INET;
- sockAddr->sin_port = htons(address->port);
- char tAddr[20];
- dSprintf(tAddr, 20, "%d.%d.%d.%d", address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3]);
- //fprintf(stdout,"netToIPSocketAddress(): %s\n",tAddr);fflush(NULL);
- sockAddr->sin_addr.s_addr = inet_addr(tAddr);
- }
- static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
- {
- address->type = NetAddress::IPAddress;
- address->port = htons(sockAddr->sin_port);
- #ifndef TORQUE_OS_XENON
- char *tAddr;
- tAddr = inet_ntoa(sockAddr->sin_addr);
- //fprintf(stdout,"IPSocketToNetAddress(): %s\n",tAddr);fflush(NULL);
- U8 nets[4];
- nets[0] = atoi(strtok(tAddr, "."));
- nets[1] = atoi(strtok(NULL, "."));
- nets[2] = atoi(strtok(NULL, "."));
- nets[3] = atoi(strtok(NULL, "."));
- //fprintf(stdout,"0 = %d, 1 = %d, 2 = %d, 3 = %d\n", nets[0], nets[1], nets[2], nets[3]);
- address->netNum[0] = nets[0];
- address->netNum[1] = nets[1];
- address->netNum[2] = nets[2];
- address->netNum[3] = nets[3];
- #else
- address->netNum[0] = sockAddr->sin_addr.s_net;
- address->netNum[1] = sockAddr->sin_addr.s_host;
- address->netNum[2] = sockAddr->sin_addr.s_lh;
- address->netNum[3] = sockAddr->sin_addr.s_impno;
- #endif
- }
- NetSocket Net::openListenPort(U16 port)
- {
- if(Journal::IsPlaying())
- {
- U32 ret;
- Journal::Read(&ret);
- return NetSocket(ret);
- }
- NetSocket sock = openSocket();
- if (sock == InvalidSocket)
- {
- Con::errorf("Unable to open listen socket: %s", strerror(errno));
- return InvalidSocket;
- }
- if (bind(sock, port) != NoError)
- {
- Con::errorf("Unable to bind port %d: %s", port, strerror(errno));
- ::closesocket(sock);
- return InvalidSocket;
- }
- if (listen(sock, 4) != NoError)
- {
- Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));
- ::closesocket(sock);
- return InvalidSocket;
- }
- setBlocking(sock, false);
- addPolledSocket(sock, Listening);
- if(Journal::IsRecording())
- Journal::Write(U32(sock));
- return sock;
- }
- NetSocket Net::openConnectTo(const char *addressString)
- {
- if(!dStrnicmp(addressString, "ipx:", 4))
- // ipx support deprecated
- return InvalidSocket;
- if(!dStrnicmp(addressString, "ip:", 3))
- addressString += 3; // eat off the ip:
- char remoteAddr[256];
- dStrcpy(remoteAddr, addressString);
- char *portString = dStrchr(remoteAddr, ':');
- U16 port;
- if(portString)
- {
- *portString++ = 0;
- port = htons(dAtoi(portString));
- }
- else
- port = htons(defaultPort);
- if(!dStricmp(remoteAddr, "broadcast"))
- return InvalidSocket;
- if(Journal::IsPlaying())
- {
- U32 ret;
- Journal::Read(&ret);
- return NetSocket(ret);
- }
- NetSocket sock = openSocket();
- setBlocking(sock, false);
- sockaddr_in ipAddr;
- dMemset(&ipAddr, 0, sizeof(ipAddr));
- ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);
- if(ipAddr.sin_addr.s_addr != INADDR_NONE)
- {
- ipAddr.sin_port = port;
- ipAddr.sin_family = AF_INET;
- if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1)
- {
- S32 err = getLastError();
- if(err != Net::WouldBlock)
- {
- Con::errorf("Error connecting %s: %s",
- addressString, strerror(err));
- ::closesocket(sock);
- sock = InvalidSocket;
- }
- }
- if(sock != InvalidSocket)
- {
- // add this socket to our list of polled sockets
- addPolledSocket(sock, ConnectionPending);
- }
- }
- else
- {
- // need to do an asynchronous name lookup. first, add the socket
- // to the polled list
- addPolledSocket(sock, NameLookupRequired, remoteAddr, port);
- // queue the lookup
- gNetAsync.queueLookup(remoteAddr, sock);
- }
- if(Journal::IsRecording())
- Journal::Write(U32(sock));
- return sock;
- }
- void Net::closeConnectTo(NetSocket sock)
- {
- if(Journal::IsPlaying())
- return;
- // if this socket is in the list of polled sockets, remove it
- for (S32 i = 0; i < gPolledSockets.size(); ++i)
- {
- if (gPolledSockets[i]->fd == sock)
- {
- delete gPolledSockets[i];
- gPolledSockets.erase(i);
- break;
- }
- }
- closeSocket(sock);
- }
- Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, S32 bufferSize)
- {
- if(Journal::IsPlaying())
- {
- U32 e;
- Journal::Read(&e);
- return (Net::Error) e;
- }
- Net::Error e = send(socket, buffer, bufferSize);
- if(Journal::IsRecording())
- Journal::Write(U32(e));
- return e;
- }
- bool Net::openPort(S32 port, bool doBind)
- {
- if(udpSocket != InvalidSocket)
- ::closesocket(udpSocket);
- // we turn off VDP in non-release builds because VDP does not support broadcast packets
- // which are required for LAN queries (PC->Xbox connectivity). The wire protocol still
- // uses the VDP packet structure, though.
- S32 protocol = 0;
- bool useVDP = false;
- #ifdef TORQUE_DISABLE_PC_CONNECTIVITY
- // Xbox uses a VDP (voice/data protocol) socket for networking
- protocol = IPPROTO_VDP;
- useVDP = true;
- #endif
- udpSocket = socket(AF_INET, SOCK_DGRAM, protocol);
- if(udpSocket != InvalidSocket)
- {
- Net::Error error = NoError;
- if (doBind)
- {
- error = bind(udpSocket, port);
- }
- if(error == NoError)
- error = setBufferSize(udpSocket, 32768);
- if(error == NoError && !useVDP)
- error = setBroadcast(udpSocket, true);
- if(error == NoError)
- error = setBlocking(udpSocket, false);
- if(error == NoError)
- Con::printf("UDP initialized on port %d", port);
- else
- {
- ::closesocket(udpSocket);
- udpSocket = InvalidSocket;
- Con::printf("Unable to initialize UDP - error %d", error);
- }
- }
- netPort = port;
- return udpSocket != InvalidSocket;
- }
- NetSocket Net::getPort()
- {
- return udpSocket;
- }
- void Net::closePort()
- {
- if(udpSocket != InvalidSocket)
- ::closesocket(udpSocket);
- }
- Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
- {
- if(Journal::IsPlaying())
- return NoError;
- if(address->type == NetAddress::IPAddress)
- {
- sockaddr_in ipAddr;
- netToIPSocketAddress(address, &ipAddr);
- if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
- (sockaddr *) &ipAddr, sizeof(sockaddr_in)) == SOCKET_ERROR)
- return getLastError();
- else
- return NoError;
- }
- else
- {
- SOCKADDR_IN ipAddr;
- netToIPSocketAddress(address, &ipAddr);
- if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
- (PSOCKADDR) &ipAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
- return getLastError();
- else
- return NoError;
- }
- }
- void Net::process()
- {
- sockaddr sa;
- sa.sa_family = AF_UNSPEC;
- NetAddress srcAddress;
- RawData tmpBuffer;
- tmpBuffer.alloc(MaxPacketDataSize);
- for(;;)
- {
- socklen_t addrLen = sizeof(sa);
- S32 bytesRead = -1;
- if(udpSocket != InvalidSocket)
- bytesRead = recvfrom(udpSocket, (char *) tmpBuffer.data, MaxPacketDataSize, 0, &sa, &addrLen);
- if(bytesRead == -1)
- break;
- if(sa.sa_family == AF_INET)
- IPSocketToNetAddress((sockaddr_in *) &sa, &srcAddress);
- else
- continue;
- if(bytesRead <= 0)
- continue;
- if(srcAddress.type == NetAddress::IPAddress &&
- srcAddress.netNum[0] == 127 &&
- srcAddress.netNum[1] == 0 &&
- srcAddress.netNum[2] == 0 &&
- srcAddress.netNum[3] == 1 &&
- srcAddress.port == netPort)
- continue;
- tmpBuffer.size = bytesRead;
- Net::smPacketReceive.trigger(srcAddress, tmpBuffer);
- }
- // process the polled sockets. This blob of code performs functions
- // similar to WinsockProc in winNet.cc
- if (gPolledSockets.size() == 0)
- return;
- S32 optval;
- socklen_t optlen = sizeof(S32);
- S32 bytesRead;
- Net::Error err;
- bool removeSock = false;
- Socket *currentSock = NULL;
- sockaddr_in ipAddr;
- NetSocket incoming = InvalidSocket;
- char out_h_addr[1024];
- S32 out_h_length = 0;
- RawData readBuff;
- for (S32 i = 0; i < gPolledSockets.size();
- /* no increment, this is done at end of loop body */)
- {
- removeSock = false;
- currentSock = gPolledSockets[i];
- switch (currentSock->state)
- {
- case ::InvalidState:
- Con::errorf("Error, InvalidState socket in polled sockets list");
- break;
- case ::ConnectionPending:
- // see if it is now connected
- #ifdef TORQUE_OS_XENON
- // WSASetLastError has no return value, however part of the SO_ERROR behavior
- // is to clear the last error, so this needs to be done here.
- if( ( optval = _getLastErrorAndClear() ) == -1 )
- #else
- if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR,
- (char*)&optval, &optlen) == -1)
- #endif
- {
- Con::errorf("Error getting socket options: %s", strerror(errno));
- Net::smConnectionNotify.trigger(currentSock->fd, Net::ConnectFailed);
- removeSock = true;
- }
- else
- {
- if (optval == EINPROGRESS)
- // still connecting...
- break;
- if (optval == 0)
- {
- // poll for writable status to be sure we're connected.
- bool ready = netSocketWaitForWritable(currentSock->fd,0);
- if(!ready)
- break;
- currentSock->state = ::Connected;
- Net::smConnectionNotify.trigger(currentSock->fd, Net::Connected);
- }
- else
- {
- // some kind of error
- Con::errorf("Error connecting: %s", strerror(errno));
- Net::smConnectionNotify.trigger(currentSock->fd, Net::ConnectFailed);
- removeSock = true;
- }
- }
- break;
- case ::Connected:
- // try to get some data
- bytesRead = 0;
- readBuff.alloc(MaxPacketDataSize);
- err = Net::recv(currentSock->fd, (U8*)readBuff.data, MaxPacketDataSize, &bytesRead);
- if(err == Net::NoError)
- {
- if (bytesRead > 0)
- {
- // got some data, post it
- readBuff.size = bytesRead;
- Net::smConnectionReceive.trigger(currentSock->fd, readBuff);
- }
- else
- {
- // ack! this shouldn't happen
- if (bytesRead < 0)
- Con::errorf("Unexpected error on socket: %s", strerror(errno));
- // zero bytes read means EOF
- Net::smConnectionNotify.trigger(currentSock->fd, Net::Disconnected);
- removeSock = true;
- }
- }
- else if (err != Net::NoError && err != Net::WouldBlock)
- {
- Con::errorf("Error reading from socket: %s", strerror(errno));
- Net::smConnectionNotify.trigger(currentSock->fd, Net::Disconnected);
- removeSock = true;
- }
- break;
- case ::NameLookupRequired:
- // is the lookup complete?
- if (!gNetAsync.checkLookup(
- currentSock->fd, out_h_addr, &out_h_length,
- sizeof(out_h_addr)))
- break;
- U32 newState;
- if (out_h_length == -1)
- {
- Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);
- newState = Net::DNSFailed;
- removeSock = true;
- }
- else
- {
- // try to connect
- dMemcpy(&(ipAddr.sin_addr.s_addr), out_h_addr, out_h_length);
- ipAddr.sin_port = currentSock->remotePort;
- ipAddr.sin_family = AF_INET;
- if(::connect(currentSock->fd, (struct sockaddr *)&ipAddr,
- sizeof(ipAddr)) == -1)
- {
- S32 errorCode;
- #if defined(TORQUE_USE_WINSOCK)
- errorCode = WSAGetLastError();
- if( errorCode == WSAEINPROGRESS || errorCode == WSAEWOULDBLOCK )
- #else
- errorCode = errno;
- if (errno == EINPROGRESS)
- #endif
- {
- newState = Net::DNSResolved;
- currentSock->state = ::ConnectionPending;
- }
- else
- {
- const char* errorString;
- #if defined(TORQUE_USE_WINSOCK)
- errorString = strerror_wsa( errorCode );
- #else
- errorString = strerror( errorCode );
- #endif
- Con::errorf("Error connecting to %s: %s (%i)",
- currentSock->remoteAddr, errorString, errorCode);
- newState = Net::ConnectFailed;
- removeSock = true;
- }
- }
- else
- {
- newState = Net::Connected;
- currentSock->state = Net::Connected;
- }
- }
- Net::smConnectionNotify.trigger(currentSock->fd, newState);
- break;
- case ::Listening:
- NetAddress incomingAddy;
- incoming = Net::accept(currentSock->fd, &incomingAddy);
- if(incoming != InvalidSocket)
- {
- setBlocking(incoming, false);
- addPolledSocket(incoming, Connected);
- Net::smConnectionAccept.trigger(currentSock->fd, incoming, incomingAddy);
- }
- break;
- }
- // only increment index if we're not removing the connection, since
- // the removal will shift the indices down by one
- if (removeSock)
- closeConnectTo(currentSock->fd);
- else
- i++;
- }
- }
- NetSocket Net::openSocket()
- {
- NetSocket retSocket;
- retSocket = socket(AF_INET, SOCK_STREAM, 0);
- if(retSocket == InvalidSocket)
- return InvalidSocket;
- else
- return retSocket;
- }
- Net::Error Net::closeSocket(NetSocket socket)
- {
- if(socket != InvalidSocket)
- {
- if(!closesocket(socket))
- return NoError;
- else
- return getLastError();
- }
- else
- return NotASocket;
- }
- Net::Error Net::connect(NetSocket socket, const NetAddress *address)
- {
- if(address->type != NetAddress::IPAddress)
- return WrongProtocolType;
- sockaddr_in socketAddress;
- netToIPSocketAddress(address, &socketAddress);
- if(!::connect(socket, (sockaddr *) &socketAddress, sizeof(socketAddress)))
- return NoError;
- return getLastError();
- }
- Net::Error Net::listen(NetSocket socket, S32 backlog)
- {
- if(!::listen(socket, backlog))
- return NoError;
- return getLastError();
- }
- NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
- {
- sockaddr_in socketAddress;
- socklen_t addrLen = sizeof(socketAddress);
- NetSocket retVal = ::accept(acceptSocket, (sockaddr *) &socketAddress, &addrLen);
- if(retVal != InvalidSocket)
- {
- IPSocketToNetAddress(&socketAddress, remoteAddress);
- return retVal;
- }
- return InvalidSocket;
- }
- Net::Error Net::bind(NetSocket socket, U16 port)
- {
- S32 error;
- sockaddr_in socketAddress;
- dMemset((char *)&socketAddress, 0, sizeof(socketAddress));
- socketAddress.sin_family = AF_INET;
- // It's entirely possible that there are two NIC cards.
- // We let the user specify which one the server runs on.
- // thanks to [TPG]P1aGu3 for the name
- const char* serverIP = Con::getVariable( "pref::Net::BindAddress" );
- // serverIP is guaranteed to be non-0.
- AssertFatal( serverIP, "serverIP is NULL!" );
- if( serverIP[0] != '\0' ) {
- // we're not empty
- socketAddress.sin_addr.s_addr = inet_addr( serverIP );
- if( socketAddress.sin_addr.s_addr != INADDR_NONE ) {
- Con::printf( "Binding server port to %s", serverIP );
- } else {
- Con::warnf( ConsoleLogEntry::General,
- "inet_addr() failed for %s while binding!",
- serverIP );
- socketAddress.sin_addr.s_addr = INADDR_ANY;
- }
- } else {
- Con::printf( "Binding server port to default IP" );
- socketAddress.sin_addr.s_addr = INADDR_ANY;
- }
- socketAddress.sin_port = htons(port);
- error = ::bind(socket, (sockaddr *) &socketAddress, sizeof(socketAddress));
- if(!error)
- return NoError;
- return getLastError();
- }
- Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
- {
- S32 error;
- error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
- if(!error)
- error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
- if(!error)
- return NoError;
- return getLastError();
- }
- Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
- {
- S32 bc = broadcast;
- S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
- if(!error)
- return NoError;
- return getLastError();
- }
- Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
- {
- unsigned long notblock = !blockingIO;
- S32 error = ioctl(socket, FIONBIO, ¬block);
- if(!error)
- return NoError;
- return getLastError();
- }
- Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
- {
- errno = 0;
- S32 bytesWritten = ::send(socket, (const char*)buffer, bufferSize, 0);
- if(bytesWritten == -1)
- #if defined(TORQUE_USE_WINSOCK)
- Con::errorf("Could not write to socket. Error: %s",strerror_wsa( WSAGetLastError() ));
- #else
- Con::errorf("Could not write to socket. Error: %s",strerror(errno));
- #endif
- return getLastError();
- }
- Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead)
- {
- *bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0);
- if(*bytesRead == -1)
- return getLastError();
- return NoError;
- }
- bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
- {
- if((a1->type != a2->type) ||
- (*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
- (a1->port != a2->port))
- return false;
- if(a1->type == NetAddress::IPAddress)
- return true;
- for(S32 i = 0; i < 6; i++)
- if(a1->nodeNum[i] != a2->nodeNum[i])
- return false;
- return true;
- }
- bool Net::stringToAddress(const char *addressString, NetAddress *address)
- {
- if(!dStrnicmp(addressString, "ipx:", 4))
- // ipx support deprecated
- return false;
- if(!dStrnicmp(addressString, "ip:", 3))
- addressString += 3; // eat off the ip:
- sockaddr_in ipAddr;
- char remoteAddr[256];
- if(strlen(addressString) > 255)
- return false;
- dStrcpy(remoteAddr, addressString);
- char *portString = dStrchr(remoteAddr, ':');
- if(portString)
- *portString++ = '\0';
- if(!dStricmp(remoteAddr, "broadcast"))
- ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
- else
- {
- ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);
- if (ipAddr.sin_addr.s_addr == INADDR_NONE) // error
- {
- // On the Xbox, 'gethostbyname' does not exist so...
- #ifndef TORQUE_OS_XENON
- struct hostent *hp;
- if((hp = gethostbyname(remoteAddr)) == 0)
- return false;
- else
- memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr));
- #else
- // On the Xbox do XNetDnsLookup
- XNDNS *pxndns = NULL;
- HANDLE hEvent = CreateEvent(NULL, false, false, NULL);
- XNetDnsLookup(remoteAddr, hEvent, &pxndns);
- // Wait for event (passing NULL as a handle to XNetDnsLookup will NOT
- // cause it to behave synchronously, so do not remove the handle/wait
- while(pxndns->iStatus == WSAEINPROGRESS)
- WaitForSingleObject(hEvent, INFINITE);
- bool foundAddr = pxndns->iStatus == 0 && pxndns->cina > 0;
- if(foundAddr)
- {
- // Lets just grab the first address returned, for now
- memcpy(&ipAddr.sin_addr, pxndns->aina, sizeof(IN_ADDR));
- }
- XNetDnsRelease(pxndns);
- CloseHandle(hEvent);
- // If we didn't successfully resolve the DNS lookup, bail after the
- // handles are released
- if(!foundAddr)
- return false;
- #endif
- }
- }
- if(portString)
- ipAddr.sin_port = htons(dAtoi(portString));
- else
- ipAddr.sin_port = htons(defaultPort);
- ipAddr.sin_family = AF_INET;
- IPSocketToNetAddress(&ipAddr, address);
- return true;
- }
- void Net::addressToString(const NetAddress *address, char addressString[256])
- {
- if(address->type == NetAddress::IPAddress)
- {
- sockaddr_in ipAddr;
- netToIPSocketAddress(address, &ipAddr);
- if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST))
- dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
- else
- {
- #ifndef TORQUE_OS_XENON
- dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr),
- ntohs(ipAddr.sin_port));
- #else
- dSprintf(addressString, 256, "IP:%d.%d.%d.%d:%d", ipAddr.sin_addr.s_net,
- ipAddr.sin_addr.s_host, ipAddr.sin_addr.s_lh,
- ipAddr.sin_addr.s_impno, ntohs( ipAddr.sin_port ) );
- #endif
- }
- }
- else
- {
- *addressString = 0;
- return;
- }
- }
|