* [PATCH liburing v2 1/4] liburing: Introduce getsockname operation
2025-11-20 22:13 [PATCH liburing v2 0/4] liburing: getsockname support Gabriel Krisman Bertazi
@ 2025-11-20 22:13 ` Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 2/4] test/bind-listen.t: Use ephemeral port Gabriel Krisman Bertazi
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-11-20 22:13 UTC (permalink / raw)
Cc: Gabriel Krisman Bertazi, io-uring, csander
This implements the functionality of getsockname(2) and getpeername(2)
under a single operation.
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
src/include/liburing.h | 13 +++++++++++++
src/include/liburing/io_uring.h | 1 +
2 files changed, 14 insertions(+)
diff --git a/src/include/liburing.h b/src/include/liburing.h
index 83819eb7..1626f3bb 100644
--- a/src/include/liburing.h
+++ b/src/include/liburing.h
@@ -1572,6 +1572,19 @@ IOURINGINLINE void io_uring_prep_cmd_sock(struct io_uring_sqe *sqe,
sqe->level = level;
}
+IOURINGINLINE void io_uring_prep_cmd_getsockname(struct io_uring_sqe *sqe,
+ int fd, struct sockaddr *sockaddr,
+ socklen_t *sockaddr_len,
+ int peer)
+ LIBURING_NOEXCEPT
+{
+ io_uring_prep_uring_cmd(sqe, SOCKET_URING_OP_GETSOCKNAME, fd);
+
+ sqe->addr = (uintptr_t) sockaddr;
+ sqe->addr3 = (unsigned long) (uintptr_t) sockaddr_len;
+ sqe->optlen = peer;
+}
+
IOURINGINLINE void io_uring_prep_waitid(struct io_uring_sqe *sqe,
idtype_t idtype,
id_t id,
diff --git a/src/include/liburing/io_uring.h b/src/include/liburing/io_uring.h
index a54e5b42..8e8b8e6a 100644
--- a/src/include/liburing/io_uring.h
+++ b/src/include/liburing/io_uring.h
@@ -966,6 +966,7 @@ enum io_uring_socket_op {
SOCKET_URING_OP_GETSOCKOPT,
SOCKET_URING_OP_SETSOCKOPT,
SOCKET_URING_OP_TX_TIMESTAMP,
+ SOCKET_URING_OP_GETSOCKNAME,
};
/*
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH liburing v2 2/4] test/bind-listen.t: Use ephemeral port
2025-11-20 22:13 [PATCH liburing v2 0/4] liburing: getsockname support Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 1/4] liburing: Introduce getsockname operation Gabriel Krisman Bertazi
@ 2025-11-20 22:13 ` Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 3/4] bind-listen.t: Add tests for getsockname Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 4/4] man/io_uring_prep_getsockname.3: Add man page Gabriel Krisman Bertazi
3 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-11-20 22:13 UTC (permalink / raw)
Cc: Gabriel Krisman Bertazi, io-uring, csander
This test fails if port 8000 is already in use by something else. Now
that we have getsockname with direct file descriptors, use an ephemeral
port instead.
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
test/bind-listen.c | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)
diff --git a/test/bind-listen.c b/test/bind-listen.c
index 6f80f177..7c229a17 100644
--- a/test/bind-listen.c
+++ b/test/bind-listen.c
@@ -22,7 +22,6 @@ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec)
}
static const char *magic = "Hello World!";
-static int use_port = 8000;
enum {
SRV_INDEX = 0,
@@ -74,18 +73,19 @@ static int connect_client(struct io_uring *ring, unsigned short peer_port)
return T_SETUP_OK;
}
-static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
+static int setup_srv(struct io_uring *ring)
{
+ struct sockaddr_in server_addr;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
struct __kernel_timespec ts;
int ret, val, submitted;
unsigned head;
- memset(server_addr, 0, sizeof(struct sockaddr_in));
- server_addr->sin_family = AF_INET;
- server_addr->sin_port = htons(use_port++);
- server_addr->sin_addr.s_addr = htons(INADDR_ANY);
+ memset(&server_addr, 0, sizeof(struct sockaddr_in));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = htons(0);
+ server_addr.sin_addr.s_addr = htons(INADDR_ANY);
sqe = io_uring_get_sqe(ring);
io_uring_prep_socket_direct(sqe, AF_INET, SOCK_STREAM, 0, SRV_INDEX, 0);
@@ -98,7 +98,7 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
sqe = io_uring_get_sqe(ring);
- io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) server_addr,
+ io_uring_prep_bind(sqe, SRV_INDEX, (struct sockaddr *) &server_addr,
sizeof(struct sockaddr_in));
sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
@@ -132,7 +132,8 @@ static int setup_srv(struct io_uring *ring, struct sockaddr_in *server_addr)
static int test_good_server(unsigned int ring_flags)
{
- struct sockaddr_in server_addr;
+ struct sockaddr_in saddr = {};
+ socklen_t saddr_len = sizeof(saddr);
struct __kernel_timespec ts;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
@@ -155,13 +156,25 @@ static int test_good_server(unsigned int ring_flags)
return T_SETUP_SKIP;
}
- ret = setup_srv(&ring, &server_addr);
+ ret = setup_srv(&ring);
if (ret != T_SETUP_OK) {
fprintf(stderr, "srv startup failed.\n");
return T_EXIT_FAIL;
}
- if (connect_client(&ring, server_addr.sin_port) != T_SETUP_OK) {
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_cmd_getsockname(sqe, SRV_INDEX, (struct sockaddr*)&saddr,
+ &saddr_len, 0);
+ sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK;
+ io_uring_submit(&ring);
+ io_uring_wait_cqe(&ring, &cqe);
+ if (cqe->res < 0) {
+ fprintf(stderr, "getsockname server failed. %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ if (connect_client(&ring, saddr.sin_port) != T_SETUP_OK) {
fprintf(stderr, "cli startup failed.\n");
return T_SETUP_SKIP;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH liburing v2 3/4] bind-listen.t: Add tests for getsockname
2025-11-20 22:13 [PATCH liburing v2 0/4] liburing: getsockname support Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 1/4] liburing: Introduce getsockname operation Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 2/4] test/bind-listen.t: Use ephemeral port Gabriel Krisman Bertazi
@ 2025-11-20 22:13 ` Gabriel Krisman Bertazi
2025-11-20 22:13 ` [PATCH liburing v2 4/4] man/io_uring_prep_getsockname.3: Add man page Gabriel Krisman Bertazi
3 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-11-20 22:13 UTC (permalink / raw)
Cc: Gabriel Krisman Bertazi, io-uring, csander
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
test/bind-listen.c | 104 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 2 deletions(-)
diff --git a/test/bind-listen.c b/test/bind-listen.c
index 7c229a17..22dd9a32 100644
--- a/test/bind-listen.c
+++ b/test/bind-listen.c
@@ -138,7 +138,7 @@ static int test_good_server(unsigned int ring_flags)
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
struct io_uring ring;
- int ret;
+ int ret, port;
int fds[3];
char buf[1024];
@@ -179,7 +179,7 @@ static int test_good_server(unsigned int ring_flags)
return T_SETUP_SKIP;
}
- /* Wait for a request */
+ /* Wait for a connection */
sqe = io_uring_get_sqe(&ring);
io_uring_prep_accept_direct(sqe, SRV_INDEX, NULL, NULL, 0, CONN_INDEX);
sqe->flags |= IOSQE_FIXED_FILE;
@@ -192,6 +192,30 @@ static int test_good_server(unsigned int ring_flags)
}
io_uring_cqe_seen(&ring, cqe);
+ /* Test that getsockname on the peer (getpeername) yields a
+ * sane result.
+ */
+ sqe = io_uring_get_sqe(&ring);
+ saddr_len = sizeof(saddr);
+ port = saddr.sin_port;
+ io_uring_prep_cmd_getsockname(sqe, CONN_INDEX, (struct sockaddr*)&saddr,
+ &saddr_len, 1);
+ sqe->flags |= IOSQE_FIXED_FILE;
+ io_uring_submit(&ring);
+ io_uring_wait_cqe(&ring, &cqe);
+ if (cqe->res < 0) {
+ fprintf(stderr, "getsockname client failed. %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ } else {
+ if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) ||
+ saddr.sin_port != port) {
+ fprintf(stderr, "getsockname peer got wrong address: %s:%d\n",
+ inet_ntoa(saddr.sin_addr), saddr.sin_port);
+ return T_EXIT_FAIL;
+ }
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
sqe = io_uring_get_sqe(&ring);
io_uring_prep_recv(sqe, CONN_INDEX, buf, sizeof(buf), 0);
sqe->flags |= IOSQE_FIXED_FILE;
@@ -368,6 +392,77 @@ fail:
return ret;
}
+static int test_bad_sockname(void)
+{
+ struct sockaddr_in saddr;
+ socklen_t saddr_len;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ int sock = -1, err;
+ int ret = T_EXIT_FAIL;
+
+ memset(&saddr, 0, sizeof(struct sockaddr_in));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = htons(8001);
+ saddr.sin_addr.s_addr = htons(INADDR_ANY);
+
+ err = t_create_ring(1, &ring, 0);
+ if (err < 0) {
+ fprintf(stderr, "queue_init: %d\n", err);
+ return T_SETUP_SKIP;
+ }
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket");
+ goto fail;
+ }
+
+ err = t_bind_ephemeral_port(sock, &saddr);
+ if (err) {
+ fprintf(stderr, "bind: %s\n", strerror(-err));
+ goto fail;
+ }
+
+ /* getsockname on a !socket fd. with getsockname(2), this would
+ * return -ENOTSOCK, but we can't do it in an io_uring_cmd.
+ */
+ sqe = io_uring_get_sqe(&ring);
+ saddr_len = sizeof(saddr);
+ io_uring_prep_cmd_getsockname(sqe, 1, (struct sockaddr*)&saddr, &saddr_len, 0);
+ err = io_uring_submit(&ring);
+ if (err < 0)
+ goto fail;
+ err = io_uring_wait_cqe(&ring, &cqe);
+ if (err)
+ goto fail;
+ if (cqe->res != -ENOTSUP)
+ goto fail;
+ io_uring_cqe_seen(&ring, cqe);
+
+ /* getsockname with weird parameters */
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_cmd_getsockname(sqe, sock, (struct sockaddr*)&saddr,
+ &saddr_len, 3);
+ err = io_uring_submit(&ring);
+ if (err < 0)
+ goto fail;
+ err = io_uring_wait_cqe(&ring, &cqe);
+ if (err)
+ goto fail;
+ if (cqe->res != -EINVAL)
+ goto fail;
+ io_uring_cqe_seen(&ring, cqe);
+
+ ret = T_EXIT_PASS;
+fail:
+ io_uring_queue_exit(&ring);
+ if (sock != -1)
+ close(sock);
+ return ret;
+}
+
int main(int argc, char *argv[])
{
struct io_uring_probe *probe;
@@ -417,5 +512,10 @@ int main(int argc, char *argv[])
return T_EXIT_FAIL;
}
+ ret = test_bad_sockname();
+ if (ret) {
+ fprintf(stderr, "bad sockname failed\n");
+ return T_EXIT_FAIL;
+ }
return T_EXIT_PASS;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH liburing v2 4/4] man/io_uring_prep_getsockname.3: Add man page
2025-11-20 22:13 [PATCH liburing v2 0/4] liburing: getsockname support Gabriel Krisman Bertazi
` (2 preceding siblings ...)
2025-11-20 22:13 ` [PATCH liburing v2 3/4] bind-listen.t: Add tests for getsockname Gabriel Krisman Bertazi
@ 2025-11-20 22:13 ` Gabriel Krisman Bertazi
3 siblings, 0 replies; 7+ messages in thread
From: Gabriel Krisman Bertazi @ 2025-11-20 22:13 UTC (permalink / raw)
Cc: Gabriel Krisman Bertazi, io-uring, csander
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
man/io_uring_prep_getsockname.3 | 76 +++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 man/io_uring_prep_getsockname.3
diff --git a/man/io_uring_prep_getsockname.3 b/man/io_uring_prep_getsockname.3
new file mode 100644
index 00000000..71e65f1d
--- /dev/null
+++ b/man/io_uring_prep_getsockname.3
@@ -0,0 +1,76 @@
+.\" Copyright (C) 2024 SUSE LLC.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+.TH io_uring_prep_getsockname 3 "Oct 23, 2025" "liburing-2.11" "liburing Manual"
+.SH NAME
+io_uring_prep_getsockname \- prepare a getsockname or getpeername request
+.SH SYNOPSIS
+.nf
+.B #include <sys/socket.h>
+.B #include <liburing.h>
+.PP
+.BI "void io_uring_prep_getsockname(struct io_uring_sqe *" sqe ","
+.BI " int " sockfd ","
+.BI " struct sockaddr *" sockaddr ","
+.BI " socklen_t *" sockaddr_len ","
+.BI " int " peer ");"
+.fi
+.SH DESCRIPTION
+The
+.BR io_uring_prep_getsockname (3)
+function prepares a getsockname/getpeername request.
+The submission queue entry
+.I sqe
+is setup to fetch the locally bound address or peer address of the socket
+file descriptor pointed by
+.IR sockfd.
+The parameter
+.IR sockaddr
+points to a region of size
+.IR sockaddr_len
+where the output is written.
+.IR sockaddr_len
+is modified by the kernel to indicate how many bytes were written.
+The output address is the locally bound address if
+.IR peer
+is set to 0
+or the peer address if
+.IR peer
+is set to 1.
+
+This function prepares an async
+.BR getsockname (2)
+or
+.BR getpeername (2)
+request. See those man pages for details.
+
+.SH RETURN VALUE
+None
+.SH ERRORS
+The CQE
+.I res
+field will contain the result of the operation. See the related man page for
+details on possible values. Note that where synchronous system calls will return
+.B -1
+on failure and set
+.I errno
+to the actual error value, io_uring never uses
+.IR errno .
+Instead it returns the negated
+.I errno
+directly in the CQE
+.I res
+field.
+.BR
+Differently from the equivalent system calls, if the user attempts to
+use this operation on a non-socket file descriptor, the CQE error result
+is
+.IR ENOTSUP
+instead of
+.IR ENOSOCK.
+.SH SEE ALSO
+.BR io_uring_get_sqe (3),
+.BR io_uring_submit (3),
+.BR io_uring_prep_getsockname (2)
+.BR io_uring_prep_getpeername (2)
--
2.51.0
^ permalink raw reply related [flat|nested] 7+ messages in thread