Description: Implement capability for IPv6.
Migration to 'getaddrinfo()' and 'struct sockaddr_storage'
make both address families AF_INET and AF_INET6 viable.
.
The preferred form of a port is as a string value in getaddrinfo(),
so named ports are no possible, alongside numerical ports.
.
The goto statement is left because the previous code enforced
a similar construct. It should really be removed.
Author: Mats Erik Andersson <debian@gisladisker.se>
Forwarded: no
Last-Updated: 2010-03-03
Index: netris-0.52/inet.c
===================================================================
--- netris-0.52.orig/inet.c
+++ netris-0.52/inet.c
@@ -49,32 +49,60 @@ ExtFunc void InitNet(void)
ExtFunc int WaitForConnection(char *portStr)
{
- struct sockaddr_in addr;
- struct hostent *host;
- int sockListen;
+ struct sockaddr_storage addr;
+ struct sockaddr_in *sa4 = (struct sockaddr_in *) &addr;
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &addr;
+ struct hostent *host = NULL;
+ struct addrinfo hints, *ai, *aiptr;
+ char portStrDef[12];
+ int sockListen, status;
socklen_t addrLen;
- short port;
int val1;
struct linger val2;
- if (portStr)
- port = atoi(portStr); /* XXX Error checking */
- else
- port = DEFAULT_PORT;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
- sockListen = socket(AF_INET, SOCK_STREAM, 0);
- if (sockListen < 0)
+ if (!portStr || !strlen(portStr)) {
+ snprintf(portStrDef, sizeof(portStrDef), "%u", DEFAULT_PORT);
+ portStr = portStrDef;
+ }
+ /* XXX Error checking of port string. */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+
+ if ( (status = getaddrinfo(NULL, portStr, &hints, &ai)) ) {
+ fprintf(stderr, "getaddrinfo() failed: %s\n",
+ gai_strerror(status));
+ die("getaddrinfo");
+ }
+
+ for (aiptr = ai; aiptr; aiptr = aiptr->ai_next) {
+ if ( (sockListen = socket(aiptr->ai_family,
+ aiptr->ai_socktype,
+ aiptr->ai_protocol))
+ < 0 )
+ continue;
+
+ val1 = 1;
+ setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&val1, sizeof(val1));
+ val1 = 0;
+ setsockopt(sockListen, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&val1, sizeof(val1));
+
+ if ( bind(sockListen, aiptr->ai_addr, aiptr->ai_addrlen)
+ == 0 )
+ if ( listen(sockListen, 1) >= 0 )
+ break;
+
+ close(sockListen);
+ }
+
+ freeaddrinfo(ai);
+ if (aiptr == NULL)
die("socket");
- val1 = 1;
- setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
- (void *)&val1, sizeof(val1));
- if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
- die("bind");
- if (listen(sockListen, 1) < 0)
- die("listen");
+
addrLen = sizeof(addr);
sock = accept(sockListen, (struct sockaddr *)&addr, &addrLen);
if (sock < 0)
@@ -86,13 +114,18 @@ ExtFunc int WaitForConnection(char *port
(void *)&val2, sizeof(val2));
netGen.fd = sock;
strcpy(opponentHost, "???");
- if (addr.sin_family == AF_INET) {
- host = gethostbyaddr((void *)&addr.sin_addr,
- sizeof(struct in_addr), AF_INET);
- if (host) {
- strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
- opponentHost[sizeof(opponentHost)-1] = 0;
- }
+ switch (addr.ss_family) {
+ case AF_INET6:
+ host = gethostbyaddr((void *)&sa6->sin6_addr,
+ sizeof(struct in6_addr), addr.ss_family);
+ break;
+ case AF_INET:
+ host = gethostbyaddr((void *)&sa4->sin_addr,
+ sizeof(struct in_addr), addr.ss_family);
+ }
+ if (host) {
+ strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
+ opponentHost[sizeof(opponentHost)-1] = 0;
}
AddEventGen(&netGen);
isServer = 1;
@@ -101,36 +134,54 @@ ExtFunc int WaitForConnection(char *port
ExtFunc int InitiateConnection(char *hostStr, char *portStr)
{
- struct sockaddr_in addr;
- struct hostent *host;
- short port;
- int mySock;
-
- if (portStr)
- port = atoi(portStr); /* XXX Error checking */
- else
- port = DEFAULT_PORT;
- host = gethostbyname(hostStr);
- if (!host)
- die("gethostbyname");
- assert(host->h_addrtype == AF_INET);
- strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
- opponentHost[sizeof(opponentHost)-1] = 0;
- again:
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = host->h_addrtype;
- memcpy(&addr.sin_addr, host->h_addr, host->h_length);
- addr.sin_port = htons(port);
- mySock = socket(AF_INET, SOCK_STREAM, 0);
- if (mySock < 0)
- die("socket");
- if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- if (errno != ECONNREFUSED)
- die("connect");
+ struct addrinfo hints, *ai, *aiptr;
+ char portStrDef[12];
+ int mySock, status;
+
+ if (!portStr || !strlen(portStr)) {
+ snprintf(portStrDef, sizeof(portStrDef), "%u", DEFAULT_PORT);
+ portStr = portStrDef;
+ }
+ /* XXX Error checking of port string. */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
+
+ if ( (status = getaddrinfo(hostStr, portStr, &hints, &ai)) ) {
+ fprintf(stderr, "getaddrinfo() failed: %s\n",
+ gai_strerror(status));
+ die("getaddrinfo");
+ }
+
+ for (aiptr = ai; aiptr; aiptr = aiptr->ai_next) {
+again:
+ if ( (mySock = socket(aiptr->ai_family, aiptr->ai_socktype,
+ aiptr->ai_protocol))
+ < 0 )
+ continue;
+ while ( (status = connect(mySock, aiptr->ai_addr,
+ aiptr->ai_addrlen)) < 0
+ && errno == ECONNREFUSED ) {
+ close(mySock);
+ sleep(1);
+ goto again;
+ }
+ if (status >= 0)
+ break;
+ /* Failure to connect. */
close(mySock);
- sleep(1);
- goto again;
}
+
+ if (aiptr == NULL) {
+ freeaddrinfo(ai);
+ die("socket/connect");
+ }
+
+ strncpy(opponentHost, aiptr->ai_canonname, sizeof(opponentHost)-1);
+ opponentHost[sizeof(opponentHost)-1] = 0;
+ freeaddrinfo(ai);
netGen.fd = sock = mySock;
AddEventGen(&netGen);
return 0;