[PATCH v2] net: enhance decoding of getsockopt(SO_ERROR)

Masatake YAMATO yamato at redhat.com
Sun Dec 16 09:40:56 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.

Change in v2:
* Use print_xlat_ex to print errno.
  Suggested by ldv.

Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
 net.c                       |  21 +++++++
 tests/gen_tests.in          |   1 +
 tests/pure_executables.list |   1 +
 tests/so_error.c            | 121 ++++++++++++++++++++++++++++++++++++
 4 files changed, 144 insertions(+)
 create mode 100644 tests/so_error.c

diff --git a/net.c b/net.c
index f65b6619..209275af 100644
--- a/net.c
+++ b/net.c
@@ -671,6 +671,24 @@ 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;
+
+	tprints("[");
+	print_xlat_ex(err, err_name(err), XLAT_STYLE_FMT_U);
+	tprints("]");
+}
+
 #ifdef PACKET_STATISTICS
 static void
 print_tpacket_stats(struct tcb *const tcp, const kernel_ulong_t addr,
@@ -786,6 +804,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