r1305 - in trunk/code: client q3_ui qcommon server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Apr 9 10:37:42 EDT 2008


Author: thilo
Date: 2008-04-09 10:37:42 -0400 (Wed, 09 Apr 2008)
New Revision: 1305

Modified:
   trunk/code/client/cl_main.c
   trunk/code/client/cl_ui.c
   trunk/code/q3_ui/ui_servers2.c
   trunk/code/qcommon/files.c
   trunk/code/qcommon/net_chan.c
   trunk/code/qcommon/net_ip.c
   trunk/code/qcommon/q_shared.c
   trunk/code/qcommon/q_shared.h
   trunk/code/qcommon/qcommon.h
   trunk/code/server/sv_init.c
Log:
Add Multicast capabilities for LAN server scanning.


Modified: trunk/code/client/cl_main.c
===================================================================
--- trunk/code/client/cl_main.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/client/cl_main.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -1975,7 +1975,7 @@
 
 	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 @@
 		}
 		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 @@
 	}
 
 	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 @@
 	//
 	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 @@
 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 @@
 			{
 				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 @@
 		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 @@
 
 			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 @@
 		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;

Modified: trunk/code/client/cl_ui.c
===================================================================
--- trunk/code/client/cl_ui.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/client/cl_ui.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -251,25 +251,25 @@
 	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;

Modified: trunk/code/q3_ui/ui_servers2.c
===================================================================
--- trunk/code/q3_ui/ui_servers2.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/q3_ui/ui_servers2.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -142,6 +142,7 @@
 static char* netnames[] = {
 	"???",
 	"UDP",
+	"UDP6",
 	NULL
 };
 

Modified: trunk/code/qcommon/files.c
===================================================================
--- trunk/code/qcommon/files.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/files.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -2475,7 +2475,7 @@
 
 /*
 ================
-FS_idPak
+FS_CheckDirTraversal
 
 Check whether the string contains stuff like "../" to prevent directory traversal bugs
 and return qtrue if it does.

Modified: trunk/code/qcommon/net_chan.c
===================================================================
--- trunk/code/qcommon/net_chan.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/net_chan.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -686,10 +686,9 @@
 		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 @@
 				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 ) {

Modified: trunk/code/qcommon/net_ip.c
===================================================================
--- trunk/code/qcommon/net_ip.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/net_ip.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -33,7 +33,12 @@
 #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 @@
 #include <errno.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <net/if.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -79,10 +85,13 @@
 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,22 +104,44 @@
 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;
 
-#define	MAX_IPS		16
-static	int		numIP;
-static	int		numIP6;
+// Keep track of currently joined multicast group.
+static struct ipv6_mreq curgroup;
+// And the currently bound address.
+static struct sockaddr_in6 boundto;
 
-static	byte	localIP[MAX_IPS][4];
-static	byte	localIPmask[MAX_IPS][4];
-static	byte	localIP6[MAX_IPS][16];
-static	byte	localIP6mask[MAX_IPS][16];
+#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;
+
+static nip_localaddr_t localIP[MAX_IPS];
+static int numIP;
+
+
 //=============================================================================
 
 
@@ -190,6 +221,12 @@
 		((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 @@
 	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,7 @@
 	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)
 		{
@@ -514,7 +551,36 @@
 			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)
+		{
+			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;
+		}
+	}
 	
+	
 	return qfalse;
 }
 
@@ -531,14 +597,20 @@
 	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));
 	NetadrToSockadr( &to, (struct sockaddr *) &addr );
 
@@ -586,8 +658,9 @@
 ==================
 */
 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 @@
 
 		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 @@
 			return qtrue;
 		if((adr.ip6[0] & 0xfe) == 0xfc)
 			return qtrue;
+	}
+	
+	// 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);
+			}
 
-		for(index = 0; index < numIP6; index++)
-		{
 			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 @@
 			
 			if(!differed)
 				return qtrue;
+
 		}
 	}
 	
@@ -661,28 +738,17 @@
 */
 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++)
+	for(i = 0; i < numIP; i++)
 	{
-		memset(&sa, 0, sizeof(sa));
+		Sys_SockaddrToString(addrbuf, sizeof(addrbuf), (struct sockaddr *) &localIP[i].addr, sizeof((*localIP).addr));
 
-		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);
+		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);
 	}
-	for (i = 0; i < numIP6; i++)
-	{
-		memset(&sa6, 0, sizeof(sa6));
-
-		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);
-	}
 }
 
 
@@ -765,7 +831,7 @@
 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 @@
 
 	*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 @@
 	}
 #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,13 +899,118 @@
 		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;
+	}
+}
+
+/*
+====================
 NET_OpenSocks
 ====================
 */
@@ -1022,76 +1191,41 @@
 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;
-	}
+		Q_strncpyz(localIP[numIP].ifname, ifname, sizeof(localIP[numIP].ifname));
+	
+		localIP[numIP].family = family;
 
-	return -1;
-}
-
-void NET_AddLocalNetmask(struct sockaddr *sa, int position)
-{
-	struct sockaddr_in *sin;
-	struct sockaddr_in6 *sin6;
-
-	if(sa->sa_family == AF_INET)
-	{
-		sin = (struct sockaddr_in *) sa;
+		memcpy(&localIP[numIP].addr, addr, addrlen);
+		memcpy(&localIP[numIP].netmask, netmask, addrlen);
 		
-		memcpy(localIPmask[position], &sin->sin_addr.s_addr, sizeof(*localIPmask));
+		numIP++;
 	}
-	else if(sa->sa_family == AF_INET6)
-	{
-		sin6 = (struct sockaddr_in6 *) sa;
-		
-		memcpy(localIP6mask[position], &sin6->sin6_addr, sizeof(*localIP6mask));
-	}
 }
 
 #if defined(__linux__) || defined(MACOSX) || defined(__BSD__)
 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 @@
 	{
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	{
 		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 @@
 		if(ip6_socket == INVALID_SOCKET)
 			Com_Printf( "WARNING: Couldn't bind to a v6 ip address.\n");
 	}
-
-	NET_GetLocalAddress();
 }
 
 
@@ -1226,7 +1375,7 @@
 	}
 	
 #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 @@
 	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 @@
 			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 @@
 		
 	}
 
-	if( start ) {
-		if (net_enabled->integer) {
+	if( start )
+	{
+		if (net_enabled->integer)
+		{
 			NET_OpenIP();
+			NET_SetMulticast6();
 		}
 	}
 }

Modified: trunk/code/qcommon/q_shared.c
===================================================================
--- trunk/code/qcommon/q_shared.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/q_shared.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -921,6 +921,18 @@
 	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;

Modified: trunk/code/qcommon/q_shared.h
===================================================================
--- trunk/code/qcommon/q_shared.h	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/q_shared.h	2008-04-09 14:37:42 UTC (rev 1305)
@@ -693,6 +693,8 @@
 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);
 
 //=============================================
 

Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/qcommon/qcommon.h	2008-04-09 14:37:42 UTC (rev 1305)
@@ -138,6 +138,7 @@
 	NA_BROADCAST,
 	NA_IP,
 	NA_IP6,
+	NA_MULTICAST6,
 	NA_UNSPEC
 } netadrtype_t;
 
@@ -172,6 +173,8 @@
 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);
 
 

Modified: trunk/code/server/sv_init.c
===================================================================
--- trunk/code/server/sv_init.c	2008-04-08 18:56:03 UTC (rev 1304)
+++ trunk/code/server/sv_init.c	2008-04-09 14:37:42 UTC (rev 1305)
@@ -286,6 +286,9 @@
 	}
 
 	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 @@
 
 	Com_Printf( "----- Server Shutdown (%s) -----\n", finalmsg );
 
+	NET_LeaveMulticast6();
+
 	if ( svs.clients && !com_errorEntered ) {
 		SV_FinalMessage( finalmsg );
 	}




More information about the quake3-commits mailing list