/* * NET_TCP_Send */ static int NET_TCP_Send( const socket_t *socket, const void *data, size_t length ) { #ifdef USE_TCP_NOSIGPIPE int opt_val = 1; #endif int ret; assert( socket && socket->open && socket->type == SOCKET_TCP ); assert( data ); assert( length > 0 ); #ifdef USE_TCP_NOSIGPIPE // Disable SIGPIPE // Currently ignore the return code from setsockopt setsockopt( socket->handle, SOL_SOCKET, SO_NOSIGPIPE, &opt_val, sizeof( opt_val ) ); #endif ret = send( socket->handle, data, length, MSG_NOSIGNAL ); #ifdef USE_TCP_NOSIGPIPE // Enable SIGPIPE opt_val = 0; setsockopt( socket->handle, SOL_SOCKET, SO_NOSIGPIPE, &opt_val, sizeof( opt_val ) ); #endif if( ret == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "send" ); if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK ) // would block return 0; return -1; } return ret; }
/* * NET_TCP_Connect */ static connection_status_t NET_TCP_Connect( socket_t *socket, const netadr_t *address ) { struct sockaddr_storage sockaddress; socklen_t addrlen; assert( socket && socket->open && socket->type == SOCKET_TCP && socket->handle && !socket->connected ); assert( address ); if( !AddressToSockaddress( address, &sockaddress ) ) return CONNECTION_FAILED; addrlen = ( sockaddress.ss_family == AF_INET6 ? sizeof( struct sockaddr_in6 ) : sizeof( struct sockaddr_in ) ); if( connect( socket->handle, (struct sockaddr*)&sockaddress, addrlen ) == SOCKET_ERROR ) { net_error_t err; err = Sys_NET_GetLastError(); if( err == NET_ERR_INPROGRESS || err == NET_ERR_WOULDBLOCK ) { socket->remoteAddress = *address; return CONNECTION_INPROGRESS; } else { NET_SetErrorStringFromLastError( "connect" ); return CONNECTION_FAILED; } } socket->connected = qtrue; socket->remoteAddress = *address; return CONNECTION_SUCCEEDED; }
/* * NET_SendFile */ int64_t NET_SendFile( const socket_t *socket, int file, size_t offset, size_t count, const netadr_t *address ) { int ret, err; assert( socket->open ); if( !socket->open ) return -1; if( address->type == NA_NOTRANSMIT ) return -1; #ifndef TCP_SUPPORT return -1; #else if( socket->type != SOCKET_TCP ) return -1; ret = Sys_NET_SendFile( socket->handle, file, offset, count ); if( ret == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "sendfile" ); err = Sys_NET_GetLastError(); if( err == NET_ERR_WOULDBLOCK || err == NET_ERR_CONNRESET ) // would block return 0; return -1; } return ret; #endif }
/* * GetLastErrorString */ static const char *GetLastErrorString( void ) { switch( Sys_NET_GetLastError() ) { case NET_ERR_UNKNOWN: return "Unknown error"; case NET_ERR_NONE: return "No error"; case NET_ERR_CONNRESET: return "Connection reset or refused"; case NET_ERR_INPROGRESS: return "Operation in progress"; case NET_ERR_MSGSIZE: return "Oversized packet"; case NET_ERR_WOULDBLOCK: return "Operation should have blocked"; case NET_ERR_UNSUPPORTED: return "Unsupported address or protocol"; default: return "Unsupported error code"; } }
/* * NET_UDP_GetPacket */ static int NET_UDP_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message ) { struct sockaddr_storage from; socklen_t fromlen; int ret; assert( socket && socket->open && socket->type == SOCKET_UDP ); assert( address ); assert( message ); assert( message->data ); assert( message->maxsize > 0 ); fromlen = sizeof( from ); ret = recvfrom( socket->handle, (char*)message->data, message->maxsize, 0, (struct sockaddr *)&from, &fromlen ); if( ret == SOCKET_ERROR ) { net_error_t err; NET_SetErrorStringFromLastError( "recvfrom" ); err = Sys_NET_GetLastError(); if( err == NET_ERR_WOULDBLOCK || err == NET_ERR_CONNRESET ) // would block return 0; return -1; } if( !SockaddressToAddress( (struct sockaddr*)&from, address ) ) return -1; if( ret == (int)message->maxsize ) { NET_SetErrorString( "Oversized packet" ); return -1; } message->readcount = 0; message->cursize = ret; return 1; }
/* * NET_TCP_Accept */ static int NET_TCP_Accept( const socket_t *socket, socket_t *newsocket, netadr_t *address ) { struct sockaddr_storage sockaddress; socklen_t sockaddress_size; int handle; assert( socket && socket->open && socket->type == SOCKET_TCP && socket->handle ); assert( newsocket ); assert( address ); sockaddress_size = sizeof( sockaddress ); handle = accept( socket->handle, (struct sockaddr *)&sockaddress, &sockaddress_size ); if( handle == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "accept" ); if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK ) // would block return 0; return -1; } if( !SockaddressToAddress( (struct sockaddr *)&sockaddress, address ) ) return -1; // make the new socket non-blocking if( !NET_SocketMakeNonBlocking( handle ) ) { Sys_NET_SocketClose( handle ); return -1; } newsocket->open = qtrue; newsocket->type = SOCKET_TCP; newsocket->server = socket->server; newsocket->address = socket->address; newsocket->remoteAddress = *address; newsocket->handle = handle; return 1; }
/* * NET_TCP_Get */ static int NET_TCP_Get( const socket_t *socket, netadr_t *address, void *data, size_t length ) { int ret; assert( socket && socket->open && socket->type == SOCKET_TCP ); assert( data ); assert( length > 0 ); ret = recv( socket->handle, data, length, 0 ); if( ret == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "recv" ); if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK ) // would block return 0; return -1; } if( address ) *address = socket->remoteAddress; return ret; }
/* * NET_TCP_GetPacket */ static int NET_TCP_GetPacket( const socket_t *socket, netadr_t *address, msg_t *message ) { int ret; qbyte buffer[MAX_PACKETLEN + 4]; int len; assert( socket && socket->open && socket->connected && socket->type == SOCKET_TCP ); assert( address ); assert( message ); // peek the message to see if the whole packet is ready ret = recv( socket->handle, (char*)buffer, sizeof( buffer ), MSG_PEEK ); if( ret == SOCKET_ERROR ) { NET_SetErrorStringFromLastError( "recv" ); if( Sys_NET_GetLastError() == NET_ERR_WOULDBLOCK ) // would block return 0; return -1; } if( ret < 4 ) // the length information is not yet received return 0; memcpy( &len, buffer, 4 ); len = LittleLong( len ); if( len > MAX_PACKETLEN || len > (int)message->maxsize ) { NET_SetErrorString( "Oversized packet" ); return -1; } if( ret < len + 4 ) // the whole packet is not yet ready return 0; // ok we have the whole packet ready, get it // read the 4 byte header ret = NET_TCP_Get( socket, NULL, buffer, 4 ); if( ret == -1 ) return -1; if( ret != 4 ) { NET_SetErrorString( "Couldn't read the whole packet" ); return -1; } ret = NET_TCP_Get( socket, NULL, message->data, len ); if( ret == SOCKET_ERROR ) return -1; if( ret != (int)len ) { NET_SetErrorString( "Couldn't read the whole packet" ); return -1; } *address = socket->remoteAddress; message->readcount = 0; message->cursize = ret; return qtrue; }