diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 45f884fb..23a07d67 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -2172,7 +2172,7 @@ void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) { CL_ServersResponsePacket =================== */ -void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { +void CL_ServersResponsePacket( const netadr_t* from, msg_t *msg, qboolean extended ) { int i, count, total; netadr_t addresses[MAX_SERVERSPERPACKET]; int numservers; @@ -2195,7 +2195,7 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { // advance to initial token do { - if(*buffptr == '\\' || *buffptr == '/') + if(*buffptr == '\\' || (extended && *buffptr == '/')) break; buffptr++; @@ -2203,6 +2203,7 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { while (buffptr + 1 < buffend) { + // IPv4 address if (*buffptr == '\\') { buffptr++; @@ -2215,7 +2216,8 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { addresses[numservers].type = NA_IP; } - else + // IPv6 address, if it's an extended response + else if (extended && *buffptr == '/') { buffptr++; @@ -2226,7 +2228,11 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { addresses[numservers].ip6[i] = *buffptr++; addresses[numservers].type = NA_IP6; + addresses[numservers].scope_id = from->scope_id; } + else + // syntax error! + break; // parse out port addresses[numservers].port = (*buffptr++) << 8; @@ -2378,9 +2384,15 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { return; } - // echo request from server + // list of servers sent back by a master server (classic) if ( !Q_strncmp(c, "getserversResponse", 18) ) { - CL_ServersResponsePacket( from, msg ); + CL_ServersResponsePacket( &from, msg, qfalse ); + return; + } + + // list of servers sent back by a master server (extended) + if ( !Q_strncmp(c, "getserversExtResponse", 21) ) { + CL_ServersResponsePacket( &from, msg, qtrue ); return; } @@ -3616,6 +3628,7 @@ void CL_GlobalServers_f( void ) { netadr_t to; int count, i, masterNum; char command[1024], *masteraddress; + char *cmdname; if ((count = Cmd_Argc()) < 3 || (masterNum = atoi(Cmd_Argv(1))) < 0 || masterNum > 4) { @@ -3650,7 +3663,17 @@ void CL_GlobalServers_f( void ) { cls.numglobalservers = -1; cls.pingUpdateSource = AS_GLOBAL; - Com_sprintf( command, sizeof(command), "getservers %s", Cmd_Argv(2) ); + // Use the extended query for IPv6 masters + if (to.type == NA_IP6 || to.type == NA_MULTICAST6) + { + cmdname = "getserversExt " GAMENAME; + + // TODO: test if we only have an IPv6 connection. If it's the case, + // request IPv6 servers only by appending " ipv6" to the command + } + else + cmdname = "getservers"; + Com_sprintf( command, sizeof(command), "%s %s", cmdname, Cmd_Argv(2) ); for (i=3; i < count; i++) { diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index e93ee237..ac78a831 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -227,6 +227,7 @@ static void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) { ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6; ((struct sockaddr_in6 *)s)->sin6_addr = * ((struct in6_addr *) &a->ip6); ((struct sockaddr_in6 *)s)->sin6_port = a->port; + ((struct sockaddr_in6 *)s)->sin6_scope_id = a->scope_id; } else if(a->type == NA_MULTICAST6) { @@ -248,6 +249,7 @@ static void SockadrToNetadr( struct sockaddr *s, netadr_t *a ) { a->type = NA_IP6; memcpy(a->ip6, &((struct sockaddr_in6 *)s)->sin6_addr, sizeof(a->ip6)); a->port = ((struct sockaddr_in6 *)s)->sin6_port; + a->scope_id = ((struct sockaddr_in6 *)s)->sin6_scope_id; } } @@ -279,14 +281,11 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s memset(sadr, '\0', sizeof(*sadr)); memset(&hints, '\0', sizeof(hints)); - // workaround for buggy MacOSX getaddrinfo implementation that doesn't handle AF_UNSPEC in hints correctly. - if(family == AF_UNSPEC) - hintsp = NULL; - else - { - hintsp = &hints; - hintsp->ai_family = family; - } + hintsp = &hints; + hintsp->ai_family = family; + hintsp->ai_socktype = SOCK_DGRAM; + // FIXME: we should set "->ai_flags" to AI_PASSIVE if we intend + // to use this structure for a bind() - instead of a sendto() retval = getaddrinfo(s, NULL, hintsp, &res); @@ -399,7 +398,7 @@ qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) if (a.type == NA_IP6) { - if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6))) + if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)) && a.scope_id == b.scope_id) return qtrue; return qfalse; @@ -720,6 +719,8 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { } else { + // TODO? should we check the scope_id here? + compareip = (byte *) &((struct sockaddr_in6 *) &localIP[index].addr)->sin6_addr; comparemask = (byte *) &((struct sockaddr_in6 *) &localIP[index].netmask)->sin6_addr; compareadr = adr.ip6; diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 248fcf12..9a7ddacd 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -38,6 +38,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define CLIENT_WINDOW_MIN_TITLE "ioq3" #endif +#define GAMENAME BASEGAME + #ifdef _MSC_VER #define PRODUCT_VERSION "1.35" #endif diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index 72ea6172..006342a4 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -155,6 +155,7 @@ typedef struct { byte ip6[16]; unsigned short port; + unsigned long scope_id; // Needed for IPv6 link-local addresses } netadr_t; void NET_Init( void ); diff --git a/code/server/sv_main.c b/code/server/sv_main.c index b05a7850..4be0af4c 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -233,6 +233,7 @@ but not on every player enter or exit. void SV_MasterHeartbeat( void ) { static netadr_t adr[MAX_MASTER_SERVERS]; int i; + int res; // "dedicated 1" is for lan play, "dedicated 2" is for inet public play if ( !com_dedicated || com_dedicated->integer != 2 ) { @@ -259,7 +260,8 @@ void SV_MasterHeartbeat( void ) { sv_master[i]->modified = qfalse; Com_Printf( "Resolving %s\n", sv_master[i]->string ); - if ( !NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ) ) { + res = NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ); + if ( !res ) { // if the address failed to resolve, clear it // so we don't take repeated dns hits Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); @@ -267,7 +269,8 @@ void SV_MasterHeartbeat( void ) { sv_master[i]->modified = qfalse; continue; } - if ( !strchr( sv_master[i]->string, ':' ) ) { + if ( res == 2 ) { + // if no port was specified, use the default master port adr[i].port = BigShort( PORT_MASTER ); } Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i])); @@ -410,6 +413,7 @@ void SVC_Info( netadr_t from ) { va("%i", sv_maxclients->integer - sv_privateClients->integer ) ); Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) ); Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) ); + Info_SetValueForKey( infostring, "gamename", GAMENAME ); #ifdef USE_VOIP if (sv_voip->integer) {