mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2025-12-29 17:10:09 +01:00
util: add fd passing to the iobufs
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
56ca4b4ac7
commit
dabd48c028
2 changed files with 94 additions and 0 deletions
|
|
@ -33,6 +33,7 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "util-macros.h"
|
||||
#include "util-mem.h"
|
||||
|
||||
/**
|
||||
|
|
@ -194,6 +195,7 @@ struct iobuf {
|
|||
size_t sz;
|
||||
size_t len;
|
||||
char *data;
|
||||
int fds[32];
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -214,6 +216,11 @@ iobuf_new(size_t size)
|
|||
.data = data,
|
||||
};
|
||||
|
||||
int *fd;
|
||||
ARRAY_FOR_EACH(buf->fds, fd) {
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
@ -254,6 +261,19 @@ iobuf_data(struct iobuf *buf)
|
|||
return buf->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next available file descriptor in this buffer or -1.
|
||||
* The fd is removed from this buffer and belongs to the caller.
|
||||
*/
|
||||
static inline int
|
||||
iobuf_take_fd(struct iobuf *buf)
|
||||
{
|
||||
int fd = buf->fds[0];
|
||||
if (fd != -1)
|
||||
memmove(buf->fds, buf->fds + 1, ARRAY_LENGTH(buf->fds) - 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the data bytes from the buffer. The caller must free() the data.
|
||||
* The buffer state is the same as iobuf_new() after this call.
|
||||
|
|
@ -315,6 +335,48 @@ iobuf_append_from_fd(struct iobuf *buf, int fd)
|
|||
return nread == 0 ? rc : (int)nread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append all available data from the file descriptor to the pointer. The
|
||||
* file descriptor shold be in O_NONBLOCK or this call will block. If the
|
||||
* data exceeds the current buffer size it is resized automatically.
|
||||
*
|
||||
* Any file descriptors passed through the fd are placed
|
||||
*
|
||||
* @return The number of bytes read or a negative errno on failure. Zero
|
||||
* indicates EOF.
|
||||
*/
|
||||
static inline int
|
||||
iobuf_recv_from_fd(struct iobuf *buf, int fd)
|
||||
{
|
||||
char data[1024];
|
||||
size_t nread = 0;
|
||||
ssize_t rc;
|
||||
do {
|
||||
_cleanup_free_ int *fds = NULL;
|
||||
rc = xread_with_fds(fd, data, sizeof(data), &fds);
|
||||
if (rc == 0 || rc == -EAGAIN) {
|
||||
break;
|
||||
} else if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
iobuf_append(buf, data, rc);
|
||||
|
||||
if (fds) {
|
||||
int *fd = fds;
|
||||
for (size_t idx = 0; *fd != -1 && idx < ARRAY_LENGTH(buf->fds) - 1; idx++) {
|
||||
if (buf->fds[idx] == -1) {
|
||||
buf->fds[idx] = *fd;
|
||||
fd++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nread += rc;
|
||||
} while (rc == sizeof(data));
|
||||
|
||||
return nread == 0 ? rc : (int)nread;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the memory associated with this iobuf. Use iobuf_take_data()
|
||||
* prevent the data from being free()d.
|
||||
|
|
@ -327,6 +389,10 @@ iobuf_free(struct iobuf *buf)
|
|||
buf->sz = 0;
|
||||
buf->len = 0;
|
||||
buf->data = NULL;
|
||||
|
||||
int fd;
|
||||
while ((fd = iobuf_take_fd(buf)) != -1)
|
||||
xclose(fd);
|
||||
free(buf);
|
||||
}
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,34 @@ MUNIT_TEST(test_iobuf_append_fd)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_iobuf_recv_fd)
|
||||
{
|
||||
int fds[2];
|
||||
int rc = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, fds);
|
||||
munit_assert_int(rc, ==, 0);
|
||||
|
||||
_cleanup_close_ int left = fds[0];
|
||||
_cleanup_close_ int right = fds[1];
|
||||
_cleanup_fclose_ FILE *fp = tmpfile();
|
||||
|
||||
/* actual message data to be sent */
|
||||
char data[] = "some data\n";
|
||||
|
||||
/* Send the fd from left to right */
|
||||
int sendfds[2] = { fileno(fp), -1 };
|
||||
int sendrc = xsend_with_fd(left, data, sizeof(data), sendfds);
|
||||
munit_assert_int(sendrc, ==, sizeof(data));
|
||||
|
||||
_cleanup_iobuf_ struct iobuf *buf = iobuf_new(64);
|
||||
rc = iobuf_recv_from_fd(buf, right);
|
||||
munit_assert_int(rc, ==, sizeof(data));
|
||||
|
||||
_cleanup_close_ int fd = iobuf_take_fd(buf);
|
||||
munit_assert_int(fd, !=, -1);
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_pass_fd)
|
||||
{
|
||||
int fds[2];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue