Browse Source

net_ws refactoring, fix minor bugs

pull/2/head
Alibek Omarov 7 years ago
parent
commit
69549787bc
  1. 348
      engine/common/net_ws.c

348
engine/common/net_ws.c

@ -119,7 +119,6 @@ static dllfunc_t kernel32_funcs[] =
dll_info_t kernel32_dll = { "kernel32.dll", kernel32_funcs, false }; dll_info_t kernel32_dll = { "kernel32.dll", kernel32_funcs, false };
static void NET_InitializeCriticalSections( void ); static void NET_InitializeCriticalSections( void );
qboolean NET_OpenWinSock( void ) qboolean NET_OpenWinSock( void )
@ -136,7 +135,7 @@ void NET_FreeWinSock( void )
{ {
Sys_FreeLibrary( &winsock_dll ); Sys_FreeLibrary( &winsock_dll );
} }
#else #else // _WIN32
#define pHtons htons #define pHtons htons
#define pConnect connect #define pConnect connect
#define pInet_Addr inet_addr #define pInet_Addr inet_addr
@ -157,9 +156,47 @@ void NET_FreeWinSock( void )
#define pGetHostByName gethostbyname #define pGetHostByName gethostbyname
#define pSelect select #define pSelect select
#define pGetAddrInfo getaddrinfo #define pGetAddrInfo getaddrinfo
#define pWSAGetLastError() errno
#define SOCKET int #define SOCKET int
#define INVALID_SOCKET 0 #define INVALID_SOCKET -1
#endif
#define WSAEINTR EINTR
#define WSAEBADF EBADF
#define WSAEACCES EACCES
#define WSAEFAULT EFAULT
#define WSAEINVAL EINVAL
#define WSAEMFILE EMFILE
#define WSAEWOULDBLOCK EWOULDBLOCK
#define WSAEINPROGRESS EINPROGRESS
#define WSAEALREADY EALREADY
#define WSAENOTSOCK ENOTSOCK
#define WSAEDESTADDRREQ EDESTADDRREQ
#define WSAEMSGSIZE EMSGSIZE
#define WSAEPROTOTYPE EPROTOTYPE
#define WSAENOPROTOOPT ENOPROTOOPT
#define WSAEPROTONOSUPPORT EPROTONOSUPPORT
#define WSAESOCKTNOSUPPORT ESOCKTNOSUPPORT
#define WSAEOPNOTSUPP EOPNOTSUPP
#define WSAEPFNOSUPPORT EPFNOSUPPORT
#define WSAEAFNOSUPPORT EAFNOSUPPORT
#define WSAEADDRINUSE EADDRINUSE
#define WSAEADDRNOTAVAIL EADDRNOTAVAIL
#define WSAENETDOWN ENETDOWN
#define WSAENETUNREACH ENETUNREACH
#define WSAENETRESET ENETRESET
#define WSAECONNABORTED ECONNABORTED
#define WSAECONNRESET ECONNRESET
#define WSAENOBUFS ENOBUFS
#define WSAEISCONN EISCONN
#define WSAENOTCONN ENOTCONN
#define WSAESHUTDOWN ESHUTDOWN
#define WSAETOOMANYREFS ETOOMANYREFS
#define WSAETIMEDOUT ETIMEDOUT
#define WSAECONNREFUSED ECONNREFUSED
#define WSAELOOP ELOOP
#define WSAENAMETOOLONG ENAMETOOLONG
#define WSAEHOSTDOWN EHOSTDOWN
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
/* All socket operations are non-blocking already */ /* All socket operations are non-blocking already */
@ -169,7 +206,8 @@ static int ioctl_stub( int d, unsigned long r, ...)
} }
#undef pIoctlSocket #undef pIoctlSocket
#define pIoctlSocket ioctl_stub #define pIoctlSocket ioctl_stub
#endif #endif // __EMSCRIPTEN__
#endif // !_WIN32
typedef struct typedef struct
{ {
@ -223,6 +261,7 @@ typedef struct
long sequence_number; long sequence_number;
int ip_sockets[NS_COUNT]; int ip_sockets[NS_COUNT];
qboolean initialized; qboolean initialized;
qboolean threads_initialized;
qboolean configured; qboolean configured;
qboolean allow_ip; qboolean allow_ip;
#ifdef _WIN32 #ifdef _WIN32
@ -260,7 +299,6 @@ char *NET_ErrorString( void )
case WSAEINTR: return "WSAEINTR"; case WSAEINTR: return "WSAEINTR";
case WSAEBADF: return "WSAEBADF"; case WSAEBADF: return "WSAEBADF";
case WSAEACCES: return "WSAEACCES"; case WSAEACCES: return "WSAEACCES";
case WSAEDISCON: return "WSAEDISCON";
case WSAEFAULT: return "WSAEFAULT"; case WSAEFAULT: return "WSAEFAULT";
case WSAEINVAL: return "WSAEINVAL"; case WSAEINVAL: return "WSAEINVAL";
case WSAEMFILE: return "WSAEMFILE"; case WSAEMFILE: return "WSAEMFILE";
@ -294,6 +332,7 @@ char *NET_ErrorString( void )
case WSAELOOP: return "WSAELOOP"; case WSAELOOP: return "WSAELOOP";
case WSAENAMETOOLONG: return "WSAENAMETOOLONG"; case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
case WSAEHOSTDOWN: return "WSAEHOSTDOWN"; case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
case WSAEDISCON: return "WSAEDISCON";
case WSASYSNOTREADY: return "WSASYSNOTREADY"; case WSASYSNOTREADY: return "WSASYSNOTREADY";
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED"; case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
case WSANOTINITIALISED: return "WSANOTINITIALISED"; case WSANOTINITIALISED: return "WSANOTINITIALISED";
@ -322,7 +361,7 @@ _inline qboolean NET_IsSocketValid( int socket )
#ifdef _WIN32 #ifdef _WIN32
return socket != INVALID_SOCKET; return socket != INVALID_SOCKET;
#else #else
return socket; return socket >= 0;
#endif #endif
} }
@ -364,12 +403,52 @@ static void NET_SockadrToNetadr( struct sockaddr *s, netadr_t *a )
} }
} }
/*
============
NET_GetHostByName
============
*/
int NET_GetHostByName( const char *hostname )
{
#ifdef HAVE_GETADDRINFO
struct addrinfo *ai = NULL, *cur;
struct addrinfo hints;
int ip;
memset( &hints, 0, sizeof( hints ));
hints.ai_family = AF_INET;
if( !pGetAddrInfo( hostname, NULL, &hints, &ai ))
{
for( cur = ai; cur; cur = cur->ai_next )
{
if( cur->ai_family == AF_INET )
{
ip = *((int*)&((struct sockaddr_in *)cur->ai_addr)->sin_addr);
break;
}
}
if( ai )
freeaddrinfo( ai );
}
return ip;
#else
struct hostent *h;
if(!( h = pGetHostByName( copy )))
return 0;
return *(int *)h->h_addr_list[0];
#endif
}
#if !defined XASH_NO_ASYNC_NS_RESOLVE && ( defined _WIN32 || !defined __EMSCRIPTEN__ ) #if !defined XASH_NO_ASYNC_NS_RESOLVE && ( defined _WIN32 || !defined __EMSCRIPTEN__ )
#define CAN_ASYNC_NS_RESOLVE #define CAN_ASYNC_NS_RESOLVE
#endif #endif
#ifdef CAN_ASYNC_NS_RESOLVE #ifdef CAN_ASYNC_NS_RESOLVE
static void NET_ResolveThread( void ); static void NET_ResolveThread( void );
#if !defined _WIN32 #if !defined _WIN32
#include <pthread.h> #include <pthread.h>
#define mutex_lock pthread_mutex_lock #define mutex_lock pthread_mutex_lock
@ -385,14 +464,14 @@ void *NET_ThreadStart( void *unused )
NET_ResolveThread(); NET_ResolveThread();
return NULL; return NULL;
} }
#else // WIN32 #else // WIN32
struct cs { typedef struct cs
{
void* p1; void* p1;
int i1, i2; int i1, i2;
void *p2, *p3; void *p2, *p3;
uint i4; uint i4;
}; } mutex_t;
#define mutex_lock pEnterCriticalSection #define mutex_lock pEnterCriticalSection
#define mutex_unlock pLeaveCriticalSection #define mutex_unlock pLeaveCriticalSection
#define detach_thread( x ) CloseHandle(x) #define detach_thread( x ) CloseHandle(x)
@ -405,7 +484,7 @@ DWORD WINAPI NET_ThreadStart( LPVOID unused )
ExitThread(0); ExitThread(0);
return 0; return 0;
} }
#endif #endif // !_WIN32
#ifdef DEBUG_RESOLVE #ifdef DEBUG_RESOLVE
#define RESOLVE_DBG(x) Sys_PrintLog(x) #define RESOLVE_DBG(x) Sys_PrintLog(x)
@ -430,6 +509,7 @@ static struct nsthread_s
#ifdef _WIN32 #ifdef _WIN32
static void NET_InitializeCriticalSections( void ) static void NET_InitializeCriticalSections( void )
{ {
net.threads_initialized = true;
pInitializeCriticalSection( &nsthread.mutexns ); pInitializeCriticalSection( &nsthread.mutexns );
pInitializeCriticalSection( &nsthread.mutexres ); pInitializeCriticalSection( &nsthread.mutexres );
} }
@ -437,75 +517,29 @@ static void NET_InitializeCriticalSections( void )
void NET_ResolveThread( void ) void NET_ResolveThread( void )
{ {
#ifdef HAVE_GETADDRINFO
struct addrinfo *ai = NULL, *cur;
struct addrinfo hints;
int sin_addr = 0; int sin_addr = 0;
RESOLVE_DBG( "[resolve thread] starting resolve for " ); RESOLVE_DBG( "[resolve thread] starting resolve for " );
RESOLVE_DBG( nsthread.hostname ); RESOLVE_DBG( nsthread.hostname );
#ifdef HAVE_GETADDRINFO
RESOLVE_DBG( " with getaddrinfo\n" ); RESOLVE_DBG( " with getaddrinfo\n" );
memset( &hints, 0, sizeof( hints ) ); #else
hints.ai_family = AF_INET; RESOLVE_DBG( " with gethostbyname\n" );
if( !pGetAddrInfo( nsthread.hostname, NULL, &hints, &ai ) ) #endif
{
for( cur = ai; cur; cur = cur->ai_next ) {
if( cur->ai_family == AF_INET ) {
sin_addr = *((int*)&((struct sockaddr_in *)cur->ai_addr)->sin_addr);
freeaddrinfo( ai );
ai = NULL;
break;
}
}
if( ai ) sin_addr = NET_GetHostByName( nsthread.hostname );
freeaddrinfo( ai );
}
if( sin_addr ) if( sin_addr )
RESOLVE_DBG( "[resolve thread] getaddrinfo success\n" ); RESOLVE_DBG( "[resolve thread] success\n" );
else else
RESOLVE_DBG( "[resolve thread] getaddrinfo failed\n" ); RESOLVE_DBG( "[resolve thread] failed\n" );
mutex_lock( &nsthread.mutexres ); mutex_lock( &nsthread.mutexres );
nsthread.result = sin_addr; nsthread.result = sin_addr;
nsthread.busy = false; nsthread.busy = false;
RESOLVE_DBG( "[resolve thread] returning result\n" ); RESOLVE_DBG( "[resolve thread] returning result\n" );
mutex_unlock( &nsthread.mutexres ); mutex_unlock( &nsthread.mutexres );
RESOLVE_DBG( "[resolve thread] exiting thread\n" ); RESOLVE_DBG( "[resolve thread] exiting thread\n" );
#else
struct hostent *res;
RESOLVE_DBG( "[resolve thread] starting resolve for " );
RESOLVE_DBG( nsthread.hostname );
RESOLVE_DBG( " with gethostbyname\n" );
mutex_lock( &nsthread.mutexns );
RESOLVE_DBG( "[resolve thread] locked gethostbyname mutex\n" );
res = pGetHostByName( nsthread.hostname );
if(res)
RESOLVE_DBG( "[resolve thread] gethostbyname success\n" );
else
RESOLVE_DBG( "[resolve thread] gethostbyname failed\n" );
mutex_lock( &nsthread.mutexres );
RESOLVE_DBG( "[resolve thread] returning result\n" );
if( res )
nsthread.result = *(int *)res->h_addr_list[0];
else
nsthread.result = 0;
nsthread.busy = false;
mutex_unlock( &nsthread.mutexns );
RESOLVE_DBG( "[resolve thread] unlocked gethostbyname mutex\n" );
mutex_unlock( &nsthread.mutexres );
RESOLVE_DBG( "[resolve thread] exiting thread\n" );
#endif
} }
#endif // CAN_ASYNC_NS_RESOLVE #endif // CAN_ASYNC_NS_RESOLVE
@ -526,7 +560,8 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr *sadr, qboolean
char *colon; char *colon;
char copy[128]; char copy[128];
if( !net.initialized ) return false; if( !net.initialized )
return false;
memset( sadr, 0, sizeof( *sadr )); memset( sadr, 0, sizeof( *sadr ));
@ -551,122 +586,50 @@ static int NET_StringToSockaddr( const char *s, struct sockaddr *sadr, qboolean
} }
else else
{ {
qboolean asyncfailed = true;
#ifdef CAN_ASYNC_NS_RESOLVE #ifdef CAN_ASYNC_NS_RESOLVE
qboolean asyncfailed = false; if( net.threads_initialized && !nonblocking )
#ifdef _WIN32
if( pInitializeCriticalSection )
#endif // _WIN32
{ {
if( !nonblocking ) mutex_lock( &nsthread.mutexres );
{
#ifdef HAVE_GETADDRINFO
struct addrinfo *ai = NULL, *cur;
struct addrinfo hints;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET;
if( !pGetAddrInfo( copy, NULL, &hints, &ai ) )
{
for( cur = ai; cur; cur = cur->ai_next )
{
if( cur->ai_family == AF_INET )
{
ip = *((int*)&((struct sockaddr_in *)cur->ai_addr)->sin_addr);
freeaddrinfo(ai);
ai = NULL;
break;
}
}
if( ai )
freeaddrinfo(ai);
}
#else
struct hostent *h;
mutex_lock( &nsthread.mutexns ); if( nsthread.busy )
h = pGetHostByName( copy ); {
if( !h ) mutex_unlock( &nsthread.mutexres );
{ return 2;
mutex_unlock( &nsthread.mutexns ); }
return 0;
}
ip = *(int *)h->h_addr_list[0]; if( !Q_strcmp( copy, nsthread.hostname ) )
mutex_unlock( &nsthread.mutexns ); {
#endif ip = nsthread.result;
nsthread.hostname[0] = 0;
detach_thread( nsthread.thread );
} }
else else
{ {
mutex_lock( &nsthread.mutexres ); Q_strncpy( nsthread.hostname, copy, MAX_STRING );
nsthread.busy = true;
mutex_unlock( &nsthread.mutexres );
if( nsthread.busy ) if( create_thread( NET_ThreadStart ) )
{ {
mutex_unlock( &nsthread.mutexres ); asyncfailed = false;
return 2; return 2;
} }
else // failed to create thread
if( !Q_strcmp( copy, nsthread.hostname ) )
{
ip = nsthread.result;
nsthread.hostname[0] = 0;
detach_thread( nsthread.thread );
}
else
{ {
Q_strncpy( nsthread.hostname, copy, MAX_STRING ); MsgDev( D_ERROR, "NET_StringToSockaddr: failed to create thread!\n");
nsthread.busy = true; nsthread.busy = false;
mutex_unlock( &nsthread.mutexres );
if( create_thread( NET_ThreadStart ) )
return 2;
else // failed to create thread
{
MsgDev( D_ERROR, "NET_StringToSockaddr: failed to create thread!\n");
nsthread.busy = false;
asyncfailed = true;
}
} }
mutex_unlock( &nsthread.mutexres );
} }
mutex_unlock( &nsthread.mutexres );
} }
#ifdef _WIN32
else
asyncfailed = true;
#else
if( asyncfailed )
#endif // _WIN32
#endif // CAN_ASYNC_NS_RESOLVE #endif // CAN_ASYNC_NS_RESOLVE
{
#ifdef HAVE_GETADDRINFO
struct addrinfo *ai = NULL, *cur;
struct addrinfo hints;
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET;
if( !pGetAddrInfo( copy, NULL, &hints, &ai ) )
{
for( cur = ai; cur; cur = cur->ai_next )
{
if( cur->ai_family == AF_INET )
{
ip = *((int*)&((struct sockaddr_in *)cur->ai_addr)->sin_addr);
freeaddrinfo(ai);
ai = NULL;
break;
}
}
if( ai ) if( asyncfailed )
freeaddrinfo(ai); {
} ip = NET_GetHostByName( copy );
#else
struct hostent *h;
if(!( h = pGetHostByName( copy )))
return 0;
ip = *(int *)h->h_addr_list[0];
#endif
} }
if( !ip ) if( !ip )
@ -1272,7 +1235,6 @@ qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size_t *len
} }
else else
{ {
#ifdef _WIN32
int err = pWSAGetLastError(); int err = pWSAGetLastError();
switch( err ) switch( err )
@ -1286,19 +1248,6 @@ qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size_t *len
MsgDev( D_ERROR, "NET_QueuePacket: %s from %s\n", NET_ErrorString(), NET_AdrToString( *from )); MsgDev( D_ERROR, "NET_QueuePacket: %s from %s\n", NET_ErrorString(), NET_AdrToString( *from ));
break; break;
} }
#else
switch( errno )
{
case EWOULDBLOCK:
case ECONNRESET:
case ECONNREFUSED:
case EMSGSIZE:
break;
default: // let's continue even after errors
MsgDev( D_ERROR, "NET_QueuePacket: %s from %s\n", NET_ErrorString(), NET_AdrToString( *from ));
break;
}
#endif
} }
} }
@ -1434,37 +1383,21 @@ void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to
if( NET_IsSocketError( ret )) if( NET_IsSocketError( ret ))
{ {
int err = 0; int err = pWSAGetLastError();
{
#ifdef _WIN32
err = pWSAGetLastError();
// WSAEWOULDBLOCK is silent // WSAEWOULDBLOCK is silent
if( err == WSAEWOULDBLOCK ) if( err == WSAEWOULDBLOCK )
return; return;
// some PPP links don't allow broadcasts // some PPP links don't allow broadcasts
if( err == WSAEADDRNOTAVAIL && to.type == NA_BROADCAST ) if( err == WSAEADDRNOTAVAIL && to.type == NA_BROADCAST )
return; return;
#else
// WSAEWOULDBLOCK is silent
if( errno == EWOULDBLOCK )
return;
// some PPP links don't allow broadcasts
if( errno == EADDRNOTAVAIL && to.type == NA_BROADCAST )
return;
#endif
}
if( Host_IsDedicated() ) if( Host_IsDedicated() )
{ {
MsgDev( D_ERROR, "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString( to )); MsgDev( D_ERROR, "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString( to ));
} }
#ifdef _WIN32
else if( err == WSAEADDRNOTAVAIL || err == WSAENOBUFS ) else if( err == WSAEADDRNOTAVAIL || err == WSAENOBUFS )
#else
else if( errno == EADDRNOTAVAIL || errno == ENOBUFS )
#endif
{ {
MsgDev( D_ERROR, "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString( to )); MsgDev( D_ERROR, "NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString( to ));
} }
@ -1552,12 +1485,8 @@ static int NET_IPSocket( const char *net_interface, int port, qboolean multicast
if( NET_IsSocketError(( net_socket = pSocket( PF_INET, SOCK_DGRAM, IPPROTO_UDP )) ) ) if( NET_IsSocketError(( net_socket = pSocket( PF_INET, SOCK_DGRAM, IPPROTO_UDP )) ) )
{ {
#ifdef _WIN32 err = pWSAGetLastError();
int err = pWSAGetLastError();
if( err != WSAEAFNOSUPPORT ) if( err != WSAEAFNOSUPPORT )
#else
if( err != EAFNOSUPPORT )
#endif
MsgDev( D_WARN, "NET_UDPSocket: socket = %s\n", NET_ErrorString( )); MsgDev( D_WARN, "NET_UDPSocket: socket = %s\n", NET_ErrorString( ));
return INVALID_SOCKET; return INVALID_SOCKET;
} }
@ -1594,12 +1523,8 @@ static int NET_IPSocket( const char *net_interface, int port, qboolean multicast
if( NET_IsSocketError( pSetSockopt( net_socket, IPPROTO_IP, IP_TOS, (const char *)&optval, sizeof( optval )) ) ) if( NET_IsSocketError( pSetSockopt( net_socket, IPPROTO_IP, IP_TOS, (const char *)&optval, sizeof( optval )) ) )
{ {
#ifdef _WIN32
err = pWSAGetLastError(); err = pWSAGetLastError();
if( err != WSAENOPROTOOPT ) if( err != WSAENOPROTOOPT )
#else
if( errno != ENOPROTOOPT )
#endif
Con_Printf( S_WARN "NET_UDPSocket: port: %d setsockopt IP_TOS: %s\n", port, NET_ErrorString( )); Con_Printf( S_WARN "NET_UDPSocket: port: %d setsockopt IP_TOS: %s\n", port, NET_ErrorString( ));
pCloseSocket( net_socket ); pCloseSocket( net_socket );
return INVALID_SOCKET; return INVALID_SOCKET;
@ -1887,6 +1812,9 @@ void NET_Init( void )
NET_FreeWinSock(); NET_FreeWinSock();
return; return;
} }
#else
// we have pthreads by default
net.threads_initialized = true;
#endif #endif
if( Sys_CheckParm( "-noip" )) if( Sys_CheckParm( "-noip" ))

Loading…
Cancel
Save