#include <arpa/inet.h>
#include <errno.h>
#include <linux/net_namespace.h>
+#include <linux/unix_diag.h>
#include <net/if.h>
#include <string.h>
+#include <sys/stat.h>
+
+#include "sd-netlink.h"
#include "alloc-util.h"
#include "errno-util.h"
#include "log.h"
#include "memory-util.h"
#include "namespace-util.h"
+#include "netlink-sock-diag.h"
#include "netlink-util.h"
#include "parse-util.h"
#include "socket-netlink.h"
return -ENXIO;
}
+
+int af_unix_get_qlen(int fd, uint32_t *ret) {
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ /* Returns the current queue length for an AF_UNIX listening socket */
+
+ struct stat st;
+ if (fstat(fd, &st) < 0)
+ return -errno;
+ if (!S_ISSOCK(st.st_mode))
+ return -ENOTSOCK;
+
+ _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL;
+ r = sd_sock_diag_socket_open(&nl);
+ if (r < 0)
+ return r;
+
+ uint64_t cookie = 0;
+ socklen_t cookie_len = sizeof(cookie);
+ if (getsockopt(fd, SOL_SOCKET, SO_COOKIE, &cookie, &cookie_len) < 0)
+ return -errno;
+
+ assert(cookie_len == sizeof(cookie));
+
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
+ r = sd_sock_diag_message_new_unix(nl, &message, st.st_ino, cookie, UDIAG_SHOW_RQLEN);
+ if (r < 0)
+ return r;
+
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
+ r = sd_netlink_call(nl, message, /* usec= */ 0, &reply);
+ if (r < 0)
+ return r;
+
+ for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0)
+ return r;
+
+ _cleanup_free_ void *data = NULL;
+ size_t size = 0;
+
+ r = sd_netlink_message_read_data(m, UNIX_DIAG_RQLEN, &size, &data);
+ if (r == -ENODATA)
+ continue;
+ if (r < 0)
+ return r;
+
+ assert(size == sizeof(struct unix_diag_rqlen));
+ const struct unix_diag_rqlen *udrql = ASSERT_PTR(data);
+
+ *ret = udrql->udiag_rqueue;
+ return 0;
+ }
+
+ return -ENODATA;
+}
const char* in_addr_full_to_string(struct in_addr_full *a);
int netns_get_nsid(int netnsfd, uint32_t *ret);
+
+int af_unix_get_qlen(int fd, uint32_t *ret);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <sys/eventfd.h>
+
#include "alloc-util.h"
+#include "fd-util.h"
#include "missing_network.h"
#include "socket-netlink.h"
#include "string-util.h"
log_info("Our NSID is %" PRIu32, u);
}
+TEST(af_unix_get_qlen) {
+ _cleanup_close_ int unix_fd = ASSERT_FD(socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0));
+ ASSERT_OK(socket_autobind(unix_fd, /* ret_name= */ NULL));
+ ASSERT_OK_ERRNO(listen(unix_fd, 123));
+
+ uint32_t q;
+ ASSERT_OK(af_unix_get_qlen(unix_fd, &q));
+ ASSERT_EQ(q, 0U);
+
+ _cleanup_close_ int conn_fd = ASSERT_FD(socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
+ union sockaddr_union sa;
+ socklen_t salen = sizeof(sa);
+ ASSERT_OK_ERRNO(getsockname(unix_fd, &sa.sa, &salen));
+ ASSERT_OK(connect(conn_fd, &sa.sa, salen));
+
+ ASSERT_OK(af_unix_get_qlen(unix_fd, &q));
+ ASSERT_EQ(q, 1U);
+
+ _cleanup_close_ int conn2_fd = ASSERT_FD(socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0));
+ ASSERT_OK(connect(conn2_fd, &sa.sa, salen));
+
+ ASSERT_OK(af_unix_get_qlen(unix_fd, &q));
+ ASSERT_EQ(q, 2U);
+
+ _cleanup_close_ int efd = ASSERT_FD(eventfd(0, EFD_CLOEXEC));
+ ASSERT_ERROR(af_unix_get_qlen(efd, &q), ENOTSOCK);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);