From d07f81b00b41cf18a47fc70029bc1db85bc8c1a4 Mon Sep 17 00:00:00 2001 From: thilo Date: Wed, 9 Apr 2008 14:37:42 +0000 Subject: Add Multicast capabilities for LAN server scanning. git-svn-id: svn://svn.icculus.org/quake3/trunk@1305 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/client/cl_main.c | 23 +-- code/client/cl_ui.c | 8 +- code/q3_ui/ui_servers2.c | 1 + code/qcommon/files.c | 2 +- code/qcommon/net_chan.c | 9 +- code/qcommon/net_ip.c | 433 +++++++++++++++++++++++++++++++++-------------- code/qcommon/q_shared.c | 12 ++ code/qcommon/q_shared.h | 2 + code/qcommon/qcommon.h | 3 + code/server/sv_init.c | 5 + 10 files changed, 348 insertions(+), 150 deletions(-) (limited to 'code') diff --git a/code/client/cl_main.c b/code/client/cl_main.c index a03b9e7..0d373bb 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -1975,7 +1975,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { c = Cmd_Argv(0); - Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c); + Com_DPrintf ("CL packet %s: %s\n", NET_AdrToStringwPort(from), c); // challenge from the server we are connecting to if ( !Q_stricmp(c, "challengeResponse") ) { @@ -2008,8 +2008,8 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) { Com_Printf( "connectResponse from a different address. Ignored.\n" ); - Com_Printf( "%s should have been %s\n", NET_AdrToString( from ), - NET_AdrToString( clc.serverAddress ) ); + Com_Printf( "%s should have been %s\n", NET_AdrToStringwPort( from ), + NET_AdrToStringwPort( clc.serverAddress ) ); return; } Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) ); @@ -2095,7 +2095,7 @@ void CL_PacketEvent( netadr_t from, msg_t *msg ) { } if ( msg->cursize < 4 ) { - Com_Printf ("%s: Runt packet\n",NET_AdrToString( from )); + Com_Printf ("%s: Runt packet\n", NET_AdrToStringwPort( from )); return; } @@ -2104,7 +2104,7 @@ void CL_PacketEvent( netadr_t from, msg_t *msg ) { // if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) { Com_DPrintf ("%s:sequenced packet without connection\n" - ,NET_AdrToString( from ) ); + , NET_AdrToStringwPort( from ) ); // FIXME: send a client disconnect? return; } @@ -2924,7 +2924,6 @@ CL_ServerInfoPacket void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { int i, type; char info[MAX_INFO_STRING]; - char* str; char *infoString; int prot; @@ -2955,12 +2954,12 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { { case NA_BROADCAST: case NA_IP: - str = "udp"; type = 1; break; - + case NA_IP6: + type = 2; + break; default: - str = "???"; type = 0; break; } @@ -3013,7 +3012,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { if (info[strlen(info)-1] != '\n') { strncat(info, "\n", sizeof(info) - 1); } - Com_Printf( "%s: %s", NET_AdrToString( from ), info ); + Com_Printf( "%s: %s", NET_AdrToStringwPort( from ), info ); } } @@ -3246,6 +3245,8 @@ void CL_LocalServers_f( void ) { to.type = NA_BROADCAST; NET_SendPacket( NS_CLIENT, strlen( message ), message, to ); + to.type = NA_MULTICAST6; + NET_SendPacket( NS_CLIENT, strlen( message ), message, to ); } } } @@ -3318,7 +3319,7 @@ void CL_GetPing( int n, char *buf, int buflen, int *pingtime ) return; } - str = NET_AdrToString( cl_pinglist[n].adr ); + str = NET_AdrToStringwPort( cl_pinglist[n].adr ); Q_strncpyz( buf, str, buflen ); time = cl_pinglist[n].time; diff --git a/code/client/cl_ui.c b/code/client/cl_ui.c index 2854b12..0ca9943 100644 --- a/code/client/cl_ui.c +++ b/code/client/cl_ui.c @@ -251,25 +251,25 @@ static void LAN_GetServerAddressString( int source, int n, char *buf, int buflen switch (source) { case AS_LOCAL : if (n >= 0 && n < MAX_OTHER_SERVERS) { - Q_strncpyz(buf, NET_AdrToString( cls.localServers[n].adr) , buflen ); + Q_strncpyz(buf, NET_AdrToStringwPort( cls.localServers[n].adr) , buflen ); return; } break; case AS_MPLAYER : if (n >= 0 && n < MAX_OTHER_SERVERS) { - Q_strncpyz(buf, NET_AdrToString( cls.mplayerServers[n].adr) , buflen ); + Q_strncpyz(buf, NET_AdrToStringwPort( cls.mplayerServers[n].adr) , buflen ); return; } break; case AS_GLOBAL : if (n >= 0 && n < MAX_GLOBAL_SERVERS) { - Q_strncpyz(buf, NET_AdrToString( cls.globalServers[n].adr) , buflen ); + Q_strncpyz(buf, NET_AdrToStringwPort( cls.globalServers[n].adr) , buflen ); return; } break; case AS_FAVORITES : if (n >= 0 && n < MAX_OTHER_SERVERS) { - Q_strncpyz(buf, NET_AdrToString( cls.favoriteServers[n].adr) , buflen ); + Q_strncpyz(buf, NET_AdrToStringwPort( cls.favoriteServers[n].adr) , buflen ); return; } break; diff --git a/code/q3_ui/ui_servers2.c b/code/q3_ui/ui_servers2.c index 57c76ab..fa679f6 100644 --- a/code/q3_ui/ui_servers2.c +++ b/code/q3_ui/ui_servers2.c @@ -142,6 +142,7 @@ static char* gamenames[] = { static char* netnames[] = { "???", "UDP", + "UDP6", NULL }; diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 5e001ed..a1d3312 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -2475,7 +2475,7 @@ qboolean FS_idPak( char *pak, char *base ) { /* ================ -FS_idPak +FS_CheckDirTraversal Check whether the string contains stuff like "../" to prevent directory traversal bugs and return qtrue if it does. diff --git a/code/qcommon/net_chan.c b/code/qcommon/net_chan.c index ac7b30b..e4b1739 100644 --- a/code/qcommon/net_chan.c +++ b/code/qcommon/net_chan.c @@ -686,10 +686,9 @@ qboolean NET_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) { return qtrue; } - // look for a port number Q_strncpyz( base, s, sizeof( base ) ); - if(*base == '[') + if(*base == '[' || Q_CountChar(base, ':') > 1) { // This is an ipv6 address, handle it specially. search = strchr(base, ']'); @@ -702,10 +701,14 @@ qboolean NET_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) { port = search + 1; } - search = base + 1; + if(*base == '[') + search = base + 1; + else + search = base; } else { + // look for a port number port = strchr( base, ':' ); if ( port ) { diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index b2fa6a2..e39351e 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -33,7 +33,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif typedef int socklen_t; +#ifdef ADDRESS_FAMILY +#define sa_family_t ADDRESS_FAMILY +#else typedef unsigned short sa_family_t; +#endif + #define EAGAIN WSAEWOULDBLOCK #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define EAFNOSUPPORT WSAEAFNOSUPPORT @@ -54,6 +59,7 @@ static qboolean winsockInitialized = qfalse; #include #include #include +#include #include #include #include @@ -79,10 +85,13 @@ typedef int SOCKET; static qboolean usingSocks = qfalse; static int networkingEnabled = 0; -#define NET_ENABLEV4 0x01 -#define NET_ENABLEV6 0x02 +#define NET_ENABLEV4 0x01 +#define NET_ENABLEV6 0x02 // if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found. -#define NET_PRIOV6 0x04 +#define NET_PRIOV6 0x04 +// disables ipv6 multicast support if set. +#define NET_DISABLEMCAST 0x08 + static cvar_t *net_enabled; static cvar_t *net_socksEnabled; @@ -95,21 +104,43 @@ static cvar_t *net_ip; static cvar_t *net_ip6; static cvar_t *net_port; static cvar_t *net_port6; +static cvar_t *net_mcast6addr; +static cvar_t *net_mcast6iface; static struct sockaddr socksRelayAddr; static SOCKET ip_socket = INVALID_SOCKET; static SOCKET ip6_socket = INVALID_SOCKET; static SOCKET socks_socket = INVALID_SOCKET; +static SOCKET multicast6_socket = INVALID_SOCKET; + +// Keep track of currently joined multicast group. +static struct ipv6_mreq curgroup; +// And the currently bound address. +static struct sockaddr_in6 boundto; + +#ifndef IF_NAMESIZE + #define IF_NAMESIZE 16 +#endif + +// use an admin local address per default so that network admins can decide on how to handle quake3 traffic. +#define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533" + +#define MAX_IPS 32 + +typedef struct +{ + char ifname[IF_NAMESIZE]; + + netadrtype_t type; + sa_family_t family; + struct sockaddr_storage addr; + struct sockaddr_storage netmask; +} nip_localaddr_t; -#define MAX_IPS 16 -static int numIP; -static int numIP6; +static nip_localaddr_t localIP[MAX_IPS]; +static int numIP; -static byte localIP[MAX_IPS][4]; -static byte localIPmask[MAX_IPS][4]; -static byte localIP6[MAX_IPS][16]; -static byte localIP6mask[MAX_IPS][16]; //============================================================================= @@ -190,6 +221,12 @@ static void NetadrToSockadr( netadr_t *a, struct sockaddr *s ) { ((struct sockaddr_in6 *)s)->sin6_addr = * ((struct in6_addr *) &a->ip6); ((struct sockaddr_in6 *)s)->sin6_port = a->port; } + else if(a->type == NA_MULTICAST6) + { + ((struct sockaddr_in6 *)s)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)s)->sin6_addr = curgroup.ipv6mr_multiaddr; + ((struct sockaddr_in6 *)s)->sin6_port = a->port; + } } @@ -446,7 +483,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { if(ip_socket != INVALID_SOCKET) { fromlen = sizeof(from); - ret = recvfrom( ip_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen ); + ret = recvfrom( ip_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen ); if (ret == SOCKET_ERROR) { @@ -490,7 +527,35 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { if(ip6_socket != INVALID_SOCKET) { fromlen = sizeof(from); - ret = recvfrom(ip6_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen); + ret = recvfrom(ip6_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen); + + if (ret == SOCKET_ERROR) + { + err = socketError; + + if( err != EAGAIN && err != ECONNRESET ) + Com_Printf( "NET_GetPacket: %s\n", NET_ErrorString() ); + } + else + { + SockadrToNetadr((struct sockaddr *) &from, net_from); + net_message->readcount = 0; + + if(ret == net_message->maxsize) + { + Com_Printf( "Oversize packet from %s\n", NET_AdrToString (*net_from) ); + return qfalse; + } + + net_message->cursize = ret; + return qtrue; + } + } + + if(multicast6_socket != INVALID_SOCKET && multicast6_socket != ip6_socket) + { + fromlen = sizeof(from); + ret = recvfrom(multicast6_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *) &from, &fromlen); if (ret == SOCKET_ERROR) { @@ -515,6 +580,7 @@ qboolean Sys_GetPacket( netadr_t *net_from, msg_t *net_message ) { } } + return qfalse; } @@ -531,12 +597,18 @@ void Sys_SendPacket( int length, const void *data, netadr_t to ) { int ret = SOCKET_ERROR; struct sockaddr_storage addr; - if( to.type != NA_BROADCAST && to.type != NA_IP && to.type != NA_IP6 ) { + if( to.type != NA_BROADCAST && to.type != NA_IP && to.type != NA_IP6 && to.type != NA_MULTICAST6) + { Com_Error( ERR_FATAL, "Sys_SendPacket: bad address type" ); return; } - if((ip_socket == INVALID_SOCKET && to.type == NA_IP) || (ip6_socket == INVALID_SOCKET && to.type == NA_IP6)) + if( (ip_socket == INVALID_SOCKET && to.type == NA_IP) || + (ip6_socket == INVALID_SOCKET && to.type == NA_IP6) || + (ip6_socket == INVALID_SOCKET && to.type == NA_MULTICAST6) ) + return; + + if(net_enabled->integer & NET_DISABLEMCAST) return; memset(&addr, 0, sizeof(addr)); @@ -586,8 +658,9 @@ LAN clients will have their rate var ignored ================== */ qboolean Sys_IsLANAddress( netadr_t adr ) { - int index, run; + int index, run, addrsize; qboolean differed; + byte *compareadr, *comparemask, *compareip; if( adr.type == NA_LOOPBACK ) { return qtrue; @@ -608,23 +681,6 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { if(adr.ip[0] == 127) return qtrue; - - for(index = 0; index < numIP; index++) - { - differed = qfalse; - - for(run = 0; run < sizeof(*localIP); run++) - { - if((localIP[index][run] & localIPmask[index][run]) != (adr.ip[run] & localIPmask[index][run])) - { - differed = qtrue; - break; - } - } - - if(!differed) - return qtrue; - } } else if(adr.type == NA_IP6) { @@ -632,14 +688,34 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { return qtrue; if((adr.ip6[0] & 0xfe) == 0xfc) return qtrue; - - for(index = 0; index < numIP6; index++) + } + + // Now compare against the networks this computer is member of. + for(index = 0; index < numIP; index++) + { + if(localIP[index].type == adr.type) { + if(adr.type == NA_IP) + { + compareip = (byte *) &((struct sockaddr_in *) &localIP[index].addr)->sin_addr.s_addr; + comparemask = (byte *) &((struct sockaddr_in *) &localIP[index].netmask)->sin_addr.s_addr; + compareadr = adr.ip; + + addrsize = sizeof(adr.ip); + } + else if(adr.type == NA_IP6) + { + compareip = (byte *) &((struct sockaddr_in6 *) &localIP[index].addr)->sin6_addr; + comparemask = (byte *) &((struct sockaddr_in6 *) &localIP[index].netmask)->sin6_addr; + compareadr = adr.ip6; + + addrsize = sizeof(adr.ip6); + } + differed = qfalse; - - for(run = 0; run < sizeof(*localIP6); run++) + for(run = 0; run < addrsize; run++) { - if((localIP6[index][run] & localIP6mask[index][run]) != (adr.ip6[run] & localIP6mask[index][run])) + if((compareip[run] & comparemask[run]) != (compareadr[run] & comparemask[run])) { differed = qtrue; break; @@ -648,6 +724,7 @@ qboolean Sys_IsLANAddress( netadr_t adr ) { if(!differed) return qtrue; + } } @@ -661,27 +738,16 @@ Sys_ShowIP */ void Sys_ShowIP(void) { int i; - char buf[NET_ADDRSTRMAXLEN]; - struct sockaddr_in sa; - struct sockaddr_in6 sa6; + char addrbuf[NET_ADDRSTRMAXLEN]; - for (i = 0; i < numIP; i++) - { - memset(&sa, 0, sizeof(sa)); - - memcpy( &sa.sin_addr.s_addr, localIP[i], sizeof(sa.sin_addr.s_addr) ); - sa.sin_family = AF_INET; - Sys_SockaddrToString(buf, sizeof(buf), (struct sockaddr *) &sa, sizeof(sa)); - Com_Printf( "IP: %s\n", buf); - } - for (i = 0; i < numIP6; i++) + for(i = 0; i < numIP; i++) { - memset(&sa6, 0, sizeof(sa6)); + Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr, sizeof((*localIP).addr)); - memcpy( &sa6.sin6_addr, localIP6[i], sizeof(sa6.sin6_addr) ); - sa6.sin6_family = AF_INET6; - Sys_SockaddrToString(buf, sizeof(buf), (struct sockaddr *) &sa6, sizeof(sa6)); - Com_Printf( "IP6: %s\n", buf); + if(localIP[i].type == NA_IP) + Com_Printf( "IP: %s\n", addrbuf); + else if(localIP[i].type == NA_IP6) + Com_Printf( "IP6: %s\n", addrbuf); } } @@ -765,7 +831,7 @@ int NET_IPSocket( char *net_interface, int port, int *err ) { NET_IP6Socket ==================== */ -int NET_IP6Socket( char *net_interface, int port, int *err ) { +int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { SOCKET newsocket; struct sockaddr_in6 address; qboolean _true = qtrue; @@ -773,12 +839,16 @@ int NET_IP6Socket( char *net_interface, int port, int *err ) { *err = 0; - if( net_interface ) { - Com_Printf( "Opening IP6 socket: [%s]:%i\n", net_interface, port ); + 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 { + else Com_Printf( "Opening IP6 socket: localhost:%i\n", port ); - } if( ( newsocket = socket( PF_INET6, SOCK_DGRAM, IPPROTO_UDP ) ) == INVALID_SOCKET ) { *err = socketError; @@ -803,12 +873,6 @@ int NET_IP6Socket( char *net_interface, int port, int *err ) { } #endif - // make it broadcast capable - if( setsockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *) &i, sizeof(i) ) == SOCKET_ERROR ) { - Com_Printf( "WARNING: NET_IP6Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString() ); -// return newsocket; - } - if( !net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost") ) { address.sin6_family = AF_INET6; address.sin6_addr = in6addr_any; @@ -835,10 +899,115 @@ int NET_IP6Socket( char *net_interface, int port, int *err ) { closesocket( newsocket ); return INVALID_SOCKET; } + + if(bindto) + *bindto = address; return newsocket; } +/* +==================== +NET_SetMulticast +Set the current multicast group +==================== +*/ +void NET_SetMulticast6(void) +{ + struct sockaddr_in6 addr; + + if(!*net_mcast6addr->string || !Sys_StringToSockaddr(net_mcast6addr->string, (struct sockaddr *) &addr, sizeof(addr), AF_INET6)) + { + Com_Printf("WARNING: NET_JoinMulticast6: Incorrect multicast address given, " + "please set cvar %s to a sane value.\n", net_mcast6addr->name); + + Cvar_Set(net_enabled->name, va("%d", net_enabled->integer | NET_DISABLEMCAST)); + + return; + } + + memcpy(&curgroup.ipv6mr_multiaddr, &addr.sin6_addr, sizeof(curgroup.ipv6mr_multiaddr)); + + if(!*net_mcast6iface->string) + { +#ifdef _WIN32 + curgroup.ipv6mr_interface = atoi(net_mcast6iface->string); +#else + curgroup.ipv6mr_interface = if_nametoindex(net_mcast6iface->string); +#endif + } + else + curgroup.ipv6mr_interface = 0; +} + +/* +==================== +NET_JoinMulticast +Join an ipv6 multicast group +==================== +*/ +void NET_JoinMulticast6(void) +{ + int err; + + if(ip6_socket == INVALID_SOCKET || multicast6_socket != INVALID_SOCKET || net_enabled->integer & NET_DISABLEMCAST) + return; + + if(IN6_IS_ADDR_MULTICAST(&boundto.sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(&boundto.sin6_addr)) + { + // The way the socket was bound does not prohibit receiving multi-cast packets. So we don't need to open a new one. + multicast6_socket = ip6_socket; + } + else + { + if((multicast6_socket = NET_IP6Socket(net_mcast6addr->string, ntohs(boundto.sin6_port), NULL, &err)) == INVALID_SOCKET) + { + // If the OS does not support binding to multicast addresses, like WinXP, at least try with the normal file descriptor. + multicast6_socket = ip6_socket; + } + } + + if(curgroup.ipv6mr_interface) + { + if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *) &curgroup.ipv6mr_interface, sizeof(curgroup.ipv6mr_interface)) < 0) + { + Com_Printf("NET_JoinMulticast6: Couldn't set scope on multicast socket: %s\n", NET_ErrorString()); + + if(multicast6_socket != ip6_socket) + { + closesocket(multicast6_socket); + multicast6_socket = INVALID_SOCKET; + return; + } + } + } + + if (setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &curgroup, sizeof(curgroup))) + { + Com_Printf("NET_JoinMulticast6: Couldn't join multicast group: %s\n", NET_ErrorString()); + + if(multicast6_socket != ip6_socket) + { + closesocket(multicast6_socket); + multicast6_socket = INVALID_SOCKET; + return; + } + } +} + +void NET_LeaveMulticast6() +{ + if(multicast6_socket != INVALID_SOCKET) + { + if(multicast6_socket != ip6_socket) + closesocket(multicast6_socket); + else + setsockopt(multicast6_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &curgroup, sizeof(curgroup)); + + multicast6_socket = INVALID_SOCKET; + } +} /* ==================== @@ -1022,68 +1191,34 @@ void NET_OpenSocks( int port ) { NET_GetLocalAddress ===================== */ -int NET_AddLocalAddress(struct sockaddr *sa) +void NET_AddLocalAddress(char *ifname, struct sockaddr *addr, struct sockaddr *netmask) { - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - int index; + int addrlen; + sa_family_t family = addr->sa_family; - if(sa->sa_family == AF_INET) + if(numIP < MAX_IPS) { - if(numIP > MAX_IPS) - return -1; - - sin = (struct sockaddr_in *) sa; - - for(index = 0; index < numIP; index++) + if(family == AF_INET) { - if( !memcmp(&localIP[index], &sin->sin_addr.s_addr, sizeof(*localIP)) ) - break; + addrlen = sizeof(struct sockaddr_in); + localIP[numIP].type = NA_IP; } - - if(index >= numIP) - memcpy(localIP[numIP++], &sin->sin_addr.s_addr, sizeof(*localIP)); - - return numIP - 1; - } - else if(sa->sa_family == AF_INET6) - { - if(numIP6 > MAX_IPS) - return -1; - - sin6 = (struct sockaddr_in6 *) sa; - - for(index = 0; index < numIP6; index++) + else if(family == AF_INET6) { - if( !memcmp(&localIP6[index], &sin6->sin6_addr, sizeof(*localIP6)) ) - break; + addrlen = sizeof(struct sockaddr_in6); + localIP[numIP].type = NA_IP6; } - - if(index >= numIP6) - memcpy(localIP6[numIP6++], &sin6->sin6_addr, sizeof(*localIP6)); + else + return; - return numIP6 - 1; - } - - return -1; -} - -void NET_AddLocalNetmask(struct sockaddr *sa, int position) -{ - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; + Q_strncpyz(localIP[numIP].ifname, ifname, sizeof(localIP[numIP].ifname)); + + localIP[numIP].family = family; - if(sa->sa_family == AF_INET) - { - sin = (struct sockaddr_in *) sa; - - memcpy(localIPmask[position], &sin->sin_addr.s_addr, sizeof(*localIPmask)); - } - else if(sa->sa_family == AF_INET6) - { - sin6 = (struct sockaddr_in6 *) sa; + memcpy(&localIP[numIP].addr, addr, addrlen); + memcpy(&localIP[numIP].netmask, netmask, addrlen); - memcpy(localIP6mask[position], &sin6->sin6_addr, sizeof(*localIP6mask)); + numIP++; } } @@ -1091,7 +1226,6 @@ void NET_AddLocalNetmask(struct sockaddr *sa, int position) void NET_GetLocalAddress(void) { struct ifaddrs *ifap, *search; - int retval; if(getifaddrs(&ifap)) Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces: %s\n", NET_ErrorString()); @@ -1099,8 +1233,9 @@ void NET_GetLocalAddress(void) { for(search = ifap; search; search = search->ifa_next) { - if((retval = NET_AddLocalAddress(search->ifa_addr)) >= 0) - NET_AddLocalNetmask(search->ifa_netmask, retval); + // Only add interfaces that are up. + if(ifap->ifa_flags & IFF_UP) + NET_AddLocalAddress(search->ifa_name, search->ifa_addr, search->ifa_netmask); } freeifaddrs(ifap); @@ -1114,6 +1249,8 @@ void NET_GetLocalAddress( void ) { struct addrinfo hint; struct addrinfo *res = NULL; struct addrinfo *search; + struct sockaddr_in mask4; + struct sockaddr_in6 mask6; if(gethostname( hostname, 256 ) == SOCKET_ERROR) return; @@ -1128,13 +1265,25 @@ void NET_GetLocalAddress( void ) { if(getaddrinfo(hostname, NULL, &hint, &res)) return; + /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a + * netmask with all bits set. */ + + memset(&mask4, 0, sizeof(mask4)); + memset(&mask6, 0, sizeof(mask6)); + mask4.sin_family = AF_INET; + memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr)); + mask6.sin6_family = AF_INET6; + memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr)); + // add all IPs from returned list. for(search = res; search; search = search->ai_next) - NET_AddLocalAddress(search->ai_addr); + { + if(search->ai_family == AF_INET) + NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4); + else if(search->ai_family == AF_INET6) + NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6); + } - memset(localIPmask, 0, sizeof(localIPmask)); - memset(localIP6mask, 0xFF, sizeof(localIP6mask)); - Sys_ShowIP(); } #endif @@ -1158,6 +1307,8 @@ void NET_OpenIP( void ) { port = net_port->integer; port6 = net_port6->integer; + NET_GetLocalAddress(); + // automatically scan for a valid port, so multiple // dedicated servers can be started without requiring // a different net_port for each one @@ -1188,7 +1339,7 @@ void NET_OpenIP( void ) { { for( i = 0 ; i < 10 ; i++ ) { - ip6_socket = NET_IP6Socket(net_ip6->string, port6 + i, &err); + ip6_socket = NET_IP6Socket(net_ip6->string, port6 + i, &boundto, &err); if (ip6_socket != INVALID_SOCKET) { Cvar_SetValue( "net_port6", port6 + i ); @@ -1203,8 +1354,6 @@ void NET_OpenIP( void ) { if(ip6_socket == INVALID_SOCKET) Com_Printf( "WARNING: Couldn't bind to a v6 ip address.\n"); } - - NET_GetLocalAddress(); } @@ -1226,7 +1375,7 @@ static qboolean NET_GetCvars( void ) { } #ifdef DEDICATED - // I want server owners to explicitly turn ipv6 support on. + // I want server owners to explicitly turn on ipv6 support. net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE ); #else /* End users have it enabled so they can connect to ipv6-only hosts, but ipv4 will be @@ -1234,6 +1383,17 @@ static qboolean NET_GetCvars( void ) { net_enabled = Cvar_Get( "net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE ); #endif + // Some cvars for configuring multicast options which facilitates scanning for servers on local subnets. + if( net_mcast6addr && net_mcast6addr->modified ) { + modified = qtrue; + } + net_mcast6addr = Cvar_Get( "net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE ); + + if( net_mcast6iface && net_mcast6iface->modified ) { + modified = qtrue; + } + net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE ); + if( net_socksEnabled && net_socksEnabled->modified ) { modified = qtrue; } @@ -1314,6 +1474,14 @@ void NET_Config( qboolean enableNetworking ) { ip_socket = INVALID_SOCKET; } + if(multicast6_socket) + { + if(multicast6_socket != ip6_socket) + closesocket(multicast6_socket); + + multicast6_socket = INVALID_SOCKET; + } + if ( ip6_socket != INVALID_SOCKET ) { closesocket( ip6_socket ); ip6_socket = INVALID_SOCKET; @@ -1326,9 +1494,12 @@ void NET_Config( qboolean enableNetworking ) { } - if( start ) { - if (net_enabled->integer) { + if( start ) + { + if (net_enabled->integer) + { NET_OpenIP(); + NET_SetMulticast6(); } } } diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 18b71d3..1bc8076 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -921,6 +921,18 @@ char *Q_CleanStr( char *string ) { return string; } +int Q_CountChar(const char *string, char tocount) +{ + int count; + + for(count = 0; *string; string++) + { + if(*string == tocount) + count++; + } + + return count; +} void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { int len; diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 8f5dbe4..81083d1 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -693,6 +693,8 @@ void Q_strcat( char *dest, int size, const char *src ); int Q_PrintStrlen( const char *string ); // removes color sequences from string char *Q_CleanStr( char *string ); +// Count the number of char tocount encountered in string +int Q_CountChar(const char *string, char tocount); //============================================= diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index a941882..d47bb21 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -138,6 +138,7 @@ typedef enum { NA_BROADCAST, NA_IP, NA_IP6, + NA_MULTICAST6, NA_UNSPEC } netadrtype_t; @@ -172,6 +173,8 @@ const char *NET_AdrToString (netadr_t a); const char *NET_AdrToStringwPort (netadr_t a); qboolean NET_StringToAdr ( const char *s, netadr_t *a, netadrtype_t family); qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, msg_t *net_message); +void NET_JoinMulticast6(void); +void NET_LeaveMulticast6(void); void NET_Sleep(int msec); diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 69d08ea..3b9cf3d 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -286,6 +286,9 @@ void SV_Startup( void ) { } Cvar_Set( "sv_running", "1" ); + + // Join the ipv6 multicast group now that a map is running so clients can scan for us on the local network. + NET_JoinMulticast6(); } @@ -734,6 +737,8 @@ void SV_Shutdown( char *finalmsg ) { Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg ); + NET_LeaveMulticast6(); + if ( svs.clients && !com_errorEntered ) { SV_FinalMessage( finalmsg ); } -- cgit v1.2.3