On Windows Vista / Windows Server 2008 and later it is possible to add
multihoming support by using the IP_PKTINFO socket option.
---
 snmplib/transports/snmpUDPBaseDomain.c     |  129 ++++++++++++++++++++++++++++
 snmplib/transports/snmpUDPIPv4BaseDomain.c |   11 +++
 win32/net-snmp/net-snmp-config.h           |    5 +-
 win32/net-snmp/net-snmp-config.h.in        |    5 +-
 win32/transports/snmp_transport_inits.h    |    1 +
 5 files changed, 149 insertions(+), 2 deletions(-)

diff --git a/snmplib/transports/snmpUDPBaseDomain.c 
b/snmplib/transports/snmpUDPBaseDomain.c
index d67257b..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>
@@ -112,12 +115,18 @@ enum {
 #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;
@@ -135,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;
@@ -149,6 +184,7 @@ 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(HAVE_IP_PKTINFO)
         if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_PKTINFO) {
@@ -169,12 +205,26 @@ netsnmp_udpbase_recvfrom(int s, void *buf, int len, 
struct sockaddr *from,
         }
 #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)];
@@ -258,6 +308,54 @@ 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 /* HAVE_IP_PKTINFO || HAVE_IP_RECVDSTADDR */
 
@@ -364,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/snmpUDPIPv4BaseDomain.c 
b/snmplib/transports/snmpUDPIPv4BaseDomain.c
index ae856b4..58bc21b 100644
--- a/snmplib/transports/snmpUDPIPv4BaseDomain.c
+++ b/snmplib/transports/snmpUDPIPv4BaseDomain.c
@@ -157,6 +157,17 @@ 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,
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