# define IDN_FLAGS 0
#endif
+/* From the kernel's include/net/scm.h */
+#ifndef SCM_MAX_FD
+# define SCM_MAX_FD 253
+#endif
+
static const char* const socket_address_type_table[] = {
[SOCK_STREAM] = "Stream",
[SOCK_DGRAM] = "Datagram",
return false;
if (a->sockaddr.un.sun_path[0]) {
- if (!path_equal_or_files_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
+ if (!path_equal_or_inode_same(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, 0))
return false;
} else {
if (a->size != b->size)
int getpeercred(int fd, struct ucred *ucred) {
socklen_t n = sizeof(struct ucred);
struct ucred u;
- int r;
assert(fd >= 0);
assert(ucred);
- r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
- if (r < 0)
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n) < 0)
return -errno;
if (n != sizeof(struct ucred))
if (!s)
return -ENOMEM;
- if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n) >= 0)
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n) >= 0) {
+ s[n] = 0;
break;
+ }
if (errno != ERANGE)
return -errno;
return (int) n;
}
+ssize_t send_many_fds_iov_sa(
+ int transport_fd,
+ int *fds_array, size_t n_fds_array,
+ const struct iovec *iov, size_t iovlen,
+ const struct sockaddr *sa, socklen_t len,
+ int flags) {
+
+ _cleanup_free_ struct cmsghdr *cmsg = NULL;
+ struct msghdr mh = {
+ .msg_name = (struct sockaddr*) sa,
+ .msg_namelen = len,
+ .msg_iov = (struct iovec *)iov,
+ .msg_iovlen = iovlen,
+ };
+ ssize_t k;
+
+ assert(transport_fd >= 0);
+ assert(fds_array || n_fds_array == 0);
+
+ /* The kernel will reject sending more than SCM_MAX_FD FDs at once */
+ if (n_fds_array > SCM_MAX_FD)
+ return -E2BIG;
+
+ /* We need either an FD array or data to send. If there's nothing, return an error. */
+ if (n_fds_array == 0 && !iov)
+ return -EINVAL;
+
+ if (n_fds_array > 0) {
+ mh.msg_controllen = CMSG_SPACE(sizeof(int) * n_fds_array);
+ mh.msg_control = cmsg = malloc(mh.msg_controllen);
+ if (!cmsg)
+ return -ENOMEM;
+
+ *cmsg = (struct cmsghdr) {
+ .cmsg_len = CMSG_LEN(sizeof(int) * n_fds_array),
+ .cmsg_level = SOL_SOCKET,
+ .cmsg_type = SCM_RIGHTS,
+ };
+ memcpy(CMSG_DATA(cmsg), fds_array, sizeof(int) * n_fds_array);
+ }
+ k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags);
+ if (k < 0)
+ return (ssize_t) -errno;
+
+ return k;
+}
+
ssize_t send_one_fd_iov_sa(
int transport_fd,
int fd,
return (int) send_one_fd_iov_sa(transport_fd, fd, NULL, 0, sa, len, flags);
}
+ssize_t receive_many_fds_iov(
+ int transport_fd,
+ struct iovec *iov, size_t iovlen,
+ int **ret_fds_array, size_t *ret_n_fds_array,
+ int flags) {
+
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int) * SCM_MAX_FD)) control;
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ .msg_iov = iov,
+ .msg_iovlen = iovlen,
+ };
+ _cleanup_free_ int *fds_array = NULL;
+ size_t n_fds_array = 0;
+ struct cmsghdr *cmsg;
+ ssize_t k;
+
+ assert(transport_fd >= 0);
+ assert(ret_fds_array);
+ assert(ret_n_fds_array);
+
+ /*
+ * Receive many FDs via @transport_fd. We don't care for the transport-type. We retrieve all the FDs
+ * at once. This is best used in combination with send_many_fds().
+ */
+
+ k = recvmsg_safe(transport_fd, &mh, MSG_CMSG_CLOEXEC | flags);
+ if (k < 0)
+ return k;
+
+ CMSG_FOREACH(cmsg, &mh)
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ size_t n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+
+ fds_array = GREEDY_REALLOC(fds_array, n_fds_array + n);
+ if (!fds_array) {
+ cmsg_close_all(&mh);
+ return -ENOMEM;
+ }
+
+ memcpy(fds_array + n_fds_array, CMSG_TYPED_DATA(cmsg, int), sizeof(int) * n);
+ n_fds_array += n;
+ }
+
+ if (n_fds_array == 0) {
+ cmsg_close_all(&mh);
+
+ /* If didn't receive an FD or any data, return an error. */
+ if (k == 0)
+ return -EIO;
+ }
+
+ *ret_fds_array = TAKE_PTR(fds_array);
+ *ret_n_fds_array = n_fds_array;
+
+ return k;
+}
+
+int receive_many_fds(int transport_fd, int **ret_fds_array, size_t *ret_n_fds_array, int flags) {
+ ssize_t k;
+
+ k = receive_many_fds_iov(transport_fd, NULL, 0, ret_fds_array, ret_n_fds_array, flags);
+ if (k == 0)
+ return 0;
+
+ /* k must be negative, since receive_many_fds_iov() only returns a positive value if data was received
+ * through the iov. */
+ assert(k < 0);
+ return (int) k;
+}
+
ssize_t receive_one_fd_iov(
int transport_fd,
struct iovec *iov, size_t iovlen,
}
if (found)
- *ret_fd = *(int*) CMSG_DATA(found);
+ *ret_fd = *CMSG_TYPED_DATA(found, int);
else
*ret_fd = -EBADF;
return NULL;
}
+void* cmsg_find_and_copy_data(struct msghdr *mh, int level, int type, void *buf, size_t buf_len) {
+ struct cmsghdr *cmsg;
+
+ assert(mh);
+ assert(buf);
+ assert(buf_len > 0);
+
+ /* This is similar to cmsg_find_data(), but copy the found data to buf. This should be typically used
+ * when reading possibly unaligned data such as timestamp, as time_t is 64-bit and size_t is 32-bit on
+ * RISCV32. See issue #27241. */
+
+ cmsg = cmsg_find(mh, level, type, CMSG_LEN(buf_len));
+ if (!cmsg)
+ return NULL;
+
+ return memcpy_safe(buf, CMSG_DATA(cmsg), buf_len);
+}
+
int socket_ioctl_fd(void) {
int fd;
return n;
}
-int socket_get_family(int fd, int *ret) {
+int socket_get_family(int fd) {
int af;
socklen_t sl = sizeof(af);
}
int socket_set_recvpktinfo(int fd, int af, bool b) {
- int r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
int socket_set_unicast_if(int fd, int af, int ifi) {
be32_t ifindex_be = htobe32(ifi);
- int r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
}
int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) {
- int r;
-
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
int mtu, r;
if (af == AF_UNSPEC) {
- r = socket_get_family(fd, &af);
- if (r < 0)
- return r;
+ af = socket_get_family(fd);
+ if (af < 0)
+ return af;
}
switch (af) {
_cleanup_free_ char *n = NULL;
char *e, *cid_start;
unsigned port, cid;
- int r;
+ int type, r;
assert(ret_address);
assert(s);
- cid_start = startswith(s, "vsock:");
- if (!cid_start)
+ if ((cid_start = startswith(s, "vsock:")))
+ type = 0;
+ else if ((cid_start = startswith(s, "vsock-dgram:")))
+ type = SOCK_DGRAM;
+ else if ((cid_start = startswith(s, "vsock-seqpacket:")))
+ type = SOCK_SEQPACKET;
+ else if ((cid_start = startswith(s, "vsock-stream:")))
+ type = SOCK_STREAM;
+ else
return -EPROTO;
e = strchr(cid_start, ':');
.svm_family = AF_VSOCK,
.svm_port = port,
},
+ .type = type,
.size = sizeof(struct sockaddr_vm),
};