x86UNIXNet.cpp

Engine/source/platformX86UNIX/x86UNIXNet.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23#if 0
 24
 25#include "platformX86UNIX/platformX86UNIX.h"
 26#include "platform/platform.h"
 27#include "platform/event.h"
 28#include "platform/platformNetAsync.h"
 29
 30#include <unistd.h>
 31#include <sys/types.h>
 32#include <sys/socket.h>
 33#include <sys/poll.h>
 34#include <arpa/inet.h>
 35#include <netdb.h>
 36#include <netinet/in.h>
 37#include <errno.h>
 38
 39/* for PROTO_IPX */
 40#if defined(__linux__)
 41#include <net/if_ppp.h>
 42#include <sys/ioctl.h>   /* ioctl() */
 43#include <net/ppp_defs.h>
 44#elif defined(__OpenBSD__) || defined(__FreeBSD__)
 45#include <sys/ioctl.h>   /* ioctl() */
 46#include <net/ppp_defs.h>
 47#endif
 48
 49#include <netipx/ipx.h>
 50#include <stdlib.h>
 51
 52#include "console/console.h"
 53#include "platform/gameInterface.h"
 54#include "core/fileStream.h"
 55#include "core/tVector.h"
 56
 57static Net::Error getLastError();
 58static S32 defaultPort = 28000;
 59static S32 netPort = 0;
 60static int ipxSocket = InvalidSocket;
 61static int udpSocket = InvalidSocket;
 62
 63// local enum for socket states for polled sockets
 64enum SocketState
 65{
 66   InvalidState,
 67   Connected,
 68   ConnectionPending,
 69   Listening,
 70   NameLookupRequired
 71};
 72
 73// the Socket structure helps us keep track of the
 74// above states
 75struct Socket
 76{
 77      Socket()
 78      {
 79         fd = InvalidSocket;
 80         state = InvalidState;
 81         remoteAddr[0] = 0;
 82         remotePort = -1;
 83      }
 84
 85      NetSocket fd;
 86      S32 state;
 87      char remoteAddr[256];
 88      S32 remotePort;
 89};
 90
 91// list of polled sockets
 92static Vector<Socket*> gPolledSockets;
 93
 94static Socket* addPolledSocket(NetSocket& fd, S32 state,
 95                               char* remoteAddr = NULL, S32 port = -1)
 96{
 97   Socket* sock = new Socket();
 98   sock->fd = fd;
 99   sock->state = state;
100   if (remoteAddr)
101      dStrcpy(sock->remoteAddr, remoteAddr, 256);
102   if (port != -1)
103      sock->remotePort = port;
104   gPolledSockets.push_back(sock);
105   return sock;
106}
107
108enum {
109   MaxConnections = 1024,
110};
111
112S32 Poll(NetSocket fd, S32 eventMask, S32 timeoutMs)
113{
114   pollfd pfd;
115   S32 retVal;
116   pfd.fd = fd;
117   pfd.events = eventMask;
118
119   retVal = poll(&pfd, 1, timeoutMs);
120   return retVal;
121   if (retVal <= 0)
122      return retVal;
123   else
124      return pfd.revents;
125}
126
127bool Net::init()
128{
129   NetAsync::startAsync();
130   return(true);
131}
132
133void Net::shutdown()
134{
135   while (gPolledSockets.size() > 0)
136      closeConnectTo(gPolledSockets[0]->fd);
137   
138   closePort();
139   NetAsync::stopAsync();
140}
141
142static void netToIPSocketAddress(const NetAddress *address, struct sockaddr_in *sockAddr)
143{
144   dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
145   sockAddr->sin_family = AF_INET;
146   sockAddr->sin_port = htons(address->port);
147   char tAddr[20];
148   dSprintf(tAddr, 20, "%d.%d.%d.%d\n", address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3]);
149//fprintf(stdout,"netToIPSocketAddress(): %s\n",tAddr);fflush(NULL);
150   sockAddr->sin_addr.s_addr = inet_addr(tAddr);
151//   sockAddr->sin_addr.s_addr = address->netNum[0];  // hopefully this will work.
152}
153
154static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
155{
156   address->type = NetAddress::IPAddress;
157   address->port = htons(sockAddr->sin_port);
158   char *tAddr;
159   tAddr = inet_ntoa(sockAddr->sin_addr);
160//fprintf(stdout,"IPSocketToNetAddress(): %s\n",tAddr);fflush(NULL);
161   U8 nets[4];
162   nets[0] = atoi(strtok(tAddr, "."));
163   nets[1] = atoi(strtok(NULL, "."));
164   nets[2] = atoi(strtok(NULL, "."));
165   nets[3] = atoi(strtok(NULL, "."));
166//fprintf(stdout,"0 = %d, 1 = %d, 2 = %d, 3 = %d\n", nets[0], nets[1], nets[2], nets[3]);
167   address->netNum[0] = nets[0];
168   address->netNum[1] = nets[1];
169   address->netNum[2] = nets[2];
170   address->netNum[3] = nets[3];
171}
172
173static void netToIPXSocketAddress(const NetAddress *address, sockaddr_ipx *sockAddr)
174{
175#if !defined(__FreeBSD__)
176   dMemset(sockAddr, 0, sizeof(sockaddr_ipx));
177   sockAddr->sipx_family = AF_INET;
178   sockAddr->sipx_port = htons(address->port);
179   sockAddr->sipx_network = address->netNum[0];
180   sockAddr->sipx_node[0] = address->nodeNum[0];
181   sockAddr->sipx_node[1] = address->nodeNum[1];
182   sockAddr->sipx_node[2] = address->nodeNum[2];
183   sockAddr->sipx_node[3] = address->nodeNum[3];
184   sockAddr->sipx_node[4] = address->nodeNum[4];
185   sockAddr->sipx_node[5] = address->nodeNum[5];
186#endif
187}
188
189static void IPXSocketToNetAddress(const sockaddr_ipx *sockAddr, NetAddress *address)
190{
191#if !defined(__FreeBSD__)
192   address->type = NetAddress::IPXAddress;
193   address->port = htons(sockAddr->sipx_port);
194   address->netNum[0]  = sockAddr->sipx_network;
195   address->nodeNum[0] = sockAddr->sipx_node[0];
196   address->nodeNum[1] = sockAddr->sipx_node[1];
197   address->nodeNum[2] = sockAddr->sipx_node[2];
198   address->nodeNum[3] = sockAddr->sipx_node[3];
199   address->nodeNum[4] = sockAddr->sipx_node[4];
200   address->nodeNum[5] = sockAddr->sipx_node[5];
201#endif
202}
203
204NetSocket Net::openListenPort(U16 port)
205{
206   if(Game->isJournalReading())
207   {
208      U32 ret;
209      Game->journalRead(&ret);
210      return NetSocket(ret);
211   }
212   NetSocket sock = openSocket();
213   if (sock == InvalidSocket)
214   {
215      Con::errorf("Unable to open listen socket: %s", strerror(errno));
216      return InvalidSocket;
217   }
218
219   if (bind(sock, port) != NoError)
220   {
221      Con::errorf("Unable to bind port %d: %s", port, strerror(errno));
222      ::close(sock);
223      return InvalidSocket;
224   }
225   if (listen(sock, 4) != NoError)
226   {
227      Con::errorf("Unable to listen on port %d: %s", port, strerror(errno));
228      ::close(sock);
229      return InvalidSocket;
230   }
231
232   setBlocking(sock, false);
233   addPolledSocket(sock, Listening);
234   if (Game->isJournalWriting())
235      Game->journalWrite(U32(sock));
236   return sock;
237}
238
239NetSocket Net::openConnectTo(const char *addressString)
240{
241   if(!dStrnicmp(addressString, "ipx:", 4))
242      return InvalidSocket;
243   if(!dStrnicmp(addressString, "ip:", 3))
244      addressString += 3;  // eat off the ip:
245   char remoteAddr[256];
246   dStrcpy(remoteAddr, addressString, 256);
247      
248   char *portString = dStrchr(remoteAddr, ':');
249
250   U16 port;
251   if(portString)
252   {
253      *portString++ = 0;
254      port = htons(dAtoi(portString));
255   }
256   else
257      port = htons(defaultPort);
258
259   if(!dStricmp(remoteAddr, "broadcast"))
260      return InvalidSocket;
261
262   if(Game->isJournalReading())
263   {
264      U32 ret;
265      Game->journalRead(&ret);
266      return NetSocket(ret);
267   }
268   NetSocket sock = openSocket();
269   setBlocking(sock, false);
270
271   sockaddr_in ipAddr;
272   dMemset(&ipAddr, 0, sizeof(ipAddr));
273   
274   if (inet_aton(remoteAddr, &ipAddr.sin_addr) != 0)
275   {
276      ipAddr.sin_port = port;
277      ipAddr.sin_family = AF_INET;
278      if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1 &&
279         errno != EINPROGRESS)
280      {
281         Con::errorf("Error connecting %s: %s", 
282           addressString, strerror(errno));
283         ::close(sock);
284         sock = InvalidSocket;
285      }
286      if(sock != InvalidSocket) {
287         // add this socket to our list of polled sockets
288         addPolledSocket(sock, ConnectionPending);
289      }
290   }
291   else
292   {
293      // need to do an asynchronous name lookup.  first, add the socket
294      // to the polled list
295      addPolledSocket(sock, NameLookupRequired, remoteAddr, port);
296      // queue the lookup
297      gNetAsync.queueLookup(remoteAddr, sock);
298   }
299   if(Game->isJournalWriting())
300      Game->journalWrite(U32(sock));
301   return sock;
302}
303
304void Net::closeConnectTo(NetSocket sock)
305{
306   if(Game->isJournalReading())
307      return;
308
309   // if this socket is in the list of polled sockets, remove it
310   for (int i = 0; i < gPolledSockets.size(); ++i)
311      if (gPolledSockets[i]->fd == sock)
312      {
313         delete gPolledSockets[i];
314         gPolledSockets.erase(i);
315         break;
316      }
317   
318   closeSocket(sock);
319}
320
321Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, int bufferSize)
322{
323   if(Game->isJournalReading())
324   {
325      U32 e;
326      Game->journalRead(&e);
327      
328      return (Net::Error) e;
329   }
330   Net::Error e = send(socket, buffer, bufferSize);
331   if(Game->isJournalWriting())
332      Game->journalWrite(U32(e));
333   return e;
334}
335
336bool Net::openPort(S32 port)
337{
338   if(udpSocket != InvalidSocket)
339      close(udpSocket);
340   if(ipxSocket != InvalidSocket)
341      close(ipxSocket);
342      
343   udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
344   ipxSocket = socket(AF_IPX, SOCK_DGRAM, 0);
345
346   if(udpSocket != InvalidSocket)
347   {
348      Net::Error error;
349      error = bind(udpSocket, port);
350      if(error == NoError)
351         error = setBufferSize(udpSocket, 32768);
352      if(error == NoError)
353         error = setBroadcast(udpSocket, true);
354      if(error == NoError)
355         error = setBlocking(udpSocket, false);
356      if(error == NoError)
357         Con::printf("UDP initialized on port %d", port);
358      else
359      {
360         close(udpSocket);
361         udpSocket = InvalidSocket;
362         Con::printf("Unable to initialize UDP - error %d", error);
363      }
364   }
365   if(ipxSocket != InvalidSocket)
366   {
367      Net::Error error = NoError;
368      sockaddr_ipx ipxAddress;   
369      memset((char *)&ipxAddress, 0, sizeof(ipxAddress));
370      ipxAddress.sipx_family = AF_IPX;
371      ipxAddress.sipx_port = htons(port);
372      S32 err = ::bind(ipxSocket, (struct sockaddr *)&ipxAddress, sizeof(ipxAddress));
373      if(err)
374         error = getLastError();
375      if(error == NoError)
376         error = setBufferSize(ipxSocket, 32768);
377      if(error == NoError)
378         error = setBroadcast(ipxSocket, true);
379      if(error == NoError)
380         error = setBlocking(ipxSocket, false);
381      if(error == NoError)
382         Con::printf("IPX initialized on port %d", port);
383      else
384      {
385         close(ipxSocket);
386         ipxSocket = InvalidSocket;
387         Con::printf("Unable to initialize IPX - error %d", error);
388      }
389   }
390   netPort = port;
391   return ipxSocket != InvalidSocket || udpSocket != InvalidSocket;
392}
393
394void Net::closePort()
395{
396   if(ipxSocket != InvalidSocket)
397      close(ipxSocket);
398   if(udpSocket != InvalidSocket)
399      close(udpSocket);
400}
401
402Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
403{
404   if(Game->isJournalReading())
405      return NoError;
406
407   if(address->type == NetAddress::IPXAddress)
408   {
409      sockaddr_ipx ipxAddr;
410      netToIPXSocketAddress(address, &ipxAddr);
411      if(::sendto(ipxSocket, (const char*)buffer, bufferSize, 0,
412                  (sockaddr *) &ipxAddr, sizeof(sockaddr_ipx)) == -1)
413         return getLastError();
414      else
415         return NoError;
416   }
417   else
418   {
419      sockaddr_in ipAddr;
420      netToIPSocketAddress(address, &ipAddr);
421      if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
422                  (sockaddr *) &ipAddr, sizeof(sockaddr_in)) == -1)
423         return getLastError();
424      else
425         return NoError;
426   }
427}
428
429void Net::process()
430{
431   sockaddr sa;
432
433   PacketReceiveEvent receiveEvent;
434   for(;;)
435   {
436      U32 addrLen = sizeof(sa);
437      S32 bytesRead = -1;
438      if(udpSocket != InvalidSocket)
439         bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
440      if(bytesRead == -1 && ipxSocket != InvalidSocket)
441      {
442         addrLen = sizeof(sa);
443         bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
444      }
445      
446      if(bytesRead == -1)
447         break;
448      
449      if(sa.sa_family == AF_INET)
450         IPSocketToNetAddress((sockaddr_in *) &sa, &receiveEvent.sourceAddress);
451      else if(sa.sa_family == AF_IPX)
452         IPXSocketToNetAddress((sockaddr_ipx *) &sa, &receiveEvent.sourceAddress);
453      else
454         continue;
455         
456      NetAddress &na = receiveEvent.sourceAddress;
457      if(na.type == NetAddress::IPAddress &&
458         na.netNum[0] == 127 &&
459         na.netNum[1] == 0 &&
460         na.netNum[2] == 0 &&
461         na.netNum[3] == 1 &&
462         na.port == netPort)
463         continue;
464      if(bytesRead <= 0)
465         continue;
466      receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead;
467      Game->postEvent(receiveEvent);
468   }
469
470   // process the polled sockets.  This blob of code performs functions
471   // similar to WinsockProc in winNet.cc
472
473   if (gPolledSockets.size() == 0)
474      return;
475
476   static ConnectedNotifyEvent notifyEvent;
477   static ConnectedAcceptEvent acceptEvent;
478   static ConnectedReceiveEvent cReceiveEvent;
479
480   S32 optval;
481   socklen_t optlen = sizeof(S32);
482   S32 bytesRead;
483   Net::Error err;
484   bool removeSock = false;
485   Socket *currentSock = NULL;
486   sockaddr_in ipAddr;
487   NetSocket incoming = InvalidSocket;
488   char out_h_addr[1024];
489   int out_h_length = 0;
490
491   for (S32 i = 0; i < gPolledSockets.size(); 
492        /* no increment, this is done at end of loop body */)
493   {
494      removeSock = false;
495      currentSock = gPolledSockets[i];
496      switch (currentSock->state)
497      {
498         case InvalidState:
499            Con::errorf("Error, InvalidState socket in polled sockets list");
500            break;
501         case ConnectionPending:
502            notifyEvent.tag = currentSock->fd;
503            // see if it is now connected
504            if (getsockopt(currentSock->fd, SOL_SOCKET, SO_ERROR, 
505                           &optval, &optlen) == -1)
506            {
507               Con::errorf("Error getting socket options: %s", strerror(errno));
508               notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
509               Game->postEvent(notifyEvent);
510               removeSock = true;
511            }
512            else
513            {
514               if (optval == EINPROGRESS)
515                  // still connecting...
516                  break;
517
518               if (optval == 0)
519               {
520                  // connected
521                  notifyEvent.state = ConnectedNotifyEvent::Connected;
522                  Game->postEvent(notifyEvent);
523                  currentSock->state = Connected;
524               }
525               else
526               {
527                  // some kind of error
528                  Con::errorf("Error connecting: %s", strerror(errno));
529                  notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
530                  Game->postEvent(notifyEvent);
531                  removeSock = true;
532               }
533            }
534            break;
535         case Connected:
536            bytesRead = 0;
537            // try to get some data
538            err = Net::recv(currentSock->fd, cReceiveEvent.data, 
539                            MaxPacketDataSize, &bytesRead);
540            if(err == Net::NoError)
541            {
542               if (bytesRead > 0)
543               {
544                  // got some data, post it
545                  cReceiveEvent.tag = currentSock->fd;
546                  cReceiveEvent.size = ConnectedReceiveEventHeaderSize + 
547                     bytesRead;
548                  Game->postEvent(cReceiveEvent);
549               }
550               else 
551               {
552                  // zero bytes read means EOF
553                  if (bytesRead < 0)
554                     // ack! this shouldn't happen
555                     Con::errorf("Unexpected error on socket: %s", 
556                                 strerror(errno));
557
558                  notifyEvent.tag = currentSock->fd;
559                  notifyEvent.state = ConnectedNotifyEvent::Disconnected;
560                  Game->postEvent(notifyEvent);
561                  removeSock = true;
562               }
563            }
564            else if (err != Net::NoError && err != Net::WouldBlock)
565            {
566               Con::errorf("Error reading from socket: %s", strerror(errno));
567               notifyEvent.tag = currentSock->fd;
568               notifyEvent.state = ConnectedNotifyEvent::Disconnected;
569               Game->postEvent(notifyEvent);
570               removeSock = true;
571            }
572            break;
573         case NameLookupRequired:
574            // is the lookup complete?
575            if (!gNetAsync.checkLookup(
576                   currentSock->fd, out_h_addr, &out_h_length, 
577                   sizeof(out_h_addr)))
578               break;
579            
580            notifyEvent.tag = currentSock->fd;
581            if (out_h_length == -1)
582            {
583               Con::errorf("DNS lookup failed: %s", currentSock->remoteAddr);
584               notifyEvent.state = ConnectedNotifyEvent::DNSFailed;
585               removeSock = true;
586            }
587            else
588            {
589               // try to connect
590               dMemcpy(&(ipAddr.sin_addr.s_addr), out_h_addr, out_h_length);
591               ipAddr.sin_port = currentSock->remotePort;
592               ipAddr.sin_family = AF_INET;
593               if(::connect(currentSock->fd, (struct sockaddr *)&ipAddr, 
594                            sizeof(ipAddr)) == -1)
595               {
596                  if (errno == EINPROGRESS)
597                  {
598                     notifyEvent.state = ConnectedNotifyEvent::DNSResolved;
599                     currentSock->state = ConnectionPending;
600                  }
601                  else
602                  {
603                     Con::errorf("Error connecting to %s: %s", 
604                                 currentSock->remoteAddr, strerror(errno));
605                     notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
606                     removeSock = true;
607                  }
608               }
609               else
610               {
611                  notifyEvent.state = ConnectedNotifyEvent::Connected;
612                  currentSock->state = Connected;
613               }
614            }
615            Game->postEvent(notifyEvent);       
616            break;
617       case Listening:
618            incoming = 
619               Net::accept(currentSock->fd, &acceptEvent.address);
620            if(incoming != InvalidSocket)
621            {
622               acceptEvent.portTag = currentSock->fd;
623               acceptEvent.connectionTag = incoming;
624               setBlocking(incoming, false);
625               addPolledSocket(incoming, Connected);
626               Game->postEvent(acceptEvent);
627            }
628            break;
629      }
630
631      // only increment index if we're not removing the connection, since 
632      // the removal will shift the indices down by one
633      if (removeSock)
634         closeConnectTo(currentSock->fd);
635      else
636         i++;
637   }
638}
639                 
640NetSocket Net::openSocket()
641{
642   int retSocket;
643   retSocket = socket(AF_INET, SOCK_STREAM, 0);
644
645   if(retSocket == InvalidSocket)
646      return InvalidSocket;
647   else
648      return retSocket;
649}
650
651Net::Error Net::closeSocket(NetSocket socket)
652{
653   if(socket != InvalidSocket)
654   {
655      if(!close(socket))
656         return NoError;
657      else
658         return getLastError();
659   }
660   else
661      return NotASocket;
662}
663
664Net::Error Net::connect(NetSocket socket, const NetAddress *address)
665{
666   if(address->type != NetAddress::IPAddress)
667      return WrongProtocolType;
668   sockaddr_in socketAddress;
669   netToIPSocketAddress(address, &socketAddress);
670   if(!::connect(socket, (sockaddr *) &socketAddress, sizeof(socketAddress)))
671      return NoError;
672   return getLastError();
673}
674
675Net::Error Net::listen(NetSocket socket, S32 backlog)
676{
677   if(!::listen(socket, backlog))
678      return NoError;
679   return getLastError();
680}
681
682NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
683{
684   sockaddr_in socketAddress;
685   U32 addrLen = sizeof(socketAddress);
686   
687   int retVal = ::accept(acceptSocket, (sockaddr *) &socketAddress, &addrLen);
688   if(retVal != InvalidSocket)
689   {
690      IPSocketToNetAddress(&socketAddress, remoteAddress);
691      return retVal;
692   }
693   return InvalidSocket;
694}
695
696Net::Error Net::bind(NetSocket socket, U16 port)
697{
698   S32 error;
699   
700   sockaddr_in socketAddress;
701   dMemset((char *)&socketAddress, 0, sizeof(socketAddress));
702   socketAddress.sin_family = AF_INET;
703   // It's entirely possible that there are two NIC cards.
704   // We let the user specify which one the server runs on.
705
706   // thanks to [TPG]P1aGu3 for the name
707   const char* serverIP = Con::getVariable( "Pref::Net::BindAddress" );
708   // serverIP is guaranteed to be non-0.
709   AssertFatal( serverIP, "serverIP is NULL!" );
710
711   if( serverIP[0] != '\0' ) {
712      // we're not empty
713      socketAddress.sin_addr.s_addr = inet_addr( serverIP );
714
715      if( socketAddress.sin_addr.s_addr != INADDR_NONE ) {
716    Con::printf( "Binding server port to %s", serverIP );
717      } else {
718    Con::warnf( ConsoleLogEntry::General,
719           "inet_addr() failed for %s while binding!",
720           serverIP );
721    socketAddress.sin_addr.s_addr = INADDR_ANY;
722      }
723
724   } else {
725      Con::printf( "Binding server port to default IP" );
726      socketAddress.sin_addr.s_addr = INADDR_ANY;
727   }
728
729   socketAddress.sin_port = htons(port);
730   error = ::bind(socket, (sockaddr *) &socketAddress, sizeof(socketAddress));
731
732   if(!error)
733      return NoError;
734   return getLastError();
735}
736
737Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
738{
739   S32 error;
740   error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
741   if(!error)
742      error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
743   if(!error)
744      return NoError;
745   return getLastError();
746}
747
748Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
749{
750   S32 bc = broadcast;
751   S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
752   if(!error)
753      return NoError;
754   return getLastError();   
755}
756
757Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
758{
759   int notblock = !blockingIO;
760   S32 error = ioctl(socket, FIONBIO, &notblock);
761   if(!error)
762      return NoError;
763   return getLastError();   
764}
765
766Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
767{
768   // Poll for write status.  this blocks.  should really
769   // do this in a separate thread or set it up so that the data can
770   // get queued and sent later
771   // JMQTODO
772   Poll(socket, POLLOUT, 10000);
773
774   S32 error = ::send(socket, (const char*)buffer, bufferSize, 0);
775   if(error != -1)
776      return NoError;
777
778   return getLastError();
779}
780
781Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead)
782{
783   *bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0);
784   if(*bytesRead == -1)
785      return getLastError();
786   return NoError;
787}
788
789bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
790{
791   if((a1->type != a2->type)  || 
792      (*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
793      (a1->port != a2->port))
794      return false;
795
796   if(a1->type == NetAddress::IPAddress)
797      return true;
798   for(S32 i = 0; i < 6; i++)
799      if(a1->nodeNum[i] != a2->nodeNum[i])
800         return false;
801   return true;
802}
803
804bool Net::stringToAddress(const char *addressString, NetAddress *address)
805{
806   if(dStrnicmp(addressString, "ipx:", 4))
807   {
808      // assume IP if it doesn't have ipx: at the front.
809      
810      if(!dStrnicmp(addressString, "ip:", 3))
811         addressString += 3;  // eat off the ip:
812      
813      sockaddr_in ipAddr;
814      char remoteAddr[256];
815      if(strlen(addressString) > 255)
816         return false;
817         
818      dStrcpy(remoteAddr, addressString, 256);
819         
820      char *portString = dStrchr(remoteAddr, ':');
821      if(portString)
822         *portString++ = '\0';
823      
824      struct hostent *hp;
825      if(!dStricmp(remoteAddr, "broadcast"))
826         ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
827      else
828      {
829         if (inet_aton(remoteAddr,&ipAddr.sin_addr) == 0) // error
830         {
831            if((hp = gethostbyname(remoteAddr)) == 0)
832               return false;
833            else
834               memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr));
835         }
836      }
837      if(portString)
838         ipAddr.sin_port = htons(dAtoi(portString));
839      else
840         ipAddr.sin_port = htons(defaultPort);
841      ipAddr.sin_family = AF_INET;
842      IPSocketToNetAddress(&ipAddr, address);
843      return true;
844   }
845   else
846   {
847      S32 i;
848      S32 port;
849
850      address->type = NetAddress::IPXAddress;      
851      for(i = 0; i < 6; i++)
852         address->nodeNum[i] = 0xFF;
853         
854      // it's an IPX string
855      addressString += 4;
856      if(!dStricmp(addressString, "broadcast"))
857      {
858         address->port = defaultPort;
859         return true;
860      }
861      else if(sscanf(addressString, "broadcast:%d", &port) == 1)
862      {
863         address->port = port;
864         return true;
865      }
866      else
867      {
868         S32 nodeNum[6];
869         S32 netNum[4];
870         S32 count = dSscanf(addressString, "%2x%2x%2x%2x:%2x%2x%2x%2x%2x%2x:%d",
871                             &netNum[0], &netNum[1], &netNum[2], &netNum[3],
872                             &nodeNum[0], &nodeNum[1], &nodeNum[2], &nodeNum[3], &nodeNum[4], &nodeNum[5], 
873                             &port);
874      
875         if(count == 10)
876         {
877            port = defaultPort;
878            count++;
879         }
880         if(count != 11)
881            return false;
882
883         for(i = 0; i < 6; i++)
884            address->nodeNum[i] = nodeNum[i];
885         for(i = 0; i < 4; i++)
886            address->netNum[i] = netNum[i];
887         address->port = port;
888         return true;
889      }
890   }
891}
892
893void Net::addressToString(const NetAddress *address, char addressString[256])
894{
895   if(address->type == NetAddress::IPAddress)
896   {
897      sockaddr_in ipAddr;
898      netToIPSocketAddress(address, &ipAddr);
899      
900      if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST))
901         dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
902      else
903         dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr),
904                  ntohs(ipAddr.sin_port));
905//         dSprintf(addressString, 256, "IP:%d:%d", ipAddr.sin_addr.s_addr,
906//            ntohs(ipAddr.sin_port));
907   }
908   else
909   {
910      return;
911      dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d",
912               address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3], 
913               address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5], 
914               address->port);
915   }
916}
917
918Net::Error getLastError()
919{
920   if (errno == EAGAIN)
921      return Net::WouldBlock;
922   return Net::UnknownError;
923}
924
925#endif
926