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
+}