Index: src/process-manager/tests/test-socket.cc |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/process-manager/tests/test-socket.cc |
@@ -0,0 +1,344 @@ |
+#define _GNU_SOURCE 1 |
+#include <sys/types.h> |
+#include <sys/socket.h> |
+#include <netinet/in.h> |
+#include <linux/netlink.h> |
+#include <linux/rtnetlink.h> |
+#include <errno.h> |
+#include <sys/select.h> |
+#include <pthread.h> |
+#include "test-macros.h" |
+ |
+ |
+void test_raw (void) |
+{ |
+ int sock; |
+ const char buf[12] = "0123456789\0"; |
+ struct msghdr msg; |
+ struct iovec iov; |
+ static struct sockaddr_in dst; |
+ int ret; |
+ |
+ // ICMP Raw sock |
+ sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+ // sendmsg |
+ memset (&dst, 0, sizeof (dst)); |
+ dst.sin_family = AF_INET; |
+ dst.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
+ |
+ iov.iov_base = (void *) buf; |
+ iov.iov_len = sizeof (buf); |
+ msg.msg_name = &dst; |
+ msg.msg_namelen = sizeof (dst); |
+ msg.msg_iov = &iov; |
+ msg.msg_iovlen = 1; |
+ msg.msg_control = NULL; |
+ msg.msg_controllen = 0; |
+ |
+ ret = sendmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("RAW send ret = " << ret); |
+ |
+ // recvmsg with short buf |
+ iov.iov_base = (void *) buf; |
+ iov.iov_len = sizeof (buf); |
+ ret = recvmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("RAW recv ret = " << ret); |
+ |
+ char buf2[20]; |
+ iov.iov_base = (void *) buf2; |
+ iov.iov_len = sizeof (buf2); |
+ ret = recvmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf2)); |
+ OUTPUT ("RAW recv ret = " << ret); |
+ |
+ iov.iov_base = (void *) buf; |
+ iov.iov_len = sizeof (buf); |
+ ret = sendmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("RAW send ret = " << ret); |
+ |
+ // recvmsg with long buf |
+ char recvbuf[512]; |
+ iov.iov_base = (void *) recvbuf; |
+ iov.iov_len = sizeof (recvbuf); |
+ ret = recvmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf) + 20); |
+ OUTPUT ("RAW recv ret = " << ret); |
+ |
+ // close |
+ close (sock); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+} |
+ |
+void test_udp (void) |
+{ |
+ int sock; |
+ const char buf[12] = "0123456789\0"; |
+ struct msghdr msg; |
+ struct iovec iov; |
+ static struct sockaddr_in dst; |
+ int ret; |
+ |
+ // UDP Sock |
+ sock = socket (AF_INET, SOCK_DGRAM, 0); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+ memset (&dst, 0, sizeof (dst)); |
+ dst.sin_family = AF_INET; |
+ dst.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
+ dst.sin_port = htons (30); |
+ |
+ // bind |
+ ret = bind (sock, (struct sockaddr *)&dst, sizeof (dst)); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ |
+ // sendmsg |
+ iov.iov_base = (void *) buf; |
+ iov.iov_len = sizeof (buf); |
+ msg.msg_name = &dst; |
+ msg.msg_namelen = sizeof (dst); |
+ msg.msg_iov = &iov; |
+ msg.msg_iovlen = 1; |
+ msg.msg_control = NULL; |
+ msg.msg_controllen = 0; |
+ |
+ ret = sendmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("UDP send ret = " << ret); |
+ |
+ // recvmsg |
+ ret = recvmsg (sock, &msg, 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("UDP recv ret = " << ret); |
+ |
+ // close |
+ close (sock); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+} |
+ |
+static void * |
+thread_recv (void *arg) |
+{ |
+ int accept_sock = -1; |
+ int sock = *(int *)arg; |
+ int ret; |
+ char buf[12]; |
+ |
+ while (1) |
+ { |
+ fd_set readfd; |
+ struct timeval wait; |
+ FD_ZERO (&readfd); |
+ if (accept_sock == -1) |
+ { |
+ FD_SET (sock, &readfd); |
+ } |
+ else |
+ { |
+ FD_SET (accept_sock, &readfd); |
+ } |
+ wait.tv_sec = 1; |
+ |
+ ret = select (FD_SETSIZE, &readfd, NULL, NULL, &wait); |
+ TEST_ASSERT_UNEQUAL (ret, 0); |
+ if (errno == EINTR || errno == EAGAIN) |
+ { |
+ continue; |
+ } |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ |
+ // accept |
+ if (accept_sock == -1) |
+ { |
+ accept_sock = accept (sock, NULL, 0); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ OUTPUT ("TCP accepted ret = " << ret); |
+ } |
+ else |
+ { |
+ break; |
+ } |
+ } |
+ |
+ // recv |
+ ret = recv (accept_sock, &buf, sizeof (buf), 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("TCP recv ret = " << ret); |
+ |
+ pthread_exit (arg); |
+ // never reached. |
+ TEST_ASSERT (false); |
+ return arg; |
+} |
+ |
+void test_tcp (void) |
+{ |
+ int sock, tx_sock; |
+ const char buf[12] = "0123456789\0"; |
+ static struct sockaddr_in dst; |
+ int ret; |
+ pthread_t thread; |
+ |
+ // TCP Sock |
+ sock = socket (AF_INET, SOCK_STREAM, 0); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+ memset (&dst, 0, sizeof (dst)); |
+ dst.sin_family = AF_INET; |
+ dst.sin_addr.s_addr = htonl (INADDR_LOOPBACK); |
+ dst.sin_port = htons (30); |
+ |
+ // bind |
+ ret = bind (sock, (struct sockaddr *)&dst, sizeof (dst)); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ |
+ // listen |
+ ret = listen (sock, 5); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ |
+ // recv thread |
+ ret = pthread_create (&thread, NULL, |
+ &thread_recv, |
+ (void*)&sock); |
+ |
+ // tx sock |
+ tx_sock = socket (AF_INET, SOCK_STREAM, 0); |
+ TEST_ASSERT_UNEQUAL (tx_sock, -1); |
+ // connect |
+ ret = connect (tx_sock, (struct sockaddr *)&dst, sizeof (dst)); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ |
+ // send |
+ ret = send (tx_sock, &buf, sizeof (buf), 0); |
+ TEST_ASSERT_EQUAL (ret, sizeof (buf)); |
+ OUTPUT ("TCP send ret = " << ret); |
+ |
+ void *return_value; |
+ ret = pthread_join (thread, &return_value); |
+ |
+ // close |
+ close (sock); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ close (tx_sock); |
+ TEST_ASSERT_UNEQUAL (tx_sock, -1); |
+} |
+ |
+void test_netlink (void) |
+{ |
+ int sock; |
+ int ret; |
+ struct sockaddr_nl snl; |
+ socklen_t namelen; |
+ int seq = 0; |
+ char buf[4096]; |
+ struct iovec iov; |
+ struct msghdr msg; |
+ struct nlmsghdr *h; |
+ struct ifaddrmsg *ifa; |
+ |
+ // Netlink sock |
+ sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+ // Bind |
+ memset (&snl, 0, sizeof snl); |
+ snl.nl_family = AF_NETLINK; |
+ snl.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_ROUTE|RTMGRP_IPV4_IFADDR; |
+ ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+ // getsockname |
+ namelen = sizeof (snl); |
+ ret = getsockname (sock, (struct sockaddr *) &snl, &namelen); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ TEST_ASSERT_EQUAL (namelen, sizeof (snl)); |
+ |
+ // sendto |
+ struct |
+ { |
+ struct nlmsghdr nlh; |
+ struct rtgenmsg g; |
+ } req; |
+ |
+ memset (&snl, 0, sizeof snl); |
+ snl.nl_family = AF_NETLINK; |
+ |
+ // Get IPv4 Address |
+ req.nlh.nlmsg_len = sizeof (req); |
+ req.nlh.nlmsg_type = RTM_GETADDR; |
+ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; |
+ req.nlh.nlmsg_pid = 0; |
+ req.nlh.nlmsg_seq = ++seq; |
+ req.g.rtgen_family = AF_INET; |
+ |
+ ret = sendto (sock, (void *) &req, sizeof (req), 0, |
+ (struct sockaddr *) &snl, sizeof (snl)); |
+ TEST_ASSERT_EQUAL (ret, sizeof (req)); |
+ |
+ // recvmsg |
+ iov.iov_base = (void *) buf; |
+ iov.iov_len = sizeof (buf); |
+ msg.msg_name = (void *)&snl; |
+ msg.msg_namelen = sizeof (snl); |
+ msg.msg_iov = &iov; |
+ msg.msg_iovlen = 1; |
+ msg.msg_control = NULL; |
+ msg.msg_controllen = 0; |
+ |
+ ret = recvmsg (sock, &msg, 0); |
+ TEST_ASSERT_UNEQUAL (ret, -1); |
+ TEST_ASSERT_EQUAL (msg.msg_namelen, sizeof (snl)); |
+ |
+ // Code from zebra/rt_netlink.c |
+ for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (uint32_t) ret); |
+ h = NLMSG_NEXT (h, ret)) |
+ { |
+ if (h->nlmsg_type == NLMSG_DONE) |
+ break; |
+ |
+ /* Error handling. */ |
+ if (h->nlmsg_type == NLMSG_ERROR) |
+ { |
+ struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h); |
+ /* If the error field is zero, then this is an ACK */ |
+ if (err->error == 0) |
+ { |
+ // ACK |
+ /* return if not a multipart message, otherwise continue */ |
+ if (!(h->nlmsg_flags & NLM_F_MULTI)) |
+ { |
+ break; |
+ } |
+ continue; |
+ } |
+ |
+ TEST_ASSERT (h->nlmsg_len >= NLMSG_LENGTH (sizeof (struct nlmsgerr))); |
+ } |
+ |
+ ifa = (struct ifaddrmsg *) NLMSG_DATA (h); |
+ TEST_ASSERT (ifa->ifa_family == AF_INET || ifa->ifa_family == AF_INET6); |
+ OUTPUT ("NL: family = " << (int)ifa->ifa_family); |
+ |
+ TEST_ASSERT (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR); |
+ TEST_ASSERT (h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg) >= 0)); |
+ |
+ // We didn't get into detail to parse attribute |
+ } |
+ |
+ close (sock); |
+ TEST_ASSERT_UNEQUAL (sock, -1); |
+ |
+} |
+ |
+int main (int argc, char *argv[]) |
+{ |
+ test_raw (); |
+ test_udp (); |
+ test_tcp (); |
+ test_netlink (); |
+ return 0; |
+} |