This adds support for mapping scope/zone names to interface IDs for IPv6 
link-local addresses.  Not sure if scope or zone is the better term to 
use here, any opinions?  Could s/_zone_/_scope_/g easily enough.

Google suggests Windows supports if_nametoindex too, so the API should 
be portable, though I don't know about other platforms.

Regards, Joe
Index: include/apr_network_io.h
===================================================================
--- include/apr_network_io.h    (revision 1815933)
+++ include/apr_network_io.h    (working copy)
@@ -441,6 +441,13 @@
                                                  const apr_sockaddr_t *src,
                                                  apr_pool_t *p);
 
+/* Set the zone of an IPv6 link-local address object.
+ * @param sa Socket address object
+ * @param zone_id Zone ID (textual "eth0" or numeric "3").
+ */
+APR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa,
+                                                const char *zone_id);
+
 /**
  * Look up the host name from an apr_sockaddr_t.
  * @param hostname The hostname.
Index: configure.in
===================================================================
--- configure.in        (revision 1815933)
+++ configure.in        (working copy)
@@ -1069,7 +1069,9 @@
 #endif";;
 esac
 
-AC_CHECK_HEADERS([sys/types.h sys/mman.h sys/ipc.h sys/mutex.h sys/shm.h 
sys/file.h kernel/OS.h os2.h windows.h])
+AC_CHECK_HEADERS([sys/types.h sys/mman.h sys/ipc.h sys/mutex.h \
+                  sys/shm.h sys/file.h kernel/OS.h os2.h windows.h \
+                  net/if.h])
 AC_CHECK_FUNCS([mmap munmap shm_open shm_unlink shmget shmat shmdt shmctl \
                 create_area mprotect])
 
@@ -2755,7 +2757,7 @@
 AC_SEARCH_LIBS(getaddrinfo, socket inet6)
 AC_SEARCH_LIBS(gai_strerror, socket inet6)
 AC_SEARCH_LIBS(getnameinfo, socket inet6)
-AC_CHECK_FUNCS(gai_strerror)
+AC_CHECK_FUNCS(gai_strerror if_nametoindex)
 APR_CHECK_WORKING_GETADDRINFO
 APR_CHECK_NEGATIVE_EAI
 APR_CHECK_WORKING_GETNAMEINFO
Index: network_io/unix/sockaddr.c
===================================================================
--- network_io/unix/sockaddr.c  (revision 1815933)
+++ network_io/unix/sockaddr.c  (working copy)
@@ -25,6 +25,10 @@
 #include <stdlib.h>
 #endif
 
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
 #define APR_WANT_STRFUNC
 #include "apr_want.h"
 
@@ -1182,3 +1186,38 @@
 #endif /* APR_HAVE_IPV6 */
     return 0; /* no match */
 }
+
+APR_DECLARE(apr_status_t) apr_sockaddr_zone_set(apr_sockaddr_t *sa,
+                                                const char *zone_id)
+{
+#if !APR_HAVE_IPV6 || !defined(HAVE_IF_NAMETOINDEX)
+    return APR_ENOTIMPL;
+#else
+    unsigned int idx;
+    
+    if (sa->family != APR_INET6) {
+        return APR_EBADIP;
+    }
+
+    idx = if_nametoindex(zone_id);
+    if (idx) {
+        sa->sa.sin6.sin6_scope_id = idx;
+        return APR_SUCCESS;
+    }
+
+    if (errno != ENODEV) {
+        return errno;
+    }
+    else {
+        char *endptr;
+        apr_int64_t i = apr_strtoi64(zone_id, &endptr, 10);
+
+        if (*endptr != '\0' || errno || i < 1 || i > APR_INT16_MAX) {
+            return APR_EGENERAL;
+        }
+
+        sa->sa.sin6.sin6_scope_id = i;
+        return APR_SUCCESS;
+    }
+#endif
+}

Reply via email to