net.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "net.h"
00035 
00036 // system library includes
00037 #include <stdexcept>
00038 
00039 #if LL_WINDOWS
00040         #define WIN32_LEAN_AND_MEAN
00041         #include <winsock2.h>
00042         #include <windows.h>
00043 #else
00044         #include <sys/types.h>
00045         #include <sys/socket.h>
00046         #include <netinet/in.h>
00047         #include <arpa/inet.h>
00048         #include <fcntl.h>
00049         #include <errno.h>
00050 #endif
00051 
00052 // linden library includes
00053 #include "network.h"
00054 #include "llerror.h"
00055 #include "llhost.h"
00056 #include "lltimer.h"
00057 #include "indra_constants.h"
00058 
00059 
00060 // Globals
00061 #if LL_WINDOWS
00062 
00063 SOCKADDR_IN stDstAddr;
00064 SOCKADDR_IN stSrcAddr;
00065 SOCKADDR_IN stLclAddr;
00066 static WSADATA stWSAData;
00067 
00068 #else
00069 
00070 struct sockaddr_in stDstAddr;
00071 struct sockaddr_in stSrcAddr;
00072 struct sockaddr_in stLclAddr;
00073 
00074 #if LL_DARWIN
00075 #ifndef _SOCKLEN_T
00076 #define _SOCKLEN_T
00077 typedef int socklen_t;
00078 #endif
00079 #endif
00080 
00081 #endif
00082 
00083 
00084 const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
00085 
00086 #if LL_DARWIN
00087         // Mac OS X returns an error when trying to set these to 400000.  Smaller values succeed.
00088         const int       SEND_BUFFER_SIZE        = 200000;
00089         const int       RECEIVE_BUFFER_SIZE     = 200000;
00090 #else // LL_DARWIN
00091         const int       SEND_BUFFER_SIZE        = 400000;
00092         const int       RECEIVE_BUFFER_SIZE     = 400000;
00093 #endif // LL_DARWIN
00094 
00095 // universal functions (cross-platform)
00096 
00097 LLHost get_sender()
00098 {
00099         return LLHost(stSrcAddr.sin_addr.s_addr, ntohs(stSrcAddr.sin_port));
00100 }
00101 
00102 U32 get_sender_ip(void) 
00103 {
00104         return stSrcAddr.sin_addr.s_addr;
00105 }
00106 
00107 U32 get_sender_port() 
00108 {
00109         return ntohs(stSrcAddr.sin_port);
00110 }
00111 
00112 const char* u32_to_ip_string(U32 ip)
00113 {
00114         static char buffer[MAXADDRSTR];  /* Flawfinder: ignore */ 
00115 
00116         // Convert the IP address into a string
00117         in_addr in;
00118         in.s_addr = ip;
00119         char* result = inet_ntoa(in);
00120 
00121         // NULL indicates error in conversion
00122         if (result != NULL)
00123         {
00124                 strncpy( buffer, result, MAXADDRSTR );   /* Flawfinder: ignore */ 
00125                 buffer[MAXADDRSTR-1] = '\0';
00126                 return buffer;
00127         }
00128         else
00129         {
00130                 return "(bad IP addr)";
00131         }
00132 }
00133 
00134 
00135 // Returns ip_string if successful, NULL if not.  Copies into ip_string
00136 char *u32_to_ip_string(U32 ip, char *ip_string)
00137 {
00138         char *result;
00139         in_addr in;
00140 
00141         // Convert the IP address into a string
00142         in.s_addr = ip;
00143         result = inet_ntoa(in);
00144 
00145         // NULL indicates error in conversion
00146         if (result != NULL)
00147         {
00148                 //the function signature needs to change to pass in the lengfth of first and last.
00149                 strcpy(ip_string, result);      /*Flawfinder: ignore*/
00150                 return ip_string;
00151         }
00152         else
00153         {
00154                 return NULL;
00155         }
00156 }
00157 
00158 
00159 // Wrapper for inet_addr()
00160 U32 ip_string_to_u32(const char* ip_string)
00161 {
00162         return inet_addr(ip_string);
00163 }
00164 
00165 
00167 // Windows Versions
00169 
00170 #if LL_WINDOWS
00171  
00172 S32 start_net(S32& socket_out, int& nPort) 
00173 {                       
00174         // Create socket, make non-blocking
00175     // Init WinSock 
00176         int nRet;
00177         int hSocket;
00178 
00179         int snd_size = SEND_BUFFER_SIZE;
00180         int rec_size = RECEIVE_BUFFER_SIZE;
00181         int buff_size = 4;
00182  
00183         // Initialize windows specific stuff
00184         if(WSAStartup(0x0202, &stWSAData))
00185         {
00186                 S32 err = WSAGetLastError();
00187                 WSACleanup();
00188                 llwarns << "Windows Sockets initialization failed, err " << err << llendl;
00189                 return 1;
00190         }
00191 
00192         // Get a datagram socket
00193     hSocket = (int)socket(AF_INET, SOCK_DGRAM, 0);
00194     if (hSocket == INVALID_SOCKET)
00195         {
00196                 S32 err = WSAGetLastError();
00197                 WSACleanup();
00198                 llwarns << "socket() failed, err " << err << llendl;
00199                 return 2;
00200         }
00201 
00202         // Name the socket (assign the local port number to receive on)
00203         stLclAddr.sin_family      = AF_INET;
00204         stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00205         stLclAddr.sin_port        = htons(nPort);
00206 
00207         S32 attempt_port = nPort;
00208         llinfos << "attempting to connect on port " << attempt_port << llendl;
00209         nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
00210 
00211         if (nRet == SOCKET_ERROR)
00212         {
00213                 // If we got an address in use error...
00214                 if (WSAGetLastError() == WSAEADDRINUSE)
00215                 {
00216                         // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
00217                         for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
00218                                 attempt_port <= PORT_DISCOVERY_RANGE_MAX;
00219                                 attempt_port++)
00220                         {
00221                                 stLclAddr.sin_port = htons(attempt_port);
00222                                 llinfos << "trying port " << attempt_port << llendl;
00223                                 nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
00224 
00225                                 if (!(nRet == SOCKET_ERROR && 
00226                                         WSAGetLastError() == WSAEADDRINUSE))
00227                                 {
00228                                         break;
00229                                 }
00230                         }
00231 
00232                         if (nRet == SOCKET_ERROR)
00233                         {
00234                                 llwarns << "startNet() : Couldn't find available network port." << llendl;
00235                                 // Fail gracefully here in release
00236                                 return 3;
00237                         }
00238                 }
00239                 else
00240                 // Some other socket error
00241                 {
00242                         llwarns << llformat("bind() port: %d failed, Err: %d\n", nPort, WSAGetLastError()) << llendl;
00243                         // Fail gracefully in release.
00244                         return 4;
00245                 }
00246         }
00247 
00248         sockaddr_in socket_address;
00249         S32 socket_address_size = sizeof(socket_address);
00250         getsockname(hSocket, (SOCKADDR*) &socket_address, &socket_address_size);
00251         attempt_port = ntohs(socket_address.sin_port);
00252 
00253         llinfos << "connected on port " << attempt_port << llendl;
00254         nPort = attempt_port;
00255         
00256         // Set socket to be non-blocking
00257         unsigned long argp = 1;
00258         nRet = ioctlsocket (hSocket, FIONBIO, &argp);
00259         if (nRet == SOCKET_ERROR) 
00260         {
00261                 printf("Failed to set socket non-blocking, Err: %d\n", 
00262                 WSAGetLastError());
00263         }
00264 
00265         // set a large receive buffer
00266         nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
00267         if (nRet)
00268         {
00269                 llinfos << "Can't set receive buffer size!" << llendl;
00270         }
00271 
00272         nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
00273         if (nRet)
00274         {
00275                 llinfos << "Can't set send buffer size!" << llendl;
00276         }
00277 
00278         getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
00279         getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
00280 
00281         llinfos << "startNet - receive buffer size : " << rec_size << llendl;
00282         llinfos << "startNet - send buffer size    : " << snd_size << llendl;
00283 
00284         //  Setup a destination address
00285         char achMCAddr[MAXADDRSTR] = " ";       /* Flawfinder: ignore */ 
00286         stDstAddr.sin_family =      AF_INET;
00287     stDstAddr.sin_addr.s_addr = inet_addr(achMCAddr);
00288     stDstAddr.sin_port =        htons(nPort);
00289 
00290         socket_out = hSocket;
00291         return 0;
00292 }
00293 
00294 void end_net(S32& socket_out)
00295 {
00296         if (socket_out >= 0)
00297         {
00298                 shutdown(socket_out, SD_BOTH);
00299                 closesocket(socket_out);
00300         }
00301         WSACleanup();
00302 }
00303 
00304 S32 receive_packet(int hSocket, char * receiveBuffer)
00305 {
00306         //  Receives data asynchronously from the socket set by initNet().
00307         //  Returns the number of bytes received into dataReceived, or zero
00308         //  if there is no data received.
00309         int nRet;
00310         int addr_size = sizeof(struct sockaddr_in);
00311 
00312         nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size);
00313         if (nRet == SOCKET_ERROR ) 
00314         {
00315                 if (WSAEWOULDBLOCK == WSAGetLastError())
00316                         return 0;
00317                 if (WSAECONNRESET == WSAGetLastError())
00318                         return 0;
00319                 llinfos << "receivePacket() failed, Error: " << WSAGetLastError() << llendl;
00320         }
00321         
00322         return nRet;
00323 }
00324 
00325 // Returns TRUE on success.
00326 BOOL send_packet(int hSocket, const char *sendBuffer, int size, U32 recipient, int nPort)
00327 {
00328         //  Sends a packet to the address set in initNet
00329         //  
00330         int nRet = 0;
00331         U32 last_error = 0;
00332 
00333         stDstAddr.sin_addr.s_addr = recipient;
00334         stDstAddr.sin_port = htons(nPort);
00335         do
00336         {
00337                 nRet = sendto(hSocket, sendBuffer, size, 0, (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));                                   
00338 
00339                 if (nRet == SOCKET_ERROR ) 
00340                 {
00341                         last_error = WSAGetLastError();
00342                         if (last_error != WSAEWOULDBLOCK)
00343                         {
00344                                 // WSAECONNRESET - I think this is caused by an ICMP "connection refused"
00345                                 // message being sent back from a Linux box...  I'm not finding helpful
00346                                 // documentation or web pages on this.  The question is whether the packet
00347                                 // actually got sent or not.  Based on the structure of this code, I would
00348                                 // assume it is.  JNC 2002.01.18
00349                                 if (WSAECONNRESET == WSAGetLastError())
00350                                 {
00351                                         return TRUE;
00352                                 }
00353                                 llinfos << "sendto() failed to " << u32_to_ip_string(recipient) << ":" << nPort 
00354                                         << ", Error " << last_error << llendl;
00355                         }
00356                 }
00357         } while (  (nRet == SOCKET_ERROR)
00358                          &&(last_error == WSAEWOULDBLOCK));
00359 
00360         return (nRet != SOCKET_ERROR);
00361 }
00362 
00364 // Linux Versions
00366 
00367 #else
00368 
00369 //  Create socket, make non-blocking
00370 S32 start_net(S32& socket_out, int& nPort)
00371 {
00372         int hSocket, nRet;
00373         int snd_size = SEND_BUFFER_SIZE;
00374         int rec_size = RECEIVE_BUFFER_SIZE;
00375 
00376         socklen_t buff_size = 4;
00377     
00378         //  Create socket
00379     hSocket = socket(AF_INET, SOCK_DGRAM, 0);
00380     if (hSocket < 0)
00381         {
00382                 llwarns << "socket() failed" << llendl;
00383                 return 1;
00384         }
00385 
00386         // Don't bind() if we want the operating system to assign our ports for 
00387         // us.
00388         if (NET_USE_OS_ASSIGNED_PORT == nPort)
00389         {
00390                 // Do nothing; the operating system will do it for us.
00391         }
00392         else
00393         {
00394             // Name the socket (assign the local port number to receive on)
00395                 stLclAddr.sin_family      = AF_INET;
00396                 stLclAddr.sin_addr.s_addr = htonl(INADDR_ANY);
00397                 stLclAddr.sin_port        = htons(nPort);
00398                 U32 attempt_port = nPort;
00399                 llinfos << "attempting to connect on port " << attempt_port << llendl;
00400 
00401                 nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
00402                 if (nRet < 0)
00403                 {
00404                         // If we got an address in use error...
00405                         if (errno == EADDRINUSE)
00406                         {
00407                                 // Try all ports from PORT_DISCOVERY_RANGE_MIN to PORT_DISCOVERY_RANGE_MAX
00408                                 for(attempt_port = PORT_DISCOVERY_RANGE_MIN;
00409                                         attempt_port <= PORT_DISCOVERY_RANGE_MAX;
00410                                         attempt_port++)
00411                                 {
00412                                         stLclAddr.sin_port = htons(attempt_port);
00413                                         llinfos << "trying port " << attempt_port << llendl;
00414                                         nRet = bind(hSocket, (struct sockaddr*) &stLclAddr, sizeof(stLclAddr));
00415                                         if (!((nRet < 0) && (errno == EADDRINUSE)))
00416                                         {
00417                                                 break;
00418                                         }
00419                                 }
00420                                 if (nRet < 0)
00421                                 {
00422                                         llwarns << "startNet() : Couldn't find available network port." << llendl;
00423                                         // Fail gracefully in release.
00424                                         return 3;
00425                                 }
00426                         }
00427                         // Some other socket error
00428                         else
00429                         {
00430                                 llwarns << llformat ("bind() port: %d failed, Err: %s\n", nPort, strerror(errno)) << llendl;
00431                                 // Fail gracefully in release.
00432                                 return 4;
00433                         }
00434                 }
00435                 llinfos << "connected on port " << attempt_port << llendl;
00436                 nPort = attempt_port;
00437         }
00438         // Set socket to be non-blocking
00439         fcntl(hSocket, F_SETFL, O_NONBLOCK);
00440         // set a large receive buffer
00441         nRet = setsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, buff_size);
00442         if (nRet)
00443         {
00444                 llinfos << "Can't set receive size!" << llendl;
00445         }
00446         nRet = setsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, buff_size);
00447         if (nRet)
00448         {
00449                 llinfos << "Can't set send size!" << llendl;
00450         }
00451         getsockopt(hSocket, SOL_SOCKET, SO_RCVBUF, (char *)&rec_size, &buff_size);
00452         getsockopt(hSocket, SOL_SOCKET, SO_SNDBUF, (char *)&snd_size, &buff_size);
00453 
00454         llinfos << "startNet - receive buffer size : " << rec_size << llendl;
00455         llinfos << "startNet - send buffer size    : " << snd_size << llendl;
00456 
00457         //  Setup a destination address
00458         char achMCAddr[MAXADDRSTR] = "127.0.0.1";       /* Flawfinder: ignore */ 
00459         stDstAddr.sin_family =      AF_INET;
00460         stDstAddr.sin_addr.s_addr = inet_addr(achMCAddr);
00461         stDstAddr.sin_port =        htons(nPort);
00462 
00463         socket_out = hSocket;
00464         return 0;
00465 }
00466 
00467 void end_net(S32& socket_out)
00468 {
00469         if (socket_out >= 0)
00470         {
00471                 close(socket_out);
00472         }
00473 }
00474 
00475 int receive_packet(int hSocket, char * receiveBuffer)
00476 {
00477         //  Receives data asynchronously from the socket set by initNet().
00478         //  Returns the number of bytes received into dataReceived, or zero
00479         //  if there is no data received.
00480         // or -1 if an error occured!
00481         int nRet;
00482         socklen_t addr_size = sizeof(struct sockaddr_in);
00483 
00484         nRet = recvfrom(hSocket, receiveBuffer, NET_BUFFER_SIZE, 0, (struct sockaddr*)&stSrcAddr, &addr_size);
00485 
00486         if (nRet == -1)
00487         {
00488                 // To maintain consistency with the Windows implementation, return a zero for size on error.
00489                 return 0;
00490         }
00491 
00492         return nRet;
00493 }
00494 
00495 BOOL send_packet(int hSocket, const char * sendBuffer, int size, U32 recipient, int nPort)
00496 {
00497         int             ret;
00498         BOOL    success;
00499         BOOL    resend;
00500         S32             send_attempts = 0;
00501 
00502         stDstAddr.sin_addr.s_addr = recipient;
00503         stDstAddr.sin_port = htons(nPort);
00504 
00505         do
00506         {
00507                 ret = sendto(hSocket, sendBuffer, size, 0,      (struct sockaddr*)&stDstAddr, sizeof(stDstAddr));
00508                 send_attempts++;
00509 
00510                 if (ret >= 0)
00511                 {
00512                         // successful send
00513                         success = TRUE;
00514                         resend = FALSE;
00515                 }
00516                 else
00517                 {
00518                         // send failed, check to see if we should resend
00519                         success = FALSE;
00520 
00521                         if (errno == EAGAIN)
00522                         {
00523                                 // say nothing, just repeat send
00524                                 llinfos << "sendto() reported buffer full, resending (attempt " << send_attempts << ")" << llendl;
00525                                 llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
00526                                 resend = TRUE;
00527                         }
00528                         else if (errno == ECONNREFUSED)
00529                         {
00530                                 // response to ICMP connection refused message on earlier send
00531                                 llinfos << "sendto() reported connection refused, resending (attempt " << send_attempts << ")" << llendl;
00532                                 llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
00533                                 resend = TRUE;
00534                         }
00535                         else
00536                         {
00537                                 // some other error
00538                                 llinfos << "sendto() failed: " << errno << ", " << strerror(errno) << llendl;
00539                                 llinfos << inet_ntoa(stDstAddr.sin_addr) << ":" << nPort << llendl;
00540                                 resend = FALSE;
00541                         }
00542                 }
00543         }
00544         while ( resend && send_attempts < 3);
00545 
00546         if (send_attempts >= 3)
00547         {
00548                 llinfos << "sendPacket() bailed out of send!" << llendl;
00549                 return FALSE;
00550         }
00551 
00552         return success;
00553 }
00554 
00555 #endif
00556 
00557 //EOF

Generated on Thu Jul 1 06:09:57 2010 for Second Life Viewer by  doxygen 1.4.7