Support connecting to IPv6 servers
authorMichał Kępień <github@kempniu.pl>
Wed, 26 Sep 2018 22:33:57 +0200
changeset 726 ea6aaf57f344
parent 724 3cd39dfd5ff7
child 727 4d5bce4b7832
Support connecting to IPv6 servers
KNOWN_BUGS
loudmouth/lm-old-socket.c
loudmouth/lm-resolver.c
--- a/KNOWN_BUGS	Wed Sep 26 21:45:08 2018 +0200
+++ b/KNOWN_BUGS	Wed Sep 26 22:33:57 2018 +0200
@@ -1,2 +1,1 @@
-No IPv6 Support
 Currently Leak Resolver Objects Due To Messy Allocation Path
--- a/loudmouth/lm-old-socket.c	Wed Sep 26 21:45:08 2018 +0200
+++ b/loudmouth/lm-old-socket.c	Wed Sep 26 22:33:57 2018 +0200
@@ -20,6 +20,7 @@
 
 #include <config.h>
 
+#include <errno.h>
 #include <string.h>
 #include <sys/types.h>
 
@@ -605,7 +606,22 @@
         port = htons (socket->port);
     }
 
-    ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
+    switch (addr->ai_family) {
+    case AF_INET:
+        ((struct sockaddr_in *) addr->ai_addr)->sin_port = port;
+        break;
+    case AF_INET6:
+        ((struct sockaddr_in6 *) addr->ai_addr)->sin6_port = port;
+        break;
+    default:
+        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
+               "Unknown socket family %d\n", addr->ai_family);
+#ifndef G_OS_WIN32
+        return _lm_old_socket_failed_with_error (connect_data, EAFNOSUPPORT);
+#else
+        return _lm_old_socket_failed_with_error (connect_data, WSAEAFNOSUPPORT);
+#endif
+    }
 
     res = getnameinfo (addr->ai_addr,
                        (socklen_t)addr->ai_addrlen,
@@ -765,46 +781,48 @@
 {
     LmOldSocket *socket = (LmOldSocket *) user_data;
     char dispbuf[128];
-    struct sockaddr_in *addr; /* FIXME:IPv6 */
-    const char *converr;
+    struct addrinfo *addr;
+    void *sock_addr;
 
     lm_verbose ("LmOldSocket::host_cb (result=%d)\n", result);
 
-    if (result != LM_RESOLVER_RESULT_OK) {
-        lm_verbose ("error while resolving, bailing out\n");
-        if (socket->connect_func) {
-            (socket->connect_func) (socket, FALSE, socket->user_data);
+    if (result == LM_RESOLVER_RESULT_OK) {
+        /* Find and use the first result with a supported address family */
+        while ((addr = lm_resolver_results_get_next (resolver))) {
+            switch (addr->ai_family) {
+            case AF_INET:
+                sock_addr = & (((struct sockaddr_in *) addr->ai_addr)->sin_addr);
+                break;
+            case AF_INET6:
+                sock_addr = & (((struct sockaddr_in6 *) addr->ai_addr)->sin6_addr);
+                break;
+            default:
+                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
+                       "Resolver returned a socket address with unknown family %d\n", addr->ai_family);
+                continue;
+            }
+            if (inet_ntop (addr->ai_family, sock_addr, dispbuf, sizeof(dispbuf))) {
+                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
+                       "Attempting Connection to %s\n", dispbuf);
+            } else {
+                g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
+                       "Attempting Connection (unable to convert address to presentable format)\n");
+            };
+            socket->connect_data->current_addr = addr;
+            socket_do_connect (socket->connect_data);
+            return;
         }
-        /*FIXME: Leaking Resolvers Until Clean Up Can Be Properly Handled
-        g_object_unref (socket->resolver);
-        socket->resolver = NULL;*/
-        g_free (socket->connect_data);
-        socket->connect_data = NULL;
-
-        return;
     }
 
-    socket->connect_data->current_addr =
-        lm_resolver_results_get_next (resolver);
-
-    if (socket->connect_data->current_addr) { /* FIXME:IPv6 */
-        addr = (struct sockaddr_in *) (socket->connect_data->current_addr->ai_addr);
-        converr = inet_ntop(AF_INET,&(addr->sin_addr),dispbuf,sizeof(dispbuf));
-        if (converr) {
-            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
-                   "Attempting Connection to %s\n",dispbuf);
-        } else {
-            g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
-                   "Attempting Connection (unable to convert address to presentable format)\n");
-        };
-        socket_do_connect (socket->connect_data);
-    } else { /* FIXME: IPv6 Support? */
-        g_log (LM_LOG_DOMAIN,G_LOG_LEVEL_ERROR,
-               "Unable to locate server available over IPv4.\n");
-    };
-
-    /* FIXME: What do we do here?  How to make the mainloop exit with an
-       error, while having no ref to said mainloop */
+    lm_verbose ("error while resolving, bailing out\n");
+    if (socket->connect_func) {
+        (socket->connect_func) (socket, FALSE, socket->user_data);
+    }
+    /*FIXME: Leaking Resolvers Until Clean Up Can Be Properly Handled
+    g_object_unref (socket->resolver);
+    socket->resolver = NULL;*/
+    g_free (socket->connect_data);
+    socket->connect_data = NULL;
 }
 
 /* FIXME: Need to have a way to only get srv reply and then decide if the
--- a/loudmouth/lm-resolver.c	Wed Sep 26 21:45:08 2018 +0200
+++ b/loudmouth/lm-resolver.c	Wed Sep 26 22:33:57 2018 +0200
@@ -390,7 +390,6 @@
 
     priv = GET_PRIV (resolver);
 
-skipresult:
     if (!priv->current_result) {
         g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
                "no more results from resolver\n");
@@ -399,11 +398,6 @@
 
     ret_val = priv->current_result;
     priv->current_result = priv->current_result->ai_next;
-    if (ret_val->ai_family != AF_INET) {
-        g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_VERBOSE,
-               "skipping non-IPv4 resolver entry\n");
-        goto skipresult;
-    };
 
     return ret_val;
 }