[PATCH] net: enhance decoding of getsockopt(SO_ERROR)
Masatake YAMATO
yamato at redhat.com
Sat Dec 15 22:05:28 UTC 2018
* net.c (print_get_error): New function decoding error
number returned as option value for SO_ERROR option.
(print_getsockopt) <case SO_ERROR>: Call print_get_error.
* tests/so_error.c: New test.
* tests/gen_tests.in (so_error): Likewise.
* tests/pure_executables.list (so_error): Likewise.
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
net.c | 23 +++++++
tests/gen_tests.in | 1 +
tests/pure_executables.list | 1 +
tests/so_error.c | 121 ++++++++++++++++++++++++++++++++++++
4 files changed, 146 insertions(+)
create mode 100644 tests/so_error.c
diff --git a/net.c b/net.c
index f65b6619..4b2cba04 100644
--- a/net.c
+++ b/net.c
@@ -671,6 +671,26 @@ print_get_ucred(struct tcb *const tcp, const kernel_ulong_t addr,
tprints("}");
}
+static void
+print_get_error(struct tcb *const tcp, const kernel_ulong_t addr,
+ unsigned int len)
+{
+ unsigned int err;
+ const char *ename;
+
+ if (len > sizeof(err))
+ err = sizeof(err);
+
+ if (umoven_or_printaddr(tcp, addr, len, &err))
+ return;
+
+ ename = err_name (err);
+ if (ename)
+ tprintf("[%s]", ename);
+ else
+ tprintf("[%u]", err);
+}
+
#ifdef PACKET_STATISTICS
static void
print_tpacket_stats(struct tcb *const tcp, const kernel_ulong_t addr,
@@ -786,6 +806,9 @@ print_getsockopt(struct tcb *const tcp, const unsigned int level,
else
printaddr(addr);
return;
+ case SO_ERROR:
+ print_get_error(tcp, addr, rlen);
+ return;
}
break;
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 7374add8..d6b4a068 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -431,6 +431,7 @@ sigpending -a15
sigprocmask -a34
sigreturn -esignal='!USR1'
sigsuspend -a19 -esignal=none
+so_error -e trace=getsockopt
so_linger -e trace=getsockopt,setsockopt
so_peercred -e trace=getsockopt
so_peercred-Xabbrev -e trace=getsockopt -Xabbrev
diff --git a/tests/pure_executables.list b/tests/pure_executables.list
index a4e9020a..53adb99f 100755
--- a/tests/pure_executables.list
+++ b/tests/pure_executables.list
@@ -410,6 +410,7 @@ sigpending
sigprocmask
sigreturn
sigsuspend
+so_error
so_linger
so_peercred
so_peercred-Xabbrev
diff --git a/tests/so_error.c b/tests/so_error.c
new file mode 100644
index 00000000..85d2a889
--- /dev/null
+++ b/tests/so_error.c
@@ -0,0 +1,121 @@
+/*
+ * Check decoding of SO_ERROR socket option.
+ *
+ * Copyright (c) 2018 Masatake YAMATO <yamato at redhat.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tests.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static in_port_t
+reserve_ephemeral_port(void)
+{
+ int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sd < 0)
+ perror_msg_and_skip("(server)socket AF_UNIX SOCK_STREAM");
+
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ /* The range is defined in /proc/sys/net/ipv4/ip_local_port_range.
+ We use default range here. */
+ in_port_t port;
+ for (port = 49152; port < 61000; port++)
+ {
+ /* Just bind here. No listen. */
+ addr.sin_port = htons(port);
+ if (bind(sd, &addr, sizeof(addr)) == 0)
+ return port;
+ }
+ error_msg_and_skip("no ephemeral port available for testing purpose");
+}
+
+int
+main(void)
+{
+ in_port_t port = reserve_ephemeral_port ();
+
+ /* Connect to the reserved port in NONBLOCK mode.
+ The port is reserved but not listend. So
+ the client doing "connect" gets error asynchronously. */
+ int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (fd < 0)
+ perror_msg_and_skip("socket AF_UNIX SOCK_STREAM");
+
+ int flag = fcntl(fd, F_GETFL);
+ if (flag < 0)
+ perror_msg_and_skip("fcntl F_GETFL");
+ flag |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flag) < 0)
+ perror_msg_and_skip("fcntl F_SETFL");
+
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ .sin_port = htons(port),
+ };
+ if (connect(fd, &addr, sizeof(addr)) == 0)
+ error_msg_and_skip("successfully connected unexpectedly");
+ else if (errno != EINPROGRESS)
+ perror_msg_and_skip("failed in connect unexpectedly reason");
+
+ struct timeval to = {
+ .tv_sec = 1,
+ .tv_usec = 0,
+ };
+ fd_set wfds;
+ FD_ZERO(&wfds);
+ FD_SET(fd, &wfds);
+ if (select(fd + 1, NULL, &wfds, NULL, &to) < 0)
+ perror_msg_and_skip("select");
+
+ int sock_errno;
+ socklen_t optlen = sizeof(int);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen) < 0)
+ perror_msg_and_skip("getsockopt");
+ else if (sock_errno != ECONNREFUSED)
+ {
+ errno = sock_errno;
+ perror_msg_and_skip("unexpected socket error");
+ }
+ else if (optlen != sizeof(int))
+ error_msg_and_skip("unexpected data size for error option");
+
+ printf("getsockopt(%d, SOL_SOCKET, SO_ERROR, [ECONNREFUSED], [%u]) = 0\n",
+ fd, optlen);
+ puts("+++ exited with 0 +++");
+ return 0;
+}
--
2.17.2
More information about the Strace-devel
mailing list