Hello,

snmpd already has multihoming support on Linux and BSD derivatives. I would like
to extend that support to Windows platforms (Windows Vista / Windows Server 2008
and later). With this patch the regression tests still pas on Linux, FreeBSD,
Windows 7 + cygwin, Windows 7 + MinGW, Windows 7 + Visual Studio and Window XP
+ Visual Studio.

If anyone has any comments about the patch below - feedback is welcome.

Bart.

---
 configure                                        |  204 +++++++++++++++-------
 configure.d/config_os_misc4                      |   97 ++++++++++
 configure.d/config_os_struct_members             |   24 ---
 include/net-snmp/library/snmpUDPBaseDomain.h     |    3 +-
 include/net-snmp/library/snmpUDPDomain.h         |    3 +-
 include/net-snmp/library/snmpUDPIPv4BaseDomain.h |    3 +-
 include/net-snmp/net-snmp-config.h.in            |   12 +-
 snmplib/transports/snmpUDPBaseDomain.c           |  173 ++++++++++++++++--
 snmplib/transports/snmpUDPDomain.c               |    6 +-
 snmplib/transports/snmpUDPIPv4BaseDomain.c       |   23 ++-
 win32/net-snmp/net-snmp-config.h                 |    5 +-
 win32/net-snmp/net-snmp-config.h.in              |    5 +-
 win32/transports/snmp_transport_inits.h          |    1 +
 13 files changed, 431 insertions(+), 128 deletions(-)

diff --git a/configure b/configure
index ecda79b..8a5e857 100755
--- a/configure
+++ b/configure
@@ -26868,67 +26868,6 @@ _ACEOF
 fi
 
 
-#       struct msghdr
-#   Library:
-#
-ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_control" 
"ac_cv_member_struct_msghdr_msg_control" "
-    $ac_includes_default
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
-"
-if test "x$ac_cv_member_struct_msghdr_msg_control" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_MSGHDR_MSG_CONTROL 1
-_ACEOF
-
-
-fi
-ac_fn_c_check_member "$LINENO" "struct msghdr" "msg_flags" 
"ac_cv_member_struct_msghdr_msg_flags" "
-    $ac_includes_default
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-
-"
-if test "x$ac_cv_member_struct_msghdr_msg_flags" = xyes; then :
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_MSGHDR_MSG_FLAGS 1
-_ACEOF
-
-
-fi
-
-
 #       struct sockaddr_un
 #   Library:
 #
@@ -29513,6 +29452,149 @@ And this can be very slow." >&2;}
     ;;
 esac
 
+#   Check whether IP_PKTINFO is usable.
+#
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_PKTINFO " >&5
+$as_echo_n "checking for IP_PKTINFO ... " >&6; }
+if ${ac_cv_have_ip_pktinfo+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdio.h>  /* printf() */
+#include <stdlib.h> /* malloc() */
+#include <string.h> /* memset() */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+    void *buf;
+    int len;
+    void *from;
+    socklen_t *fromlen;
+
+    struct iovec iov;
+    char *cmsg = malloc(CMSG_SPACE(sizeof(struct in_pktinfo)));
+    struct cmsghdr *cm;
+    struct msghdr msg;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof msg);
+    msg.msg_name = from;
+    msg.msg_namelen = *fromlen;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+
+    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+        if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO) {
+            struct in_pktinfo* src = (struct in_pktinfo *)CMSG_DATA(cm);
+            printf("Address: %s; index: %d\n", inet_ntoa(src->ipi_addr),
+                  src->ipi_ifindex);
+        }
+    }
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_have_ip_pktinfo=yes
+else
+  ac_cv_have_ip_pktinfo=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ip_pktinfo" >&5
+$as_echo "$ac_cv_have_ip_pktinfo" >&6; }
+if test x$ac_cv_have_ip_pktinfo = xyes; then
+
+$as_echo "#define HAVE_IP_PKTINFO 1" >>confdefs.h
+
+fi
+
+#   Check whether IP_RECVDSTADDR is usable.
+#
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for IP_RECVDSTADDR " >&5
+$as_echo_n "checking for IP_RECVDSTADDR ... " >&6; }
+if ${ac_cv_have_ip_recvdstaddr+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdio.h>  /* printf() */
+#include <stdlib.h> /* malloc() */
+#include <string.h> /* memset() */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int
+main ()
+{
+
+    void *buf;
+    int len;
+    void *from;
+    socklen_t *fromlen;
+
+    struct iovec iov;
+    char *cmsg = malloc(CMSG_SPACE(sizeof(struct in_addr)));
+    struct cmsghdr *cm;
+    struct msghdr msg;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof msg);
+    msg.msg_name = from;
+    msg.msg_namelen = *fromlen;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+
+    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+        if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR) {
+            struct in_addr* src = (struct in_addr *)CMSG_DATA(cm);
+            printf("Address: %s\n", inet_ntoa(src));
+        }
+    }
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_have_ip_recvdstaddr=yes
+else
+  ac_cv_have_ip_recvdstaddr=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_ip_recvdstaddr" 
>&5
+$as_echo "$ac_cv_have_ip_recvdstaddr" >&6; }
+if test x$ac_cv_have_ip_recvdstaddr = xyes; then
+
+$as_echo "#define HAVE_IP_RECVDSTADDR 1" >>confdefs.h
+
+fi
+
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
diff --git a/configure.d/config_os_misc4 b/configure.d/config_os_misc4
index b6cb040..cc8bad2 100644
--- a/configure.d/config_os_misc4
+++ b/configure.d/config_os_misc4
@@ -317,3 +317,100 @@ And this can be very slow.])
     fi         # "test $ac_inet_ip_h = yes"
     ;;
 esac
+
+#   Check whether IP_PKTINFO is usable.
+#
+
+AC_CACHE_CHECK([for IP_PKTINFO ],
+                [ac_cv_have_ip_pktinfo],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([
+#include <stdio.h>  /* printf() */
+#include <stdlib.h> /* malloc() */
+#include <string.h> /* memset() */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+], [
+    void *buf;
+    int len;
+    void *from;
+    socklen_t *fromlen;
+
+    struct iovec iov;
+    char *cmsg = malloc(CMSG_SPACE(sizeof(struct in_pktinfo)));
+    struct cmsghdr *cm;
+    struct msghdr msg;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof msg);
+    msg.msg_name = from;
+    msg.msg_namelen = *fromlen;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+
+    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+        if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO) {
+            struct in_pktinfo* src = (struct in_pktinfo *)CMSG_DATA(cm);
+            printf("Address: %s; index: %d\n", inet_ntoa(src->ipi_addr),
+                  src->ipi_ifindex);
+        }
+    }
+])],
+[ac_cv_have_ip_pktinfo=yes],
+[ac_cv_have_ip_pktinfo=no]
+)])
+if test x$ac_cv_have_ip_pktinfo = xyes; then
+    AC_DEFINE(HAVE_IP_PKTINFO, 1, [Set if IP_PKTINFO is usable])
+fi
+
+#   Check whether IP_RECVDSTADDR is usable.
+#
+
+AC_CACHE_CHECK([for IP_RECVDSTADDR ],
+                [ac_cv_have_ip_recvdstaddr],
+[AC_LINK_IFELSE([AC_LANG_PROGRAM([
+#include <stdio.h>  /* printf() */
+#include <stdlib.h> /* malloc() */
+#include <string.h> /* memset() */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+], [
+    void *buf;
+    int len;
+    void *from;
+    socklen_t *fromlen;
+
+    struct iovec iov;
+    char *cmsg = malloc(CMSG_SPACE(sizeof(struct in_addr)));
+    struct cmsghdr *cm;
+    struct msghdr msg;
+
+    iov.iov_base = buf;
+    iov.iov_len = len;
+
+    memset(&msg, 0, sizeof msg);
+    msg.msg_name = from;
+    msg.msg_namelen = *fromlen;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    msg.msg_control = &cmsg;
+    msg.msg_controllen = sizeof(cmsg);
+
+    for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+        if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR) {
+            struct in_addr* src = (struct in_addr *)CMSG_DATA(cm);
+            printf("Address: %s\n", inet_ntoa(src));
+        }
+    }
+])],
+[ac_cv_have_ip_recvdstaddr=yes],
+[ac_cv_have_ip_recvdstaddr=no]
+)])
+if test x$ac_cv_have_ip_recvdstaddr = xyes; then
+    AC_DEFINE(HAVE_IP_RECVDSTADDR, 1, [Set if IP_RECVDSTADDR is usable])
+fi
diff --git a/configure.d/config_os_struct_members 
b/configure.d/config_os_struct_members
index ce77458..a62e661 100644
--- a/configure.d/config_os_struct_members
+++ b/configure.d/config_os_struct_members
@@ -205,30 +205,6 @@ AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id],,,[
 #endif
     ]])
 
-#       struct msghdr
-#   Library:
-#
-AC_CHECK_MEMBERS([struct msghdr.msg_control,
-                  struct msghdr.msg_flags],,,[
-    AC_INCLUDES_DEFAULT()
-    [
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_WINSOCK2_H
-#include <winsock2.h>
-#endif
-#ifdef HAVE_WS2TCPIP_H
-#include <ws2tcpip.h>
-#endif
-    ]])
-
 #       struct sockaddr_un
 #   Library:
 #
diff --git a/include/net-snmp/library/snmpUDPBaseDomain.h 
b/include/net-snmp/library/snmpUDPBaseDomain.h
index e61cdc8..2665e98 100644
--- a/include/net-snmp/library/snmpUDPBaseDomain.h
+++ b/include/net-snmp/library/snmpUDPBaseDomain.h
@@ -18,8 +18,7 @@ extern          "C" {
     int netsnmp_udpbase_send(netsnmp_transport *t, void *buf, int size,
                              void **opaque, int *olength);
 
-#if defined(linux) && defined(IP_PKTINFO) \
-    || defined(IP_RECVDSTADDR) && !defined(_MSC_VER)
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
     int netsnmp_udpbase_recvfrom(int s, void *buf, int len,
                                  struct sockaddr *from, socklen_t *fromlen,
                                  struct sockaddr *dstip, socklen_t *dstlen,
diff --git a/include/net-snmp/library/snmpUDPDomain.h 
b/include/net-snmp/library/snmpUDPDomain.h
index f030360..3a09dfd 100644
--- a/include/net-snmp/library/snmpUDPDomain.h
+++ b/include/net-snmp/library/snmpUDPDomain.h
@@ -48,8 +48,7 @@ void            netsnmp_udp_ctor(void);
  * protected-ish functions used by other core-code
  */
 char *netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int len);
-#if defined(linux) && defined(IP_PKTINFO) || \
-    defined(IP_RECVDSTADDR) && !defined(_MSC_VER)
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
 int netsnmp_udp_recvfrom(int s, void *buf, int len, struct sockaddr *from,
                          socklen_t *fromlen, struct sockaddr *dstip,
                          socklen_t *dstlen, int *if_index);
diff --git a/include/net-snmp/library/snmpUDPIPv4BaseDomain.h 
b/include/net-snmp/library/snmpUDPIPv4BaseDomain.h
index 54f8a49..6f7f2c2 100644
--- a/include/net-snmp/library/snmpUDPIPv4BaseDomain.h
+++ b/include/net-snmp/library/snmpUDPIPv4BaseDomain.h
@@ -27,8 +27,7 @@ extern          "C" {
     netsnmp_transport *netsnmp_udpipv4base_transport(struct sockaddr_in *addr,
                                                      int local);
 
-#if defined(linux) && defined(IP_PKTINFO) \
-    || defined(IP_RECVDSTADDR) && !defined(_MSC_VER)
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
     int netsnmp_udpipv4_recvfrom(int s, void *buf, int len,
                                  struct sockaddr *from, socklen_t *fromlen,
                                  struct sockaddr *dstip, socklen_t *dstlen,
diff --git a/include/net-snmp/net-snmp-config.h.in 
b/include/net-snmp/net-snmp-config.h.in
index 7bc4186..1085b2f 100644
--- a/include/net-snmp/net-snmp-config.h.in
+++ b/include/net-snmp/net-snmp-config.h.in
@@ -296,6 +296,12 @@
 /* Define to 1 if you have the <iphlpapi.h> header file. */
 #undef HAVE_IPHLPAPI_H
 
+/* Set if IP_PKTINFO is usable */
+#undef HAVE_IP_PKTINFO
+
+/* Set if IP_RECVDSTADDR is usable */
+#undef HAVE_IP_RECVDSTADDR
+
 /* Define to 1 if you have the `kinfo_get_cpus' function. */
 #undef HAVE_KINFO_GET_CPUS
 
@@ -902,12 +908,6 @@
 /* Define to 1 if `m_mbufs' is a member of `struct mbstat'. */
 #undef HAVE_STRUCT_MBSTAT_M_MBUFS
 
-/* Define to 1 if `msg_control' is a member of `struct msghdr'. */
-#undef HAVE_STRUCT_MSGHDR_MSG_CONTROL
-
-/* Define to 1 if `msg_flags' is a member of `struct msghdr'. */
-#undef HAVE_STRUCT_MSGHDR_MSG_FLAGS
-
 /* Define to 1 if `n_value' is a member of `struct nlist64'. */
 #undef HAVE_STRUCT_NLIST64_N_VALUE
 
diff --git a/snmplib/transports/snmpUDPBaseDomain.c 
b/snmplib/transports/snmpUDPBaseDomain.c
index 5a2c197..951620f 100644
--- a/snmplib/transports/snmpUDPBaseDomain.c
+++ b/snmplib/transports/snmpUDPBaseDomain.c
@@ -30,6 +30,9 @@
 #if HAVE_SYS_UIO_H
 #include <sys/uio.h>
 #endif
+#ifdef WIN32
+#include <mswsock.h>
+#endif
 #include <errno.h>
 
 #include <net-snmp/types.h>
@@ -97,32 +100,33 @@ _netsnmp_udp_sockopt_set(int fd, int local)
     netsnmp_sock_buffer_set(fd, SO_RCVBUF, local, 0);
 }
 
-#if (defined(linux) && defined(IP_PKTINFO)) \
-    || defined(IP_RECVDSTADDR) && HAVE_STRUCT_MSGHDR_MSG_CONTROL \
-                               && HAVE_STRUCT_MSGHDR_MSG_FLAGS
-#if  defined(linux) && defined(IP_PKTINFO)
-#elif defined(IP_RECVDSTADDR)
-# ifndef IP_SENDSRCADDR
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
+# if defined(IP_RECVDSTADDR) && !defined(IP_SENDSRCADDR)
 #  define IP_SENDSRCADDR IP_RECVDSTADDR /* DragonFly BSD */
 # endif
-#endif
 
 #define netsnmp_udpbase_recvfrom_sendto_defined
 
 enum {
-#if  defined(linux) && defined(IP_PKTINFO)
+#if defined(HAVE_IP_PKTINFO)
     cmsg_data_size = sizeof(struct in_pktinfo)
-#elif defined(IP_RECVDSTADDR)
+#elif defined(HAVE_IP_RECVDSTADDR)
     cmsg_data_size = sizeof(struct in_addr)
 #endif
 };
 
+#ifdef WIN32
+static LPFN_WSARECVMSG pfWSARecvMsg;
+static LPFN_WSASENDMSG pfWSASendMsg;
+#endif
+
 int
 netsnmp_udpbase_recvfrom(int s, void *buf, int len, struct sockaddr *from,
                          socklen_t *fromlen, struct sockaddr *dstip,
                          socklen_t *dstlen, int *if_index)
 {
     int r;
+#if !defined(WIN32)
     struct iovec iov;
     char cmsg[CMSG_SPACE(cmsg_data_size)];
     struct cmsghdr *cm;
@@ -140,6 +144,32 @@ netsnmp_udpbase_recvfrom(int s, void *buf, int len, struct 
sockaddr *from,
     msg.msg_controllen = sizeof(cmsg);
 
     r = recvmsg(s, &msg, MSG_DONTWAIT);
+#else /* !defined(WIN32) */
+    WSABUF wsabuf;
+    char cmsg[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
+    WSACMSGHDR *cm;
+    WSAMSG msg;
+    DWORD bytes_received;
+
+    wsabuf.buf = buf;
+    wsabuf.len = len;
+
+    msg.name = from;
+    msg.namelen = *fromlen;
+    msg.lpBuffers = &wsabuf;
+    msg.dwBufferCount = 1;
+    msg.Control.len = sizeof(cmsg);
+    msg.Control.buf = cmsg;
+    msg.dwFlags = 0;
+
+    if (pfWSARecvMsg) {
+        r = pfWSARecvMsg(s, &msg, &bytes_received, NULL, NULL) == 0 ?
+            bytes_received : -1;
+        *fromlen = msg.namelen;
+    } else {
+        r = recvfrom(s, buf, len, MSG_DONTWAIT, from, fromlen);
+    }
+#endif /* !defined(WIN32) */
 
     if (r == -1) {
         return -1;
@@ -154,8 +184,9 @@ netsnmp_udpbase_recvfrom(int s, void *buf, int len, struct 
sockaddr *from,
         netsnmp_assert(r2 == 0);
     }
 
+#if !defined(WIN32)
     for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
-#if  defined(linux) && defined(IP_PKTINFO)
+#if defined(HAVE_IP_PKTINFO)
         if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO) {
             struct in_pktinfo* src = (struct in_pktinfo *)CMSG_DATA(cm);
             netsnmp_assert(dstip->sa_family == AF_INET);
@@ -163,24 +194,37 @@ netsnmp_udpbase_recvfrom(int s, void *buf, int len, 
struct sockaddr *from,
             *if_index = src->ipi_ifindex;
             DEBUGMSGTL(("udpbase:recv",
                         "got destination (local) addr %s, iface %d\n",
-                        inet_ntoa(((struct sockaddr_in*)dstip)->sin_addr),
-                        *if_index));
+                        inet_ntoa(src->ipi_addr), *if_index));
         }
-#elif defined(IP_RECVDSTADDR)
+#elif defined(HAVE_IP_RECVDSTADDR)
         if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_RECVDSTADDR) {
             struct in_addr* src = (struct in_addr *)CMSG_DATA(cm);
             ((struct sockaddr_in*)dstip)->sin_addr = *src;
             DEBUGMSGTL(("netsnmp_udp", "got destination (local) addr %s\n",
-                        inet_ntoa(((struct sockaddr_in*)dstip)->sin_addr)));
+                        inet_ntoa(*src)));
         }
 #endif
     }
+#else /* !defined(WIN32) */
+    for (cm = WSA_CMSG_FIRSTHDR(&msg); cm; cm = WSA_CMSG_NXTHDR(&msg, cm)) {
+        if (cm->cmsg_level == IPPROTO_IP && cm->cmsg_type == IP_PKTINFO) {
+            struct in_pktinfo* src = (struct in_pktinfo *)WSA_CMSG_DATA(cm);
+            netsnmp_assert(dstip->sa_family == AF_INET);
+            ((struct sockaddr_in*)dstip)->sin_addr = src->ipi_addr;
+            *if_index = src->ipi_ifindex;
+            DEBUGMSGTL(("udpbase:recv",
+                        "got destination (local) addr %s, iface %d\n",
+                        inet_ntoa(src->ipi_addr), *if_index));
+        }
+    }
+#endif /* !defined(WIN32) */
     return r;
 }
 
 int netsnmp_udpbase_sendto(int fd, struct in_addr *srcip, int if_index,
                            struct sockaddr *remote, void *data, int len)
 {
+#if !defined(WIN32)
     struct iovec iov;
     struct msghdr m = { 0 };
     char          cmsg[CMSG_SPACE(cmsg_data_size)];
@@ -208,14 +252,20 @@ int netsnmp_udpbase_sendto(int fd, struct in_addr *srcip, 
int if_index,
         cm = CMSG_FIRSTHDR(&m);
         cm->cmsg_len = CMSG_LEN(cmsg_data_size);
 
-#if  defined(linux) && defined(IP_PKTINFO)
+#if defined(HAVE_IP_PKTINFO)
         cm->cmsg_level = SOL_IP;
         cm->cmsg_type = IP_PKTINFO;
 
         {
-            struct in_pktinfo ipi = { 0 };
-            ipi.ipi_ifindex = 0;
+            struct in_pktinfo ipi;
+
+            memset(&ipi, 0, sizeof(ipi));
+            ipi.ipi_ifindex = if_index;
+#if defined(cygwin)
+            ipi.ipi_addr.s_addr = srcip->s_addr;
+#else
             ipi.ipi_spec_dst.s_addr = srcip->s_addr;
+#endif
             memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
         }
 
@@ -232,9 +282,15 @@ int netsnmp_udpbase_sendto(int fd, struct in_addr *srcip, 
int if_index,
         DEBUGMSGTL(("udpbase:sendto", "re-sending on iface %d\n", if_index));
 
         {
-            struct in_pktinfo ipi = { 0 };
+            struct in_pktinfo ipi;
+
+            memset(&ipi, 0, sizeof(ipi));
             ipi.ipi_ifindex = if_index;
+#if defined(cygwin)
+            ipi.ipi_addr.s_addr = INADDR_ANY;
+#else
             ipi.ipi_spec_dst.s_addr = INADDR_ANY;
+#endif
             memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
         }
 #elif defined(IP_SENDSRCADDR)
@@ -252,8 +308,56 @@ int netsnmp_udpbase_sendto(int fd, struct in_addr *srcip, 
int if_index,
     }
 
     return sendmsg(fd, &m, MSG_NOSIGNAL|MSG_DONTWAIT);
+#else /* !defined(WIN32) */
+    WSABUF        wsabuf;
+    WSAMSG        m;
+    char          cmsg[WSA_CMSG_SPACE(sizeof(struct in_pktinfo))];
+    DWORD         bytes_sent;
+    int           rc;
+
+    wsabuf.buf = data;
+    wsabuf.len = len;
+
+    memset(&m, 0, sizeof(m));
+    m.name          = remote;
+    m.namelen       = sizeof(struct sockaddr_in);
+    m.lpBuffers     = &wsabuf;
+    m.dwBufferCount = 1;
+
+    if (pfWSASendMsg && srcip && srcip->s_addr != INADDR_ANY) {
+        WSACMSGHDR *cm;
+
+        DEBUGMSGTL(("udpbase:sendto", "sending from [%d] %s\n", if_index,
+                    inet_ntoa(*srcip)));
+
+        memset(cmsg, 0, sizeof(cmsg));
+
+        m.Control.buf = cmsg;
+        m.Control.len = sizeof(cmsg);
+
+        cm = WSA_CMSG_FIRSTHDR(&m);
+        cm->cmsg_len = WSA_CMSG_LEN(cmsg_data_size);
+        cm->cmsg_level = IPPROTO_IP;
+        cm->cmsg_type = IP_PKTINFO;
+
+        {
+            struct in_pktinfo ipi = { 0 };
+            ipi.ipi_ifindex = if_index;
+            ipi.ipi_addr.s_addr = srcip->s_addr;
+            memcpy(WSA_CMSG_DATA(cm), &ipi, sizeof(ipi));
+        }
+
+        rc = pfWSASendMsg(fd, &m, 0, &bytes_sent, NULL, NULL);
+        if (rc == 0)
+            return bytes_sent;
+        DEBUGMSGTL(("udpbase:sendto", "sending from [%d] %s failed: %d\n",
+                    if_index, inet_ntoa(*srcip), WSAGetLastError()));
+    }
+    rc = sendto(fd, data, len, 0, remote, sizeof(struct sockaddr));
+    return rc;
+#endif /* !defined(WIN32) */
 }
-#endif /* (linux && IP_PKTINFO) || IP_RECVDSTADDR */
+#endif /* HAVE_IP_PKTINFO || HAVE_IP_RECVDSTADDR */
 
 /*
  * You can write something into opaque that will subsequently get passed back 
@@ -358,3 +462,34 @@ netsnmp_udpbase_send(netsnmp_transport *t, void *buf, int 
size,
     }
     return rc;
 }
+
+void
+netsnmp_udp_base_ctor(void)
+{
+#if defined(WIN32) && defined(HAVE_IP_PKTINFO)
+    SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
+    GUID WSARecvMsgGuid = WSAID_WSARECVMSG;
+    GUID WSASendMsgGuid = WSAID_WSASENDMSG;
+    DWORD nbytes;
+    int result;
+
+    netsnmp_assert(s != SOCKET_ERROR);
+    /* WSARecvMsg(): Windows XP / Windows Server 2003 and later */
+    result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                      &WSARecvMsgGuid, sizeof(WSARecvMsgGuid),
+                      &pfWSARecvMsg, sizeof(pfWSARecvMsg), &nbytes, NULL, 
NULL);
+    if (result == SOCKET_ERROR)
+        DEBUGMSGTL(("netsnmp_udp", "WSARecvMsg() not found (errno %ld)\n",
+                    WSAGetLastError()));
+
+    /* WSASendMsg(): Windows Vista / Windows Server 2008 and later */
+    result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+                      &WSASendMsgGuid, sizeof(WSASendMsgGuid),
+                      &pfWSASendMsg, sizeof(pfWSASendMsg), &nbytes, NULL, 
NULL);
+    if (result == SOCKET_ERROR)
+        DEBUGMSGTL(("netsnmp_udp", "WSASendMsg() not found (errno %ld)\n",
+                    WSAGetLastError()));
+
+    closesocket(s);
+#endif
+}
diff --git a/snmplib/transports/snmpUDPDomain.c 
b/snmplib/transports/snmpUDPDomain.c
index 638c2b1..ba127b3 100644
--- a/snmplib/transports/snmpUDPDomain.c
+++ b/snmplib/transports/snmpUDPDomain.c
@@ -102,9 +102,7 @@ netsnmp_udp_fmtaddr(netsnmp_transport *t, void *data, int 
len)
 
 
 
-#if (defined(linux) && defined(IP_PKTINFO)) \
-    || defined(IP_RECVDSTADDR) && HAVE_STRUCT_MSGHDR_MSG_CONTROL \
-                               && HAVE_STRUCT_MSGHDR_MSG_FLAGS
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
 
 int netsnmp_udp_recvfrom(int s, void *buf, int len, struct sockaddr *from, 
socklen_t *fromlen, struct sockaddr *dstip, socklen_t *dstlen, int *if_index)
 {
@@ -119,7 +117,7 @@ int netsnmp_udp_sendto(int fd, struct in_addr *srcip, int 
if_index, struct socka
     /** udpiv4 just calls udpbase. should we skip directly to there? */
     return netsnmp_udpipv4_sendto(fd, srcip, if_index, remote, data, len);
 }
-#endif /* (linux && IP_PKTINFO) || IP_RECVDSTADDR */
+#endif /* HAVE_IP_PKTINFO || HAVE_IP_RECVDSTADDR */
 
 /*
  * Open a UDP-based transport for SNMP.  Local is TRUE if addr is the local
diff --git a/snmplib/transports/snmpUDPIPv4BaseDomain.c 
b/snmplib/transports/snmpUDPIPv4BaseDomain.c
index 0ca046c..58bc21b 100644
--- a/snmplib/transports/snmpUDPIPv4BaseDomain.c
+++ b/snmplib/transports/snmpUDPIPv4BaseDomain.c
@@ -44,9 +44,7 @@
 #include <net-snmp/library/sd-daemon.h>
 #endif
 
-#if (defined(linux) && defined(IP_PKTINFO)) \
-    || defined(IP_RECVDSTADDR) && HAVE_STRUCT_MSGHDR_MSG_CONTROL \
-                               && HAVE_STRUCT_MSGHDR_MSG_FLAGS
+#if defined(HAVE_IP_PKTINFO) || defined(HAVE_IP_RECVDSTADDR)
 
 int netsnmp_udpipv4_recvfrom(int s, void *buf, int len, struct sockaddr *from,
                              socklen_t *fromlen, struct sockaddr *dstip,
@@ -61,7 +59,7 @@ int netsnmp_udpipv4_sendto(int fd, struct in_addr *srcip, int 
if_index,
 {
     return netsnmp_udpbase_sendto(fd, srcip, if_index, remote, data, len);
 }
-#endif /* (linux && IP_PKTINFO) || IP_RECVDSTADDR */
+#endif /* HAVE_IP_PKTINFO || HAVE_IP_RECVDSTADDR */
 
 netsnmp_transport *
 netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int local)
@@ -135,7 +133,8 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int 
local)
         t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
         t->local_length = 6;
 
-#if defined(linux) && defined(IP_PKTINFO)
+#ifndef WIN32
+#if defined(HAVE_IP_PKTINFO)
         { 
             int sockopt = 1;
             if (setsockopt(t->sock, SOL_IP, IP_PKTINFO, &sockopt, sizeof 
sockopt) == -1) {
@@ -146,7 +145,7 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, int 
local)
             }
             DEBUGMSGTL(("netsnmp_udpbase", "set IP_PKTINFO\n"));
         }
-#elif defined(IP_RECVDSTADDR)
+#elif defined(HAVE_IP_RECVDSTADDR)
         {
             int sockopt = 1;
             if (setsockopt(t->sock, IPPROTO_IP, IP_RECVDSTADDR, &sockopt, 
sizeof sockopt) == -1) {
@@ -158,6 +157,18 @@ netsnmp_udpipv4base_transport(struct sockaddr_in *addr, 
int local)
             DEBUGMSGTL(("netsnmp_udp", "set IP_RECVDSTADDR\n"));
         }
 #endif
+#else /* !defined(WIN32) */
+        { 
+            int sockopt = 1;
+            if (setsockopt(t->sock, IPPROTO_IP, IP_PKTINFO, (void *)&sockopt,
+                          sizeof(sockopt)) == -1) {
+                DEBUGMSGTL(("netsnmp_udpbase", "couldn't set IP_PKTINFO: %d\n",
+                            WSAGetLastError()));
+            } else {
+                DEBUGMSGTL(("netsnmp_udpbase", "set IP_PKTINFO\n"));
+            }
+        }
+#endif /* !defined(WIN32) */
         if (!socket_initialized) {
             rc = bind(t->sock, (struct sockaddr *) addr,
                     sizeof(struct sockaddr));
diff --git a/win32/net-snmp/net-snmp-config.h b/win32/net-snmp/net-snmp-config.h
index 1eccf42..4895491 100644
--- a/win32/net-snmp/net-snmp-config.h
+++ b/win32/net-snmp/net-snmp-config.h
@@ -41,7 +41,7 @@
  * We need at least SP1 for some IPv6 defines in ws2ipdef.h
  */
 #ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x501 /*_WIN32_WINNT_WIN2K*/
+#define _WIN32_WINNT 0x600 /*_WIN32_WINNT_WIN6*/
 #else
 #if _WIN32_WINNT < 0x501
 #error _WIN32_WINNT is too low - it should be set to at least 0x501.
@@ -939,6 +939,9 @@
 /* Define to 1 if you have the <ws2tcpip.h> header file. */
 #define HAVE_WS2TCPIP_H 1
 
+/* Set if IP_PKTINFO is usable */
+#define HAVE_IP_PKTINFO 1
+
 /* Define to 1 if you have the <xti.h> header file. */
 /* #undef HAVE_XTI_H */
 
diff --git a/win32/net-snmp/net-snmp-config.h.in 
b/win32/net-snmp/net-snmp-config.h.in
index 1607bfa..6aede5f 100644
--- a/win32/net-snmp/net-snmp-config.h.in
+++ b/win32/net-snmp/net-snmp-config.h.in
@@ -41,7 +41,7 @@
  * We need at least SP1 for some IPv6 defines in ws2ipdef.h
  */
 #ifndef _WIN32_WINNT
-#define _WIN32_WINNT 0x501 /*_WIN32_WINNT_WIN2K*/
+#define _WIN32_WINNT 0x600 /*_WIN32_WINNT_WIN6*/
 #else
 #if _WIN32_WINNT < 0x501
 #error _WIN32_WINNT is too low - it should be set to at least 0x501.
@@ -939,6 +939,9 @@
 /* Define to 1 if you have the <ws2tcpip.h> header file. */
 #define HAVE_WS2TCPIP_H 1
 
+/* Set if IP_PKTINFO is usable */
+#define HAVE_IP_PKTINFO 1
+
 /* Define to 1 if you have the <xti.h> header file. */
 /* #undef HAVE_XTI_H */
 
diff --git a/win32/transports/snmp_transport_inits.h 
b/win32/transports/snmp_transport_inits.h
index 2fa0301..1bf1409 100644
--- a/win32/transports/snmp_transport_inits.h
+++ b/win32/transports/snmp_transport_inits.h
@@ -1,4 +1,5 @@
 #ifdef NETSNMP_TRANSPORT_UDP_DOMAIN
+netsnmp_udp_base_ctor();
 netsnmp_udp_ctor();
 #endif
 #ifdef NETSNMP_TRANSPORT_TCP_DOMAIN
-- 
1.7.10.4


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_feb
_______________________________________________
Net-snmp-coders mailing list
Net-snmp-coders@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to