1 Description: Implement capability for IPv6.
2 Migration to 'getaddrinfo()' and 'struct sockaddr_storage'
3 make both address families AF_INET and AF_INET6 viable.
5 The preferred form of a port is as a string value in getaddrinfo(),
6 so named ports are no possible, alongside numerical ports.
8 The goto statement is left because the previous code enforced
9 a similar construct. It should really be removed.
10 Author: Mats Erik Andersson <debian@gisladisker.se>
12 Last-Updated: 2010-03-03
15 ===================================================================
18 @@ -49,32 +49,60 @@ ExtFunc void InitNet(void)
20 ExtFunc int WaitForConnection(char *portStr)
22 - struct sockaddr_in addr;
23 - struct hostent *host;
25 + struct sockaddr_storage addr;
26 + struct sockaddr_in *sa4 = (struct sockaddr_in *) &addr;
27 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &addr;
28 + struct hostent *host = NULL;
29 + struct addrinfo hints, *ai, *aiptr;
30 + char portStrDef[12];
31 + int sockListen, status;
38 - port = atoi(portStr); /* XXX Error checking */
40 - port = DEFAULT_PORT;
41 - memset(&addr, 0, sizeof(addr));
42 - addr.sin_family = AF_INET;
43 - addr.sin_addr.s_addr = htonl(INADDR_ANY);
44 - addr.sin_port = htons(port);
45 - sockListen = socket(AF_INET, SOCK_STREAM, 0);
47 + if (!portStr || !strlen(portStr)) {
48 + snprintf(portStrDef, sizeof(portStrDef), "%u", DEFAULT_PORT);
49 + portStr = portStrDef;
51 + /* XXX Error checking of port string. */
53 + memset(&hints, 0, sizeof(hints));
54 + hints.ai_family = AF_INET6;
55 + hints.ai_socktype = SOCK_STREAM;
56 + hints.ai_flags = AI_PASSIVE;
58 + if ( (status = getaddrinfo(NULL, portStr, &hints, &ai)) ) {
59 + fprintf(stderr, "getaddrinfo() failed: %s\n",
60 + gai_strerror(status));
64 + for (aiptr = ai; aiptr; aiptr = aiptr->ai_next) {
65 + if ( (sockListen = socket(aiptr->ai_family,
67 + aiptr->ai_protocol))
72 + setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
73 + (void *)&val1, sizeof(val1));
75 + setsockopt(sockListen, IPPROTO_IPV6, IPV6_V6ONLY,
76 + (void *)&val1, sizeof(val1));
78 + if ( bind(sockListen, aiptr->ai_addr, aiptr->ai_addrlen)
80 + if ( listen(sockListen, 1) >= 0 )
90 - setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
91 - (void *)&val1, sizeof(val1));
92 - if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
94 - if (listen(sockListen, 1) < 0)
97 addrLen = sizeof(addr);
98 sock = accept(sockListen, (struct sockaddr *)&addr, &addrLen);
100 @@ -86,13 +114,18 @@ ExtFunc int WaitForConnection(char *port
101 (void *)&val2, sizeof(val2));
103 strcpy(opponentHost, "???");
104 - if (addr.sin_family == AF_INET) {
105 - host = gethostbyaddr((void *)&addr.sin_addr,
106 - sizeof(struct in_addr), AF_INET);
108 - strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
109 - opponentHost[sizeof(opponentHost)-1] = 0;
111 + switch (addr.ss_family) {
113 + host = gethostbyaddr((void *)&sa6->sin6_addr,
114 + sizeof(struct in6_addr), addr.ss_family);
117 + host = gethostbyaddr((void *)&sa4->sin_addr,
118 + sizeof(struct in_addr), addr.ss_family);
121 + strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
122 + opponentHost[sizeof(opponentHost)-1] = 0;
124 AddEventGen(&netGen);
126 @@ -101,36 +134,54 @@ ExtFunc int WaitForConnection(char *port
128 ExtFunc int InitiateConnection(char *hostStr, char *portStr)
130 - struct sockaddr_in addr;
131 - struct hostent *host;
136 - port = atoi(portStr); /* XXX Error checking */
138 - port = DEFAULT_PORT;
139 - host = gethostbyname(hostStr);
141 - die("gethostbyname");
142 - assert(host->h_addrtype == AF_INET);
143 - strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
144 - opponentHost[sizeof(opponentHost)-1] = 0;
146 - memset(&addr, 0, sizeof(addr));
147 - addr.sin_family = host->h_addrtype;
148 - memcpy(&addr.sin_addr, host->h_addr, host->h_length);
149 - addr.sin_port = htons(port);
150 - mySock = socket(AF_INET, SOCK_STREAM, 0);
153 - if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
154 - if (errno != ECONNREFUSED)
156 + struct addrinfo hints, *ai, *aiptr;
157 + char portStrDef[12];
158 + int mySock, status;
160 + if (!portStr || !strlen(portStr)) {
161 + snprintf(portStrDef, sizeof(portStrDef), "%u", DEFAULT_PORT);
162 + portStr = portStrDef;
164 + /* XXX Error checking of port string. */
166 + memset(&hints, 0, sizeof(hints));
167 + hints.ai_family = AF_UNSPEC;
168 + hints.ai_socktype = SOCK_STREAM;
169 + hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
171 + if ( (status = getaddrinfo(hostStr, portStr, &hints, &ai)) ) {
172 + fprintf(stderr, "getaddrinfo() failed: %s\n",
173 + gai_strerror(status));
174 + die("getaddrinfo");
177 + for (aiptr = ai; aiptr; aiptr = aiptr->ai_next) {
179 + if ( (mySock = socket(aiptr->ai_family, aiptr->ai_socktype,
180 + aiptr->ai_protocol))
183 + while ( (status = connect(mySock, aiptr->ai_addr,
184 + aiptr->ai_addrlen)) < 0
185 + && errno == ECONNREFUSED ) {
192 + /* Failure to connect. */
198 + if (aiptr == NULL) {
200 + die("socket/connect");
203 + strncpy(opponentHost, aiptr->ai_canonname, sizeof(opponentHost)-1);
204 + opponentHost[sizeof(opponentHost)-1] = 0;
206 netGen.fd = sock = mySock;
207 AddEventGen(&netGen);