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
[email protected]
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders