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