diff --git a/src/d_clisrv.c b/src/d_clisrv.c index c2b19add8..ca9f4a24e 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1318,9 +1318,9 @@ static boolean CL_SendJoin(void) static INT32 FindRejoinerNum(SINT8 node) { - char strippednodeaddress[64]; + char addressbuffer[64]; const char *nodeaddress; - char *port; + const char *strippednodeaddress; INT32 i; // Make sure there is no dead dress before proceeding to the stripping @@ -1331,10 +1331,8 @@ static INT32 FindRejoinerNum(SINT8 node) return -1; // Strip the address of its port - strcpy(strippednodeaddress, nodeaddress); - port = strchr(strippednodeaddress, ':'); - if (port) - *port = '\0'; + strcpy(addressbuffer, nodeaddress); + strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL); // Check if any player matches the stripped address for (i = 0; i < MAXPLAYERS; i++) @@ -3771,14 +3769,13 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) if (server && I_GetNodeAddress) { + char addressbuffer[64]; const char *address = I_GetNodeAddress(node); - char *port = NULL; if (address) // MI: fix msvcrt.dll!_mbscat crash? { - strcpy(playeraddress[newplayernum], address); - port = strchr(playeraddress[newplayernum], ':'); - if (port) - *port = '\0'; + strcpy(addressbuffer, address); + strcpy(playeraddress[newplayernum], + I_NetSplitAddress(addressbuffer, NULL)); } } } diff --git a/src/d_net.c b/src/d_net.c index 7de3dba56..768c9ac7e 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -1207,26 +1207,32 @@ static void Internal_FreeNodenum(INT32 nodenum) (void)nodenum; } +char *I_NetSplitAddress(char *host, char **port) +{ + boolean v4 = (strchr(host, '.') != NULL); + + host = strtok(host, v4 ? ":" : "[]"); + + if (port) + *port = strtok(NULL, ":"); + + return host; +} + SINT8 I_NetMakeNode(const char *hostname) { SINT8 newnode = -1; if (I_NetMakeNodewPort) { char *localhostname = strdup(hostname); - char *t = localhostname; - const char *port; + char *port; if (!localhostname) return newnode; + // retrieve portnum from address! - strtok(localhostname, ":"); - port = strtok(NULL, ":"); + hostname = I_NetSplitAddress(localhostname, &port); - // remove the port in the hostname as we've it already - while ((*t != ':') && (*t != '\0')) - t++; - *t = '\0'; - - newnode = I_NetMakeNodewPort(localhostname, port); + newnode = I_NetMakeNodewPort(hostname, port); free(localhostname); } return newnode; diff --git a/src/http-mserv.c b/src/http-mserv.c index b4dba0db9..b7032e89a 100644 --- a/src/http-mserv.c +++ b/src/http-mserv.c @@ -216,7 +216,11 @@ HMS_connect (const char *format, ...) curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + +#ifndef NO_IPV6 + if (M_CheckParm("-noipv6")) +#endif + curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(curl, CURLOPT_TIMEOUT, cv_masterserver_timeout.value); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, HMS_on_read); diff --git a/src/i_net.h b/src/i_net.h index 9f2c38c7b..12a07f183 100644 --- a/src/i_net.h +++ b/src/i_net.h @@ -109,6 +109,17 @@ extern boolean (*I_NetCanSend)(void); */ extern void (*I_NetFreeNodenum)(INT32 nodenum); +/** + \brief split a string into address and port + + \param address string to split + + \param port double pointer to hold port component (optional) + + \return address component +*/ +extern char *I_NetSplitAddress(char *address, char **port); + /** \brief open a connection with specified address \param address address to connect to diff --git a/src/i_tcp.c b/src/i_tcp.c index 3820155b8..d95b381f4 100644 --- a/src/i_tcp.c +++ b/src/i_tcp.c @@ -340,8 +340,14 @@ static inline void I_UPnP_rem(const char *port, const char * servicetype) static const char *SOCK_AddrToStr(mysockaddr_t *sk) { - static char s[64]; // 255.255.255.255:65535 or IPv6:65535 + static char s[64]; // 255.255.255.255:65535 or + // [ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535 #ifdef HAVE_NTOP +#ifdef HAVE_IPV6 + int v6 = (sk->any.sa_family == AF_INET6); +#else + int v6 = 0; +#endif void *addr; if(sk->any.sa_family == AF_INET) @@ -355,14 +361,21 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk) if(addr == NULL) sprintf(s, "No address"); - else if(inet_ntop(sk->any.sa_family, addr, s, sizeof (s)) == NULL) + else if(inet_ntop(sk->any.sa_family, addr, &s[v6], sizeof (s) - v6) == NULL) sprintf(s, "Unknown family type, error #%u", errno); #ifdef HAVE_IPV6 - else if(sk->any.sa_family == AF_INET6 && sk->ip6.sin6_port != 0) - strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + else if(sk->any.sa_family == AF_INET6) + { + s[0] = '['; + strcat(s, "]"); + + if (sk->ip6.sin6_port != 0) + strcat(s, va(":%d", ntohs(sk->ip6.sin6_port))); + } #endif else if(sk->any.sa_family == AF_INET && sk->ip4.sin_port != 0) strcat(s, va(":%d", ntohs(sk->ip4.sin_port))); + #else if (sk->any.sa_family == AF_INET) { @@ -427,7 +440,7 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) && (b->ip4.sin_port == 0 || (a->ip4.sin_port == b->ip4.sin_port)); #ifdef HAVE_IPV6 else if (b->any.sa_family == AF_INET6) - return memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) + return !memcmp(&a->ip6.sin6_addr, &b->ip6.sin6_addr, sizeof(b->ip6.sin6_addr)) && (b->ip6.sin6_port == 0 || (a->ip6.sin6_port == b->ip6.sin6_port)); #endif else @@ -735,8 +748,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen unsigned long trueval = true; #endif mysockaddr_t straddr; - struct sockaddr_in sin; - socklen_t len = sizeof(sin); + socklen_t len = sizeof(straddr); if (s == (SOCKET_TYPE)ERRSOCKET) return (SOCKET_TYPE)ERRSOCKET; @@ -754,14 +766,12 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen } #endif - straddr.any = *addr; + memcpy(&straddr, addr, addrlen); I_OutputMsg("Binding to %s\n", SOCK_AddrToStr(&straddr)); if (family == AF_INET) { - mysockaddr_t tmpaddr; - tmpaddr.any = *addr ; - if (tmpaddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) + if (straddr.ip4.sin_addr.s_addr == htonl(INADDR_ANY)) { opt = true; opts = (socklen_t)sizeof(opt); @@ -778,7 +788,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen #ifdef HAVE_IPV6 else if (family == AF_INET6) { - if (memcmp(addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL + if (memcmp(&straddr.ip6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) //IN6_ARE_ADDR_EQUAL { opt = true; opts = (socklen_t)sizeof(opt); @@ -788,7 +798,7 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen // make it IPv6 ony opt = true; opts = (socklen_t)sizeof(opt); - if (setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *)&opt, opts)) + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, opts)) { CONS_Alert(CONS_WARNING, M_GetText("Could not limit IPv6 bind\n")); // I do not care anymore } @@ -830,10 +840,17 @@ static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen CONS_Printf(M_GetText("Network system buffer set to: %dKb\n"), opt>>10); } - if (getsockname(s, (struct sockaddr *)&sin, &len) == -1) + if (getsockname(s, &straddr.any, &len) == -1) CONS_Alert(CONS_WARNING, M_GetText("Failed to get port number\n")); else - current_port = (UINT16)ntohs(sin.sin_port); + { + if (family == AF_INET) + current_port = (UINT16)ntohs(straddr.ip4.sin_port); +#ifdef HAVE_IPV6 + else if (family == AF_INET6) + current_port = (UINT16)ntohs(straddr.ip6.sin6_port); +#endif + } return s; } @@ -844,7 +861,7 @@ static boolean UDP_Socket(void) struct my_addrinfo *ai, *runp, hints; int gaie; #ifdef HAVE_IPV6 - const INT32 b_ipv6 = M_CheckParm("-ipv6"); + const INT32 b_ipv6 = !M_CheckParm("-noipv6"); #endif const char *serv; @@ -1156,6 +1173,7 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) SINT8 newnode = -1; struct my_addrinfo *ai = NULL, *runp, hints; int gaie; + size_t i; if (!port || !port[0]) port = DEFAULTPORT; @@ -1183,13 +1201,24 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) while (runp != NULL) { - // find ip of the server - if (sendto(mysockets[0], NULL, 0, 0, runp->ai_addr, runp->ai_addrlen) == 0) + // test ip address of server + for (i = 0; i < mysocketses; ++i) { - memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); - break; + /* sendto tests that there is a network to this + address */ + if (runp->ai_addr->sa_family == myfamily[i] && + sendto(mysockets[i], NULL, 0, 0, + runp->ai_addr, runp->ai_addrlen) == 0) + { + memcpy(&clientaddress[newnode], runp->ai_addr, runp->ai_addrlen); + break; + } } - runp = runp->ai_next; + + if (i < mysocketses) + runp = runp->ai_next; + else + break; } I_freeaddrinfo(ai); return newnode; diff --git a/src/m_menu.c b/src/m_menu.c index ae089e97c..f9f52335d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -975,7 +975,7 @@ static menuitem_t MP_MainMenu[] = { {IT_HEADER, NULL, "Join a game", NULL, 0}, {IT_STRING|IT_CALL, NULL, "Server browser...", M_ConnectMenuModChecks, 12}, - {IT_STRING|IT_KEYHANDLER, NULL, "Specify IPv4 address:", M_HandleConnectIP, 22}, + {IT_STRING|IT_KEYHANDLER, NULL, "Specify server address:", M_HandleConnectIP, 22}, {IT_HEADER, NULL, "Host a game", NULL, 54}, {IT_STRING|IT_CALL, NULL, "Internet/LAN...", M_StartServerMenu, 66}, {IT_STRING|IT_CALL, NULL, "Splitscreen...", M_StartSplitServerMenu, 76}, @@ -11738,35 +11738,19 @@ static void M_StartServerMenu(INT32 choice) #define CONNIP_LEN 128 static char setupm_ip[CONNIP_LEN]; - #define DOTS "... " -// Draw the funky Connect IP menu. Tails 11-19-2002 -// So much work for such a little thing! -static void M_DrawMPMainMenu(void) +static void M_DrawConnectIP(void) { INT32 x = currentMenu->x; - INT32 y = currentMenu->y; + INT32 y = currentMenu->y + 22; + const INT32 boxwidth = /*16*8 + 6*/ (BASEVIDWIDTH - 2*(x+5)); const INT32 maxstrwidth = boxwidth - 5; char *drawnstr = malloc(sizeof(setupm_ip)); char *drawnstr_orig = drawnstr; boolean drawthin, shorten = false; - // use generic drawer for cursor, items and title - M_DrawGenericMenu(); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66, - ((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS)); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76, - ((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)"); - - V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116, - ((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)"); - - y += 22; - V_DrawFill(x+5, y+4+5, boxwidth, 8+6, 159); strcpy(drawnstr, setupm_ip); @@ -11814,6 +11798,28 @@ static void M_DrawMPMainMenu(void) free(drawnstr_orig); } +// Draw the funky Connect IP menu. Tails 11-19-2002 +// So much work for such a little thing! +static void M_DrawMPMainMenu(void) +{ + INT32 x = currentMenu->x; + INT32 y = currentMenu->y; + + // use generic drawer for cursor, items and title + M_DrawGenericMenu(); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+66, + ((itemOn == 4) ? V_YELLOWMAP : 0), va("(2-%d players)", MAXPLAYERS)); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+76, + ((itemOn == 5) ? V_YELLOWMAP : 0), "(2 players)"); + + V_DrawRightAlignedString(BASEVIDWIDTH-x, y+116, + ((itemOn == 8) ? V_YELLOWMAP : 0), "(splitscreen)"); + + M_DrawConnectIP(); +} + #undef DOTS // Tails 11-19-2002 @@ -11951,7 +11957,11 @@ static void M_HandleConnectIP(INT32 choice) break; // Rudimentary number and period enforcing - also allows letters so hostnames can be used instead - if ((choice >= '-' && choice <= ':') || (choice >= 'A' && choice <= 'Z') || (choice >= 'a' && choice <= 'z')) + // and square brackets for RFC 2732 IPv6 addresses + if ((choice >= '-' && choice <= ':') || + (choice == '[' || choice == ']') || + (choice >= 'A' && choice <= 'Z') || + (choice >= 'a' && choice <= 'z')) { S_StartSound(NULL,sfx_menu1); // Tails setupm_ip[l] = (char)choice; diff --git a/src/mserv.h b/src/mserv.h index 1c8d742d8..07253da85 100644 --- a/src/mserv.h +++ b/src/mserv.h @@ -33,7 +33,7 @@ typedef union typedef struct { msg_header_t header; - char ip[16]; + char ip[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"]; char port[8]; char name[32]; INT32 room;