summaryrefslogtreecommitdiff
path: root/ACE
diff options
context:
space:
mode:
authorJustin R. Wilson <wilsonj@objectcomputing.com>2019-02-21 09:22:09 -0600
committerJustin R. Wilson <wilsonj@objectcomputing.com>2019-02-22 09:48:09 -0600
commitfa2ecd983d5a4f844b9ee419bcd73edc23d1408c (patch)
tree6f2a41f3735521a4920b6c4a580076e0d0c8aa70 /ACE
parentb584d571ee82182fb39a572f24fd8083e50eb0ec (diff)
downloadATCD-fa2ecd983d5a4f844b9ee419bcd73edc23d1408c.tar.gz
Provide option for local address for SOCK_Dgram recvmsg
Diffstat (limited to 'ACE')
-rw-r--r--ACE/ace/OS_NS_sys_socket.h14
-rw-r--r--ACE/ace/SOCK_Dgram.cpp64
-rw-r--r--ACE/ace/SOCK_Dgram.h12
-rw-r--r--ACE/tests/SOCK_Dgram_Test.cpp76
4 files changed, 155 insertions, 11 deletions
diff --git a/ACE/ace/OS_NS_sys_socket.h b/ACE/ace/OS_NS_sys_socket.h
index aa814443362..1f972a9f24d 100644
--- a/ACE/ace/OS_NS_sys_socket.h
+++ b/ACE/ace/OS_NS_sys_socket.h
@@ -58,6 +58,20 @@
#define ACE_SHUTDOWN_BOTH 2
#endif /* SD_BOTH */
+#if defined (IP_RECVDSTADDR)
+#define ACE_RECVPKTINFO IP_RECVDSTADDR
+#elif defined (IP_PKTINFO)
+#define ACE_RECVPKTINFO IP_PKTINFO
+#endif
+
+#if defined (ACE_HAS_IPV6)
+#if defined (IPV6_PKTINFO)
+#define ACE_RECVPKTINFO6 IPV6_PKTINFO
+#elif defined (IPV6_RECVPKTINFO)
+#define ACE_RECVPKTINFO6 IPV6_RECVPKTINFO
+#endif
+#endif
+
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
class ACE_Accept_QoS_Params;
diff --git a/ACE/ace/SOCK_Dgram.cpp b/ACE/ace/SOCK_Dgram.cpp
index 710ac47f7ef..754e2c3898f 100644
--- a/ACE/ace/SOCK_Dgram.cpp
+++ b/ACE/ace/SOCK_Dgram.cpp
@@ -308,11 +308,26 @@ ssize_t
ACE_SOCK_Dgram::recv (iovec iov[],
int n,
ACE_Addr &addr,
- int flags) const
+ int flags,
+ ACE_INET_Addr *to_addr) const
{
ACE_TRACE ("ACE_SOCK_Dgram::recv");
msghdr recv_msg;
+#if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG)
+ union control_buffer {
+ cmsghdr control_msg_header;
+#if defined (IP_RECVDSTADDR)
+ u_char padding[CMSG_SPACE(sizeof (struct in_addr))];
+#elif defined (IP_PKTINFO)
+ u_char padding[CMSG_SPACE(sizeof (struct in_pktinfo))];
+#endif
+#if defined (ACE_HAS_IPV6)
+ u_char padding6[CMSG_SPACE(sizeof (struct in6_pktinfo))];
+#endif
+ } cbuf;
+#endif /* ACE_HAS_4_4BSD_SENDMSG_RECVMSG */
+
recv_msg.msg_iov = (iovec *) iov;
recv_msg.msg_iovlen = n;
#if defined (ACE_HAS_SOCKADDR_MSG_NAME)
@@ -323,8 +338,8 @@ ACE_SOCK_Dgram::recv (iovec iov[],
recv_msg.msg_namelen = addr.get_size ();
#if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG)
- recv_msg.msg_control = 0 ;
- recv_msg.msg_controllen = 0 ;
+ recv_msg.msg_control = to_addr ? &cbuf : 0;
+ recv_msg.msg_controllen = to_addr ? sizeof (cbuf) : 0;
#elif !defined ACE_LACKS_SENDMSG
recv_msg.msg_accrights = 0;
recv_msg.msg_accrightslen = 0;
@@ -335,6 +350,49 @@ ACE_SOCK_Dgram::recv (iovec iov[],
flags);
addr.set_size (recv_msg.msg_namelen);
addr.set_type (((sockaddr_in *) addr.get_addr())->sin_family);
+
+#if defined (ACE_HAS_4_4BSD_SENDMSG_RECVMSG)
+ if (to_addr) {
+ this->get_local_addr (*to_addr);
+ if (to_addr->get_type() == AF_INET) {
+#if defined (IP_RECVDSTADDR) || defined (IP_PKTINFO)
+ for (cmsghdr *ptr = CMSG_FIRSTHDR (&recv_msg); ptr != 0; ptr = CMSG_NXTHDR (&recv_msg, ptr)) {
+#if defined (IP_RECVDSTADDR)
+ if (ptr->cmsg_level == IPPROTO_IP &&
+ ptr->cmsg_type == IP_RECVDSTADDR) {
+ to_addr->set_address ((const char *)(CMSG_DATA (ptr)),
+ sizeof (struct in_addr),
+ 0);
+ break;
+ }
+#else
+ if (ptr->cmsg_level == IPPROTO_IP &&
+ ptr->cmsg_type == IP_PKTINFO) {
+ to_addr->set_address ((const char *)&(((struct in_pktinfo *)(CMSG_DATA (ptr)))->ipi_addr),
+ sizeof (struct in_addr),
+ 0);
+ break;
+ }
+#endif
+ }
+#endif
+ }
+#if defined (ACE_HAS_IPV6) && defined (IPV6_PKTINFO)
+ else if (to_addr->get_type() == AF_INET6) {
+ for (cmsghdr *ptr = CMSG_FIRSTHDR (&recv_msg); ptr != 0; ptr = CMSG_NXTHDR (&recv_msg, ptr)) {
+ if (ptr->cmsg_level == IPPROTO_IPV6 && ptr->cmsg_type == IPV6_PKTINFO) {
+ to_addr->set_address ((const char *)&(((struct in6_pktinfo *)(CMSG_DATA (ptr)))->ipi6_addr),
+ sizeof (struct in6_addr),
+ 0);
+
+ break;
+ }
+ }
+ }
+#endif
+ }
+#endif /* ACE_HAS_4_4BSD_SENDMSG_RECVMSG */
+
return status;
}
diff --git a/ACE/ace/SOCK_Dgram.h b/ACE/ace/SOCK_Dgram.h
index 92705f2aa56..ff567997592 100644
--- a/ACE/ace/SOCK_Dgram.h
+++ b/ACE/ace/SOCK_Dgram.h
@@ -15,6 +15,9 @@
#include "ace/SOCK.h"
#include "ace/INET_Addr.h"
+// Included so users have access to ACE_RECVPKTINFO and ACE_RECVPKTINFO6 .
+#include "ace/OS_NS_sys_socket.h"
+
#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */
@@ -120,11 +123,16 @@ public:
int flags = 0) const;
/// Recv an <iovec> of size @a n to the datagram socket (uses
- /// <recvmsg(3)>).
+ /// <recvmsg(3)>). The IP destination address will be placed in @a
+ /// *to_addr if it is not null and set_option has been called with
+ /// 1) level IPPROTO_IP, option ACE_RECVPKTINFO, and value 1 for
+ /// IPV4 addresses or 2) IPPROTO_IPV6, option ACE_RECVPKTINFO6, and
+ /// value 1 for IPV6 addresses.
ssize_t recv (iovec iov[],
int n,
ACE_Addr &addr,
- int flags = 0) const;
+ int flags = 0,
+ ACE_INET_Addr *to_addr = 0) const;
/**
* Wait up to @a timeout amount of time to receive a datagram into
diff --git a/ACE/tests/SOCK_Dgram_Test.cpp b/ACE/tests/SOCK_Dgram_Test.cpp
index d5620a69fc7..14ee0af7eae 100644
--- a/ACE/tests/SOCK_Dgram_Test.cpp
+++ b/ACE/tests/SOCK_Dgram_Test.cpp
@@ -64,21 +64,81 @@ client (void *arg)
ACE_TEXT("(%P|%t) protocol %d, %p\n"),
server_addr.get_type (),
ACE_TEXT ("SOCK_Dgram open")));
+ return 0;
}
- else if (cli_dgram.send (TEST_DATA, sizeof (TEST_DATA), server_addr) == -1)
+
+ {
+ if (remote_addr->get_type () == AF_INET) {
+#if defined (ACE_RECVPKTINFO)
+ int sockopt = 1;
+ if (cli_dgram.set_option(IPPROTO_IP, ACE_RECVPKTINFO, &sockopt, sizeof sockopt) == -1) {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("(%P|%t) setsockopt failed\n")));
+ return 0;
+ } else {
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT("(%P|%t) setsockopt succeeded\n")));
+ }
+#endif
+ }
+#if defined (ACE_HAS_IPV6)
+ else {
+#if defined (ACE_RECVPKTINFO6)
+ int sockopt = 1;
+ if (cli_dgram.set_option(IPPROTO_IPV6, ACE_RECVPKTINFO6, &sockopt, sizeof sockopt) == -1) {
+ ACE_ERROR((LM_ERROR,
+ ACE_TEXT("(%P|%t) setsockopt failed\n")));
+ return;
+ } else {
+ ACE_DEBUG((LM_DEBUG,
+ ACE_TEXT("(%P|%t) setsockopt succeeded\n")));
+ }
+#endif
+ }
+#endif
+ }
+
+ if (cli_dgram.send (TEST_DATA, sizeof (TEST_DATA), server_addr) == -1)
{
ACE_ERROR((LM_ERROR,
ACE_TEXT("(%P|%t) UDP send to %s %p\n"),
hostname_string,
ACE_TEXT ("failed")));
+ return 0;
}
- else
+
{
- ssize_t rcv_cnt = cli_dgram.recv (buf,
- sizeof (buf),
+ ACE_INET_Addr local_addr;
+ cli_dgram.get_local_addr(local_addr);
+
+ if (local_addr.get_type () == AF_INET)
+ {
+ local_addr.set (local_addr.get_port_number (),
+ ACE_LOCALHOST,
+ 1,
+ local_addr.get_type ());
+ }
+#if defined (ACE_HAS_IPV6)
+ else
+ {
+ local_addr.set (local_addr.get_port_number(),
+ ACE_IPV6_LOCALHOST,
+ 1,
+ local_addr.get_type ());
+ }
+#endif /* ACE_HAS_IPV6 */
+
+ ACE_INET_Addr to_addr = local_addr;
+
+ iovec iov[1];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 20;
+
+ ssize_t rcv_cnt = cli_dgram.recv (iov,
+ 1,
peer_addr,
0,
- &timeout);
+ &to_addr);
if (rcv_cnt == -1)
{
if (errno == ETIME)
@@ -97,7 +157,7 @@ client (void *arg)
}
else
{
- // recv() ok, check data and 'from' address
+ // recv() ok, check data, 'from', and 'to' address
size_t rcv_siz = static_cast<size_t> (rcv_cnt);
if (rcv_siz != sizeof (TEST_DATA))
{
@@ -125,6 +185,10 @@ client (void *arg)
ACE_TEXT ("(%P|%t) recv addr size %d; should be %d\n"),
peer_addr.get_size (),
server_addr.get_size ()));
+ if (local_addr != to_addr) {
+ ACE_ERROR ((LM_ERROR,
+ ACE_TEXT ("(%P|%t) local addr is not equal to server addr\n")));
+ }
}
}