/* ==================== NET_IP6Socket ==================== */ SOCKET NET_IP6Socket( const char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { SOCKET newsocket; struct sockaddr_in6 address; u_long _true = 1; qboolean brackets = net_interface && Q_CountChar( net_interface, ':' ); *err = 0; // Print the name in brackets if there is a colon: Com_Printf(_( "Opening IP6 socket: %s%s%s:%s\n"), brackets ? "[" : "", net_interface ? net_interface : "[::]", brackets ? "]" : "", port ? va( "%i", port ) : "*" ); if ( ( newsocket = socket( PF_INET6, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) { *err = socketError; Com_Printf( "WARNING: NET_IP6Socket: socket: %s\n", NET_ErrorString() ); return newsocket; } // make it non-blocking if ( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) { Com_Printf( "WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n", NET_ErrorString() ); *err = socketError; closesocket( newsocket ); return INVALID_SOCKET; } #ifdef IPV6_V6ONLY { int i = 1; // IPv4 addresses should not be allowed to connect via this socket. if ( setsockopt( newsocket, IPPROTO_IPV6, IPV6_V6ONLY, ( char * ) &i, sizeof( i ) ) == SOCKET_ERROR ) { // win32 systems don't seem to support this anyways. Com_DPrintf( "WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString() ); } } #endif if ( !net_interface || !net_interface[ 0 ] ) { address.sin6_family = AF_INET6; address.sin6_addr = in6addr_any; } else { if ( !Sys_StringToSockaddr( net_interface, ( struct sockaddr * ) &address, sizeof( address ), AF_INET6 ) ) { closesocket( newsocket ); return INVALID_SOCKET; } } address.sin6_port = htons( ( short ) port ); if ( bind( newsocket, ( void * ) &address, sizeof( address ) ) == SOCKET_ERROR ) { Com_Printf( "WARNING: NET_IP6Socket: bind: %s\n", NET_ErrorString() ); *err = socketError; closesocket( newsocket ); return INVALID_SOCKET; } if ( bindto ) { // random port? find what was chosen if ( address.sin6_port == 0 ) { struct sockaddr_in6 addr; // enough space socklen_t addrlen = sizeof( addr ); if ( !getsockname( newsocket, (struct sockaddr *) &addr, &addrlen ) && addrlen ) { address.sin6_port = addr.sin6_port; } } *bindto = address; } return newsocket; }
/* ==================== NET_IP6Socket ==================== */ int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { SOCKET newsocket; struct sockaddr_in6 address; u_long _true = 1; *err = 0; if ( net_interface ) { // Print the name in brackets if there is a colon: if ( Q_CountChar( net_interface, ':' ) ) { Com_Printf(_( "Opening IP6 socket: [%s]:%i\n"), net_interface, port ); } else { Com_Printf(_( "Opening IP6 socket: %s:%i\n"), net_interface, port ); } } else { Com_Printf(_( "Opening IP6 socket: [::]:%i\n"), port ); } if ( ( newsocket = socket( PF_INET6, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) { *err = socketError; Com_Printf(_( "WARNING: NET_IP6Socket: socket: %s\n"), NET_ErrorString() ); return newsocket; } // make it non-blocking if ( ioctlsocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR ) { Com_Printf(_( "WARNING: NET_IP6Socket: ioctl FIONBIO: %s\n"), NET_ErrorString() ); *err = socketError; closesocket( newsocket ); return INVALID_SOCKET; } #ifdef IPV6_V6ONLY { int i = 1; // ipv4 addresses should not be allowed to connect via this socket. if ( setsockopt( newsocket, IPPROTO_IPV6, IPV6_V6ONLY, ( char * ) &i, sizeof( i ) ) == SOCKET_ERROR ) { // win32 systems don't seem to support this anyways. Com_DPrintf( "WARNING: NET_IP6Socket: setsockopt IPV6_V6ONLY: %s\n", NET_ErrorString() ); } } #endif if ( !net_interface || !net_interface[ 0 ] ) { address.sin6_family = AF_INET6; address.sin6_addr = in6addr_any; } else { if ( !Sys_StringToSockaddr( net_interface, ( struct sockaddr * ) &address, sizeof( address ), AF_INET6 ) ) { closesocket( newsocket ); return INVALID_SOCKET; } } if ( port == PORT_ANY ) { address.sin6_port = 0; } else { address.sin6_port = htons( ( short ) port ); } if ( bind( newsocket, ( void * ) &address, sizeof( address ) ) == SOCKET_ERROR ) { Com_Printf(_( "WARNING: NET_IP6Socket: bind: %s\n"), NET_ErrorString() ); *err = socketError; closesocket( newsocket ); return INVALID_SOCKET; } if ( bindto ) { *bindto = address; } return newsocket; }
/* ============= NET_StringToAdr Traps "localhost" for loopback, passes everything else to system return 0 on address not found, 1 on address found with port, 2 on address found without port. ============= */ int NET_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) { char base[ MAX_STRING_CHARS ], *search; char *port = nullptr; if ( !strcmp( s, "localhost" ) ) { Com_Memset( a, 0, sizeof( *a ) ); a->type = NA_LOOPBACK; // as NA_LOOPBACK doesn't require ports report port was given. return 1; } Q_strncpyz( base, s, sizeof( base ) ); if ( *base == '[' || Q_CountChar( base, ':' ) > 1 ) { // This is an IPv6 address, handle it specially. search = strchr( base, ']' ); if ( search ) { *search = '\0'; search++; if ( *search == ':' ) { port = search + 1; } } if ( *base == '[' ) { search = base + 1; } else { search = base; } } else { // look for a port number port = strchr( base, ':' ); if ( port ) { *port = '\0'; port++; } search = base; } if ( !Sys_StringToAdr( search, a, family ) ) { a->type = NA_BAD; return 0; } if ( port ) { a->port = BigShort( ( short ) atoi( port ) ); return 1; } else { a->port = BigShort( PORT_SERVER ); return 2; } }