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