| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 | //-----------------------------------------------------------------------------// 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.//-----------------------------------------------------------------------------#if 0#include "platformX86UNIX/platformX86UNIX.h"#include "platform/platform.h"#include "platform/event.h"#include "platform/platformNetAsync.h"#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>/* for PROTO_IPX */#if defined(__linux__)#include <net/if_ppp.h>#include <sys/ioctl.h>   /* ioctl() */#include <net/ppp_defs.h>#elif defined(__OpenBSD__) || defined(__FreeBSD__)#include <sys/ioctl.h>   /* ioctl() */#include <net/ppp_defs.h>#endif#include <netipx/ipx.h>#include <stdlib.h>#include "console/console.h"#include "platform/gameInterface.h"#include "core/fileStream.h"#include "core/tVector.h"static Net::Error getLastError();static S32 defaultPort = 28000;static S32 netPort = 0;static int ipxSocket = InvalidSocket;static int udpSocket = InvalidSocket;// local enum for socket states for polled socketsenum SocketState{   InvalidState,   Connected,   ConnectionPending,   Listening,   NameLookupRequired};// the Socket structure helps us keep track of the// above statesstruct Socket{      Socket()      {         fd = InvalidSocket;         state = InvalidState;         remoteAddr[0] = 0;         remotePort = -1;      }      NetSocket fd;      S32 state;      char remoteAddr[256];      S32 remotePort;};// list of polled socketsstatic Vector<Socket*> gPolledSockets;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,};S32 Poll(NetSocket fd, S32 eventMask, S32 timeoutMs){   pollfd pfd;   S32 retVal;   pfd.fd = fd;   pfd.events = eventMask;   retVal = poll(&pfd, 1, timeoutMs);   return retVal;   if (retVal <= 0)      return retVal;   else      return pfd.revents;}bool Net::init(){   NetAsync::startAsync();   return(true);}void Net::shutdown(){   while (gPolledSockets.size() > 0)      closeConnectTo(gPolledSockets[0]->fd);      closePort();   NetAsync::stopAsync();}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\n", 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);//   sockAddr->sin_addr.s_addr = address->netNum[0];  // hopefully this will work.}static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address){   address->type = NetAddress::IPAddress;   address->port = htons(sockAddr->sin_port);   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];}static void netToIPXSocketAddress(const NetAddress *address, sockaddr_ipx *sockAddr){#if !defined(__FreeBSD__)   dMemset(sockAddr, 0, sizeof(sockaddr_ipx));   sockAddr->sipx_family = AF_INET;   sockAddr->sipx_port = htons(address->port);   sockAddr->sipx_network = address->netNum[0];   sockAddr->sipx_node[0] = address->nodeNum[0];   sockAddr->sipx_node[1] = address->nodeNum[1];   sockAddr->sipx_node[2] = address->nodeNum[2];   sockAddr->sipx_node[3] = address->nodeNum[3];   sockAddr->sipx_node[4] = address->nodeNum[4];   sockAddr->sipx_node[5] = address->nodeNum[5];#endif}static void IPXSocketToNetAddress(const sockaddr_ipx *sockAddr, NetAddress *address){#if !defined(__FreeBSD__)   address->type = NetAddress::IPXAddress;   address->port = htons(sockAddr->sipx_port);   address->netNum[0]  = sockAddr->sipx_network;   address->nodeNum[0] = sockAddr->sipx_node[0];   address->nodeNum[1] = sockAddr->sipx_node[1];   address->nodeNum[2] = sockAddr->sipx_node[2];   address->nodeNum[3] = sockAddr->sipx_node[3];   address->nodeNum[4] = sockAddr->sipx_node[4];   address->nodeNum[5] = sockAddr->sipx_node[5];#endif}NetSocket Net::openListenPort(U16 port){   if(Game->isJournalReading())   {      U32 ret;      Game->journalRead(&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));      ::close(sock);      return InvalidSocket;   }   if (listen(sock, 4) != NoError)   {      Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));      ::close(sock);      return InvalidSocket;   }   setBlocking(sock, false);   addPolledSocket(sock, Listening);   if (Game->isJournalWriting())      Game->journalWrite(U32(sock));   return sock;}NetSocket Net::openConnectTo(const char *addressString){   if(!dStrnicmp(addressString, "ipx:", 4))      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(Game->isJournalReading())   {      U32 ret;      Game->journalRead(&ret);      return NetSocket(ret);   }   NetSocket sock = openSocket();   setBlocking(sock, false);   sockaddr_in ipAddr;   dMemset(&ipAddr, 0, sizeof(ipAddr));      if (inet_aton(remoteAddr, &ipAddr.sin_addr) != 0)   {      ipAddr.sin_port = port;      ipAddr.sin_family = AF_INET;      if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1 &&         errno != EINPROGRESS)      {         Con::errorf("Error connecting %s: %s", 		     addressString, strerror(errno));         ::close(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(Game->isJournalWriting())      Game->journalWrite(U32(sock));   return sock;}void Net::closeConnectTo(NetSocket sock){   if(Game->isJournalReading())      return;   // if this socket is in the list of polled sockets, remove it   for (int 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, int bufferSize){   if(Game->isJournalReading())   {      U32 e;      Game->journalRead(&e);            return (Net::Error) e;   }   Net::Error e = send(socket, buffer, bufferSize);   if(Game->isJournalWriting())      Game->journalWrite(U32(e));   return e;}bool Net::openPort(S32 port){   if(udpSocket != InvalidSocket)      close(udpSocket);   if(ipxSocket != InvalidSocket)      close(ipxSocket);         udpSocket = socket(AF_INET, SOCK_DGRAM, 0);   ipxSocket = socket(AF_IPX, SOCK_DGRAM, 0);   if(udpSocket != InvalidSocket)   {      Net::Error error;      error = bind(udpSocket, port);      if(error == NoError)         error = setBufferSize(udpSocket, 32768);      if(error == NoError)         error = setBroadcast(udpSocket, true);      if(error == NoError)         error = setBlocking(udpSocket, false);      if(error == NoError)         Con::printf("UDP initialized on port %d", port);      else      {         close(udpSocket);         udpSocket = InvalidSocket;         Con::printf("Unable to initialize UDP - error %d", error);      }   }   if(ipxSocket != InvalidSocket)   {      Net::Error error = NoError;      sockaddr_ipx ipxAddress;         memset((char *)&ipxAddress, 0, sizeof(ipxAddress));      ipxAddress.sipx_family = AF_IPX;      ipxAddress.sipx_port = htons(port);      S32 err = ::bind(ipxSocket, (struct sockaddr *)&ipxAddress, sizeof(ipxAddress));      if(err)         error = getLastError();      if(error == NoError)         error = setBufferSize(ipxSocket, 32768);      if(error == NoError)         error = setBroadcast(ipxSocket, true);      if(error == NoError)         error = setBlocking(ipxSocket, false);      if(error == NoError)         Con::printf("IPX initialized on port %d", port);      else      {         close(ipxSocket);         ipxSocket = InvalidSocket;         Con::printf("Unable to initialize IPX - error %d", error);      }   }   netPort = port;   return ipxSocket != InvalidSocket || udpSocket != InvalidSocket;}void Net::closePort(){   if(ipxSocket != InvalidSocket)      close(ipxSocket);   if(udpSocket != InvalidSocket)      close(udpSocket);}Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize){   if(Game->isJournalReading())      return NoError;   if(address->type == NetAddress::IPXAddress)   {      sockaddr_ipx ipxAddr;      netToIPXSocketAddress(address, &ipxAddr);      if(::sendto(ipxSocket, (const char*)buffer, bufferSize, 0,                  (sockaddr *) &ipxAddr, sizeof(sockaddr_ipx)) == -1)         return getLastError();      else         return NoError;   }   else   {      sockaddr_in ipAddr;      netToIPSocketAddress(address, &ipAddr);      if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,                  (sockaddr *) &ipAddr, sizeof(sockaddr_in)) == -1)         return getLastError();      else         return NoError;   }}void Net::process(){   sockaddr sa;   PacketReceiveEvent receiveEvent;   for(;;)   {      U32 addrLen = sizeof(sa);      S32 bytesRead = -1;      if(udpSocket != InvalidSocket)         bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);      if(bytesRead == -1 && ipxSocket != InvalidSocket)      {         addrLen = sizeof(sa);         bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);      }            if(bytesRead == -1)         break;            if(sa.sa_family == AF_INET)         IPSocketToNetAddress((sockaddr_in *) &sa, &receiveEvent.sourceAddress);      else if(sa.sa_family == AF_IPX)         IPXSocketToNetAddress((sockaddr_ipx *) &sa, &receiveEvent.sourceAddress);      else         continue;               NetAddress &na = receiveEvent.sourceAddress;      if(na.type == NetAddress::IPAddress &&         na.netNum[0] == 127 &&         na.netNum[1] == 0 &&         na.netNum[2] == 0 &&         na.netNum[3] == 1 &&         na.port == netPort)         continue;      if(bytesRead <= 0)         continue;      receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead;      Game->postEvent(receiveEvent);   }   // process the polled sockets.  This blob of code performs functions   // similar to WinsockProc in winNet.cc   if (gPolledSockets.size() == 0)      return;   static ConnectedNotifyEvent notifyEvent;   static ConnectedAcceptEvent acceptEvent;   static ConnectedReceiveEvent cReceiveEvent;   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];   int out_h_length = 0;   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:            notifyEvent.tag = currentSock->fd;            // see if it is now connected            if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR,                            &optval, &optlen) == -1)            {               Con::errorf("Error getting socket options: %s", strerror(errno));               notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;               Game->postEvent(notifyEvent);               removeSock = true;            }            else            {               if (optval == EINPROGRESS)                  // still connecting...                  break;               if (optval == 0)               {                  // connected                  notifyEvent.state = ConnectedNotifyEvent::Connected;                  Game->postEvent(notifyEvent);                  currentSock->state = Connected;               }               else               {                  // some kind of error                  Con::errorf("Error connecting: %s", strerror(errno));                  notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;                  Game->postEvent(notifyEvent);                  removeSock = true;               }            }            break;         case Connected:            bytesRead = 0;            // try to get some data            err = Net::recv(currentSock->fd, cReceiveEvent.data,                             MaxPacketDataSize, &bytesRead);            if(err == Net::NoError)            {               if (bytesRead > 0)               {                  // got some data, post it                  cReceiveEvent.tag = currentSock->fd;                  cReceiveEvent.size = ConnectedReceiveEventHeaderSize +                      bytesRead;                  Game->postEvent(cReceiveEvent);               }               else                {                  // zero bytes read means EOF                  if (bytesRead < 0)                     // ack! this shouldn't happen                     Con::errorf("Unexpected error on socket: %s",                                  strerror(errno));                  notifyEvent.tag = currentSock->fd;                  notifyEvent.state = ConnectedNotifyEvent::Disconnected;                  Game->postEvent(notifyEvent);                  removeSock = true;               }            }            else if (err != Net::NoError && err != Net::WouldBlock)            {               Con::errorf("Error reading from socket: %s", strerror(errno));               notifyEvent.tag = currentSock->fd;               notifyEvent.state = ConnectedNotifyEvent::Disconnected;               Game->postEvent(notifyEvent);               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;                        notifyEvent.tag = currentSock->fd;            if (out_h_length == -1)            {               Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);               notifyEvent.state = ConnectedNotifyEvent::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)               {                  if (errno == EINPROGRESS)                  {                     notifyEvent.state = ConnectedNotifyEvent::DNSResolved;                     currentSock->state = ConnectionPending;                  }                  else                  {                     Con::errorf("Error connecting to %s: %s",                                  currentSock->remoteAddr, strerror(errno));                     notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;                     removeSock = true;                  }               }               else               {                  notifyEvent.state = ConnectedNotifyEvent::Connected;                  currentSock->state = Connected;               }            }            Game->postEvent(notifyEvent);			            break;    	 case Listening:            incoming =                Net::accept(currentSock->fd, &acceptEvent.address);            if(incoming != InvalidSocket)            {               acceptEvent.portTag = currentSock->fd;               acceptEvent.connectionTag = incoming;               setBlocking(incoming, false);               addPolledSocket(incoming, Connected);               Game->postEvent(acceptEvent);            }            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(){   int 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(!close(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;   U32 addrLen = sizeof(socketAddress);      int 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){   int 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){   // Poll for write status.  this blocks.  should really   // do this in a separate thread or set it up so that the data can   // get queued and sent later   // JMQTODO   Poll(socket, POLLOUT, 10000);   S32 error = ::send(socket, (const char*)buffer, bufferSize, 0);   if(error != -1)      return NoError;   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))   {      // assume IP if it doesn't have ipx: at the front.            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';            struct hostent *hp;      if(!dStricmp(remoteAddr, "broadcast"))         ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);      else      {         if (inet_aton(remoteAddr,&ipAddr.sin_addr) == 0) // error         {            if((hp = gethostbyname(remoteAddr)) == 0)               return false;            else               memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr));         }      }      if(portString)         ipAddr.sin_port = htons(dAtoi(portString));      else         ipAddr.sin_port = htons(defaultPort);      ipAddr.sin_family = AF_INET;      IPSocketToNetAddress(&ipAddr, address);      return true;   }   else   {      S32 i;      S32 port;      address->type = NetAddress::IPXAddress;            for(i = 0; i < 6; i++)         address->nodeNum[i] = 0xFF;               // it's an IPX string      addressString += 4;      if(!dStricmp(addressString, "broadcast"))      {         address->port = defaultPort;         return true;      }      else if(sscanf(addressString, "broadcast:%d", &port) == 1)      {         address->port = port;         return true;      }      else      {         S32 nodeNum[6];         S32 netNum[4];         S32 count = dSscanf(addressString, "%2x%2x%2x%2x:%2x%2x%2x%2x%2x%2x:%d",                             &netNum[0], &netNum[1], &netNum[2], &netNum[3],                             &nodeNum[0], &nodeNum[1], &nodeNum[2], &nodeNum[3], &nodeNum[4], &nodeNum[5],                              &port);               if(count == 10)         {            port = defaultPort;            count++;         }         if(count != 11)            return false;         for(i = 0; i < 6; i++)            address->nodeNum[i] = nodeNum[i];         for(i = 0; i < 4; i++)            address->netNum[i] = netNum[i];         address->port = port;         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         dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr),                  ntohs(ipAddr.sin_port));//         dSprintf(addressString, 256, "IP:%d:%d", ipAddr.sin_addr.s_addr,//            ntohs(ipAddr.sin_port));   }   else   {      return;      dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d",               address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3],                address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5],                address->port);   }}Net::Error getLastError(){   if (errno == EAGAIN)      return Net::WouldBlock;   return Net::UnknownError;}#endif
 |