00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdnet.h"
00027
00028 #include "nel/net/sock.h"
00029 #include "nel/misc/time_nl.h"
00030
00031 #ifdef NL_OS_WINDOWS
00032
00033 # include <winsock2.h>
00034
00035 # define socklen_t int
00036 # define ERROR_NUM WSAGetLastError()
00037 # define ERROR_WOULDBLOCK WSAEWOULDBLOCK
00038
00039 #elif defined NL_OS_UNIX
00040
00041 # include <unistd.h>
00042 # include <sys/types.h>
00043 # include <sys/time.h>
00044 # include <sys/socket.h>
00045 # include <netinet/in.h>
00046 # include <netinet/tcp.h>
00047 # include <arpa/inet.h>
00048 # include <netdb.h>
00049 # include <fcntl.h>
00050 # include <errno.h>
00051 # define SOCKET_ERROR -1
00052 # define INVALID_SOCKET -1
00053 # define ERROR_NUM errno
00054 # define ERROR_WOULDBLOCK EWOULDBLOCK
00055 # define ERROR_MSG strerror(errno)
00056 typedef int SOCKET;
00057
00058 #endif
00059
00060 using namespace std;
00061 using namespace NLMISC;
00062
00063 namespace NLNET {
00064
00065
00066 bool CSock::_Initialized = false;
00067
00068 long CSock::_TimeoutS = 0;
00069
00070 long CSock::_TimeoutMs = 0;
00071
00072
00073
00074
00075
00076 ESocket::ESocket( const char *reason, bool systemerror, CInetAddress *addr )
00077 {
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 _Reason = "Socket error: ";
00092 uint errornum = CSock::getLastError();
00093 char str[256];
00094 if ( addr != NULL )
00095 {
00096
00097 smprintf( str, 256, reason, addr->asString().c_str() );
00098 _Reason += str;
00099 }
00100 else
00101 {
00102
00103 _Reason += reason;
00104 }
00105 if ( systemerror )
00106 {
00107 _Reason += " (";
00108 smprintf( str, 256, "%d", errornum );
00109 _Reason += str;
00110 if ( errornum != 0 )
00111 {
00112 _Reason += ": ";
00113 _Reason += CSock::errorString( errornum );
00114 }
00115 _Reason += ")";
00116 }
00117 nlwarning( "Exception will be launched: %s", _Reason.c_str() );
00118 }
00119
00120
00121
00122
00123
00124 void CSock::initNetwork()
00125 {
00126 if ( ! CSock::_Initialized )
00127 {
00128 #ifdef NL_OS_WINDOWS
00129 WORD winsock_version = MAKEWORD( 2, 0 );
00130 WSADATA wsaData;
00131 if ( WSAStartup( winsock_version, &wsaData ) != 0 )
00132 {
00133 throw ESocket( "Winsock initialization failed" );
00134 }
00135 #endif
00136 CSock::_Initialized = true;
00137 }
00138 }
00139
00140
00141
00142
00143 void CSock::releaseNetwork()
00144 {
00145 #ifdef NL_OS_WINDOWS
00146 WSACleanup();
00147 #endif
00148 CSock::_Initialized = false;
00149 }
00150
00151
00152
00153
00154
00155
00156 uint CSock::getLastError()
00157 {
00158 return (uint)ERROR_NUM;
00159 }
00160
00161
00162
00163
00164
00165 std::string CSock::errorString( uint errorcode )
00166 {
00167 #ifdef NL_OS_WINDOWS
00168 switch( errorcode )
00169 {
00170 case WSAEINTR : return "Blocking operation interrupted";
00171 case WSAEINVAL : return "Invalid socket (maybe not bound) or argument";
00172 case WSAEMFILE : return "Too many open sockets";
00173 case WSAENOTSOCK : return "Socket operation on nonsocket (maybe invalid select descriptor)";
00174 case WSAEMSGSIZE : return "Message too long";
00175 case WSAEADDRINUSE : return "Address already in use (is this service already running in this computer?)";
00176 case WSAEADDRNOTAVAIL: return "Address not available";
00177 case WSAENETDOWN : return "Network is down";
00178 case WSAENETUNREACH : return "Network is unreachable";
00179 case WSAECONNRESET : return "Connection reset by peer";
00180 case WSAENOBUFS : return "No buffer space available; please close applications or reboot";
00181 case WSAESHUTDOWN : return "Cannot send/receive after socket shutdown";
00182 case WSAETIMEDOUT : return "Connection timed-out";
00183 case WSAECONNREFUSED : return "Connection refused, the server may be offline";
00184 case WSAEHOSTUNREACH : return "Remote host is unreachable";
00185 case WSANOTINITIALISED : return "'Windows Sockets' not initialized";
00186 default: return "";
00187 }
00188 #elif defined NL_OS_UNIX
00189 return std::string( strerror( errorcode ) );
00190 #endif
00191
00192 }
00193
00194
00195
00196
00197
00198
00199 CSock::CSock( bool logging ) :
00200 _Sock( INVALID_SOCKET ),
00201 _Logging( logging ),
00202 _BytesReceived( 0 ),
00203 _BytesSent( 0 ),
00204 _NonBlocking( false ),
00205 _MaxReceiveTime( 0 ),
00206 _MaxSendTime( 0 )
00207 {
00208 nlassert( CSock::_Initialized );
00209
00210
00211
00212
00213 _Connected = false;
00214 }
00215
00216
00217
00218
00219
00220 CSock::CSock( SOCKET sock, const CInetAddress& remoteaddr ) :
00221 _Sock( sock ),
00222 _Logging( true ),
00223 _BytesReceived( 0 ),
00224 _BytesSent( 0 ),
00225 _RemoteAddr( remoteaddr ),
00226 _NonBlocking( false ),
00227 _MaxReceiveTime( 0 ),
00228 _MaxSendTime( 0 )
00229 {
00230 nlassert( CSock::_Initialized );
00231
00232
00233
00234
00235 _Connected = true;
00236
00237
00238 if ( ! _RemoteAddr.isValid() )
00239 {
00240 throw ESocket( "Could not init a socket object with an invalid address", false );
00241 }
00242
00243
00244 setLocalAddress();
00245 }
00246
00247
00248
00249
00250
00251 void CSock::createSocket( int type, int protocol )
00252 {
00253 nlassert( _Sock == INVALID_SOCKET );
00254
00255 _Sock = socket( AF_INET, type, protocol );
00256 if ( _Sock == INVALID_SOCKET )
00257 {
00258 throw ESocket( "Socket creation failed" );
00259 }
00260
00261 if ( _Logging )
00262 {
00263
00264 }
00265 }
00266
00267
00268
00269
00270
00271 void CSock::close()
00272 {
00273 if ( _Logging )
00274 {
00275 nldebug( "LNETL0: Socket %d closing for %s at %s", _Sock, _RemoteAddr.asString().c_str(), _LocalAddr.asString().c_str() );
00276 }
00277 #ifdef NL_OS_WINDOWS
00278 closesocket( _Sock );
00279 #elif defined NL_OS_UNIX
00280 ::close( _Sock );
00281 #endif
00282 _Sock = INVALID_SOCKET;
00283 }
00284
00285
00286
00287
00288
00289 CSock::~CSock()
00290 {
00291 nlinfo( "Report for %s socket %s: Max send time: %u Max recv time: %u", _NonBlocking?"non-blocking":"blocking", remoteAddr().asString().c_str(), _MaxSendTime, _MaxReceiveTime );
00292 nlinfo( "Max send time: %u", _MaxSendTime);
00293 if ( _Sock != INVALID_SOCKET )
00294 {
00295 if ( _Logging )
00296 {
00297 nldebug( "LNETL0: Socket %d closing for %s at %s", _Sock, _RemoteAddr.asString().c_str(), _LocalAddr.asString().c_str() );
00298 }
00299
00300 if ( connected() )
00301 {
00302 #ifdef NL_OS_WINDOWS
00303 shutdown( _Sock, SD_BOTH );
00304 }
00305 closesocket( _Sock );
00306 #elif defined NL_OS_UNIX
00307 shutdown( _Sock, SHUT_RDWR );
00308 }
00309 ::close( _Sock );
00310 #endif
00311 _Sock = INVALID_SOCKET;
00312 }
00313 }
00314
00315
00316
00317
00318
00319 void CSock::connect( const CInetAddress& addr )
00320 {
00321 nldebug( "LNETL0: Socket %d connecting to %s...", _Sock, addr.asString().c_str() );
00322
00323
00324 if ( ! addr.isValid() )
00325 {
00326 throw ESocket( "Unable to connect to invalid address", false );
00327 }
00328
00329 #ifndef NL_OS_WINDOWS
00330
00331 int value = true;
00332 if ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )
00333 {
00334 throw ESocket( "ReuseAddr failed" );
00335 }
00336 #endif
00337
00338
00339 if ( ::connect( _Sock, (const sockaddr *)(addr.sockAddr()), sizeof(sockaddr_in) ) != 0 )
00340 {
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 throw ESocketConnectionFailed( addr );
00351 }
00352 setLocalAddress();
00353 if ( _Logging )
00354 {
00355 nldebug( "LNETL0: Socket %d connected to %s (local %s)", _Sock, addr.asString().c_str(), _LocalAddr.asString().c_str() );
00356 }
00357 _RemoteAddr = addr;
00358
00359 _BytesReceived = 0;
00360 _BytesSent = 0;
00361
00362
00363
00364 _Connected = true;
00365 }
00366
00367
00368
00369
00370
00371 bool CSock::dataAvailable()
00372 {
00373 fd_set fdset;
00374 FD_ZERO( &fdset );
00375 FD_SET( _Sock, &fdset );
00376 timeval tv;
00377 tv.tv_sec = CSock::_TimeoutS;
00378 tv.tv_usec = CSock::_TimeoutMs;
00379
00380
00381 int res = select( _Sock+1, &fdset, NULL, NULL, &tv );
00382 switch ( res )
00383 {
00384 case 0 : return false;
00385 case -1 : throw ESocket( "CSock::dataAvailable(): select failed" ); return false;
00386 default : return true;
00387 }
00388 }
00389
00390
00391
00392
00393
00394 void CSock::setLocalAddress()
00395 {
00396 sockaddr saddr;
00397 socklen_t saddrlen = sizeof(saddr);
00398 if ( getsockname( _Sock, &saddr, &saddrlen ) != 0 )
00399 {
00400 throw ESocket( "Unable to find local address" );
00401 }
00402 _LocalAddr.setSockAddr( (const sockaddr_in *)&saddr );
00403 }
00404
00405
00406
00407
00408
00409 CSock::TSockResult CSock::send( const uint8 *buffer, uint32& len, bool throw_exception )
00410 {
00411 uint32 realLen = len;
00412 TTicks before = CTime::getPerformanceTime();
00413 len = ::send( _Sock, (const char*)buffer, len, 0 );
00414 _MaxSendTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxSendTime );
00415
00416 if ( _Logging )
00417 {
00418
00419 }
00420
00421 if ( len == SOCKET_ERROR )
00422 {
00423 if ( ERROR_NUM == ERROR_WOULDBLOCK )
00424 {
00425 len = 0;
00426 return Ok;
00427 }
00428 if ( throw_exception )
00429 {
00430 throw ESocket( "Unable to send data" );
00431 }
00432 return Error;
00433 }
00434 _BytesSent += len;
00435
00436 return Ok;
00437 }
00438
00439
00440
00441
00442
00443
00444 CSock::TSockResult CSock::receive( uint8 *buffer, uint32& len, bool throw_exception )
00445 {
00446 if ( _NonBlocking )
00447 {
00448
00449
00450 uint32 realLen = len;
00451
00452 TTicks before = CTime::getPerformanceTime();
00453 len = ::recv( _Sock, (char*)buffer, len, 0 );
00454
00455 if ( _Logging )
00456 {
00457
00458 }
00459
00460 _MaxReceiveTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxReceiveTime );
00461 switch ( len )
00462 {
00463
00464 case 0 :
00465 {
00466
00467
00468
00469
00470 _Connected = false;
00471 if ( throw_exception )
00472 {
00473 throw ESocketConnectionClosed();
00474 }
00475 return CSock::ConnectionClosed;
00476 }
00477
00478
00479 case SOCKET_ERROR :
00480 {
00481 len = 0;
00482 if ( ERROR_NUM == ERROR_WOULDBLOCK )
00483 {
00484
00485 return CSock::WouldBlock;
00486 }
00487 else
00488 {
00489
00490 if ( throw_exception )
00491 {
00492 throw ESocket( "Unable to receive data" );
00493 }
00494 return CSock::Error;
00495 }
00496 }
00497 }
00498 }
00499 else
00500 {
00501
00502 uint total = 0;
00503 uint brecvd;
00504
00505 uint32 realLen = len;
00506
00507 while ( total < len )
00508 {
00509 TTicks before = CTime::getPerformanceTime();
00510 brecvd = ::recv( _Sock, (char*)(buffer+total), len-total, 0 );
00511
00512
00513
00514 _MaxReceiveTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxReceiveTime );
00515
00516 switch ( brecvd )
00517 {
00518
00519 case 0 :
00520 {
00521
00522
00523
00524
00525 _Connected = false;
00526 if ( throw_exception )
00527 {
00528 throw ESocketConnectionClosed();
00529 }
00530 return CSock::ConnectionClosed;
00531 }
00532
00533
00534 case SOCKET_ERROR :
00535 {
00536 if ( throw_exception )
00537 {
00538 throw ESocket( "Unable to receive data" );
00539 }
00540 return CSock::Error;
00541 }
00542 }
00543 total += brecvd;
00544 }
00545 }
00546
00547
00548
00549
00550
00551 _BytesReceived += len;
00552 return CSock::Ok;
00553 }
00554
00555
00556
00557
00558
00559 bool CSock::connected()
00560 {
00561
00562
00563
00564
00565
00566
00567
00568
00569 return _Connected;
00570 }
00571
00572
00573
00574
00575
00576 void CSock::setNonBlockingMode ( bool bm )
00577 {
00578 if ( _NonBlocking != bm )
00579 {
00580 #ifdef NL_OS_WINDOWS
00581 u_long b = bm;
00582 if ( ioctlsocket( _Sock, FIONBIO, &b ) != 0 )
00583 #else
00584 if ( fcntl( _Sock, F_SETFL, FNDELAY | fcntl( _Sock, F_GETFL, 0 ) ) == -1 )
00585 #endif
00586 {
00587 throw ESocket( "Cannot set nonblocking mode" );
00588 }
00589 _NonBlocking = bm;
00590 }
00591 }
00592
00593
00594 }