glib-aux: add nm_fd_next_datagram_size() helper

This commit is contained in:
Thomas Haller 2022-10-13 10:45:04 +02:00
parent 4b35168193
commit f7bc47a26f
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
2 changed files with 42 additions and 0 deletions

View file

@ -12,6 +12,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include "nm-str-buf.h"
#include "nm-shared-utils.h"
@ -496,6 +497,45 @@ nm_utils_fd_read(int fd, NMStrBuf *out_string)
/*****************************************************************************/
/* Taken from systemd's next_datagram_size_fd(). */
gssize
nm_fd_next_datagram_size(int fd)
{
gssize l;
int k;
/* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
* actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't
* do. This difference is actually of major importance as we need to be sure that the size returned here
* actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
* the wrong size. */
l = recv(fd, NULL, 0, MSG_PEEK | MSG_TRUNC);
if (l < 0) {
if (NM_IN_SET(errno, EOPNOTSUPP, EFAULT))
goto fallback;
return -errno;
}
if (l == 0)
goto fallback;
return l;
fallback:
k = 0;
/* Some sockets (AF_PACKET) do not support null-sized recv() with MSG_TRUNC set, let's fall back to FIONREAD
* for them. Checksums don't matter for raw sockets anyway, hence this should be fine. */
if (ioctl(fd, FIONREAD, &k) < 0)
return -errno;
return (gssize) k;
}
/*****************************************************************************/
typedef struct {
GSubprocess *subprocess;
GSource *timeout_source;

View file

@ -52,6 +52,8 @@ struct _NMStrBuf;
gssize nm_utils_fd_read(int fd, struct _NMStrBuf *out_string);
gssize nm_fd_next_datagram_size(int fd);
struct stat;
int nm_utils_file_stat(const char *filename, struct stat *out_st);