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