Index: code/unix/unix_net.c =================================================================== --- code/unix/unix_net.c (revision 55) +++ code/unix/unix_net.c (working copy) @@ -34,6 +34,7 @@ #include #include #include +#include #include #ifdef MACOS_X @@ -49,8 +50,8 @@ netadr_t net_local_adr; -int ip_socket; -int ipx_socket; +int ip_socket = 0; +int ipx_socket = 0; #define MAX_IPS 16 static int numIP; @@ -61,12 +62,13 @@ //============================================================================= -void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s) +void NetadrToSockadr (netadr_t *a, struct sockaddr *sa) { - memset (s, 0, sizeof(*s)); - if (a->type == NA_BROADCAST) { + struct sockaddr_in *s = (struct sockaddr_in*) sa; + memset (s, 0, sizeof(*s)); + s->sin_family = AF_INET; s->sin_port = a->port; @@ -74,26 +76,77 @@ } else if (a->type == NA_IP) { + struct sockaddr_in *s = (struct sockaddr_in*) sa; + memset (s, 0, sizeof(*s)); + s->sin_family = AF_INET; *(int *)&s->sin_addr = *(int *)&a->ip; s->sin_port = a->port; } +#ifdef ENABLE_IPV6 + else if(a->type == NA_IP6) + { + struct sockaddr_in6 *s = (struct sockaddr_in6*) sa; + memset (s, 0, sizeof(*s)); + + s->sin6_family = AF_INET6; + + memcpy(&s->sin6_addr, a->ip6, sizeof(a->ip6)); + s->sin6_port = a->port; + } + else if(a->type == NA_BROADCAST_IP6) + { + const static byte broadcast[16] = { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }; // link local multicast + struct sockaddr_in6 *s = (struct sockaddr_in6*) sa; + memset (s, 0, sizeof(*s)); + + s->sin6_family = AF_INET6; + + memcpy(&s->sin6_addr, broadcast, sizeof(broadcast)); + s->sin6_port = a->port; + } +#endif } -void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a) +void SockadrToNetadr (struct sockaddr *sa, netadr_t *a) { + if(sa->sa_family == AF_INET) + { + struct sockaddr_in* s = (struct sockaddr_in*) sa; + *(int *)&a->ip = *(int *)&s->sin_addr; a->port = s->sin_port; a->type = NA_IP; + } +#ifdef ENABLE_IPV6 + else if(sa->sa_family == AF_INET6) + { + struct sockaddr_in6* s = (struct sockaddr_in6*) sa; + + memcpy(a->ip6, &s->sin6_addr, sizeof(a->ip6)); + a->port = s->sin6_port; + a->type = NA_IP6; + } +#endif } char *NET_BaseAdrToString (netadr_t a) { static char s[64]; +#ifdef ENABLE_IPV6 + if(a.type == NA_IP6) + { + struct sockaddr_in6 sa; + NetadrToSockadr(&a, (struct sockaddr*) &sa); + getnameinfo((struct sockaddr*) &sa, sizeof(sa), s, sizeof(s), NULL, 0, NI_NUMERICHOST); + } + else +#endif // well, we can use getnameinfo for IPv4 too...but let's leave it as it is (for sure) Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + return s; } @@ -105,29 +158,35 @@ 192.246.40.70 ============= */ -qboolean Sys_StringToSockaddr (const char *s, struct sockaddr *sadr) +qboolean StringToSockaddr (const char *s, struct sockaddr *sadr, int family) { - struct hostent *h; + struct addrinfo hint; + struct addrinfo* res = NULL; //char *colon; // bk001204 - unused memset (sadr, 0, sizeof(*sadr)); - ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + memset (&hint, 0, sizeof(hint)); - ((struct sockaddr_in *)sadr)->sin_port = 0; + hint.ai_family = family; - if ( s[0] >= '0' && s[0] <= '9') + getaddrinfo(s, NULL, &hint, &res); + if(res != NULL) { - *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s); + memcpy(sadr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return qtrue; } else - { - if (! (h = gethostbyname(s)) ) return qfalse; - *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0]; - } - - return qtrue; } +qboolean Sys_StringToSockaddr (const char *s, struct sockaddr *sadr) +{ +#ifdef ENABLE_IPV6 + return StringToSockaddr(s,sadr,PF_UNSPEC); +#else + return StringToSockaddr(s,sadr,PF_INET); +#endif +} /* ============= @@ -142,12 +201,12 @@ */ qboolean Sys_StringToAdr (const char *s, netadr_t *a) { - struct sockaddr_in sadr; + struct sockaddr_storage sadr; - if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr)) + if (!StringToSockaddr (s, (struct sockaddr *)&sadr, PF_UNSPEC)) return qfalse; - SockadrToNetadr (&sadr, a); + SockadrToNetadr ((struct sockaddr*) &sadr, a); return qtrue; } @@ -158,7 +217,7 @@ qboolean Sys_GetPacket (netadr_t *net_from, msg_t *net_message) { int ret; - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; int net_socket; int protocol; @@ -178,7 +237,7 @@ ret = recvfrom (net_socket, net_message->data, net_message->maxsize , 0, (struct sockaddr *)&from, &fromlen); - SockadrToNetadr (&from, net_from); + SockadrToNetadr ((struct sockaddr*) &from, net_from); // bk000305: was missing net_message->readcount = 0; @@ -211,9 +270,20 @@ void Sys_SendPacket( int length, const void *data, netadr_t to ) { int ret; - struct sockaddr_in addr; + struct sockaddr_storage addr; int net_socket; +#ifdef ENABLE_IPV6 + if (to.type == NA_IP6) + { + net_socket = ip_socket; + } + else if(to.type == NA_BROADCAST_IP6) + { + net_socket = ip_socket; + } + else +#endif if (to.type == NA_BROADCAST) { net_socket = ip_socket; @@ -238,7 +308,7 @@ if (!net_socket) return; - NetadrToSockadr (&to, &addr); + NetadrToSockadr (&to, (struct sockaddr*) &addr); ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) ); if (ret == -1) @@ -269,6 +339,15 @@ return qtrue; } +#ifdef ENABLE_IPV6 + if(adr.type == NA_IP6) + { + if(adr.ip6[0] == 0xfe && adr.ip6[1] == 0x80) + return qtrue; + return qfalse; + } +#endif + if( adr.type != NA_IP ) { return qfalse; } @@ -438,6 +517,7 @@ } #else + void NET_GetLocalAddress( void ) { char hostname[256]; struct hostent *hostInfo; @@ -461,7 +541,7 @@ Com_Printf( "Alias: %s\n", p ); } - if ( hostInfo->h_addrtype != AF_INET ) { + if ( hostInfo->h_addrtype != AF_INET) { return; } @@ -475,7 +555,7 @@ Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff ); } } -#endif +#endif // !defined(MACOS_X) /* ==================== @@ -484,6 +564,7 @@ */ // bk001204 - prototype needed int NET_IPSocket (char *net_interface, int port); +int NET_IP6Socket (char *net_interface, int port); void NET_OpenIP (void) { cvar_t *ip; @@ -495,13 +576,19 @@ port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value; for ( i = 0 ; i < 10 ; i++ ) { +#ifdef ENABLE_IPV6 + ip_socket = NET_IP6Socket (ip->string, port + i); +#else ip_socket = NET_IPSocket (ip->string, port + i); +#endif + if ( ip_socket ) { Cvar_SetValue( "net_port", port + i ); NET_GetLocalAddress(); return; } } + Com_Error (ERR_FATAL, "Couldn't allocate IP port"); } @@ -526,6 +613,7 @@ NET_IPSocket ==================== */ +#ifndef ENABLE_IPV6 int NET_IPSocket (char *net_interface, int port) { int newsocket; @@ -562,7 +650,7 @@ if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost")) address.sin_addr.s_addr = INADDR_ANY; else - Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address); + StringToSockaddr (net_interface, (struct sockaddr *)&address, PF_INET); if (port == PORT_ANY) address.sin_port = 0; @@ -580,7 +668,66 @@ return newsocket; } +#else +int NET_IP6Socket (char *net_interface, int port) +{ + int newsocket; + struct sockaddr_in6 address; + qboolean _qtrue = qtrue; + int i = 1; + + if(net_interface && Q_stricmp(net_interface, "localhost") == 0) + net_interface = "ip6-localhost"; + if ( net_interface ) { + Com_Printf("Opening IP socket: %s:%i\n", net_interface, port ); + } else { + Com_Printf("Opening IP socket: localhost:%i\n", port ); + } + + if ((newsocket = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString()); + return 0; + } + + // make it non-blocking + if (ioctl (newsocket, FIONBIO, &_qtrue) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString()); + return 0; + } + + // make it broadcast capable + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString()); + return 0; + } + + if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "ip6-localhost")) + address.sin6_addr = in6addr_any; + else + StringToSockaddr (net_interface, (struct sockaddr *)&address, PF_INET6); + + if (port == PORT_ANY) + address.sin6_port = 0; + else + address.sin6_port = htons((short)port); + + address.sin6_family = AF_INET6; + + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString()); + close (newsocket); + return 0; + } + + return newsocket; +} +#endif + /* ==================== NET_Shutdown @@ -621,7 +768,9 @@ FD_ZERO(&fdset); if (stdin_active) FD_SET(0, &fdset); // stdin is processed too + FD_SET(ip_socket, &fdset); // network socket + timeout.tv_sec = msec/1000; timeout.tv_usec = (msec%1000)*1000; select(ip_socket+1, &fdset, NULL, NULL, &timeout); Index: code/qcommon/qcommon.h =================================================================== --- code/qcommon/qcommon.h (revision 55) +++ code/qcommon/qcommon.h (working copy) @@ -131,7 +131,9 @@ NA_BROADCAST, NA_IP, NA_IPX, - NA_BROADCAST_IPX + NA_BROADCAST_IPX, + NA_IP6, + NA_BROADCAST_IP6 } netadrtype_t; typedef enum { @@ -144,6 +146,7 @@ byte ip[4]; byte ipx[10]; + byte ip6[16]; unsigned short port; } netadr_t; Index: code/qcommon/net_chan.c =================================================================== --- code/qcommon/net_chan.c (revision 55) +++ code/qcommon/net_chan.c (working copy) @@ -489,8 +489,15 @@ return qtrue; return qfalse; } +#ifdef ENABLE_IPV6 + if(a.type == NA_IP6) + { + if(memcmp(a.ip6, b.ip6, 16) == 0) + return qtrue; + return qfalse; + } +#endif - Com_Printf ("NET_CompareBaseAdr: bad address type\n"); return qfalse; } @@ -506,6 +513,13 @@ } else if (a.type == NA_IP) { Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%hu", a.ip[0], a.ip[1], a.ip[2], a.ip[3], BigShort(a.port)); +#ifdef ENABLE_IPV6 + } else if (a.type == NA_IP6) { + Com_sprintf(s, sizeof(s), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x@%hu", + a.ip6[0], a.ip6[1], a.ip6[2], a.ip6[3], a.ip6[4], a.ip6[5], a.ip6[6], a.ip6[7], a.ip6[8], + a.ip6[9], a.ip6[10], a.ip6[11], a.ip6[12], a.ip6[13], a.ip6[14], a.ip6[15], a.ip6[16], + BigShort(a.port)); +#endif } else { Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x.%02x%02x%02x%02x%02x%02x:%hu", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], @@ -537,6 +551,14 @@ return qtrue; return qfalse; } +#ifdef ENABLE_IPV6 + if(a.type == NA_IP6) + { + if(memcmp(a.ip6, b.ip6, 16) == 0 && a.port == b.port) + return qtrue; + return qfalse; + } +#endif Com_Printf ("NET_CompareAdr: bad address type\n"); return qfalse; @@ -712,11 +734,49 @@ // look for a port number Q_strncpyz( base, s, sizeof( base ) ); - port = strstr( base, ":" ); + + port = strrchr( base, ':' ); // find last ':' +#ifdef ENABLE_IPV6 + if(strrchr(base, '@') > port) + { + port = strrchr(base, '@'); // another way of port in IPv6 + } +#endif + +Com_Printf("address: %s\n", base); + if ( port ) { +#ifdef ENABLE_IPV6 + if(port > base && *port == ':') + { + // FIXME: :: is valid in the case of seven : too + if(*(port-1) == ':' && strstr(base, "::") != port-1) // there are more :: + { + *(port-1) = 0; // zero the first : in the last :: + } + else if(*(port-1) == ']') + { + // getaddrinfo doesn't accept [aaaa::bbbb] addresses + memmove(base,base+1,sizeof(base)-1); // remove '[' + port--; + *(port-1) = 0; // remove ']' + } + else if(strchr(base, ':') != port) // this should be IPv6 + { + // FIXME: workaround an client problem - Q3 just adds :port to address :( + if(strlen(port) <= 5) // accept the last segment as a port if len is > 4+1 + port = NULL; + } + } + +#endif + if(port) + { *port = 0; port++; } + } + Com_Printf("address2: %s\n", base); r = Sys_StringToAdr( base, a ); @@ -725,12 +785,6 @@ return qfalse; } - // inet_addr returns this if out of range - if ( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 ) { - a->type = NA_BAD; - return qfalse; - } - if ( port ) { a->port = BigShort( (short)atoi( port ) ); } else { Index: code/client/cl_main.c =================================================================== --- code/client/cl_main.c (revision 55) +++ code/client/cl_main.c (working copy) @@ -2547,7 +2547,13 @@ str = "udp"; type = 1; break; - +#ifdef ENABLE_IPV6 + case NA_BROADCAST_IP6: + case NA_IP6: + str = "udp6"; + type = 3; + break; +#endif case NA_IPX: case NA_BROADCAST_IPX: str = "ipx"; @@ -2841,7 +2847,10 @@ to.type = NA_BROADCAST; NET_SendPacket( NS_CLIENT, strlen( message ), message, to ); - +#ifdef ENABLE_IPV6 + to.type = NA_BROADCAST_IP6; + NET_SendPacket( NS_CLIENT, strlen( message ), message, to ); +#endif to.type = NA_BROADCAST_IPX; NET_SendPacket( NS_CLIENT, strlen( message ), message, to ); }