diff --git a/src/lib/core/sio.c b/src/lib/core/sio.c
index 72f0248c845f118cfb20366bfab445fdc312c742..c9bfa13b567b8b2f17d691a06fcbf8f0ceaa26c0 100644
--- a/src/lib/core/sio.c
+++ b/src/lib/core/sio.c
@@ -55,38 +55,49 @@ static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV,
  * checks and all.
  */
 static int
-sio_socketname_to_buffer(int fd, char *buf, int size)
+sio_socketname_to_buffer(int fd,
+			 const struct sockaddr *base_addr, socklen_t addrlen,
+			 const struct sockaddr *peer_addr, socklen_t peerlen,
+			 char *buf, int size)
 {
 	int n = 0;
 	(void)n;
 	SNPRINT(n, snprintf, buf, size, "fd %d", fd);
 	if (fd < 0)
 		return 0;
-	struct sockaddr_storage addr;
-	socklen_t addrlen = sizeof(addr);
-	struct sockaddr *base_addr = (struct sockaddr *)&addr;
-	int rc = getsockname(fd, base_addr, &addrlen);
-	if (rc == 0) {
+	if (base_addr != NULL) {
 		SNPRINT(n, snprintf, buf, size, ", aka ");
 		SNPRINT(n, sio_addr_snprintf, buf, size, base_addr, addrlen);
 	}
-	addrlen = sizeof(addr);
-	rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen);
-	if (rc == 0) {
+	if (peer_addr != NULL) {
 		SNPRINT(n, snprintf, buf, size, ", peer of ");
-		SNPRINT(n, sio_addr_snprintf, buf, size, base_addr, addrlen);
+		SNPRINT(n, sio_addr_snprintf, buf, size,
+			peer_addr, peerlen);
 	}
 	return 0;
 }
 
 const char *
-sio_socketname(int fd)
+sio_socketname_addr(int fd, const struct sockaddr *base_addr,
+		    socklen_t addrlen)
 {
 	/* Preserve errno */
 	int save_errno = errno;
 	int name_size = SERVICE_NAME_MAXLEN;
 	char *name = static_alloc(name_size);
-	int rc = sio_socketname_to_buffer(fd, name, name_size);
+
+	struct sockaddr_storage peer_addr_storage;
+	socklen_t peerlen = sizeof(peer_addr_storage);
+	struct sockaddr *peer_addr = (struct sockaddr *)&peer_addr_storage;
+	int rcp = getpeername(fd, peer_addr, &peerlen);
+	if (rcp != 0) {
+		peer_addr = NULL;
+	}
+
+	int rc = sio_socketname_to_buffer(fd,
+					  base_addr, addrlen,
+					  peer_addr, peerlen,
+					  name, name_size);
 	/*
 	 * Could fail only because of a bad format in snprintf, but it is not
 	 * bad, so should not fail.
@@ -101,6 +112,29 @@ sio_socketname(int fd)
 	return name;
 }
 
+const char *
+sio_socketname(int fd)
+{
+	/* Preserve errno */
+	int save_errno = errno;
+
+	struct sockaddr_storage addr;
+	socklen_t addrlen = sizeof(addr);
+	struct sockaddr *base_addr = (struct sockaddr *)&addr;
+	int rcb = getsockname(fd, base_addr, &addrlen);
+	if (rcb != 0) {
+		base_addr = NULL;
+	}
+
+	const char *name = sio_socketname_addr(fd, base_addr, addrlen);
+	/*
+	 * Restore the original errno, it might have been reset by
+	 * getsockname().
+	 */
+	errno = save_errno;
+	return name;
+}
+
 /** Get a string representation of a socket option name,
  * for logging.
  */
@@ -245,7 +279,9 @@ sio_bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
 {
 	int rc = bind(fd, addr, addrlen);
 	if (rc < 0)
-		diag_set(SocketError, sio_socketname(fd), "bind");
+		diag_set(SocketError,
+			 sio_socketname_addr(fd, addr, addrlen),
+			 "bind");
 	return rc;
 }
 
diff --git a/src/lib/core/sio.h b/src/lib/core/sio.h
index bb599fa451cf7d6ba7c44b74bfa7b2cb14b06637..1687d3403d9c77b497917be13c5ec17cf249e593 100644
--- a/src/lib/core/sio.h
+++ b/src/lib/core/sio.h
@@ -236,6 +236,16 @@ ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags,
 int
 sio_uri_to_addr(const char *uri, struct sockaddr *addr, bool *is_host_empty);
 
+/* internals, for unit testing */
+
+/**
+ * Return a string containing fd, base address and peer from arguments.
+ * Used mostly in error messages.
+ */
+const char *
+sio_socketname_addr(int fd, const struct sockaddr *base_addr,
+		    socklen_t addrlen);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 #endif /* defined(__cplusplus) */
diff --git a/test/unit/sio.c b/test/unit/sio.c
index 79426c372b1e19d66ed4e3cd2c2b16d579107e6f..d2fd3b1129581eb2f12ecac6c052905cd0631734 100644
--- a/test/unit/sio.c
+++ b/test/unit/sio.c
@@ -89,6 +89,32 @@ check_uri_to_addr(void)
 	footer();
 }
 
+static void
+check_sio_socketname_addr(void)
+{
+	header();
+	plan(2);
+	struct sockaddr_storage base_storage;
+	struct sockaddr *base_addr = (struct sockaddr *)&base_storage;
+	socklen_t addrlen = sizeof(base_storage);
+
+	bool is_host_empty;
+	char base_addr_str[] = "192.0.2.255:1";
+	sio_uri_to_addr(base_addr_str, base_addr, &is_host_empty);
+
+	const char *name = sio_socketname_addr(-3,
+					       base_addr, addrlen);
+
+	is_str(name, "fd -3", "works for invalid fd");
+
+	name = sio_socketname_addr(3, base_addr, addrlen);
+	char expectedbase[] = "fd 3, aka 192.0.2.255:1";
+	is_str(name, expectedbase, "works for fd and base_addr only");
+
+	check_plan();
+	footer();
+}
+
 static void
 check_auto_bind(void)
 {
@@ -118,9 +144,10 @@ main(void)
 	fiber_init(fiber_c_invoke);
 
 	header();
-	plan(2);
+	plan(3);
 	check_uri_to_addr();
 	check_auto_bind();
+	check_sio_socketname_addr();
 	int rc = check_plan();
 	footer();
 
diff --git a/test/unit/unit.h b/test/unit/unit.h
index bb0e53136db8a68fad16db2235710ce1c9984410..4dd0b290a0fd77f7897665a4df691ab7547cec3a 100644
--- a/test/unit/unit.h
+++ b/test/unit/unit.h
@@ -118,6 +118,8 @@ int check_plan(void);
 #define is(a, b, ...)		_ok0((a) == (b), #a " == " #b, ##__VA_ARGS__)
 #define isnt(a, b, ...)		_ok0((a) != (b), #a " != " #b, ##__VA_ARGS__)
 
+#define is_str(a, b, fmt, args...) ok(strcmp(a, b) == 0, fmt, ##args)
+
 #if UNIT_TAP_COMPATIBLE
 
 #define header()					\
diff --git a/test/unit/uri.c b/test/unit/uri.c
index 34961d6c6c636d5956f431805ccb7f298103de1f..016558fbc0935e6b2bde0f7b2cc7704868e4d52b 100644
--- a/test/unit/uri.c
+++ b/test/unit/uri.c
@@ -10,8 +10,6 @@
 #define URI_PARAM_MAX 10
 #define URI_PARAM_VALUE_MAX 10
 
-#define is_str(a, b, fmt, args...) ok(strcmp(a, b) == 0, fmt, ##args)
-
 static void
 sample_uri_create(struct uri *uri)
 {