Browse code

bb11171 - Listening on :: breaks on hosts where IPv6 is disabled

Shawn Webb authored on 2014/11/06 02:30:13
Showing 1 changed files
... ...
@@ -49,6 +49,7 @@
49 49
 int tcpserver(int **lsockets, unsigned int *nlsockets, char *ipaddr, const struct optstruct *opts)
50 50
 {
51 51
     struct addrinfo hints, *info, *p;
52
+    char host[NI_MAXHOST], serv[NI_MAXSERV];
52 53
     int *sockets;
53 54
     int sockfd, backlog;
54 55
     int *t;
... ...
@@ -66,19 +67,12 @@ int tcpserver(int **lsockets, unsigned int *nlsockets, char *ipaddr, const struc
66 66
     hints.ai_socktype = SOCK_STREAM;
67 67
     hints.ai_flags = AI_PASSIVE;
68 68
 
69
-#if C_LINUX
70
-    if (!(ipaddr)) {
71
-        /*
72
-         * By default, getaddrinfo() will return 0.0.0.0 if NULL is passed in as the first parameter.
73
-         * Binding to 0.0.0.0 will prevent us from also binding IPv6 ::0 (errno = EADDRINUSE). However,
74
-         * if we bind to ::0 (or shorthand, ::), then Linux will bind to both IPv4 and IPv6.
75
-         */
76
-        ipaddr = "::";
77
-    }
69
+#ifdef AI_ADDRCONFIG
70
+    hints.ai_flags |= AI_ADDRCONFIG;
78 71
 #endif
79 72
 
80 73
     if ((res = getaddrinfo(ipaddr, port, &hints, &info))) {
81
-        logg("!TCP: getaddrinfo: %s\n", gai_strerror(res));
74
+        logg("!TCP: getaddrinfo failed: %s\n", gai_strerror(res));
82 75
         return -1;
83 76
     }
84 77
 
... ...
@@ -102,26 +96,35 @@ int tcpserver(int **lsockets, unsigned int *nlsockets, char *ipaddr, const struc
102 102
             logg("!TCP: setsocktopt(SO_REUSEADDR) error: %s\n", strerror(errno));
103 103
         }
104 104
 
105
+#ifdef IPV6_V6ONLY
106
+        if (p->ai_family == AF_INET6 &&
107
+            setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1) {
108
+            estr = strerror(errno);
109
+            logg("!TCP: setsocktopt(IPV6_V6ONLY) error: %s\n", estr);
110
+        }
111
+#endif /* IPV6_V6ONLY */
112
+
113
+        if ((res = getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof(host),
114
+                               serv, sizeof(serv), NI_NUMERICHOST|NI_NUMERICSERV))) {
115
+            logg("!TCP: getnameinfo failed: %s\n", gai_strerror(res));
116
+            host[0] = '\0';
117
+            serv[0] = '\0';
118
+        }
105 119
         if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
106 120
             estr = strerror(errno);
107
-            if (ipaddr || i == 0)
108
-                logg("!TCP: bind() error when trying to listen on [%s]:%s: %s\n", ipaddr, port, estr);
121
+            logg("!TCP: Cannot bind to [%s]:%s: %s\n", host, serv, estr);
109 122
             closesocket(sockfd);
110 123
 
111 124
             continue;
112
-        } else {
113
-            if((ipaddr))
114
-                logg("#TCP: Bound to address %s on port %u\n", ipaddr, (unsigned int) optget(opts, "TCPSocket")->numarg);
115
-            else
116
-                logg("#TCP: Bound to port %u\n", (unsigned int) optget(opts, "TCPSocket")->numarg);
117 125
         }
126
+        logg("#TCP: Bound to [%s]:%s\n", host, serv);
118 127
 
119 128
         backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
120 129
         logg("#TCP: Setting connection queue length to %d\n", backlog);
121 130
 
122 131
         if(listen(sockfd, backlog) == -1) {
123 132
             estr = strerror(errno);
124
-            logg("!TCP: listen() error: %s\n", estr);
133
+            logg("!TCP: Cannot listen on [%s]:%s: %s\n", host, serv, estr);
125 134
             closesocket(sockfd);
126 135
 
127 136
             continue;