-
|
I am trying to set up a multishot recv() call on a UDP socket. However, while the single-shot version works, the multi-shot version always fails. I have a hunch it's with how I'm setting up the buffer ring, but I can't see the problem. All comparisons to similar code snippets make it seem like this is correct (I tried to boil it down as far as I could): #include <arpa/inet.h>
#include <liburing.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define BUF_BGID 0
#define N_BUFS 128
#define PAGESIZE 4096
#define BUFSIZE 8192
#define PORT 49000
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int sock_fd;
char* bufs; // All bufs go here
int i;
struct io_uring ring;
struct io_uring_buf_ring* br = NULL;
struct io_uring_sqe *sqe;
struct io_uring_cqe* cqe;
/* Set up socket */
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_aton("0.0.0.0", &addr.sin_addr);
/* Create UDP socket */
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr));
/* Create uring */
if (io_uring_queue_init(N_BUFS, &ring, 0) < 0) {
fprintf(stderr, "Could not init ring.\n");
return 1;
}
/* Create buffers and buffer ring */
if (posix_memalign((void**)&bufs, PAGESIZE, BUFSIZE * N_BUFS)) {
fprintf(stderr, "Could not allocate memory.\n");
return 1;
}
memset((void*)bufs, 0, BUFSIZE * N_BUFS);
int err = 0;
br = io_uring_setup_buf_ring(&ring, N_BUFS, BUF_BGID, 0, &err);
if (!br) {
fprintf(stderr, "Could not create buffer ring.\n");
}
io_uring_buf_ring_init(br);
for (i = 0; i < N_BUFS; i++) {
io_uring_buf_ring_add(br, bufs + i * BUFSIZE, BUFSIZE, i,
io_uring_buf_ring_mask(N_BUFS), i);
}
io_uring_buf_ring_advance(br, N_BUFS);
/* Set up recv SQE */
sqe = io_uring_get_sqe(&ring);
io_uring_sqe_set_flags(sqe, IOSQE_BUFFER_SELECT);
sqe->buf_group = BUF_BGID;
io_uring_prep_recv_multishot(sqe, sock_fd, NULL, 0, 0); /* This doesn't work! */
/*io_uring_prep_recv(sqe, sock_fd, bufs, BUFSIZE, 0);*/ /* This works! */
if (io_uring_submit(&ring) < 0) {
fprintf(stderr, "Failed to submit SQE.\n");
return 1;
}
if (io_uring_wait_cqe(&ring, &cqe) < 0) {
fprintf(stderr, "Could not get CQE.\n");
return 1;
}
if (cqe->res < 0) {
fprintf(stderr, "Bad CQE result: %s\n", strerror(-cqe->res));
return 1;
}
fprintf(stderr, "Buffer index: %d\n", cqe->flags >> IORING_CQE_BUFFER_SHIFT);
/* Now do handling and cleanup. */
return 0;
}This can be compiled and executed without modifications ( With the multishot version, the return value cqe->res of the read call is always -EINVAL, but the single-shot version works, making me think it's not a problem on the socket, but with the provided buffers. Any suggestions where I'm going wrong? Notes:
|
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
|
You probably want to upgrade your liburing, that's ancient. Not sure what the problem is, I ran it here with a newer kernel (should not matter) and with current liburing, and it works fine for me. General note - do io_uring_prep_foo() first, before fiddling with the SQE. The sqe prep may overwrite some bits you already set. Here's running a slightly modified version of yours which loops getting CQEs until the mshot terminates: |
Beta Was this translation helpful? Give feedback.
-
|
Here's what I ran, only change is looping for CQEs and doing the prep side in a more solid fashion. The latter may make a difference on your old liburing. |
Beta Was this translation helpful? Give feedback.
-
|
As another general note, the 6.8 kernel is some ubuntu special which isn't part of stable and doesn't receive updates from me. It may have bugs, I don't know, as they don't use the stable series of kernels that I support. Probably not your issue here (I suspect old liburing), but worth mentioning as a general caution that I do not support these types of kernels, as it's simply not possible for me to do. |
Beta Was this translation helpful? Give feedback.
Here's what I ran, only change is looping for CQEs and doing the prep side in a more solid fashion. The latter may make a difference on your old liburing.