From 26d0689c61f20625a4d9baea7debf93d847b5bd5 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 3 Aug 2026 06:15:49 +0800 Subject: [PATCH 1/5] components/dfs: support unix socket nodes AF_UNIX pathname binding and descriptor passing require DFSv2 socket nodes and retained open file descriptions across fd tables. Add socket-node creation for tmpfs and devtmpfs, fd reference helpers, and socket F_SETFL forwarding. Impact: DFSv2 socket nodes and descriptor reference handling. Validation: git diff --cached --check. --- .../dfs/dfs_v2/filesystems/devfs/devtmpfs.c | 17 +++ .../dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c | 16 +++ .../dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h | 2 +- components/dfs/dfs_v2/include/dfs.h | 6 + components/dfs/dfs_v2/include/dfs_file.h | 1 + components/dfs/dfs_v2/src/dfs.c | 114 ++++++++++++++- components/dfs/dfs_v2/src/dfs_file.c | 133 +++++++++++++++++- 7 files changed, 283 insertions(+), 6 deletions(-) diff --git a/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c b/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c index 82ab422529ba..50882746cf76 100644 --- a/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c +++ b/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c @@ -27,6 +27,7 @@ #define TMPFS_TYPE_FILE 0x00 #define TMPFS_TYPE_DIR 0x01 #define TMPFS_TYPE_DYN_DEV 0x02 /* dynamic device */ +#define TMPFS_TYPE_SOCKET 0x03 struct devtmpfs_sb; @@ -325,6 +326,10 @@ static int devtmpfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_ { d->d_type = DT_DIR; } + if (n_file->type == TMPFS_TYPE_SOCKET) + { + d->d_type = DT_SOCK; + } d->d_reclen = (rt_uint16_t)sizeof(struct dirent); rt_strncpy(d->d_name, n_file->name, DIRENT_NAME_MAX); @@ -540,6 +545,14 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty vnode->mode &= ~S_IFMT; vnode->mode |= S_IFDIR; } + else if (type == FT_SOCKET || + (type == FT_REGULAR && S_ISSOCK(mode))) + { + d_file->type = TMPFS_TYPE_SOCKET; + vnode->type = FT_SOCKET; + vnode->mode &= ~S_IFMT; + vnode->mode |= S_IFSOCK; + } else { d_file->type = TMPFS_TYPE_FILE; @@ -585,6 +598,10 @@ static struct dfs_vnode *devtmpfs_lookup(struct dfs_dentry *dentry) { vnode->type = FT_DIRECTORY; } + else if (d_file->type == TMPFS_TYPE_SOCKET) + { + vnode->type = FT_SOCKET; + } else if (d_file->link) { vnode->type = FT_SYMLINK; diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c index 011e6e14c241..cc511415a3e2 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c +++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c @@ -535,6 +535,10 @@ static int dfs_tmpfs_getdents(struct dfs_file *file, { d->d_type = DT_DIR; } + if (n_file->type == TMPFS_TYPE_SOCKET) + { + d->d_type = DT_SOCK; + } d->d_namlen = RT_NAME_MAX; d->d_reclen = (rt_uint16_t)sizeof(struct dirent); rt_strncpy(d->d_name, n_file->name, TMPFS_NAME_MAX); @@ -664,6 +668,11 @@ static struct dfs_vnode *_dfs_tmpfs_lookup(struct dfs_dentry *dentry) vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); vnode->type = FT_DIRECTORY; } + else if (d_file->type == TMPFS_TYPE_SOCKET) + { + vnode->mode = S_IFSOCK | (S_IRWXU | S_IRWXG | S_IRWXO); + vnode->type = FT_SOCKET; + } else { vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO); @@ -750,6 +759,13 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); vnode->type = FT_DIRECTORY; } + else if (type == FT_SOCKET || + (type == FT_REGULAR && S_ISSOCK(mode))) + { + d_file->type = TMPFS_TYPE_SOCKET; + vnode->mode = S_IFSOCK | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + vnode->type = FT_SOCKET; + } else { d_file->type = TMPFS_TYPE_FILE; diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h index 8f822c6f7808..0807f06d19bc 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h +++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.h @@ -19,6 +19,7 @@ #define TMPFS_TYPE_FILE 0x00 #define TMPFS_TYPE_DIR 0x01 +#define TMPFS_TYPE_SOCKET 0x02 struct tmpfs_sb; @@ -46,4 +47,3 @@ struct tmpfs_sb int dfs_tmpfs_init(void); #endif - diff --git a/components/dfs/dfs_v2/include/dfs.h b/components/dfs/dfs_v2/include/dfs.h index 582ec428aca3..a5128b267882 100644 --- a/components/dfs/dfs_v2/include/dfs.h +++ b/components/dfs/dfs_v2/include/dfs.h @@ -134,6 +134,12 @@ int fdt_fd_associate_file(struct dfs_fdtable *fdt, int fd, struct dfs_file *file struct dfs_file *fd_get(int fd); void fd_release(int fd); +/* Reference helpers used when an open file description crosses fd tables. */ +int dfs_file_get_refs(const int *fds, size_t count, struct dfs_file **files); +/* Successful installation transfers the supplied references to the fd table. */ +int dfs_file_install_refs(struct dfs_file **files, size_t count, int *fds); +void dfs_file_put_ref(struct dfs_file *file); + void fd_init(struct dfs_file *fd); struct dfs_fdtable *dfs_fdtable_get(void); diff --git a/components/dfs/dfs_v2/include/dfs_file.h b/components/dfs/dfs_v2/include/dfs_file.h index 0e609e9eef43..280d0dbcb9de 100644 --- a/components/dfs/dfs_v2/include/dfs_file.h +++ b/components/dfs/dfs_v2/include/dfs_file.h @@ -149,6 +149,7 @@ void dfs_file_init(struct dfs_file *file); void dfs_file_deinit(struct dfs_file *file); int dfs_file_open(struct dfs_file *file, const char *path, int flags, mode_t mode); +int dfs_file_mknod(const char *path, int type, mode_t mode); int dfs_file_close(struct dfs_file *file); off_t dfs_file_get_fpos(struct dfs_file *file); diff --git a/components/dfs/dfs_v2/src/dfs.c b/components/dfs/dfs_v2/src/dfs.c index de1ea79edc59..92c688a8a070 100644 --- a/components/dfs/dfs_v2/src/dfs.c +++ b/components/dfs/dfs_v2/src/dfs.c @@ -349,23 +349,29 @@ int fdt_fd_new(struct dfs_fdtable *fdt) */ void fdt_fd_release(struct dfs_fdtable *fdt, int fd) { - if (fd < fdt->maxfd) + if (fdt == RT_NULL || dfs_file_lock() != RT_EOK) + { + return; + } + + if (fd >= 0 && fd < (int)fdt->maxfd) { struct dfs_file *file; file = fdt_get_file(fdt, fd); - if (file && file->ref_count == 1) + if (file != RT_NULL && file->ref_count == 1) { dfs_file_destroy(file); } - else + else if (file != RT_NULL) { rt_atomic_sub(&(file->ref_count), 1); } fdt->fds[fd] = RT_NULL; } + dfs_file_unlock(); } /** @@ -493,6 +499,106 @@ struct dfs_file *fd_get(int fd) return fdt_get_file(fdt, fd); } +int dfs_file_get_refs(const int *fds, size_t count, struct dfs_file **files) +{ + size_t index; + struct dfs_fdtable *fdt; + + if ((count != 0 && (fds == RT_NULL || files == RT_NULL)) || + dfs_file_lock() != RT_EOK) + { + return -EINVAL; + } + + fdt = dfs_fdtable_get(); + for (index = 0; index < count; index++) + { + files[index] = fdt_get_file(fdt, fds[index]); + if (files[index] == RT_NULL || + (files[index]->dentry == RT_NULL && files[index]->vnode == RT_NULL)) + { + dfs_file_unlock(); + return -EBADF; + } + } + + for (index = 0; index < count; index++) + { + rt_atomic_add(&files[index]->ref_count, 1); + } + dfs_file_unlock(); + return 0; +} + +int dfs_file_install_refs(struct dfs_file **files, size_t count, int *fds) +{ + int fd; + int startfd; + size_t index; + struct dfs_fdtable *fdt; + + if ((count != 0 && (files == RT_NULL || fds == RT_NULL)) || + dfs_file_lock() != RT_EOK) + { + return -EINVAL; + } + + fdt = dfs_fdtable_get(); + startfd = (fdt == &_fdtab) ? DFS_STDIO_OFFSET : 0; + for (index = 0; index < count; index++) + { + if (files[index] == RT_NULL || files[index]->magic != DFS_FD_MAGIC) + { + break; + } + + fd = _fdt_slot_alloc(fdt, startfd); + if (fd < 0) + { + break; + } + fdt->fds[fd] = files[index]; + fds[index] = fd; + } + + if (index != count) + { + while (index > 0) + { + index--; + fdt->fds[fds[index]] = RT_NULL; + } + dfs_file_unlock(); + return -EMFILE; + } + + dfs_file_unlock(); + return 0; +} + +void dfs_file_put_ref(struct dfs_file *file) +{ + if (file == RT_NULL || dfs_file_lock() != RT_EOK) + { + return; + } + + if (file->magic == DFS_FD_MAGIC && + rt_atomic_load(&file->ref_count) > 0 && + dfs_file_close(file) == 0) + { + if (rt_atomic_load(&file->ref_count) == 1) + { + dfs_file_destroy(file); + } + else + { + rt_atomic_sub(&file->ref_count, 1); + } + } + dfs_file_unlock(); +} + /** * This function will get the file descriptor table of current process. */ @@ -1238,4 +1344,4 @@ MSH_CMD_EXPORT(dfs_dlog, dfs dlog on|off); #endif #endif -/** @} */ \ No newline at end of file +/** @} */ diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c index 9c6e383e1b41..4c259f2662cf 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -823,6 +823,128 @@ int dfs_file_open(struct dfs_file *file, const char *path, int oflags, mode_t mo return ret; } +int dfs_file_mknod(const char *path, int type, mode_t mode) +{ + int ret = -EINVAL; + int create_type = type; + mode_t create_mode = mode; + char *fullpath; + struct dfs_mnt *mnt; + struct dfs_dentry *dentry; + + if (path == RT_NULL || type < FT_REGULAR || type > FT_NONLOCK) + { + return -EINVAL; + } + + fullpath = dfs_normalize_path(RT_NULL, path); + if (fullpath == RT_NULL) + { + return -ENOMEM; + } + + mnt = dfs_mnt_lookup(fullpath); + if (mnt == RT_NULL) + { + ret = -ENOENT; + goto __exit; + } + + { + char *realpath; + + realpath = dfs_file_realpath(&mnt, fullpath, DFS_REALPATH_EXCEPT_LAST); + if (realpath != RT_NULL) + { + rt_free(fullpath); + fullpath = realpath; + } + } + + if (strcmp(mnt->fullpath, fullpath) == 0) + { + ret = -EEXIST; + goto __exit; + } + + dentry = dfs_dentry_lookup(mnt, fullpath, 0); + if (dentry != RT_NULL) + { + dfs_dentry_unref(dentry); + ret = -EEXIST; + goto __exit; + } + + if (mnt->fs_ops->create_vnode == RT_NULL) + { + ret = -ENOSYS; + goto __exit; + } + + if (type == FT_SOCKET) + { + create_type = FT_REGULAR; + create_mode = (mode & ~S_IFMT) | S_IFSOCK; + } + + ret = dfs_file_lock(); + if (ret != RT_EOK) + { + goto __exit; + } + + dentry = dfs_dentry_create(mnt, fullpath); + if (dentry != RT_NULL) + { + struct dfs_vnode *vnode = RT_NULL; + + if (dfs_is_mounted(mnt) == 0) + { + vnode = mnt->fs_ops->create_vnode(dentry, create_type, + create_mode); + } + if (vnode != RT_NULL) + { + if (type == FT_SOCKET && !S_ISSOCK(vnode->mode)) + { + if (mnt->fs_ops->unlink != RT_NULL) + { + dentry->vnode = vnode; + (void)mnt->fs_ops->unlink(dentry); + dentry->vnode = RT_NULL; + } + dfs_vnode_unref(vnode); + ret = -EOPNOTSUPP; + } + else + { + vnode->type = type; + dentry->vnode = vnode; + dfs_dentry_insert(dentry); + ret = RT_EOK; + } + } + else + { + ret = -ENOENT; + } + } + else + { + ret = -ENOMEM; + } + dfs_file_unlock(); + + if (dentry != RT_NULL) + { + dfs_dentry_unref(dentry); + } + +__exit: + rt_free(fullpath); + return ret; +} + /** * @brief Close a file and release associated resources * @@ -1588,6 +1710,15 @@ int dfs_file_fcntl(int fd, int cmd, unsigned long arg) O_APPEND | O_NONBLOCK; flags &= mask; + if (file->vnode->type == FT_SOCKET && file->fops != RT_NULL && + file->fops->ioctl != RT_NULL) + { + ret = file->fops->ioctl(file, F_SETFL, (void *)(rt_base_t)flags); + if (ret < 0) + { + break; + } + } file->flags &= ~mask; file->flags |= flags; break; @@ -3029,4 +3160,4 @@ void copy(const char *src, const char *dst) } FINSH_FUNCTION_EXPORT(copy, copy file or dir) -#endif \ No newline at end of file +#endif From 93d92353105a4a1444f850291c181a411f112311 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 3 Aug 2026 06:16:04 +0800 Subject: [PATCH 2/5] components/net/sal: support local protocol providers Local IPC protocol families do not have a backing network device. Store the selected provider in each SAL socket and add a local provider registry while preserving netdev checks for Internet sockets. Handle DFSv2 close semantics, socketpair flags, and MSG_CTRUNC for AF_UNIX integration. Impact: SAL protocol dispatch for all socket families. Validation: git diff --cached --check. --- components/net/sal/include/sal_low_lvl.h | 5 + components/net/sal/include/sal_socket.h | 3 + components/net/sal/socket/net_sockets.c | 20 ++ components/net/sal/src/sal_socket.c | 226 ++++++++++++++++------- 4 files changed, 185 insertions(+), 69 deletions(-) diff --git a/components/net/sal/include/sal_low_lvl.h b/components/net/sal/include/sal_low_lvl.h index c19c10ffc146..759bad730f04 100644 --- a/components/net/sal/include/sal_low_lvl.h +++ b/components/net/sal/include/sal_low_lvl.h @@ -48,6 +48,7 @@ typedef uint32_t socklen_t; struct sockaddr; struct msghdr; struct addrinfo; +struct sal_proto_family; struct sal_socket { uint32_t magic; /* SAL socket magic word */ @@ -58,6 +59,7 @@ struct sal_socket int protocol; struct netdev *netdev; /* SAL network interface device */ + const struct sal_proto_family *protocol_family; /* selected protocol provider */ void *user_data; /* user-specific data */ #ifdef SAL_USING_TLS @@ -109,6 +111,9 @@ struct sal_proto_family /* SAL(Socket Abstraction Layer) initialize */ int sal_init(void); +/* Register and find protocol providers which do not require a netdev. */ +int sal_proto_family_register(const struct sal_proto_family *pf); +const struct sal_proto_family *sal_proto_family_find(int family); /* Get SAL socket object by socket descriptor */ struct sal_socket *sal_get_socket(int sock); diff --git a/components/net/sal/include/sal_socket.h b/components/net/sal/include/sal_socket.h index 527f3fe440b1..dc0cef0ebf49 100644 --- a/components/net/sal/include/sal_socket.h +++ b/components/net/sal/include/sal_socket.h @@ -119,6 +119,9 @@ typedef uint16_t in_port_t; #define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ #define MSG_MORE 0x10 /* Sender will send more */ +/* Output-only flags returned through struct msghdr. */ +#define MSG_CTRUNC 0x08 /* Control data was discarded due to truncation */ + #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_CONFIRM 0x0800 /* Confirm path validity */ diff --git a/components/net/sal/socket/net_sockets.c b/components/net/sal/socket/net_sockets.c index 615bb0ed033b..50c20b908afe 100644 --- a/components/net/sal/socket/net_sockets.c +++ b/components/net/sal/socket/net_sockets.c @@ -725,7 +725,11 @@ int closesocket(int s) return -1; } +#ifdef RT_USING_DFS_V2 + if (dfs_file_close(d) == 0) +#else if (sal_closesocket(socket) == 0) +#endif { error = 0; } @@ -771,8 +775,19 @@ RTM_EXPORT(closesocket); int socketpair(int domain, int type, int protocol, int *fds) { rt_err_t ret = 0; + int nonblocking = 0; int sock_fds[2]; + if ((type & SOCK_CLOEXEC) != 0) + { + type &= ~SOCK_CLOEXEC; + } + if ((type & SOCK_NONBLOCK) != 0) + { + nonblocking = 1; + type &= ~SOCK_NONBLOCK; + } + fds[0] = socket(domain, type, protocol); if (fds[0] < 0) { @@ -799,6 +814,11 @@ int socketpair(int domain, int type, int protocol, int *fds) closesocket(fds[0]); closesocket(fds[1]); } + else if (nonblocking) + { + (void)fcntl(fds[0], F_SETFL, O_NONBLOCK); + (void)fcntl(fds[1], F_SETFL, O_NONBLOCK); + } return ret; } diff --git a/components/net/sal/src/sal_socket.c b/components/net/sal/src/sal_socket.c index fa9eb9cc7467..4c9d876254e7 100644 --- a/components/net/sal/src/sal_socket.c +++ b/components/net/sal/src/sal_socket.c @@ -51,7 +51,7 @@ ((type) == SOCK_DGRAM && ((protocol) == 0 || (protocol) == IPPROTO_UDP)) || \ ((type) == SOCK_RAW && ((protocol) == IPPROTO_RAW)) \ )) || \ - ((domain) == AF_UNIX && (type) == SOCK_STREAM && (protocol) == 0) || \ + ((domain) == AF_UNIX && ((type) == SOCK_STREAM || (type) == SOCK_DGRAM) && (protocol) == 0) || \ ((domain) == AF_NETLINK && (type) == SOCK_RAW && (protocol) == 0) \ ) @@ -89,6 +89,7 @@ static struct sal_socket_table socket_table; static struct rt_mutex sal_core_lock; static rt_bool_t init_ok = RT_FALSE; static struct sal_netdev_res_table sal_dev_res_tbl[SAL_SOCKETS_NUM]; +static const struct sal_proto_family *local_proto_families[SAL_PROTO_FAMILIES_NUM]; #define IS_SOCKET_PROTO_TLS(sock) (((sock)->protocol == PROTOCOL_TLS) || \ ((sock)->protocol == PROTOCOL_DTLS)) @@ -113,23 +114,42 @@ static struct sal_netdev_res_table sal_dev_res_tbl[SAL_SOCKETS_NUM]; } \ } while (0) -#define SAL_NETDEV_IS_UP(netdev) \ - do \ - { \ - if (!netdev_is_up(netdev)) \ - { \ - return -1; \ - } \ +#define SAL_NETDEV_IS_UP(netdev) \ + do \ + { \ + if ((netdev) && !netdev_is_up(netdev)) \ + { \ + return -1; \ + } \ } while (0) -#define SAL_NETDEV_SOCKETOPS_VALID(netdev, pf, ops) \ - do \ - { \ - (pf) = (struct sal_proto_family *)netdev->sal_user_data; \ - if ((pf)->skt_ops->ops == RT_NULL) \ - { \ - return -1; \ - } \ +#define SAL_SOCKETOPS_VALID(sock, pf, ops) \ + do \ + { \ + (pf) = (sock)->protocol_family; \ + if ((pf) == RT_NULL || (pf)->skt_ops == RT_NULL || \ + (pf)->skt_ops->ops == RT_NULL) \ + { \ + rt_set_errno(EOPNOTSUPP); \ + return -1; \ + } \ + } while (0) + +#define SAL_NETDEV_SOCKETOPS_VALID(netdev, pf, ops) \ + do \ + { \ + if ((netdev) == RT_NULL) \ + { \ + rt_set_errno(EOPNOTSUPP); \ + return -1; \ + } \ + (pf) = (struct sal_proto_family *)(netdev)->sal_user_data; \ + if ((pf) == RT_NULL || (pf)->skt_ops == RT_NULL || \ + (pf)->skt_ops->ops == RT_NULL) \ + { \ + rt_set_errno(EOPNOTSUPP); \ + return -1; \ + } \ } while (0) #define SAL_NETDEV_NETDBOPS_VALID(netdev, pf, ops) \ @@ -181,6 +201,58 @@ int sal_init(void) } INIT_COMPONENT_EXPORT(sal_init); +int sal_proto_family_register(const struct sal_proto_family *pf) +{ + int index; + + if (pf == RT_NULL || pf->skt_ops == RT_NULL) + { + return -EINVAL; + } + + for (index = 0; index < SAL_PROTO_FAMILIES_NUM; index++) + { + if (local_proto_families[index] == pf) + { + return RT_EOK; + } + if (local_proto_families[index] != RT_NULL && + (local_proto_families[index]->family == pf->family || + local_proto_families[index]->sec_family == pf->family)) + { + return -EEXIST; + } + } + + for (index = 0; index < SAL_PROTO_FAMILIES_NUM; index++) + { + if (local_proto_families[index] == RT_NULL) + { + local_proto_families[index] = pf; + return RT_EOK; + } + } + + return -ENOMEM; +} + +const struct sal_proto_family *sal_proto_family_find(int family) +{ + int index; + + for (index = 0; index < SAL_PROTO_FAMILIES_NUM; index++) + { + const struct sal_proto_family *pf = local_proto_families[index]; + + if (pf != RT_NULL && (pf->family == family || pf->sec_family == family)) + { + return pf; + } + } + + return RT_NULL; +} + #ifdef SAL_INTERNET_CHECK /* check SAL network interface device internet status */ static void check_netdev_internet_up_work(struct rt_work *work, void *work_data) @@ -456,7 +528,7 @@ int sal_netdev_cleanup(struct netdev *netdev) static int socket_init(int family, int type, int protocol, struct sal_socket **res) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; struct netdev *netdv_def = netdev_default; struct netdev *netdev = RT_NULL; rt_bool_t flag = RT_FALSE; @@ -495,6 +567,14 @@ static int socket_init(int family, int type, int protocol, struct sal_socket **r return -4; } + pf = sal_proto_family_find(family); + if (pf != RT_NULL) + { + sock->protocol_family = pf; + sock->netdev = RT_NULL; + return 0; + } + /* Existing netdev selection logic */ if (netdv_def && netdev_is_up(netdv_def)) { @@ -503,6 +583,7 @@ static int socket_init(int family, int type, int protocol, struct sal_socket **r if (pf != RT_NULL && pf->skt_ops && (pf->family == family || pf->sec_family == family)) { sock->netdev = netdv_def; + sock->protocol_family = pf; flag = RT_TRUE; } } @@ -518,6 +599,11 @@ static int socket_init(int family, int type, int protocol, struct sal_socket **r } sock->netdev = netdev; + sock->protocol_family = (const struct sal_proto_family *)netdev->sal_user_data; + if (sock->protocol_family == RT_NULL || sock->protocol_family->skt_ops == RT_NULL) + { + return -3; + } } LOG_D("Socket init success: domain=%d, type=%d, protocol=%d, netdev=%s", @@ -607,6 +693,7 @@ static int socket_new(void) sock->socket = idx + SAL_SOCKET_OFFSET; sock->magic = SAL_SOCKET_MAGIC; sock->netdev = RT_NULL; + sock->protocol_family = RT_NULL; sock->user_data = RT_NULL; #ifdef SAL_USING_TLS sock->user_data_tls = RT_NULL; @@ -633,6 +720,7 @@ static void socket_delete(int socket) RT_ASSERT(sock != RT_NULL); sock->magic = 0; sock->netdev = RT_NULL; + sock->protocol_family = RT_NULL; socket_free(st, idx); sal_unlock(); } @@ -641,7 +729,7 @@ int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen) { int new_socket; struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); @@ -650,12 +738,11 @@ int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen) SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket operations */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, accept); + SAL_SOCKETOPS_VALID(sock, pf, accept); new_socket = pf->skt_ops->accept((int)(size_t)sock->user_data, addr, addrlen); if (new_socket != -1) { - int retval; int new_sal_socket; struct sal_socket *new_sock; @@ -668,19 +755,11 @@ int sal_accept(int socket, struct sockaddr *addr, socklen_t *addrlen) return -1; } - retval = socket_init(sock->domain, sock->type, sock->protocol, &new_sock); - if (retval < 0) - { - pf->skt_ops->closesocket(new_socket); - rt_memset(new_sock, 0x00, sizeof(struct sal_socket)); - /* socket init failed, delete socket */ - socket_delete(new_sal_socket); - LOG_E("New socket registered failed, return error %d.", retval); - return -1; - } - - /* new socket create by accept should have the same netdev with server*/ + new_sock->domain = sock->domain; + new_sock->type = sock->type; + new_sock->protocol = sock->protocol; new_sock->netdev = sock->netdev; + new_sock->protocol_family = sock->protocol_family; /* socket structure user_data used to store the acquired new socket */ new_sock->user_data = (void *)(size_t)new_socket; @@ -707,7 +786,7 @@ static void sal_sockaddr_to_ipaddr(const struct sockaddr *name, ip_addr_t *local int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; ip_addr_t input_ipaddr; RT_ASSERT(name); @@ -751,19 +830,20 @@ int sal_bind(int socket, const struct sockaddr *name, socklen_t namelen) return -1; } sock->netdev = new_netdev; + sock->protocol_family = input_pf; sock->user_data = (void *)(size_t)new_socket; } } } /* check and get protocol families by the network interface device */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, bind); + SAL_SOCKETOPS_VALID(sock, pf, bind); return pf->skt_ops->bind((int)(size_t)sock->user_data, name, namelen); } int sal_shutdown(int socket, int how) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; int error = 0; /* get the socket object by socket descriptor */ @@ -771,7 +851,7 @@ int sal_shutdown(int socket, int how) /* shutdown operation not need to check network interface status */ /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, shutdown); + SAL_SOCKETOPS_VALID(sock, pf, shutdown); if (pf->skt_ops->shutdown((int)(size_t)sock->user_data, how) == 0) { @@ -798,13 +878,13 @@ int sal_shutdown(int socket, int how) int sal_getpeername(int socket, struct sockaddr *name, socklen_t *namelen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getpeername); + SAL_SOCKETOPS_VALID(sock, pf, getpeername); return pf->skt_ops->getpeername((int)(size_t)sock->user_data, name, namelen); } @@ -812,13 +892,13 @@ int sal_getpeername(int socket, struct sockaddr *name, socklen_t *namelen) int sal_getsockname(int socket, struct sockaddr *name, socklen_t *namelen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getsockname); + SAL_SOCKETOPS_VALID(sock, pf, getsockname); return pf->skt_ops->getsockname((int)(size_t)sock->user_data, name, namelen); } @@ -826,13 +906,13 @@ int sal_getsockname(int socket, struct sockaddr *name, socklen_t *namelen) int sal_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, getsockopt); + SAL_SOCKETOPS_VALID(sock, pf, getsockopt); return pf->skt_ops->getsockopt((int)(size_t)sock->user_data, level, optname, optval, optlen); } @@ -840,13 +920,13 @@ int sal_getsockopt(int socket, int level, int optname, void *optval, socklen_t * int sal_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, setsockopt); + SAL_SOCKETOPS_VALID(sock, pf, setsockopt); #ifdef SAL_USING_TLS if (level == SOL_TLS) @@ -887,7 +967,7 @@ int sal_setsockopt(int socket, int level, int optname, const void *optval, sockl int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; int ret; /* get the socket object by socket descriptor */ @@ -896,7 +976,7 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, connect); + SAL_SOCKETOPS_VALID(sock, pf, connect); ret = pf->skt_ops->connect((int)(size_t)sock->user_data, name, namelen); #ifdef SAL_USING_TLS @@ -917,13 +997,13 @@ int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen) int sal_listen(int socket, int backlog) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, listen); + SAL_SOCKETOPS_VALID(sock, pf, listen); return pf->skt_ops->listen((int)(size_t)sock->user_data, backlog); } @@ -931,7 +1011,7 @@ int sal_listen(int socket, int backlog) int sal_sendmsg(int socket, const struct msghdr *message, int flags) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); @@ -939,7 +1019,7 @@ int sal_sendmsg(int socket, const struct msghdr *message, int flags) /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, sendmsg); + SAL_SOCKETOPS_VALID(sock, pf, sendmsg); #ifdef SAL_USING_TLS if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, send)) @@ -964,7 +1044,7 @@ int sal_sendmsg(int socket, const struct msghdr *message, int flags) int sal_recvmsg(int socket, struct msghdr *message, int flags) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); @@ -972,7 +1052,7 @@ int sal_recvmsg(int socket, struct msghdr *message, int flags) /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, recvmsg); + SAL_SOCKETOPS_VALID(sock, pf, recvmsg); #ifdef SAL_USING_TLS if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, recv)) @@ -998,7 +1078,7 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); @@ -1006,7 +1086,7 @@ int sal_recvfrom(int socket, void *mem, size_t len, int flags, /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, recvfrom); + SAL_SOCKETOPS_VALID(sock, pf, recvfrom); #ifdef SAL_USING_TLS if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, recv)) @@ -1032,7 +1112,7 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); @@ -1040,7 +1120,7 @@ int sal_sendto(int socket, const void *dataptr, size_t size, int flags, /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, sendto); + SAL_SOCKETOPS_VALID(sock, pf, sendto); #ifdef SAL_USING_TLS if (SAL_SOCKOPS_PROTO_TLS_VALID(sock, send)) @@ -1067,7 +1147,7 @@ int sal_socket(int domain, int type, int protocol) int retval; int socket, proto_socket; struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; /* allocate a new socket and registered socket options */ socket = socket_new(); @@ -1094,7 +1174,7 @@ int sal_socket(int domain, int type, int protocol) } /* valid the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, socket); + SAL_SOCKETOPS_VALID(sock, pf, socket); proto_socket = pf->skt_ops->socket(domain, type, protocol); if (proto_socket >= 0) @@ -1122,7 +1202,7 @@ int sal_socketpair(int domain, int type, int protocol, int *fds) int unix_fd[2]; struct sal_socket *socka; struct sal_socket *sockb; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; if (domain == AF_UNIX) { @@ -1131,15 +1211,17 @@ int sal_socketpair(int domain, int type, int protocol, int *fds) SAL_SOCKET_OBJ_GET(sockb, fds[1]); /* valid the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(socka->netdev, pf, socket); + if (socka->protocol_family != sockb->protocol_family) + { + rt_set_errno(EINVAL); + return -1; + } + SAL_SOCKETOPS_VALID(socka, pf, socketpair); unix_fd[0] = (int)(size_t)socka->user_data; unix_fd[1] = (int)(size_t)sockb->user_data; - if (pf->skt_ops->socketpair) - { - return pf->skt_ops->socketpair(domain, type, protocol, unix_fd); - } + return pf->skt_ops->socketpair(domain, type, protocol, unix_fd); } rt_set_errno(EINVAL); @@ -1150,7 +1232,7 @@ int sal_socketpair(int domain, int type, int protocol, int *fds) int sal_closesocket(int socket) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; int error = 0; /* get the socket object by socket descriptor */ @@ -1158,7 +1240,7 @@ int sal_closesocket(int socket) /* clsoesocket operation not need to vaild network interface status */ /* valid the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, closesocket); + SAL_SOCKETOPS_VALID(sock, pf, closesocket); if (pf->skt_ops->closesocket((int)(size_t)sock->user_data) == 0) { @@ -1196,13 +1278,19 @@ int sal_ioctlsocket(int socket, long cmd, void *arg) struct netdev *netdev = RT_NULL; struct netdev *cur_netdev_list = netdev_list; struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; struct sockaddr_in *addr_in = RT_NULL; struct sockaddr *addr = RT_NULL; ip_addr_t input_ipaddr; /* get the socket object by socket descriptor */ SAL_SOCKET_OBJ_GET(sock, socket); + if (sock->netdev == RT_NULL) + { + SAL_SOCKETOPS_VALID(sock, pf, ioctlsocket); + return pf->skt_ops->ioctlsocket((int)(size_t)sock->user_data, cmd, arg); + } + struct sal_ifreq *ifr = (struct sal_ifreq *)arg; if (ifr != RT_NULL) @@ -1528,7 +1616,7 @@ int sal_ioctlsocket(int socket, long cmd, void *arg) int sal_poll(struct dfs_file *file, struct rt_pollreq *req) { struct sal_socket *sock; - struct sal_proto_family *pf; + const struct sal_proto_family *pf; int socket = (int)(size_t)file->vnode->data; /* get the socket object by socket descriptor */ @@ -1537,7 +1625,7 @@ int sal_poll(struct dfs_file *file, struct rt_pollreq *req) /* check the network interface is up status */ SAL_NETDEV_IS_UP(sock->netdev); /* check the network interface socket opreation */ - SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, poll); + SAL_SOCKETOPS_VALID(sock, pf, poll); return pf->skt_ops->poll(file, req); } From e748e9930b4a579390c706a9621a8ad9e768aa12 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 3 Aug 2026 06:16:23 +0800 Subject: [PATCH 3/5] components/lwp: support unix socket messages Musl AF_UNIX addresses and ancillary data require explicit ABI and user-memory conversion at the LWP syscall boundary. Add the musl msghdr layout, bounded address and message copying, control-message level conversion, and MSG_CTRUNC translation. Correct receive buffer allocation and copy lengths while handling messages. Impact: LWP socket syscalls when SAL is enabled. Validation: git diff --cached --check. --- components/lwp/lwp_sys_socket.h | 27 ++ components/lwp/lwp_syscall.c | 507 ++++++++++++++++++++++---------- 2 files changed, 381 insertions(+), 153 deletions(-) diff --git a/components/lwp/lwp_sys_socket.h b/components/lwp/lwp_sys_socket.h index 7f1fc457da0f..6a690e3cc9cb 100644 --- a/components/lwp/lwp_sys_socket.h +++ b/components/lwp/lwp_sys_socket.h @@ -108,6 +108,33 @@ struct musl_sockaddr char sa_data[14]; }; +struct musl_msghdr +{ + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; +#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + int padding1; +#endif + int msg_iovlen; +#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + int padding1; +#endif + void *msg_control; +#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + int padding2; +#endif + socklen_t msg_controllen; +#if defined(ARCH_CPU_64BIT) && defined(__BYTE_ORDER__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + int padding2; +#endif + int msg_flags; +}; + struct musl_ifmap { unsigned long int mem_start; unsigned long int mem_end; diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index f3538c2cb4f7..8e8f8f072c30 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -299,7 +299,7 @@ static void convert_sockopt(int *level, int *optname) } #endif /* RT_USING_SAL */ -#if defined(RT_USING_LWIP) || defined(SAL_USING_UNET) +#if defined(RT_USING_LWIP) || defined(SAL_USING_UNET) || defined(RT_USING_SAL) static void sockaddr_tolwip(const struct musl_sockaddr *std, struct sockaddr *lwip) { if (std && lwip) @@ -5065,6 +5065,74 @@ rt_ssize_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, r #ifdef RT_USING_SAL /* network interfaces */ +union lwp_sockaddr_buffer +{ + struct sockaddr address; + struct sockaddr_un unix_address; +}; + +static int lwp_sockaddr_from_user(union lwp_sockaddr_buffer *kernel_address, + const struct musl_sockaddr *user_address, + socklen_t length) +{ + uint16_t family; + struct musl_sockaddr musl_address; + + if (user_address == RT_NULL || length < sizeof(family) || + length > sizeof(*kernel_address)) + { + return -EINVAL; + } + if (!lwp_user_accessable((void *)user_address, length)) + { + return -EFAULT; + } + + rt_memset(kernel_address, 0, sizeof(*kernel_address)); + lwp_get_from_user(&family, (void *)user_address, sizeof(family)); + if (family == AF_UNIX || family == AF_NETLINK) + { + lwp_get_from_user(kernel_address, (void *)user_address, length); + } + else + { + if (length > sizeof(musl_address)) + { + return -EINVAL; + } + rt_memset(&musl_address, 0, sizeof(musl_address)); + lwp_get_from_user(&musl_address, (void *)user_address, length); + sockaddr_tolwip(&musl_address, &kernel_address->address); + } + return 0; +} + +static socklen_t lwp_sockaddr_to_user( + struct musl_sockaddr *user_address, socklen_t user_length, + const union lwp_sockaddr_buffer *kernel_address, + socklen_t kernel_length) +{ + socklen_t actual_length; + socklen_t copy_length; + struct musl_sockaddr musl_address; + + if (kernel_address->unix_address.sa_family == AF_UNIX) + { + actual_length = kernel_length; + copy_length = user_length < actual_length ? user_length : actual_length; + lwp_put_to_user(user_address, (void *)kernel_address, copy_length); + } + else + { + rt_memset(&musl_address, 0, sizeof(musl_address)); + sockaddr_tomusl(&kernel_address->address, &musl_address); + actual_length = sizeof(musl_address); + copy_length = user_length < actual_length ? user_length : actual_length; + lwp_put_to_user(user_address, &musl_address, copy_length); + } + return actual_length; +} + /** * @brief Accepts a connection on a socket. * @@ -5102,8 +5170,7 @@ rt_ssize_t sys_device_write(rt_device_t dev, rt_off_t pos, const void *buffer, r sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen) { int ret = -1; - struct sockaddr ksa; - struct musl_sockaddr kmusladdr; + union lwp_sockaddr_buffer kernel_address; socklen_t uaddrlen; socklen_t kaddrlen; @@ -5125,19 +5192,16 @@ sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen) } } - kaddrlen = sizeof(struct sockaddr); - ret = accept(socket, &ksa, &kaddrlen); + rt_memset(&kernel_address, 0, sizeof(kernel_address)); + kaddrlen = sizeof(kernel_address); + ret = accept(socket, &kernel_address.address, &kaddrlen); if (ret >= 0) { if (addr) { - sockaddr_tomusl(&ksa, &kmusladdr); - if (uaddrlen > sizeof(struct musl_sockaddr)) - { - uaddrlen = sizeof(struct musl_sockaddr); - } - lwp_put_to_user(addr, &kmusladdr, uaddrlen); - lwp_put_to_user(addrlen, &uaddrlen, sizeof(socklen_t)); + kaddrlen = lwp_sockaddr_to_user(addr, uaddrlen, + &kernel_address, kaddrlen); + lwp_put_to_user(addrlen, &kaddrlen, sizeof(socklen_t)); } } return ret; @@ -5171,34 +5235,15 @@ sysret_t sys_accept(int socket, struct musl_sockaddr *addr, socklen_t *addrlen) */ sysret_t sys_bind(int socket, const struct musl_sockaddr *name, socklen_t namelen) { - rt_err_t ret = 0; - struct sockaddr sa; - struct sockaddr_un un_addr; - struct musl_sockaddr kname; - rt_uint16_t family = 0; - - if (!lwp_user_accessable((void *)name, namelen)) - { - return -EFAULT; - } + int ret; + union lwp_sockaddr_buffer kernel_address; - lwp_get_from_user(&family, (void *)name, 2); - if (family == AF_UNIX) - { - lwp_get_from_user(&un_addr, (void *)name, sizeof(struct sockaddr_un)); - ret = bind(socket, (struct sockaddr *)&un_addr, namelen); - } - else if (family == AF_NETLINK) - { - lwp_get_from_user(&sa, (void *)name, namelen); - ret = bind(socket, &sa, namelen); - } - else + ret = lwp_sockaddr_from_user(&kernel_address, name, namelen); + if (ret < 0) { - lwp_get_from_user(&kname, (void *)name, namelen); - sockaddr_tolwip(&kname, &sa); - ret = bind(socket, &sa, namelen); + return ret; } + ret = bind(socket, &kernel_address.address, namelen); return (ret < 0 ? GET_ERRNO() : ret); } @@ -5263,8 +5308,7 @@ sysret_t sys_shutdown(int socket, int how) sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *namelen) { int ret = -1; - struct sockaddr sa; - struct musl_sockaddr kname; + union lwp_sockaddr_buffer kernel_address; socklen_t unamelen; socklen_t knamelen; @@ -5283,18 +5327,15 @@ sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *name return -EFAULT; } - knamelen = sizeof(struct sockaddr); - ret = getpeername(socket, &sa, &knamelen); + rt_memset(&kernel_address, 0, sizeof(kernel_address)); + knamelen = sizeof(kernel_address); + ret = getpeername(socket, &kernel_address.address, &knamelen); if (ret == 0) { - sockaddr_tomusl(&sa, &kname); - if (unamelen > sizeof(struct musl_sockaddr)) - { - unamelen = sizeof(struct musl_sockaddr); - } - lwp_put_to_user(name, &kname, unamelen); - lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t)); + knamelen = lwp_sockaddr_to_user(name, unamelen, + &kernel_address, knamelen); + lwp_put_to_user(namelen, &knamelen, sizeof(socklen_t)); } else { @@ -5331,8 +5372,7 @@ sysret_t sys_getpeername(int socket, struct musl_sockaddr *name, socklen_t *name sysret_t sys_getsockname(int socket, struct musl_sockaddr *name, socklen_t *namelen) { int ret = -1; - struct sockaddr sa; - struct musl_sockaddr kname; + union lwp_sockaddr_buffer kernel_address; socklen_t unamelen; socklen_t knamelen; @@ -5351,17 +5391,14 @@ sysret_t sys_getsockname(int socket, struct musl_sockaddr *name, socklen_t *name return -EFAULT; } - knamelen = sizeof(struct sockaddr); - ret = getsockname(socket, &sa, &knamelen); + rt_memset(&kernel_address, 0, sizeof(kernel_address)); + knamelen = sizeof(kernel_address); + ret = getsockname(socket, &kernel_address.address, &knamelen); if (ret == 0) { - sockaddr_tomusl(&sa, &kname); - if (unamelen > sizeof(struct musl_sockaddr)) - { - unamelen = sizeof(struct musl_sockaddr); - } - lwp_put_to_user(name, &kname, unamelen); - lwp_put_to_user(namelen, &unamelen, sizeof(socklen_t)); + knamelen = lwp_sockaddr_to_user(name, unamelen, + &kernel_address, knamelen); + lwp_put_to_user(namelen, &knamelen, sizeof(socklen_t)); } else { @@ -5517,36 +5554,16 @@ sysret_t sys_setsockopt(int socket, int level, int optname, const void *optval, */ sysret_t sys_connect(int socket, const struct musl_sockaddr *name, socklen_t namelen) { - int ret = 0; - rt_uint16_t family = 0; - struct sockaddr sa; - struct musl_sockaddr kname; - struct sockaddr_un addr_un; - - if (!lwp_user_accessable((void *)name, namelen)) - { - return -EFAULT; - } - - lwp_get_from_user(&family, (void *)name, 2); - if (family == AF_UNIX) - { - if (!lwp_user_accessable((void *)name, sizeof(struct sockaddr_un))) - { - return -EFAULT; - } + int ret; + union lwp_sockaddr_buffer kernel_address; - lwp_get_from_user(&addr_un, (void *)name, sizeof(struct sockaddr_un)); - ret = connect(socket, (struct sockaddr *)(&addr_un), namelen); - } - else + ret = lwp_sockaddr_from_user(&kernel_address, name, namelen); + if (ret < 0) { - lwp_get_from_user(&kname, (void *)name, namelen); - sockaddr_tolwip(&kname, &sa); - ret = connect(socket, &sa, namelen); + return ret; } - - return ret; + ret = connect(socket, &kernel_address.address, namelen); + return (ret < 0 ? GET_ERRNO() : ret); } /** @@ -5577,6 +5594,7 @@ sysret_t sys_listen(int socket, int backlog) #define MUSLC_MSG_OOB 0x0001 #define MUSLC_MSG_PEEK 0x0002 +#define MUSLC_MSG_CTRUNC 0x0008 #define MUSLC_MSG_DONTWAIT 0x0040 #define MUSLC_MSG_WAITALL 0x0100 #define MUSLC_MSG_MORE 0x8000 @@ -5613,21 +5631,95 @@ static int netflags_muslc_2_lwip(int flags) return flgs; } +static int netflags_lwip_2_muslc(int flags) +{ + int flgs = 0; + + if (flags & MSG_CTRUNC) + { + flgs |= MUSLC_MSG_CTRUNC; + } + return flgs; +} + +static void cmsg_level_muslc_2_lwip(struct msghdr *message) +{ + struct cmsghdr *cmsg; + + for_each_cmsghdr(cmsg, message) + { + if (!CMSG_OK(message, cmsg)) + { + break; + } + if (cmsg->cmsg_level == INTF_SOL_SOCKET) + { + cmsg->cmsg_level = IMPL_SOL_SOCKET; + } + } +} + +static void cmsg_level_lwip_2_muslc(struct msghdr *message) +{ + struct cmsghdr *cmsg; + + for_each_cmsghdr(cmsg, message) + { + if (!CMSG_OK(message, cmsg)) + { + break; + } + if (cmsg->cmsg_level == IMPL_SOL_SOCKET) + { + cmsg->cmsg_level = INTF_SOL_SOCKET; + } + } +} + #ifdef ARCH_MM_MMU -static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, - struct iovec **out_iov, void **out_msg_control) +static int copy_msghdr_from_user(struct msghdr *kmsg, + struct musl_msghdr *umsg, + struct iovec **out_iov, void **out_msg_control, + void **out_msg_name, void **out_buffer) { + int index; size_t iovs_size; + struct musl_msghdr user_message; struct iovec *uiov, *kiov; size_t iovs_buffer_size = 0; - void *iovs_buffer; + char *iovs_buffer; + char *buffer_cursor; - if (!lwp_user_accessable(umsg, sizeof(*umsg))) + if (!lwp_user_accessable(umsg, sizeof(user_message))) { return -EFAULT; } - lwp_get_from_user(kmsg, umsg, sizeof(*kmsg)); + lwp_get_from_user(&user_message, umsg, sizeof(user_message)); + kmsg->msg_name = user_message.msg_name; + kmsg->msg_namelen = user_message.msg_namelen; + kmsg->msg_iov = user_message.msg_iov; + kmsg->msg_iovlen = user_message.msg_iovlen; + kmsg->msg_control = user_message.msg_control; + kmsg->msg_controllen = user_message.msg_controllen; + kmsg->msg_flags = user_message.msg_flags; + + if (kmsg->msg_iovlen < 0 || + (size_t)kmsg->msg_iovlen > SIZE_MAX / sizeof(*kmsg->msg_iov) || + kmsg->msg_namelen > sizeof(union lwp_sockaddr_buffer)) + { + return -EINVAL; + } + if (kmsg->msg_name != RT_NULL && + !lwp_user_accessable(kmsg->msg_name, kmsg->msg_namelen)) + { + return -EFAULT; + } + if (kmsg->msg_control != RT_NULL && + !lwp_user_accessable(kmsg->msg_control, kmsg->msg_controllen)) + { + return -EFAULT; + } iovs_size = sizeof(*kmsg->msg_iov) * kmsg->msg_iovlen; if (!lwp_user_accessable(kmsg->msg_iov, iovs_size)) @@ -5651,7 +5743,7 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, } kmsg->msg_iov = kiov; - for (int i = 0; i < kmsg->msg_iovlen; ++i) + for (index = 0; index < kmsg->msg_iovlen; ++index) { /* * We MUST check we can copy data to user after socket done in uiov @@ -5664,6 +5756,11 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, return -EPERM; } + if (SIZE_MAX - iovs_buffer_size < uiov->iov_len) + { + kmem_put(kmsg->msg_iov); + return -EINVAL; + } iovs_buffer_size += uiov->iov_len; kiov->iov_len = uiov->iov_len; @@ -5672,7 +5769,15 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, } /* msg_iov and msg_control */ - iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen); + if (SIZE_MAX - iovs_buffer_size < kmsg->msg_controllen || + SIZE_MAX - iovs_buffer_size - kmsg->msg_controllen < + kmsg->msg_namelen) + { + kmem_put(kmsg->msg_iov); + return -EINVAL; + } + iovs_buffer = kmem_get(iovs_buffer_size + kmsg->msg_controllen + + kmsg->msg_namelen); if (!iovs_buffer) { @@ -5681,18 +5786,22 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, return -ENOMEM; } + *out_buffer = iovs_buffer; + buffer_cursor = iovs_buffer; kiov = kmsg->msg_iov; - for (int i = 0; i < kmsg->msg_iovlen; ++i) + for (index = 0; index < kmsg->msg_iovlen; ++index) { - kiov->iov_base = iovs_buffer; - iovs_buffer += kiov->iov_len; + kiov->iov_base = buffer_cursor; + buffer_cursor += kiov->iov_len; ++kiov; } *out_msg_control = kmsg->msg_control; - /* msg_control is the end of the iovs_buffer */ - kmsg->msg_control = iovs_buffer; + kmsg->msg_control = buffer_cursor; + buffer_cursor += kmsg->msg_controllen; + *out_msg_name = kmsg->msg_name; + kmsg->msg_name = kmsg->msg_namelen != 0 ? buffer_cursor : RT_NULL; return 0; } @@ -5728,12 +5837,17 @@ static int copy_msghdr_from_user(struct msghdr *kmsg, struct msghdr *umsg, * * @see sys_sendmsg() */ -sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags) +sysret_t sys_recvmsg(int socket, struct musl_msghdr *msg, int flags) { int flgs, ret = -1; struct msghdr kmsg; #ifdef ARCH_MM_MMU + int index; + size_t remaining; + socklen_t user_name_length; + void *buffer; void *msg_control; + void *msg_name; struct iovec *uiov, *kiov; #endif @@ -5745,10 +5859,12 @@ sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags) flgs = netflags_muslc_2_lwip(flags); #ifdef ARCH_MM_MMU - ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control); + ret = copy_msghdr_from_user(&kmsg, msg, &uiov, &msg_control, + &msg_name, &buffer); if (!ret) { + user_name_length = kmsg.msg_namelen; ret = recvmsg(socket, &kmsg, flgs); if (ret < 0) @@ -5757,24 +5873,57 @@ sysret_t sys_recvmsg(int socket, struct msghdr *msg, int flags) } kiov = kmsg.msg_iov; + remaining = (size_t)ret; - for (int i = 0; i < kmsg.msg_iovlen; ++i) + for (index = 0; index < kmsg.msg_iovlen && remaining != 0; ++index) { - lwp_put_to_user(uiov->iov_base, kiov->iov_base, kiov->iov_len); + size_t copy_length = kiov->iov_len; + + if (copy_length > remaining) + { + copy_length = remaining; + } + lwp_put_to_user(uiov->iov_base, kiov->iov_base, copy_length); + remaining -= copy_length; ++kiov; ++uiov; } - lwp_put_to_user(msg_control, kmsg.msg_control, kmsg.msg_controllen); + if (msg_control != RT_NULL && kmsg.msg_controllen != 0) + { + cmsg_level_lwip_2_muslc(&kmsg); + lwp_put_to_user(msg_control, kmsg.msg_control, + kmsg.msg_controllen); + } + if (msg_name != RT_NULL && kmsg.msg_name != RT_NULL) + { + socklen_t name_length; + + name_length = lwp_sockaddr_to_user( + (struct musl_sockaddr *)msg_name, user_name_length, + (const union lwp_sockaddr_buffer *)kmsg.msg_name, + kmsg.msg_namelen); + lwp_put_to_user(&msg->msg_namelen, &name_length, + sizeof(name_length)); + } + kmsg.msg_flags = netflags_lwip_2_muslc(kmsg.msg_flags); lwp_put_to_user(&msg->msg_flags, &kmsg.msg_flags, sizeof(kmsg.msg_flags)); + lwp_put_to_user(&msg->msg_controllen, &kmsg.msg_controllen, + sizeof(kmsg.msg_controllen)); _free_res: - kmem_put(kmsg.msg_iov->iov_base); + kmem_put(buffer); kmem_put(kmsg.msg_iov); } #else - rt_memcpy(&kmsg, msg, sizeof(kmsg)); + kmsg.msg_name = msg->msg_name; + kmsg.msg_namelen = msg->msg_namelen; + kmsg.msg_iov = msg->msg_iov; + kmsg.msg_iovlen = msg->msg_iovlen; + kmsg.msg_control = msg->msg_control; + kmsg.msg_controllen = msg->msg_controllen; + kmsg.msg_flags = msg->msg_flags; ret = recvmsg(socket, &kmsg, flgs); @@ -5825,18 +5974,33 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags, struct musl_sockaddr *from, socklen_t *fromlen) { int flgs = 0; -#ifdef ARCH_MM_MMU int ret = -1; + socklen_t user_from_length = 0; + socklen_t kernel_from_length = 0; + union lwp_sockaddr_buffer kernel_address; +#ifdef ARCH_MM_MMU void *kmem = RT_NULL; #endif flgs = netflags_muslc_2_lwip(flags); -#ifdef ARCH_MM_MMU - if (!len) + if (from != RT_NULL) { - return -EINVAL; + if (fromlen == RT_NULL || + !lwp_user_accessable(fromlen, sizeof(*fromlen))) + { + return -EFAULT; + } + lwp_get_from_user(&user_from_length, fromlen, + sizeof(user_from_length)); + if (user_from_length == 0 || + !lwp_user_accessable(from, user_from_length)) + { + return -EFAULT; + } + rt_memset(&kernel_address, 0, sizeof(kernel_address)); + kernel_from_length = sizeof(kernel_address); } - +#ifdef ARCH_MM_MMU if (!lwp_user_accessable((void *)mem, len)) { return -EFAULT; @@ -5848,26 +6012,30 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags, return -ENOMEM; } - if (flags == 0x2) - { - flags = 0x1; - } - if (from) { - struct sockaddr sa; - - ret = recvfrom(socket, kmem, len, flgs, &sa, fromlen); - sockaddr_tomusl(&sa, from); + ret = recvfrom(socket, kmem, len, flgs, + &kernel_address.address, &kernel_from_length); } else { ret = recvfrom(socket, kmem, len, flgs, NULL, NULL); } - if (ret > 0) + if (ret >= 0) { - lwp_put_to_user(mem, kmem, len); + if (ret > 0) + { + lwp_put_to_user(mem, kmem, ret); + } + if (from != RT_NULL) + { + kernel_from_length = lwp_sockaddr_to_user( + from, user_from_length, &kernel_address, + kernel_from_length); + lwp_put_to_user(fromlen, &kernel_from_length, + sizeof(kernel_from_length)); + } } if (ret < 0) @@ -5879,17 +6047,22 @@ sysret_t sys_recvfrom(int socket, void *mem, size_t len, int flags, return ret; #else - int ret = -1; if (from) { - struct sockaddr sa = { 0 }; - - ret = recvfrom(socket, mem, len, flgs, &sa, fromlen); - sockaddr_tomusl(&sa, from); + ret = recvfrom(socket, mem, len, flgs, + &kernel_address.address, &kernel_from_length); + if (ret >= 0) + { + kernel_from_length = lwp_sockaddr_to_user( + from, user_from_length, &kernel_address, + kernel_from_length); + lwp_put_to_user(fromlen, &kernel_from_length, + sizeof(kernel_from_length)); + } } else { - ret = recvfrom(socket, mem, len, flags, NULL, NULL); + ret = recvfrom(socket, mem, len, flgs, NULL, NULL); } return (ret < 0 ? GET_ERRNO() : ret); #endif @@ -5930,7 +6103,7 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags) if (!lwp_user_accessable((void *)mem, len)) return -EFAULT; - kmem = kmem_get(sizeof(*kmem)); + kmem = kmem_get(len); if (kmem == RT_NULL) { return -ENOMEM; @@ -5939,7 +6112,10 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags) flgs = netflags_muslc_2_lwip(flags); ret = recvfrom(socket, kmem, len, flgs, NULL, NULL); - lwp_put_to_user((void *)mem, kmem, len); + if (ret > 0) + { + lwp_put_to_user((void *)mem, kmem, ret); + } kmem_put(kmem); return (ret < 0 ? GET_ERRNO() : ret); @@ -5977,12 +6153,15 @@ sysret_t sys_recv(int socket, void *mem, size_t len, int flags) * * @see sys_send(), sys_sendto(), sys_recvmsg() */ -sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags) +sysret_t sys_sendmsg(int socket, const struct musl_msghdr *msg, int flags) { int flgs, ret = -1; struct msghdr kmsg; #ifdef ARCH_MM_MMU + int index; + void *buffer; void *msg_control; + void *msg_name; struct iovec *uiov, *kiov; #endif if (!msg) @@ -5993,13 +6172,14 @@ sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags) flgs = netflags_muslc_2_lwip(flags); #ifdef ARCH_MM_MMU - ret = copy_msghdr_from_user(&kmsg, (struct msghdr *)msg, &uiov, &msg_control); + ret = copy_msghdr_from_user(&kmsg, (struct musl_msghdr *)msg, &uiov, + &msg_control, &msg_name, &buffer); if (!ret) { kiov = kmsg.msg_iov; - for (int i = 0; i < kmsg.msg_iovlen; ++i) + for (index = 0; index < kmsg.msg_iovlen; ++index) { lwp_get_from_user(kiov->iov_base, uiov->iov_base, kiov->iov_len); @@ -6007,22 +6187,44 @@ sysret_t sys_sendmsg(int socket, const struct msghdr *msg, int flags) ++uiov; } - lwp_get_from_user(kmsg.msg_control, msg_control, kmsg.msg_controllen); + if (msg_control != RT_NULL && kmsg.msg_controllen != 0) + { + lwp_get_from_user(kmsg.msg_control, msg_control, + kmsg.msg_controllen); + cmsg_level_muslc_2_lwip(&kmsg); + } + if (msg_name != RT_NULL && kmsg.msg_namelen != 0) + { + union lwp_sockaddr_buffer kernel_address; + + ret = lwp_sockaddr_from_user(&kernel_address, + (struct musl_sockaddr *)msg_name, + kmsg.msg_namelen); + if (ret < 0) + { + kmem_put(buffer); + kmem_put(kmsg.msg_iov); + return ret; + } + rt_memcpy(kmsg.msg_name, &kernel_address, kmsg.msg_namelen); + } ret = sendmsg(socket, &kmsg, flgs); - kmem_put(kmsg.msg_iov->iov_base); + kmem_put(buffer); kmem_put(kmsg.msg_iov); } #else - rt_memcpy(&kmsg, msg, sizeof(kmsg)); + kmsg.msg_name = msg->msg_name; + kmsg.msg_namelen = msg->msg_namelen; + kmsg.msg_iov = msg->msg_iov; + kmsg.msg_iovlen = msg->msg_iovlen; + kmsg.msg_control = msg->msg_control; + kmsg.msg_controllen = msg->msg_controllen; + kmsg.msg_flags = msg->msg_flags; ret = sendmsg(socket, &kmsg, flgs); - if (!ret) - { - msg->msg_flags = kmsg.msg_flags; - } #endif /* ARCH_MM_MMU */ return (ret < 0 ? GET_ERRNO() : ret); @@ -6061,18 +6263,22 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags, const struct musl_sockaddr *to, socklen_t tolen) { int flgs = 0; -#ifdef ARCH_MM_MMU int ret = -1; + union lwp_sockaddr_buffer kernel_address; +#ifdef ARCH_MM_MMU void *kmem = RT_NULL; #endif flgs = netflags_muslc_2_lwip(flags); -#ifdef ARCH_MM_MMU - if (!size) + if (to != RT_NULL) { - return -EINVAL; + ret = lwp_sockaddr_from_user(&kernel_address, to, tolen); + if (ret < 0) + { + return ret; + } } - +#ifdef ARCH_MM_MMU if (!lwp_user_accessable((void *)dataptr, size)) { return -EFAULT; @@ -6088,10 +6294,8 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags, if (to) { - struct sockaddr sa; - sockaddr_tolwip(to, &sa); - - ret = sendto(socket, kmem, size, flgs, &sa, tolen); + ret = sendto(socket, kmem, size, flgs, + &kernel_address.address, tolen); } else { @@ -6107,13 +6311,10 @@ sysret_t sys_sendto(int socket, const void *dataptr, size_t size, int flags, return ret; #else - int ret; if (to) { - struct sockaddr sa; - sockaddr_tolwip(to, &sa); - - ret = sendto(socket, dataptr, size, flgs, &sa, tolen); + ret = sendto(socket, dataptr, size, flgs, + &kernel_address.address, tolen); } else { From 22cb30762bea3f000e64a0878f89c44ba8171794 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 3 Aug 2026 06:16:40 +0800 Subject: [PATCH 4/5] components/net/af_unix: add local sockets Add an opt-in AF_UNIX provider for pathname-based local IPC without a synthetic network device. Support datagram and stream sockets, blocking and nonblocking I/O, timeouts, poll, socketpair, and SCM_RIGHTS descriptor passing. Include bounded Kconfig settings, component documentation, and utest coverage. Impact: enabled only by RT_USING_AF_UNIX and requires SAL POSIX with DFSv2. Validation: git diff --cached --check. --- components/net/Kconfig | 1 + components/net/af_unix/Kconfig | 42 + components/net/af_unix/README.md | 56 + components/net/af_unix/SConscript | 12 + components/net/af_unix/include/af_unix.h | 20 + components/net/af_unix/src/af_unix_core.c | 1136 +++++++++++++++++ components/net/af_unix/src/af_unix_dgram.c | 254 ++++ components/net/af_unix/src/af_unix_internal.h | 163 +++ .../net/af_unix/src/af_unix_namespace.c | 290 +++++ components/net/af_unix/src/af_unix_rights.c | 329 +++++ components/net/af_unix/src/af_unix_stream.c | 484 +++++++ .../net/af_unix/testcases/af_unix_test.c | 743 +++++++++++ 12 files changed, 3530 insertions(+) create mode 100644 components/net/af_unix/Kconfig create mode 100644 components/net/af_unix/README.md create mode 100644 components/net/af_unix/SConscript create mode 100644 components/net/af_unix/include/af_unix.h create mode 100644 components/net/af_unix/src/af_unix_core.c create mode 100644 components/net/af_unix/src/af_unix_dgram.c create mode 100644 components/net/af_unix/src/af_unix_internal.h create mode 100644 components/net/af_unix/src/af_unix_namespace.c create mode 100644 components/net/af_unix/src/af_unix_rights.c create mode 100644 components/net/af_unix/src/af_unix_stream.c create mode 100644 components/net/af_unix/testcases/af_unix_test.c diff --git a/components/net/Kconfig b/components/net/Kconfig index 7dfd1b101b16..621448375fd2 100644 --- a/components/net/Kconfig +++ b/components/net/Kconfig @@ -1,6 +1,7 @@ menu "Network" rsource "sal/Kconfig" +rsource "af_unix/Kconfig" rsource "netdev/Kconfig" rsource "lwip/Kconfig" rsource "at/Kconfig" diff --git a/components/net/af_unix/Kconfig b/components/net/af_unix/Kconfig new file mode 100644 index 000000000000..b078ae4534b4 --- /dev/null +++ b/components/net/af_unix/Kconfig @@ -0,0 +1,42 @@ +menuconfig RT_USING_AF_UNIX + bool "AF_UNIX local sockets" + depends on RT_USING_SAL + depends on SAL_USING_POSIX + depends on RT_USING_DFS_V2 + default n + help + Enable pathname-based AF_UNIX SOCK_DGRAM and SOCK_STREAM sockets. + +if RT_USING_AF_UNIX + +config AF_UNIX_DGRAM_MAX_SIZE + int "Maximum datagram size" + range 128 65535 + default 4096 + +config AF_UNIX_DGRAM_QUEUE_LEN + int "Datagram receive queue length" + range 1 256 + default 16 + +config AF_UNIX_STREAM_BUFFER_SIZE + int "Stream receive buffer size" + range 256 65535 + default 4096 + +config AF_UNIX_LISTEN_BACKLOG_MAX + int "Maximum stream listen backlog" + range 1 128 + default 16 + +config AF_UNIX_RIGHTS_MAX + int "Maximum file descriptors per SCM_RIGHTS message" + range 1 253 + default 16 + +config RT_AF_UNIX_USING_TESTCASES + bool "Build AF_UNIX test cases" + depends on RT_USING_UTESTCASES + default n + +endif diff --git a/components/net/af_unix/README.md b/components/net/af_unix/README.md new file mode 100644 index 000000000000..a6231d996b1b --- /dev/null +++ b/components/net/af_unix/README.md @@ -0,0 +1,56 @@ +# AF_UNIX local sockets + +The AF_UNIX component provides pathname-based local IPC through the existing +SAL and POSIX socket APIs. It supports `SOCK_DGRAM`, `SOCK_STREAM`, and +`socketpair()` for both socket types. + +## Configuration + +Enable `RT_USING_AF_UNIX`. The component requires `RT_USING_SAL`, +`SAL_USING_POSIX`, and `RT_USING_DFS_V2`. + +- `AF_UNIX_DGRAM_MAX_SIZE` bounds one datagram. +- `AF_UNIX_DGRAM_QUEUE_LEN` bounds queued datagrams per socket. +- `AF_UNIX_STREAM_BUFFER_SIZE` bounds each stream receive buffer. +- `AF_UNIX_LISTEN_BACKLOG_MAX` caps the stream accept queue. +- `AF_UNIX_RIGHTS_MAX` bounds the file descriptors in one `SCM_RIGHTS` send. +- `RT_AF_UNIX_USING_TESTCASES` builds the component utest suite. + +## Pathname behavior + +`bind()` creates an `S_IFSOCK` node through DFSv2. The mounted filesystem must +support special nodes through `create_vnode()`; tmpfs and devtmpfs support +socket nodes directly. Closing a bound socket leaves its pathname in the +filesystem. Applications should call `unlink()` before rebinding, which +matches common Unix daemon behavior. + +Removing a pathname prevents new lookups. Existing stream connections and +connected datagram endpoints continue to reference their established peers. + +## Descriptor passing + +`sendmsg()` and `recvmsg()` support one or more file descriptors in +`SOL_SOCKET`/`SCM_RIGHTS` control messages. The queued reference remains valid +after the sender closes its descriptor. On receive, each reference is installed +as a new descriptor in the receiving process and retains the same open file +description, including its shared file position. + +For datagram sockets, the control message is atomic with its datagram. For +stream sockets, it is associated with the first byte written by `sendmsg()` and +is delivered when a receive consumes that byte. A receive without a control +buffer discards associated descriptors and reports `MSG_CTRUNC`; `MSG_PEEK` +does not install or consume descriptors. At least one payload byte is required +when sending `SCM_RIGHTS`. + +Only `SCM_RIGHTS` ancillary data is supported. Credentials and other control +message types return `EOPNOTSUPP`. + +## Supported operations + +The component implements bind, connect, listen, accept, send/receive, +sendto/recvfrom, sendmsg/recvmsg with descriptor passing, shutdown, socket +options, nonblocking I/O, timeouts, poll/select readiness, address queries, and +socketpair. + +Linux abstract namespace addresses and credential ancillary data are not +supported. The component requires DFSv2. diff --git a/components/net/af_unix/SConscript b/components/net/af_unix/SConscript new file mode 100644 index 000000000000..c85fea549f59 --- /dev/null +++ b/components/net/af_unix/SConscript @@ -0,0 +1,12 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('src/*.c') +CPPPATH = [cwd + '/include', cwd + '/src'] + +if GetDepend('RT_AF_UNIX_USING_TESTCASES'): + src += Glob('testcases/*.c') + +group = DefineGroup('AF_UNIX', src, depend=['RT_USING_AF_UNIX'], CPPPATH=CPPPATH) + +Return('group') diff --git a/components/net/af_unix/include/af_unix.h b/components/net/af_unix/include/af_unix.h new file mode 100644 index 000000000000..cd14d0efe30a --- /dev/null +++ b/components/net/af_unix/include/af_unix.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AF_UNIX_H__ +#define AF_UNIX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int af_unix_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* AF_UNIX_H__ */ diff --git a/components/net/af_unix/src/af_unix_core.c b/components/net/af_unix/src/af_unix_core.c new file mode 100644 index 000000000000..9efb1a2c6791 --- /dev/null +++ b/components/net/af_unix/src/af_unix_core.c @@ -0,0 +1,1136 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include "af_unix_internal.h" + +static struct rt_mutex af_unix_core_lock; +static struct af_unix_socket *af_unix_handles[SAL_SOCKETS_NUM]; + +int af_unix_error(int error) +{ + rt_set_errno(error); + return -1; +} + +void af_unix_lock(void) +{ + rt_mutex_take(&af_unix_core_lock, RT_WAITING_FOREVER); +} + +void af_unix_unlock(void) +{ + rt_mutex_release(&af_unix_core_lock); +} + +int af_unix_is_nonblocking(const struct af_unix_socket *sock, int flags) +{ + return ((sock->flags & O_NONBLOCK) != 0 || (flags & MSG_DONTWAIT) != 0); +} + +int af_unix_wait(rt_wqueue_t *queue, int timeout) +{ + int result; + + result = rt_wqueue_wait_interruptible(queue, 0, timeout); + if (result == -RT_EINTR) + { + return af_unix_error(EINTR); + } + if (result != RT_EOK) + { + return af_unix_error(EAGAIN); + } + return 0; +} + +static void af_unix_message_queue_clear_locked(struct af_unix_socket *sock) +{ + while (!rt_list_isempty(&sock->message_queue)) + { + struct af_unix_message *message; + + message = rt_list_entry(sock->message_queue.next, + struct af_unix_message, node); + rt_list_remove(&message->node); + if (message->rights != RT_NULL) + { + af_unix_rights_defer_locked(message->rights); + } + rt_free(message); + } + sock->message_count = 0; +} + +static void af_unix_socket_destroy_locked(struct af_unix_socket *sock) +{ + af_unix_message_queue_clear_locked(sock); + af_unix_rights_list_defer_locked(&sock->rights_queue); + if (sock->stream_buffer != RT_NULL) + { + rt_free(sock->stream_buffer); + } + rt_free(sock); +} + +void af_unix_socket_ref_locked(struct af_unix_socket *sock) +{ + RT_ASSERT(sock != RT_NULL); + RT_ASSERT(sock->ref_count > 0); + sock->ref_count++; +} + +void af_unix_socket_unref_locked(struct af_unix_socket *sock) +{ + RT_ASSERT(sock != RT_NULL); + RT_ASSERT(sock->ref_count > 0); + + sock->ref_count--; + if (sock->ref_count == 0) + { + af_unix_socket_destroy_locked(sock); + } +} + +struct af_unix_socket *af_unix_socket_create_locked(int type) +{ + struct af_unix_socket *sock; + + sock = (struct af_unix_socket *)rt_calloc(1, sizeof(*sock)); + if (sock == RT_NULL) + { + return RT_NULL; + } + + if (type == SOCK_STREAM) + { + sock->stream_buffer = (char *)rt_malloc(AF_UNIX_STREAM_BUFFER_SIZE); + if (sock->stream_buffer == RT_NULL) + { + rt_free(sock); + return RT_NULL; + } + } + + sock->handle = -1; + sock->type = type; + sock->ref_count = 1; + sock->receive_timeout = RT_WAITING_FOREVER; + sock->send_timeout = RT_WAITING_FOREVER; + rt_wqueue_init(&sock->wait_queue); + rt_list_init(&sock->message_queue); + rt_list_init(&sock->rights_queue); + rt_list_init(&sock->pending_queue); + rt_list_init(&sock->pending_node); + af_unix_address_set(&sock->local_address, &sock->local_length, RT_NULL); + af_unix_address_set(&sock->peer_address, &sock->peer_length, RT_NULL); + + return sock; +} + +int af_unix_handle_alloc_locked(struct af_unix_socket *sock) +{ + int handle; + + for (handle = 0; handle < SAL_SOCKETS_NUM; handle++) + { + if (af_unix_handles[handle] == RT_NULL) + { + af_unix_handles[handle] = sock; + sock->handle = handle; + return handle; + } + } + + return -1; +} + +void af_unix_handle_remove_locked(struct af_unix_socket *sock) +{ + int handle; + + handle = sock->handle; + if (handle >= 0 && handle < SAL_SOCKETS_NUM && + af_unix_handles[handle] == sock) + { + af_unix_handles[handle] = RT_NULL; + sock->handle = -1; + af_unix_socket_unref_locked(sock); + } +} + +struct af_unix_socket *af_unix_socket_get(int handle) +{ + struct af_unix_socket *sock = RT_NULL; + + af_unix_lock(); + if (handle >= 0 && handle < SAL_SOCKETS_NUM) + { + sock = af_unix_handles[handle]; + if (sock != RT_NULL) + { + af_unix_socket_ref_locked(sock); + } + } + af_unix_unlock(); + + if (sock == RT_NULL) + { + af_unix_error(EBADF); + } + return sock; +} + +void af_unix_socket_put(struct af_unix_socket *sock) +{ + int error; + + error = rt_get_errno(); + af_unix_lock(); + af_unix_socket_unref_locked(sock); + af_unix_unlock(); + af_unix_rights_drain(); + rt_set_errno(error); +} + +static void af_unix_disconnect_locked(struct af_unix_socket *sock) +{ + int reciprocal; + struct af_unix_socket *peer; + + peer = sock->peer; + if (peer == RT_NULL) + { + return; + } + + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT | POLLHUP)); + rt_wqueue_wakeup_all(&peer->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT | POLLHUP)); + + reciprocal = (peer->peer == sock); + sock->peer = RT_NULL; + if (reciprocal) + { + peer->peer = RT_NULL; + af_unix_socket_unref_locked(sock); + } + af_unix_socket_unref_locked(peer); +} + +void af_unix_set_peer_locked(struct af_unix_socket *sock, + struct af_unix_socket *peer) +{ + if (sock->peer == peer) + { + return; + } + if (sock->peer != RT_NULL) + { + af_unix_disconnect_locked(sock); + } + if (peer != RT_NULL) + { + af_unix_socket_ref_locked(peer); + sock->peer = peer; + } +} + +int af_unix_connect_peers_locked(struct af_unix_socket *first, + struct af_unix_socket *second) +{ + if (first->peer != RT_NULL || second->peer != RT_NULL) + { + return af_unix_error(EISCONN); + } + + af_unix_socket_ref_locked(second); + first->peer = second; + af_unix_socket_ref_locked(first); + second->peer = first; + first->connected = 1; + second->connected = 1; + return 0; +} + +void af_unix_socket_close_locked(struct af_unix_socket *sock) +{ + if (sock->closed) + { + return; + } + + sock->closed = 1; + sock->read_shutdown = 1; + sock->write_shutdown = 1; + af_unix_namespace_detach_locked(sock); + + while (!rt_list_isempty(&sock->pending_queue)) + { + struct af_unix_socket *pending; + + pending = rt_list_entry(sock->pending_queue.next, + struct af_unix_socket, pending_node); + rt_list_remove(&pending->pending_node); + pending->pending = 0; + sock->pending_count--; + af_unix_handle_remove_locked(pending); + af_unix_socket_close_locked(pending); + } + + af_unix_message_queue_clear_locked(sock); + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT | POLLHUP | POLLERR)); + af_unix_disconnect_locked(sock); +} + +static int af_unix_socket_create(int domain, int type, int protocol) +{ + int handle; + struct af_unix_socket *sock; + + if (domain != AF_UNIX || protocol != 0 || + (type != SOCK_DGRAM && type != SOCK_STREAM)) + { + return af_unix_error(EPROTONOSUPPORT); + } + + af_unix_lock(); + sock = af_unix_socket_create_locked(type); + if (sock == RT_NULL) + { + af_unix_unlock(); + return af_unix_error(ENOMEM); + } + + handle = af_unix_handle_alloc_locked(sock); + if (handle < 0) + { + af_unix_socket_unref_locked(sock); + af_unix_unlock(); + return af_unix_error(EMFILE); + } + af_unix_unlock(); + return handle; +} + +static int af_unix_close(int handle) +{ + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + + af_unix_lock(); + af_unix_handle_remove_locked(sock); + af_unix_socket_close_locked(sock); + af_unix_unlock(); + af_unix_socket_put(sock); + return 0; +} + +static int af_unix_bind(int handle, const struct sockaddr *address, + socklen_t length) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + result = af_unix_namespace_bind(sock, address, length); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_listen(int handle, int backlog) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + result = af_unix_stream_listen(sock, backlog); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_connect(int handle, const struct sockaddr *address, + socklen_t length) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + if (sock->type == SOCK_DGRAM) + { + result = af_unix_dgram_connect(sock, address, length); + } + else + { + result = af_unix_stream_connect(sock, address, length); + } + af_unix_socket_put(sock); + return result; +} + +static int af_unix_accept(int handle, struct sockaddr *address, + socklen_t *length) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + result = af_unix_stream_accept(sock, address, length); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_sendto_with_rights( + int handle, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t to_length, + struct af_unix_rights *rights) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + if (sock->type == SOCK_DGRAM) + { + result = af_unix_dgram_send(sock, data, size, flags, to, to_length, + rights); + } + else + { + if (to != RT_NULL) + { + result = af_unix_error(EISCONN); + } + else + { + result = af_unix_stream_send(sock, data, size, flags, rights); + } + } + af_unix_socket_put(sock); + return result; +} + +static int af_unix_sendto(int handle, const void *data, size_t size, int flags, + const struct sockaddr *to, socklen_t to_length) +{ + return af_unix_sendto_with_rights(handle, data, size, flags, to, + to_length, RT_NULL); +} + +static int af_unix_recvfrom_with_rights( + int handle, void *data, size_t size, int flags, struct sockaddr *from, + socklen_t *from_length, rt_list_t *rights) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + if (sock->type == SOCK_DGRAM) + { + result = af_unix_dgram_receive(sock, data, size, flags, + from, from_length, rights); + } + else + { + result = af_unix_stream_receive(sock, data, size, flags, rights); + if (result >= 0 && from != RT_NULL) + { + (void)af_unix_address_copy(from, from_length, + &sock->peer_address, + sock->peer_length); + } + } + af_unix_socket_put(sock); + return result; +} + +static int af_unix_recvfrom(int handle, void *data, size_t size, int flags, + struct sockaddr *from, socklen_t *from_length) +{ + int result; + rt_list_t rights; + + rt_list_init(&rights); + result = af_unix_recvfrom_with_rights(handle, data, size, flags, from, + from_length, &rights); + af_unix_rights_list_release(&rights); + return result; +} + +static int af_unix_sendmsg(int handle, const struct msghdr *message, int flags) +{ + int error; + int result; + int index; + size_t total = 0; + size_t offset = 0; + char *buffer = RT_NULL; + struct af_unix_rights *rights = RT_NULL; + + if (message == RT_NULL || message->msg_iov == RT_NULL || + message->msg_iovlen < 0) + { + return af_unix_error(EINVAL); + } + for (index = 0; index < message->msg_iovlen; index++) + { + if (SIZE_MAX - total < message->msg_iov[index].iov_len) + { + return af_unix_error(EMSGSIZE); + } + total += message->msg_iov[index].iov_len; + } + if (message->msg_controllen != 0 && total == 0) + { + return af_unix_error(EINVAL); + } + if (af_unix_rights_create(message, &rights) < 0) + { + return -1; + } + + if (total != 0) + { + buffer = (char *)rt_malloc(total); + if (buffer == RT_NULL) + { + af_unix_rights_release(rights); + return af_unix_error(ENOMEM); + } + for (index = 0; index < message->msg_iovlen; index++) + { + rt_memcpy(buffer + offset, message->msg_iov[index].iov_base, + message->msg_iov[index].iov_len); + offset += message->msg_iov[index].iov_len; + } + } + + result = af_unix_sendto_with_rights( + handle, buffer, total, flags, + (const struct sockaddr *)message->msg_name, + message->msg_namelen, rights); + if (result >= 0) + { + rights = RT_NULL; + } + if (buffer != RT_NULL) + { + error = rt_get_errno(); + rt_free(buffer); + rt_set_errno(error); + } + af_unix_rights_release(rights); + return result; +} + +static int af_unix_recvmsg(int handle, struct msghdr *message, int flags) +{ + int error; + int result; + int index; + size_t total = 0; + size_t offset = 0; + char *buffer = RT_NULL; + rt_list_t rights; + + if (message == RT_NULL || message->msg_iov == RT_NULL || + message->msg_iovlen < 0) + { + return af_unix_error(EINVAL); + } + + for (index = 0; index < message->msg_iovlen; index++) + { + if (SIZE_MAX - total < message->msg_iov[index].iov_len) + { + return af_unix_error(EMSGSIZE); + } + total += message->msg_iov[index].iov_len; + } + if (total != 0) + { + buffer = (char *)rt_malloc(total); + if (buffer == RT_NULL) + { + return af_unix_error(ENOMEM); + } + } + + rt_list_init(&rights); + message->msg_flags = 0; + result = af_unix_recvfrom_with_rights( + handle, buffer, total, flags, + (struct sockaddr *)message->msg_name, &message->msg_namelen, + &rights); + if (result >= 0) + { + size_t remaining = (size_t)result; + + for (index = 0; index < message->msg_iovlen && remaining != 0; index++) + { + size_t copy_length = message->msg_iov[index].iov_len; + + if (copy_length > remaining) + { + copy_length = remaining; + } + rt_memcpy(message->msg_iov[index].iov_base, + buffer + offset, copy_length); + offset += copy_length; + remaining -= copy_length; + } + if ((flags & MSG_PEEK) != 0) + { + message->msg_controllen = 0; + } + else + { + (void)af_unix_rights_deliver(&rights, message); + } + } + af_unix_rights_list_release(&rights); + if (buffer != RT_NULL) + { + error = rt_get_errno(); + rt_free(buffer); + rt_set_errno(error); + } + return result; +} + +static int af_unix_getsockname(int handle, struct sockaddr *address, + socklen_t *length) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + af_unix_lock(); + result = af_unix_address_copy(address, length, &sock->local_address, + sock->local_length); + af_unix_unlock(); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_getpeername(int handle, struct sockaddr *address, + socklen_t *length) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + af_unix_lock(); + if (!sock->connected) + { + result = af_unix_error(ENOTCONN); + } + else + { + result = af_unix_address_copy(address, length, &sock->peer_address, + sock->peer_length); + } + af_unix_unlock(); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_timeout_from_timeval(const struct timeval *time_value) +{ + long long milliseconds; + + if (time_value->tv_sec < 0 || time_value->tv_usec < 0 || + time_value->tv_usec >= 1000000) + { + return -2; + } + if (time_value->tv_sec == 0 && time_value->tv_usec == 0) + { + return RT_WAITING_FOREVER; + } + + milliseconds = (long long)time_value->tv_sec * 1000LL; + milliseconds += ((long long)time_value->tv_usec + 999LL) / 1000LL; + if (milliseconds > INT_MAX) + { + milliseconds = INT_MAX; + } + return (int)milliseconds; +} + +static void af_unix_timeval_from_timeout(int timeout, + struct timeval *time_value) +{ + if (timeout == RT_WAITING_FOREVER) + { + time_value->tv_sec = 0; + time_value->tv_usec = 0; + } + else + { + time_value->tv_sec = timeout / 1000; + time_value->tv_usec = (timeout % 1000) * 1000; + } +} + +static int af_unix_getsockopt(int handle, int level, int option, + void *value, socklen_t *length) +{ + int result = 0; + int int_value = 0; + struct timeval time_value; + struct af_unix_socket *sock; + + if (level != SOL_SOCKET || value == RT_NULL || length == RT_NULL) + { + return af_unix_error(EINVAL); + } + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + af_unix_lock(); + switch (option) + { + case SO_RCVTIMEO: + case SO_SNDTIMEO: + if (*length < sizeof(time_value)) + { + result = af_unix_error(EINVAL); + break; + } + af_unix_timeval_from_timeout(option == SO_RCVTIMEO ? + sock->receive_timeout : sock->send_timeout, + &time_value); + rt_memcpy(value, &time_value, sizeof(time_value)); + *length = sizeof(time_value); + break; + case SO_TYPE: + int_value = sock->type; + break; + case SO_DOMAIN: + int_value = AF_UNIX; + break; + case SO_PROTOCOL: + int_value = 0; + break; + case SO_ACCEPTCONN: + int_value = sock->listening; + break; + case SO_ERROR: + int_value = sock->socket_error; + sock->socket_error = 0; + break; + case SO_SNDBUF: + case SO_RCVBUF: + int_value = sock->type == SOCK_DGRAM ? AF_UNIX_DGRAM_MAX_SIZE : + AF_UNIX_STREAM_BUFFER_SIZE; + break; + default: + result = af_unix_error(ENOPROTOOPT); + break; + } + + if (result == 0 && option != SO_RCVTIMEO && option != SO_SNDTIMEO) + { + if (*length < sizeof(int_value)) + { + result = af_unix_error(EINVAL); + } + else + { + rt_memcpy(value, &int_value, sizeof(int_value)); + *length = sizeof(int_value); + } + } + af_unix_unlock(); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_setsockopt(int handle, int level, int option, + const void *value, socklen_t length) +{ + int result = 0; + int timeout; + const struct timeval *time_value; + struct af_unix_socket *sock; + + if (level != SOL_SOCKET || value == RT_NULL) + { + return af_unix_error(EINVAL); + } + if (option != SO_RCVTIMEO && option != SO_SNDTIMEO) + { + return af_unix_error(ENOPROTOOPT); + } + if (length < sizeof(struct timeval)) + { + return af_unix_error(EINVAL); + } + + time_value = (const struct timeval *)value; + timeout = af_unix_timeout_from_timeval(time_value); + if (timeout == -2) + { + return af_unix_error(EINVAL); + } + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + af_unix_lock(); + if (option == SO_RCVTIMEO) + { + sock->receive_timeout = timeout; + } + else + { + sock->send_timeout = timeout; + } + af_unix_unlock(); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_shutdown(int handle, int how) +{ + int result; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + if (sock->type == SOCK_STREAM) + { + result = af_unix_stream_shutdown(sock, how); + } + else + { + if (how < SHUT_RD || how > SHUT_RDWR) + { + result = af_unix_error(EINVAL); + } + else + { + af_unix_lock(); + if (how == SHUT_RD || how == SHUT_RDWR) + { + sock->read_shutdown = 1; + } + if (how == SHUT_WR || how == SHUT_RDWR) + { + sock->write_shutdown = 1; + } + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT)); + af_unix_unlock(); + result = 0; + } + } + af_unix_socket_put(sock); + return result; +} + +static int af_unix_ioctl(int handle, long command, void *argument) +{ + int result = 0; + struct af_unix_socket *sock; + + sock = af_unix_socket_get(handle); + if (sock == RT_NULL) + { + return -1; + } + + af_unix_lock(); + switch (command) + { + case F_GETFL: + result = sock->flags; + break; + case F_SETFL: + sock->flags &= ~O_NONBLOCK; + sock->flags |= ((int)(rt_base_t)argument & O_NONBLOCK); + break; + case FIONBIO: + if (argument == RT_NULL) + { + result = af_unix_error(EINVAL); + } + else if (*(int *)argument != 0) + { + sock->flags |= O_NONBLOCK; + } + else + { + sock->flags &= ~O_NONBLOCK; + } + break; + case FIONREAD: + if (argument == RT_NULL) + { + result = af_unix_error(EINVAL); + } + else if (sock->type == SOCK_STREAM) + { + *(int *)argument = (int)sock->stream_length; + } + else if (rt_list_isempty(&sock->message_queue)) + { + *(int *)argument = 0; + } + else + { + struct af_unix_message *message; + + message = rt_list_entry(sock->message_queue.next, + struct af_unix_message, node); + *(int *)argument = (int)message->length; + } + break; + default: + result = af_unix_error(EINVAL); + break; + } + af_unix_unlock(); + af_unix_socket_put(sock); + return result; +} + +static int af_unix_socketpair(int domain, int type, int protocol, int *handles) +{ + int result = -1; + struct af_unix_socket *first; + struct af_unix_socket *second; + + if (domain != AF_UNIX || protocol != 0 || handles == RT_NULL || + (type != SOCK_DGRAM && type != SOCK_STREAM)) + { + return af_unix_error(EINVAL); + } + + first = af_unix_socket_get(handles[0]); + if (first == RT_NULL) + { + return -1; + } + second = af_unix_socket_get(handles[1]); + if (second == RT_NULL) + { + af_unix_socket_put(first); + return -1; + } + + af_unix_lock(); + if (first->type != type || second->type != type || + first->closed || second->closed) + { + result = af_unix_error(EINVAL); + } + else + { + result = af_unix_connect_peers_locked(first, second); + if (result == 0) + { + af_unix_address_set(&first->peer_address, &first->peer_length, + RT_NULL); + af_unix_address_set(&second->peer_address, &second->peer_length, + RT_NULL); + } + } + af_unix_unlock(); + af_unix_socket_put(second); + af_unix_socket_put(first); + return result; +} + +static int af_unix_poll(struct dfs_file *file, struct rt_pollreq *request) +{ + int mask = 0; + int sal_handle; + struct sal_socket *sal_sock; + struct af_unix_socket *sock; + + sal_handle = (int)(size_t)file->vnode->data; + sal_sock = sal_get_socket(sal_handle); + if (sal_sock == RT_NULL) + { + return POLLNVAL; + } + sock = af_unix_socket_get((int)(size_t)sal_sock->user_data); + if (sock == RT_NULL) + { + return POLLNVAL; + } + + rt_poll_add(&sock->wait_queue, request); + af_unix_lock(); + if (sock->closed) + { + mask = POLLHUP | POLLERR; + } + else if (sock->listening) + { + if (sock->pending_count > 0) + { + mask |= POLLIN; + } + } + else if (sock->type == SOCK_DGRAM) + { + if (sock->message_count > 0 || sock->read_shutdown) + { + mask |= POLLIN; + } + if (!sock->write_shutdown) + { + if (sock->peer != RT_NULL) + { + rt_poll_add(&sock->peer->wait_queue, request); + if (!sock->peer->closed && + sock->peer->message_count < AF_UNIX_DGRAM_QUEUE_LEN) + { + mask |= POLLOUT; + } + } + else + { + mask |= POLLOUT; + } + } + } + else + { + if (sock->stream_length > 0 || sock->read_shutdown || + sock->peer == RT_NULL || sock->peer->write_shutdown || + sock->peer->closed) + { + mask |= POLLIN; + } + if (sock->peer != RT_NULL) + { + rt_poll_add(&sock->peer->wait_queue, request); + if (!sock->write_shutdown && !sock->peer->closed && + !sock->peer->read_shutdown && + sock->peer->stream_length < AF_UNIX_STREAM_BUFFER_SIZE) + { + mask |= POLLOUT; + } + if (sock->peer->closed) + { + mask |= POLLHUP; + } + } + else + { + mask |= POLLHUP; + } + } + af_unix_unlock(); + af_unix_socket_put(sock); + return mask; +} + +static const struct sal_socket_ops af_unix_socket_ops = +{ + .socket = af_unix_socket_create, + .closesocket = af_unix_close, + .bind = af_unix_bind, + .listen = af_unix_listen, + .connect = af_unix_connect, + .accept = af_unix_accept, + .sendto = af_unix_sendto, + .sendmsg = af_unix_sendmsg, + .recvmsg = af_unix_recvmsg, + .recvfrom = af_unix_recvfrom, + .getsockopt = af_unix_getsockopt, + .setsockopt = af_unix_setsockopt, + .shutdown = af_unix_shutdown, + .getpeername = af_unix_getpeername, + .getsockname = af_unix_getsockname, + .ioctlsocket = af_unix_ioctl, + .socketpair = af_unix_socketpair, + .poll = af_unix_poll, +}; + +static const struct sal_proto_family af_unix_family = +{ + .family = AF_UNIX, + .sec_family = AF_UNIX, + .skt_ops = &af_unix_socket_ops, + .netdb_ops = RT_NULL, +}; + +int af_unix_init(void) +{ + int result; + + rt_memset(af_unix_handles, 0, sizeof(af_unix_handles)); + rt_mutex_init(&af_unix_core_lock, "afunix", RT_IPC_FLAG_PRIO); + result = af_unix_rights_init(); + if (result != RT_EOK) + { + return result; + } + result = af_unix_namespace_init(); + if (result != RT_EOK) + { + return result; + } + return sal_proto_family_register(&af_unix_family); +} +INIT_ENV_EXPORT(af_unix_init); diff --git a/components/net/af_unix/src/af_unix_dgram.c b/components/net/af_unix/src/af_unix_dgram.c new file mode 100644 index 000000000000..ddbcbf72546f --- /dev/null +++ b/components/net/af_unix/src/af_unix_dgram.c @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "af_unix_internal.h" + +int af_unix_dgram_connect(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length) +{ + int result = 0; + struct sockaddr_un peer_address; + socklen_t peer_length; + struct af_unix_socket *peer; + + peer = af_unix_namespace_lookup(address, length, SOCK_DGRAM, + &peer_address, &peer_length); + if (peer == RT_NULL) + { + return -1; + } + + af_unix_lock(); + if (sock->closed) + { + result = af_unix_error(EBADF); + } + else if (sock->write_shutdown) + { + result = af_unix_error(EPIPE); + } + else + { + af_unix_set_peer_locked(sock, peer); + sock->peer_address = peer_address; + sock->peer_length = peer_length; + sock->connected = 1; + } + af_unix_unlock(); + af_unix_socket_put(peer); + return result; +} + +static struct af_unix_socket *af_unix_dgram_target_get( + struct af_unix_socket *sock, const struct sockaddr *to, + socklen_t to_length) +{ + struct af_unix_socket *peer = RT_NULL; + + if (to != RT_NULL) + { + return af_unix_namespace_lookup(to, to_length, SOCK_DGRAM, + RT_NULL, RT_NULL); + } + + af_unix_lock(); + if (sock->connected && sock->peer != RT_NULL) + { + peer = sock->peer; + af_unix_socket_ref_locked(peer); + } + af_unix_unlock(); + + if (peer == RT_NULL) + { + af_unix_error(EDESTADDRREQ); + } + return peer; +} + +int af_unix_dgram_send(struct af_unix_socket *sock, const void *data, + size_t size, int flags, const struct sockaddr *to, + socklen_t to_length, struct af_unix_rights *rights) +{ + int error; + int result; + int nonblocking; + int timeout; + struct af_unix_socket *peer; + struct af_unix_message *message; + + if (size > AF_UNIX_DGRAM_MAX_SIZE) + { + return af_unix_error(EMSGSIZE); + } + if (size != 0 && data == RT_NULL) + { + return af_unix_error(EINVAL); + } + + peer = af_unix_dgram_target_get(sock, to, to_length); + if (peer == RT_NULL) + { + return -1; + } + + message = (struct af_unix_message *)rt_malloc(sizeof(*message) + size); + if (message == RT_NULL) + { + af_unix_socket_put(peer); + return af_unix_error(ENOMEM); + } + rt_list_init(&message->node); + message->length = size; + message->rights = rights; + if (size != 0) + { + rt_memcpy(message->data, data, size); + } + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + result = af_unix_error(EBADF); + af_unix_unlock(); + break; + } + if (sock->write_shutdown) + { + result = af_unix_error(EPIPE); + af_unix_unlock(); + break; + } + if (peer->closed) + { + result = af_unix_error(ECONNREFUSED); + af_unix_unlock(); + break; + } + if (peer->read_shutdown) + { + result = af_unix_error(EPIPE); + af_unix_unlock(); + break; + } + if (peer->message_count < AF_UNIX_DGRAM_QUEUE_LEN) + { + message->source = sock->local_address; + message->source_length = sock->local_length; + rt_list_insert_before(&peer->message_queue, &message->node); + peer->message_count++; + rt_wqueue_wakeup_all(&peer->wait_queue, + (void *)(rt_ubase_t)POLLIN); + af_unix_unlock(); + af_unix_socket_put(peer); + return (int)size; + } + + nonblocking = af_unix_is_nonblocking(sock, flags); + timeout = sock->send_timeout; + af_unix_unlock(); + if (nonblocking) + { + result = af_unix_error(EAGAIN); + break; + } + if (af_unix_wait(&peer->wait_queue, timeout) < 0) + { + result = -1; + break; + } + } + + error = rt_get_errno(); + rt_free(message); + af_unix_socket_put(peer); + rt_set_errno(error); + return result; +} + +int af_unix_dgram_receive(struct af_unix_socket *sock, void *data, + size_t size, int flags, struct sockaddr *from, + socklen_t *from_length, rt_list_t *rights) +{ + int result; + int nonblocking; + int timeout; + size_t copy_length; + struct af_unix_message *message; + + if (size != 0 && data == RT_NULL) + { + return af_unix_error(EINVAL); + } + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + af_unix_unlock(); + return af_unix_error(EBADF); + } + if (!rt_list_isempty(&sock->message_queue)) + { + message = rt_list_entry(sock->message_queue.next, + struct af_unix_message, node); + copy_length = message->length; + if (copy_length > size) + { + copy_length = size; + } + if (copy_length != 0) + { + rt_memcpy(data, message->data, copy_length); + } + result = af_unix_address_copy(from, from_length, + &message->source, + message->source_length); + if (result < 0) + { + af_unix_unlock(); + return result; + } + if ((flags & MSG_PEEK) == 0) + { + rt_list_remove(&message->node); + sock->message_count--; + if (message->rights != RT_NULL) + { + rt_list_insert_before(rights, &message->rights->node); + message->rights = RT_NULL; + } + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)POLLOUT); + rt_free(message); + } + af_unix_unlock(); + return (int)copy_length; + } + if (sock->read_shutdown) + { + af_unix_unlock(); + return 0; + } + + nonblocking = af_unix_is_nonblocking(sock, flags); + timeout = sock->receive_timeout; + af_unix_unlock(); + if (nonblocking) + { + return af_unix_error(EAGAIN); + } + if (af_unix_wait(&sock->wait_queue, timeout) < 0) + { + return -1; + } + } +} diff --git a/components/net/af_unix/src/af_unix_internal.h b/components/net/af_unix/src/af_unix_internal.h new file mode 100644 index 000000000000..c24639a5bdaf --- /dev/null +++ b/components/net/af_unix/src/af_unix_internal.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AF_UNIX_INTERNAL_H__ +#define AF_UNIX_INTERNAL_H__ + +#include +#include +#include +#include +#include +#include + +#ifndef AF_UNIX_DGRAM_MAX_SIZE +#define AF_UNIX_DGRAM_MAX_SIZE 4096 +#endif + +#ifndef AF_UNIX_DGRAM_QUEUE_LEN +#define AF_UNIX_DGRAM_QUEUE_LEN 16 +#endif + +#ifndef AF_UNIX_STREAM_BUFFER_SIZE +#define AF_UNIX_STREAM_BUFFER_SIZE 4096 +#endif + +#ifndef AF_UNIX_LISTEN_BACKLOG_MAX +#define AF_UNIX_LISTEN_BACKLOG_MAX 16 +#endif + +#ifndef AF_UNIX_RIGHTS_MAX +#define AF_UNIX_RIGHTS_MAX 16 +#endif + +#define AF_UNIX_PATH_MAX ((int)sizeof(((struct sockaddr_un *)0)->sun_path)) + +struct af_unix_rights +{ + rt_list_t node; + rt_uint64_t offset; + size_t count; + struct dfs_file *files[1]; +}; + +struct af_unix_message +{ + rt_list_t node; + size_t length; + struct sockaddr_un source; + socklen_t source_length; + struct af_unix_rights *rights; + char data[1]; +}; + +struct af_unix_socket +{ + int handle; + int type; + int flags; + int ref_count; + int closed; + int bound; + int connected; + int listening; + int read_shutdown; + int write_shutdown; + int socket_error; + int receive_timeout; + int send_timeout; + + struct sockaddr_un local_address; + socklen_t local_length; + struct sockaddr_un peer_address; + socklen_t peer_length; + struct af_unix_socket *peer; + void *namespace_entry; + + rt_wqueue_t wait_queue; + rt_list_t message_queue; + rt_size_t message_count; + + char *stream_buffer; + rt_size_t stream_head; + rt_size_t stream_length; + rt_uint64_t stream_read_offset; + rt_uint64_t stream_write_offset; + rt_list_t rights_queue; + + rt_list_t pending_queue; + rt_list_t pending_node; + int pending; + int backlog; + int pending_count; +}; + +void af_unix_lock(void); +void af_unix_unlock(void); +int af_unix_error(int error); +int af_unix_is_nonblocking(const struct af_unix_socket *sock, int flags); +int af_unix_wait(rt_wqueue_t *queue, int timeout); + +int af_unix_rights_create(const struct msghdr *message, + struct af_unix_rights **rights); +void af_unix_rights_release(struct af_unix_rights *rights); +void af_unix_rights_list_release(rt_list_t *list); +void af_unix_rights_defer_locked(struct af_unix_rights *rights); +void af_unix_rights_list_defer_locked(rt_list_t *list); +void af_unix_rights_drain(void); +int af_unix_rights_deliver(rt_list_t *list, struct msghdr *message); +int af_unix_rights_init(void); + +struct af_unix_socket *af_unix_socket_create_locked(int type); +struct af_unix_socket *af_unix_socket_get(int handle); +void af_unix_socket_ref_locked(struct af_unix_socket *sock); +void af_unix_socket_unref_locked(struct af_unix_socket *sock); +void af_unix_socket_put(struct af_unix_socket *sock); +int af_unix_handle_alloc_locked(struct af_unix_socket *sock); +void af_unix_handle_remove_locked(struct af_unix_socket *sock); +void af_unix_socket_close_locked(struct af_unix_socket *sock); +int af_unix_connect_peers_locked(struct af_unix_socket *first, + struct af_unix_socket *second); +void af_unix_set_peer_locked(struct af_unix_socket *sock, + struct af_unix_socket *peer); + +int af_unix_address_parse(const struct sockaddr *address, socklen_t length, + char path[AF_UNIX_PATH_MAX]); +void af_unix_address_set(struct sockaddr_un *address, socklen_t *length, + const char *path); +int af_unix_address_copy(struct sockaddr *address, socklen_t *length, + const struct sockaddr_un *source, + socklen_t source_length); +int af_unix_namespace_bind(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length); +struct af_unix_socket *af_unix_namespace_lookup( + const struct sockaddr *address, socklen_t length, int type, + struct sockaddr_un *normalized_address, socklen_t *normalized_length); +void af_unix_namespace_detach_locked(struct af_unix_socket *sock); +int af_unix_namespace_init(void); + +int af_unix_dgram_connect(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length); +int af_unix_dgram_send(struct af_unix_socket *sock, const void *data, + size_t size, int flags, const struct sockaddr *to, + socklen_t to_length, struct af_unix_rights *rights); +int af_unix_dgram_receive(struct af_unix_socket *sock, void *data, + size_t size, int flags, struct sockaddr *from, + socklen_t *from_length, rt_list_t *rights); + +int af_unix_stream_listen(struct af_unix_socket *sock, int backlog); +int af_unix_stream_connect(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length); +int af_unix_stream_accept(struct af_unix_socket *sock, + struct sockaddr *address, socklen_t *length); +int af_unix_stream_send(struct af_unix_socket *sock, const void *data, + size_t size, int flags, + struct af_unix_rights *rights); +int af_unix_stream_receive(struct af_unix_socket *sock, void *data, + size_t size, int flags, rt_list_t *rights); +int af_unix_stream_shutdown(struct af_unix_socket *sock, int how); + +#endif /* AF_UNIX_INTERNAL_H__ */ diff --git a/components/net/af_unix/src/af_unix_namespace.c b/components/net/af_unix/src/af_unix_namespace.c new file mode 100644 index 000000000000..db4c6fafab6f --- /dev/null +++ b/components/net/af_unix/src/af_unix_namespace.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "af_unix_internal.h" + +struct af_unix_namespace_entry +{ + rt_list_t node; + char path[AF_UNIX_PATH_MAX]; + struct af_unix_socket *sock; +}; + +static rt_list_t af_unix_namespace; + +static struct af_unix_namespace_entry *af_unix_namespace_find_locked( + const char *path) +{ + struct af_unix_namespace_entry *entry; + + rt_list_for_each_entry(entry, &af_unix_namespace, node) + { + if (rt_strcmp(entry->path, path) == 0) + { + return entry; + } + } + return RT_NULL; +} + +int af_unix_address_parse(const struct sockaddr *address, socklen_t length, + char path[AF_UNIX_PATH_MAX]) +{ + int index; + int path_length; + char input_path[AF_UNIX_PATH_MAX]; + char *normalized; + const struct sockaddr_un *unix_address; + const int path_offset = (int)offsetof(struct sockaddr_un, sun_path); + + if (address == RT_NULL || length <= (socklen_t)path_offset || + length > sizeof(struct sockaddr_un)) + { + return af_unix_error(EINVAL); + } + + unix_address = (const struct sockaddr_un *)address; + if (unix_address->sa_family != AF_UNIX) + { + return af_unix_error(EAFNOSUPPORT); + } + + path_length = (int)length - path_offset; + if (path_length > AF_UNIX_PATH_MAX) + { + path_length = AF_UNIX_PATH_MAX; + } + for (index = 0; index < path_length; index++) + { + if (unix_address->sun_path[index] == '\0') + { + break; + } + } + if (index == 0) + { + return af_unix_error(EINVAL); + } + if (index == path_length || index >= AF_UNIX_PATH_MAX) + { + return af_unix_error(ENAMETOOLONG); + } + + rt_memcpy(input_path, unix_address->sun_path, index); + input_path[index] = '\0'; + normalized = dfs_normalize_path(RT_NULL, input_path); + if (normalized == RT_NULL) + { + return af_unix_error(ENOMEM); + } + if (rt_strlen(normalized) >= AF_UNIX_PATH_MAX) + { + rt_free(normalized); + return af_unix_error(ENAMETOOLONG); + } + rt_strncpy(path, normalized, AF_UNIX_PATH_MAX); + path[AF_UNIX_PATH_MAX - 1] = '\0'; + rt_free(normalized); + return 0; +} + +void af_unix_address_set(struct sockaddr_un *address, socklen_t *length, + const char *path) +{ + size_t path_length = 0; + + rt_memset(address, 0, sizeof(*address)); + address->sa_family = AF_UNIX; + if (path != RT_NULL) + { + path_length = rt_strlen(path); + if (path_length >= sizeof(address->sun_path)) + { + path_length = sizeof(address->sun_path) - 1; + } + rt_memcpy(address->sun_path, path, path_length); + } + *length = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + + path_length + (path != RT_NULL ? 1 : 0)); +} + +int af_unix_address_copy(struct sockaddr *address, socklen_t *length, + const struct sockaddr_un *source, + socklen_t source_length) +{ + socklen_t copy_length; + + if (address == RT_NULL) + { + return 0; + } + if (length == RT_NULL) + { + return af_unix_error(EINVAL); + } + + copy_length = *length; + if (copy_length > source_length) + { + copy_length = source_length; + } + if (copy_length > 0) + { + rt_memcpy(address, source, copy_length); + } + *length = source_length; + return 0; +} + +int af_unix_namespace_bind(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length) +{ + int result; + char path[AF_UNIX_PATH_MAX]; + struct af_unix_namespace_entry *entry; + struct af_unix_namespace_entry *new_entry; + + result = af_unix_address_parse(address, length, path); + if (result < 0) + { + return result; + } + + af_unix_lock(); + if (sock->closed) + { + af_unix_unlock(); + return af_unix_error(EBADF); + } + if (sock->bound) + { + af_unix_unlock(); + return af_unix_error(EINVAL); + } + af_unix_unlock(); + + result = dfs_file_mknod(path, FT_SOCKET, + S_IRWXU | S_IRWXG | S_IRWXO); + if (result < 0) + { + return af_unix_error(result == -EEXIST ? EADDRINUSE : -result); + } + + new_entry = (struct af_unix_namespace_entry *)rt_calloc(1, + sizeof(*new_entry)); + if (new_entry == RT_NULL) + { + (void)dfs_file_unlink(path); + return af_unix_error(ENOMEM); + } + rt_strncpy(new_entry->path, path, sizeof(new_entry->path)); + new_entry->path[sizeof(new_entry->path) - 1] = '\0'; + rt_list_init(&new_entry->node); + + af_unix_lock(); + if (sock->closed || sock->bound) + { + af_unix_unlock(); + rt_free(new_entry); + (void)dfs_file_unlink(path); + return af_unix_error(sock->closed ? EBADF : EINVAL); + } + + entry = af_unix_namespace_find_locked(path); + if (entry == RT_NULL) + { + entry = new_entry; + new_entry = RT_NULL; + rt_list_insert_before(&af_unix_namespace, &entry->node); + } + entry->sock = sock; + sock->namespace_entry = entry; + sock->bound = 1; + af_unix_address_set(&sock->local_address, &sock->local_length, path); + af_unix_unlock(); + + if (new_entry != RT_NULL) + { + rt_free(new_entry); + } + return 0; +} + +struct af_unix_socket *af_unix_namespace_lookup( + const struct sockaddr *address, socklen_t length, int type, + struct sockaddr_un *normalized_address, socklen_t *normalized_length) +{ + int result; + char path[AF_UNIX_PATH_MAX]; + struct stat file_stat; + struct af_unix_socket *sock = RT_NULL; + struct af_unix_namespace_entry *entry; + + result = af_unix_address_parse(address, length, path); + if (result < 0) + { + return RT_NULL; + } + result = dfs_file_stat(path, &file_stat); + if (result < 0) + { + af_unix_error(ENOENT); + return RT_NULL; + } + if (!S_ISSOCK(file_stat.st_mode)) + { + af_unix_error(EPROTOTYPE); + return RT_NULL; + } + + af_unix_lock(); + entry = af_unix_namespace_find_locked(path); + if (entry != RT_NULL && entry->sock != RT_NULL && !entry->sock->closed) + { + if (entry->sock->type == type) + { + sock = entry->sock; + af_unix_socket_ref_locked(sock); + } + else + { + af_unix_error(EPROTOTYPE); + } + } + else + { + af_unix_error(ECONNREFUSED); + } + af_unix_unlock(); + + if (sock != RT_NULL && normalized_address != RT_NULL && + normalized_length != RT_NULL) + { + af_unix_address_set(normalized_address, normalized_length, path); + } + return sock; +} + +void af_unix_namespace_detach_locked(struct af_unix_socket *sock) +{ + struct af_unix_namespace_entry *entry; + + entry = (struct af_unix_namespace_entry *)sock->namespace_entry; + if (entry != RT_NULL && entry->sock == sock) + { + entry->sock = RT_NULL; + } + sock->namespace_entry = RT_NULL; +} + +int af_unix_namespace_init(void) +{ + rt_list_init(&af_unix_namespace); + return RT_EOK; +} diff --git a/components/net/af_unix/src/af_unix_rights.c b/components/net/af_unix/src/af_unix_rights.c new file mode 100644 index 000000000000..56ccdd5a80ec --- /dev/null +++ b/components/net/af_unix/src/af_unix_rights.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "af_unix_internal.h" + +static struct rt_mutex af_unix_deferred_lock; +static rt_list_t af_unix_deferred_rights; + +static size_t af_unix_cmsg_next(size_t offset, size_t length, + size_t control_length) +{ + size_t next; + + next = offset + CMSG_ALIGN(length); + if (next > control_length) + { + next = offset + length; + } + return next; +} + +int af_unix_rights_create(const struct msghdr *message, + struct af_unix_rights **out_rights) +{ + int fds[AF_UNIX_RIGHTS_MAX]; + int result; + size_t count = 0; + size_t offset = 0; + const char *control; + struct af_unix_rights *rights; + + *out_rights = RT_NULL; + if (message->msg_controllen == 0) + { + return 0; + } + if (message->msg_control == RT_NULL) + { + return af_unix_error(EINVAL); + } + + control = (const char *)message->msg_control; + while (offset < message->msg_controllen) + { + size_t data_length; + size_t fd_count; + size_t index; + size_t next; + const struct cmsghdr *cmsg; + + if (message->msg_controllen - offset < sizeof(*cmsg)) + { + return af_unix_error(EINVAL); + } + cmsg = (const struct cmsghdr *)(control + offset); + if (cmsg->cmsg_len < sizeof(*cmsg) || + cmsg->cmsg_len > message->msg_controllen - offset) + { + return af_unix_error(EINVAL); + } + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) + { + return af_unix_error(EOPNOTSUPP); + } + + data_length = cmsg->cmsg_len - sizeof(*cmsg); + if (data_length == 0 || data_length % sizeof(int) != 0) + { + return af_unix_error(EINVAL); + } + fd_count = data_length / sizeof(int); + if (fd_count > AF_UNIX_RIGHTS_MAX - count) + { + return af_unix_error(EMSGSIZE); + } + for (index = 0; index < fd_count; index++) + { + rt_memcpy(&fds[count], + (const char *)CMSG_DATA(cmsg) + index * sizeof(int), + sizeof(int)); + count++; + } + + next = af_unix_cmsg_next(offset, cmsg->cmsg_len, + message->msg_controllen); + if (next <= offset || next > message->msg_controllen) + { + return af_unix_error(EINVAL); + } + offset = next; + } + + rights = (struct af_unix_rights *)rt_calloc( + 1, sizeof(*rights) + (count - 1) * sizeof(rights->files[0])); + if (rights == RT_NULL) + { + return af_unix_error(ENOMEM); + } + rt_list_init(&rights->node); + rights->count = count; + + result = dfs_file_get_refs(fds, count, rights->files); + if (result < 0) + { + rt_free(rights); + return af_unix_error(-result); + } + + *out_rights = rights; + return 0; +} + +void af_unix_rights_release(struct af_unix_rights *rights) +{ + size_t index; + + if (rights == RT_NULL) + { + return; + } + for (index = 0; index < rights->count; index++) + { + if (rights->files[index] != RT_NULL) + { + dfs_file_put_ref(rights->files[index]); + } + } + rt_free(rights); +} + +void af_unix_rights_list_release(rt_list_t *list) +{ + while (!rt_list_isempty(list)) + { + struct af_unix_rights *rights; + + rights = rt_list_entry(list->next, struct af_unix_rights, node); + rt_list_remove(&rights->node); + af_unix_rights_release(rights); + } +} + +void af_unix_rights_defer_locked(struct af_unix_rights *rights) +{ + if (rights == RT_NULL) + { + return; + } + + rt_mutex_take(&af_unix_deferred_lock, RT_WAITING_FOREVER); + rt_list_insert_before(&af_unix_deferred_rights, &rights->node); + rt_mutex_release(&af_unix_deferred_lock); +} + +void af_unix_rights_list_defer_locked(rt_list_t *list) +{ + while (!rt_list_isempty(list)) + { + struct af_unix_rights *rights; + + rights = rt_list_entry(list->next, struct af_unix_rights, node); + rt_list_remove(&rights->node); + af_unix_rights_defer_locked(rights); + } +} + +void af_unix_rights_drain(void) +{ + rt_list_t pending; + + rt_list_init(&pending); + rt_mutex_take(&af_unix_deferred_lock, RT_WAITING_FOREVER); + while (!rt_list_isempty(&af_unix_deferred_rights)) + { + rt_list_t *node = af_unix_deferred_rights.next; + + rt_list_remove(node); + rt_list_insert_before(&pending, node); + } + rt_mutex_release(&af_unix_deferred_lock); + + af_unix_rights_list_release(&pending); +} + +static size_t af_unix_rights_count(const rt_list_t *list) +{ + size_t count = 0; + const rt_list_t *node; + + for (node = list->next; node != list; node = node->next) + { + const struct af_unix_rights *rights; + + rights = rt_list_entry(node, struct af_unix_rights, node); + count += rights->count; + } + return count; +} + +static size_t af_unix_rights_capacity(const struct msghdr *message, + size_t total) +{ + size_t capacity; + + if (message->msg_control == RT_NULL || + message->msg_controllen < CMSG_SPACE(sizeof(int))) + { + return 0; + } + + capacity = (message->msg_controllen - sizeof(struct cmsghdr)) / + sizeof(int); + if (capacity > total) + { + capacity = total; + } + while (capacity != 0 && + CMSG_SPACE(capacity * sizeof(int)) > message->msg_controllen) + { + capacity--; + } + return capacity; +} + +int af_unix_rights_deliver(rt_list_t *list, struct msghdr *message) +{ + int install_result = 0; + int *fds = RT_NULL; + size_t capacity; + size_t delivered = 0; + size_t index; + size_t total; + struct dfs_file **files = RT_NULL; + struct cmsghdr *cmsg; + rt_list_t *node; + + total = af_unix_rights_count(list); + capacity = af_unix_rights_capacity(message, total); + if (capacity != 0) + { + files = (struct dfs_file **)rt_malloc(capacity * sizeof(*files)); + fds = (int *)rt_malloc(capacity * sizeof(*fds)); + if (files == RT_NULL || fds == RT_NULL) + { + capacity = 0; + } + } + + for (node = list->next; node != list && delivered < capacity; + node = node->next) + { + struct af_unix_rights *rights; + + rights = rt_list_entry(node, struct af_unix_rights, node); + for (index = 0; index < rights->count && delivered < capacity; index++) + { + files[delivered] = rights->files[index]; + delivered++; + } + } + + if (delivered != 0) + { + install_result = dfs_file_install_refs(files, delivered, fds); + if (install_result < 0) + { + delivered = 0; + } + } + + if (delivered != 0) + { + size_t transferred = 0; + + for (node = list->next; node != list && transferred < delivered; + node = node->next) + { + struct af_unix_rights *rights; + + rights = rt_list_entry(node, struct af_unix_rights, node); + for (index = 0; + index < rights->count && transferred < delivered; index++) + { + rights->files[index] = RT_NULL; + transferred++; + } + } + + cmsg = (struct cmsghdr *)message->msg_control; + cmsg->cmsg_len = CMSG_LEN(delivered * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + rt_memcpy(CMSG_DATA(cmsg), fds, delivered * sizeof(int)); + message->msg_controllen = CMSG_SPACE(delivered * sizeof(int)); + } + else + { + message->msg_controllen = 0; + } + + if (delivered < total) + { + message->msg_flags |= MSG_CTRUNC; + } + + if (files != RT_NULL) + { + rt_free(files); + } + if (fds != RT_NULL) + { + rt_free(fds); + } + af_unix_rights_list_release(list); + return install_result; +} + +int af_unix_rights_init(void) +{ + rt_list_init(&af_unix_deferred_rights); + return rt_mutex_init(&af_unix_deferred_lock, "afuright", + RT_IPC_FLAG_PRIO); +} diff --git a/components/net/af_unix/src/af_unix_stream.c b/components/net/af_unix/src/af_unix_stream.c new file mode 100644 index 000000000000..b82dcfc2649e --- /dev/null +++ b/components/net/af_unix/src/af_unix_stream.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "af_unix_internal.h" + +static void af_unix_stream_buffer_write_locked(struct af_unix_socket *sock, + const char *data, + size_t length) +{ + size_t first_length; + size_t tail; + + tail = (sock->stream_head + sock->stream_length) % + AF_UNIX_STREAM_BUFFER_SIZE; + first_length = AF_UNIX_STREAM_BUFFER_SIZE - tail; + if (first_length > length) + { + first_length = length; + } + rt_memcpy(sock->stream_buffer + tail, data, first_length); + if (length > first_length) + { + rt_memcpy(sock->stream_buffer, data + first_length, + length - first_length); + } + sock->stream_length += length; + sock->stream_write_offset += length; +} + +static void af_unix_stream_buffer_read_locked(struct af_unix_socket *sock, + char *data, size_t length, + int peek) +{ + size_t first_length; + + first_length = AF_UNIX_STREAM_BUFFER_SIZE - sock->stream_head; + if (first_length > length) + { + first_length = length; + } + rt_memcpy(data, sock->stream_buffer + sock->stream_head, first_length); + if (length > first_length) + { + rt_memcpy(data + first_length, sock->stream_buffer, + length - first_length); + } + + if (!peek) + { + sock->stream_head = (sock->stream_head + length) % + AF_UNIX_STREAM_BUFFER_SIZE; + sock->stream_length -= length; + sock->stream_read_offset += length; + } +} + +static void af_unix_stream_collect_rights_locked(struct af_unix_socket *sock, + rt_list_t *rights) +{ + while (!rt_list_isempty(&sock->rights_queue)) + { + struct af_unix_rights *entry; + + entry = rt_list_entry(sock->rights_queue.next, + struct af_unix_rights, node); + if (entry->offset >= sock->stream_read_offset) + { + break; + } + rt_list_remove(&entry->node); + rt_list_insert_before(rights, &entry->node); + } +} + +int af_unix_stream_listen(struct af_unix_socket *sock, int backlog) +{ + int result = 0; + + af_unix_lock(); + if (sock->closed) + { + result = af_unix_error(EBADF); + } + else if (sock->type != SOCK_STREAM) + { + result = af_unix_error(EOPNOTSUPP); + } + else if (!sock->bound) + { + result = af_unix_error(EINVAL); + } + else if (sock->connected) + { + result = af_unix_error(EINVAL); + } + else + { + if (backlog < 1) + { + backlog = 1; + } + if (backlog > AF_UNIX_LISTEN_BACKLOG_MAX) + { + backlog = AF_UNIX_LISTEN_BACKLOG_MAX; + } + sock->backlog = backlog; + sock->listening = 1; + } + af_unix_unlock(); + return result; +} + +int af_unix_stream_connect(struct af_unix_socket *sock, + const struct sockaddr *address, socklen_t length) +{ + int handle; + int nonblocking; + int timeout; + int result = -1; + struct sockaddr_un peer_address; + socklen_t peer_length; + struct af_unix_socket *listener; + struct af_unix_socket *accepted; + + listener = af_unix_namespace_lookup(address, length, SOCK_STREAM, + &peer_address, &peer_length); + if (listener == RT_NULL) + { + return -1; + } + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + result = af_unix_error(EBADF); + af_unix_unlock(); + break; + } + if (sock->connected) + { + result = af_unix_error(EISCONN); + af_unix_unlock(); + break; + } + if (listener->closed || !listener->listening) + { + result = af_unix_error(ECONNREFUSED); + af_unix_unlock(); + break; + } + if (listener->pending_count < listener->backlog) + { + accepted = af_unix_socket_create_locked(SOCK_STREAM); + if (accepted == RT_NULL) + { + result = af_unix_error(ENOMEM); + af_unix_unlock(); + break; + } + handle = af_unix_handle_alloc_locked(accepted); + if (handle < 0) + { + af_unix_socket_unref_locked(accepted); + result = af_unix_error(EMFILE); + af_unix_unlock(); + break; + } + + result = af_unix_connect_peers_locked(sock, accepted); + if (result < 0) + { + af_unix_handle_remove_locked(accepted); + af_unix_unlock(); + break; + } + + sock->peer_address = peer_address; + sock->peer_length = peer_length; + accepted->local_address = listener->local_address; + accepted->local_length = listener->local_length; + accepted->peer_address = sock->local_address; + accepted->peer_length = sock->local_length; + accepted->pending = 1; + rt_list_insert_before(&listener->pending_queue, + &accepted->pending_node); + listener->pending_count++; + rt_wqueue_wakeup_all(&listener->wait_queue, + (void *)(rt_ubase_t)POLLIN); + af_unix_unlock(); + result = 0; + break; + } + + nonblocking = af_unix_is_nonblocking(sock, 0); + timeout = sock->send_timeout; + af_unix_unlock(); + if (nonblocking) + { + result = af_unix_error(EAGAIN); + break; + } + if (af_unix_wait(&listener->wait_queue, timeout) < 0) + { + result = -1; + break; + } + } + + af_unix_socket_put(listener); + return result; +} + +int af_unix_stream_accept(struct af_unix_socket *sock, + struct sockaddr *address, socklen_t *length) +{ + int handle; + int nonblocking; + int timeout; + int result; + struct af_unix_socket *accepted; + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + af_unix_unlock(); + return af_unix_error(EBADF); + } + if (!sock->listening) + { + af_unix_unlock(); + return af_unix_error(EINVAL); + } + if (!rt_list_isempty(&sock->pending_queue)) + { + accepted = rt_list_entry(sock->pending_queue.next, + struct af_unix_socket, pending_node); + result = af_unix_address_copy(address, length, + &accepted->peer_address, + accepted->peer_length); + if (result < 0) + { + af_unix_unlock(); + return result; + } + rt_list_remove(&accepted->pending_node); + accepted->pending = 0; + sock->pending_count--; + handle = accepted->handle; + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)POLLOUT); + af_unix_unlock(); + return handle; + } + + nonblocking = af_unix_is_nonblocking(sock, 0); + timeout = sock->receive_timeout; + af_unix_unlock(); + if (nonblocking) + { + return af_unix_error(EAGAIN); + } + if (af_unix_wait(&sock->wait_queue, timeout) < 0) + { + return -1; + } + } +} + +int af_unix_stream_send(struct af_unix_socket *sock, const void *data, + size_t size, int flags, + struct af_unix_rights *rights) +{ + int nonblocking; + int timeout; + size_t copy_length; + size_t space; + struct af_unix_socket *peer; + + if (size != 0 && data == RT_NULL) + { + return af_unix_error(EINVAL); + } + if (size == 0) + { + return 0; + } + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + af_unix_unlock(); + return af_unix_error(EBADF); + } + if (sock->write_shutdown) + { + af_unix_unlock(); + return af_unix_error(EPIPE); + } + peer = sock->peer; + if (!sock->connected || peer == RT_NULL) + { + af_unix_unlock(); + return af_unix_error(ENOTCONN); + } + if (peer->closed || peer->read_shutdown) + { + af_unix_unlock(); + return af_unix_error(EPIPE); + } + + space = AF_UNIX_STREAM_BUFFER_SIZE - peer->stream_length; + if (space != 0) + { + copy_length = size; + if (copy_length > space) + { + copy_length = space; + } + if (rights != RT_NULL) + { + rights->offset = peer->stream_write_offset; + rt_list_insert_before(&peer->rights_queue, &rights->node); + } + af_unix_stream_buffer_write_locked(peer, (const char *)data, + copy_length); + rt_wqueue_wakeup_all(&peer->wait_queue, + (void *)(rt_ubase_t)POLLIN); + af_unix_unlock(); + return (int)copy_length; + } + + nonblocking = af_unix_is_nonblocking(sock, flags); + timeout = sock->send_timeout; + af_unix_socket_ref_locked(peer); + af_unix_unlock(); + if (nonblocking) + { + af_unix_socket_put(peer); + return af_unix_error(EAGAIN); + } + if (af_unix_wait(&peer->wait_queue, timeout) < 0) + { + af_unix_socket_put(peer); + return -1; + } + af_unix_socket_put(peer); + } +} + +int af_unix_stream_receive(struct af_unix_socket *sock, void *data, + size_t size, int flags, rt_list_t *rights) +{ + int nonblocking; + int timeout; + int wait_all; + size_t copy_length; + size_t received = 0; + struct af_unix_socket *peer; + + if (size != 0 && data == RT_NULL) + { + return af_unix_error(EINVAL); + } + if (size == 0) + { + return 0; + } + wait_all = ((flags & MSG_WAITALL) != 0 && (flags & MSG_PEEK) == 0); + + for (;;) + { + af_unix_lock(); + if (sock->closed) + { + af_unix_unlock(); + return received != 0 ? (int)received : af_unix_error(EBADF); + } + if (sock->read_shutdown) + { + af_unix_unlock(); + return (int)received; + } + if (sock->stream_length != 0) + { + copy_length = size - received; + if (copy_length > sock->stream_length) + { + copy_length = sock->stream_length; + } + af_unix_stream_buffer_read_locked(sock, + (char *)data + received, + copy_length, + (flags & MSG_PEEK) != 0); + received += copy_length; + if ((flags & MSG_PEEK) == 0) + { + af_unix_stream_collect_rights_locked(sock, rights); + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)POLLOUT); + } + if (!wait_all || received == size) + { + af_unix_unlock(); + return (int)received; + } + } + + peer = sock->peer; + if (peer == RT_NULL || peer->closed || peer->write_shutdown) + { + af_unix_unlock(); + return (int)received; + } + + nonblocking = af_unix_is_nonblocking(sock, flags); + timeout = sock->receive_timeout; + af_unix_unlock(); + if (nonblocking) + { + return received != 0 ? (int)received : af_unix_error(EAGAIN); + } + if (af_unix_wait(&sock->wait_queue, timeout) < 0) + { + return received != 0 ? (int)received : -1; + } + } +} + +int af_unix_stream_shutdown(struct af_unix_socket *sock, int how) +{ + int result = 0; + struct af_unix_socket *peer; + + if (how < SHUT_RD || how > SHUT_RDWR) + { + return af_unix_error(EINVAL); + } + + af_unix_lock(); + if (sock->closed) + { + result = af_unix_error(EBADF); + } + else if (!sock->connected) + { + result = af_unix_error(ENOTCONN); + } + else + { + if (how == SHUT_RD || how == SHUT_RDWR) + { + sock->read_shutdown = 1; + sock->stream_head = 0; + sock->stream_read_offset += sock->stream_length; + sock->stream_length = 0; + af_unix_rights_list_defer_locked(&sock->rights_queue); + } + if (how == SHUT_WR || how == SHUT_RDWR) + { + sock->write_shutdown = 1; + } + rt_wqueue_wakeup_all(&sock->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT)); + peer = sock->peer; + if (peer != RT_NULL) + { + rt_wqueue_wakeup_all(&peer->wait_queue, + (void *)(rt_ubase_t)(POLLIN | POLLOUT)); + } + } + af_unix_unlock(); + return result; +} diff --git a/components/net/af_unix/testcases/af_unix_test.c b/components/net/af_unix/testcases/af_unix_test.c new file mode 100644 index 000000000000..8efde7b7aee3 --- /dev/null +++ b/components/net/af_unix/testcases/af_unix_test.c @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2006-2026, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AF_UNIX_DGRAM_SERVER_PATH "/dev/afudgs" +#define AF_UNIX_DGRAM_CLIENT_PATH "/dev/afudgc" +#define AF_UNIX_STREAM_PATH "/dev/afustr" +#define AF_UNIX_PENDING_PATH "/dev/afupend" +#define AF_UNIX_PERSIST_PATH "/var/afupath" + +static void af_unix_make_address(struct sockaddr_un *address, + const char *path) +{ + rt_memset(address, 0, sizeof(*address)); + address->sa_family = AF_UNIX; + rt_strncpy(address->sun_path, path, sizeof(address->sun_path) - 1); +} + +static int af_unix_send_rights(int socket_fd, const int *fds, size_t fd_count, + char payload) +{ + char control[CMSG_SPACE(2 * sizeof(int))]; + struct cmsghdr *cmsg; + struct iovec iov; + struct msghdr message; + + rt_memset(&message, 0, sizeof(message)); + rt_memset(control, 0, sizeof(control)); + iov.iov_base = &payload; + iov.iov_len = sizeof(payload); + message.msg_iov = &iov; + message.msg_iovlen = 1; + message.msg_control = control; + message.msg_controllen = CMSG_SPACE(fd_count * sizeof(int)); + cmsg = CMSG_FIRSTHDR(&message); + cmsg->cmsg_len = CMSG_LEN(fd_count * sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + rt_memcpy(CMSG_DATA(cmsg), fds, fd_count * sizeof(int)); + return sendmsg(socket_fd, &message, 0); +} + +static int af_unix_receive_rights(int socket_fd, int flags, + size_t control_length, int *fds, + size_t *fd_count, int *message_flags, + char *payload) +{ + char control[CMSG_SPACE(2 * sizeof(int))]; + int result; + size_t count = 0; + struct cmsghdr *cmsg; + struct iovec iov; + struct msghdr message; + + rt_memset(&message, 0, sizeof(message)); + rt_memset(control, 0, sizeof(control)); + iov.iov_base = payload; + iov.iov_len = sizeof(*payload); + message.msg_iov = &iov; + message.msg_iovlen = 1; + message.msg_control = control_length != 0 ? control : RT_NULL; + message.msg_controllen = control_length; + + result = recvmsg(socket_fd, &message, flags); + if (result >= 0) + { + cmsg = CMSG_FIRSTHDR(&message); + if (cmsg != RT_NULL && cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len >= CMSG_LEN(sizeof(int))) + { + count = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(int); + rt_memcpy(fds, CMSG_DATA(cmsg), count * sizeof(int)); + } + *fd_count = count; + *message_flags = message.msg_flags; + } + return result; +} + +static void af_unix_test_dgram(void) +{ + int server = -1; + int client = -1; + int error; + int result; + char buffer[16]; + const char payload[] = "datagram"; + struct sockaddr_un server_address; + struct sockaddr_un client_address; + struct sockaddr_un source_address; + socklen_t source_length; + + (void)unlink(AF_UNIX_DGRAM_SERVER_PATH); + (void)unlink(AF_UNIX_DGRAM_CLIENT_PATH); + af_unix_make_address(&server_address, AF_UNIX_DGRAM_SERVER_PATH); + af_unix_make_address(&client_address, AF_UNIX_DGRAM_CLIENT_PATH); + + server = socket(AF_UNIX, SOCK_DGRAM, 0); + client = socket(AF_UNIX, SOCK_DGRAM, 0); + uassert_true(server >= 0); + uassert_true(client >= 0); + if (server < 0 || client < 0) + { + goto __exit; + } + + uassert_int_equal(bind(server, (struct sockaddr *)&server_address, + sizeof(server_address)), 0); + uassert_int_equal(bind(client, (struct sockaddr *)&client_address, + sizeof(client_address)), 0); + uassert_int_equal(connect(client, (struct sockaddr *)&server_address, + sizeof(server_address)), 0); + uassert_int_equal(send(client, payload, sizeof(payload), 0), + sizeof(payload)); + + source_length = sizeof(source_address); + result = recvfrom(server, buffer, sizeof(buffer), 0, + (struct sockaddr *)&source_address, &source_length); + uassert_int_equal(result, sizeof(payload)); + uassert_buf_equal(buffer, payload, sizeof(payload)); + uassert_str_equal(source_address.sun_path, AF_UNIX_DGRAM_CLIENT_PATH); + + result = fcntl(server, F_SETFL, O_NONBLOCK); + uassert_int_equal(result, 0); + result = recv(server, buffer, sizeof(buffer), 0); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_true(error == EAGAIN || error == EWOULDBLOCK); + +__exit: + if (client >= 0) + { + closesocket(client); + } + if (server >= 0) + { + closesocket(server); + } + (void)unlink(AF_UNIX_DGRAM_CLIENT_PATH); + (void)unlink(AF_UNIX_DGRAM_SERVER_PATH); +} + +static void af_unix_test_pathname_lifetime(void) +{ + int first = -1; + int second = -1; + int error; + int result; + struct stat file_stat; + struct sockaddr_un address; + + (void)unlink(AF_UNIX_PERSIST_PATH); + af_unix_make_address(&address, AF_UNIX_PERSIST_PATH); + + first = socket(AF_UNIX, SOCK_DGRAM, 0); + uassert_true(first >= 0); + if (first < 0) + { + goto __exit; + } + uassert_int_equal(bind(first, (struct sockaddr *)&address, + sizeof(address)), 0); + uassert_int_equal(stat(AF_UNIX_PERSIST_PATH, &file_stat), 0); + uassert_true(S_ISSOCK(file_stat.st_mode)); + + closesocket(first); + first = -1; + uassert_int_equal(stat(AF_UNIX_PERSIST_PATH, &file_stat), 0); + uassert_true(S_ISSOCK(file_stat.st_mode)); + + second = socket(AF_UNIX, SOCK_DGRAM, 0); + uassert_true(second >= 0); + if (second < 0) + { + goto __exit; + } + result = bind(second, (struct sockaddr *)&address, sizeof(address)); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_int_equal(error, EADDRINUSE); + + uassert_int_equal(unlink(AF_UNIX_PERSIST_PATH), 0); + uassert_int_equal(bind(second, (struct sockaddr *)&address, + sizeof(address)), 0); + +__exit: + if (second >= 0) + { + closesocket(second); + } + if (first >= 0) + { + closesocket(first); + } + (void)unlink(AF_UNIX_PERSIST_PATH); +} + +static void af_unix_test_stream(void) +{ + int listener = -1; + int client = -1; + int accepted = -1; + char buffer[16]; + const char request[] = "request"; + const char response[] = "response"; + struct sockaddr_un address; + + (void)unlink(AF_UNIX_STREAM_PATH); + af_unix_make_address(&address, AF_UNIX_STREAM_PATH); + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + client = socket(AF_UNIX, SOCK_STREAM, 0); + uassert_true(listener >= 0); + uassert_true(client >= 0); + if (listener < 0 || client < 0) + { + goto __exit; + } + + uassert_int_equal(bind(listener, (struct sockaddr *)&address, + sizeof(address)), 0); + uassert_int_equal(listen(listener, 2), 0); + uassert_int_equal(connect(client, (struct sockaddr *)&address, + sizeof(address)), 0); + accepted = accept(listener, RT_NULL, RT_NULL); + uassert_true(accepted >= 0); + if (accepted < 0) + { + goto __exit; + } + + uassert_int_equal(send(client, request, sizeof(request), 0), + sizeof(request)); + uassert_int_equal(recv(accepted, buffer, sizeof(buffer), 0), + sizeof(request)); + uassert_buf_equal(buffer, request, sizeof(request)); + uassert_int_equal(send(accepted, response, sizeof(response), 0), + sizeof(response)); + uassert_int_equal(recv(client, buffer, sizeof(buffer), 0), + sizeof(response)); + uassert_buf_equal(buffer, response, sizeof(response)); + + uassert_int_equal(shutdown(client, SHUT_WR), 0); + uassert_int_equal(recv(accepted, buffer, sizeof(buffer), 0), 0); + +__exit: + if (accepted >= 0) + { + closesocket(accepted); + } + if (client >= 0) + { + closesocket(client); + } + if (listener >= 0) + { + closesocket(listener); + } + (void)unlink(AF_UNIX_STREAM_PATH); +} + +static void af_unix_test_dgram_readiness(void) +{ + int error; + int index; + int result; + int sockets[2] = {-1, -1}; + char buffer[2]; + const char payload[] = "x"; + struct pollfd poll_fd; + + result = socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sockets); + uassert_int_equal(result, 0); + if (result < 0) + { + return; + } + + poll_fd.fd = sockets[1]; + poll_fd.events = POLLIN; + poll_fd.revents = 0; + uassert_int_equal(poll(&poll_fd, 1, 0), 0); + + for (index = 0; index < AF_UNIX_DGRAM_QUEUE_LEN; index++) + { + uassert_int_equal(send(sockets[0], payload, sizeof(payload), 0), + sizeof(payload)); + } + result = send(sockets[0], payload, sizeof(payload), 0); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_int_equal(error, EAGAIN); + + poll_fd.revents = 0; + uassert_int_equal(poll(&poll_fd, 1, 0), 1); + uassert_true((poll_fd.revents & POLLIN) != 0); + uassert_int_equal(recv(sockets[1], buffer, sizeof(buffer), 0), + sizeof(payload)); + uassert_int_equal(send(sockets[0], payload, sizeof(payload), 0), + sizeof(payload)); + + result = send(sockets[0], payload, AF_UNIX_DGRAM_MAX_SIZE + 1, 0); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_int_equal(error, EMSGSIZE); + + closesocket(sockets[0]); + closesocket(sockets[1]); +} + +static void af_unix_test_stream_readiness(void) +{ + int result; + int sockets[2] = {-1, -1}; + char buffer[8]; + const char payload[] = "poll"; + struct pollfd poll_fd; + + result = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + uassert_int_equal(result, 0); + if (result < 0) + { + return; + } + + poll_fd.fd = sockets[1]; + poll_fd.events = POLLIN | POLLOUT; + poll_fd.revents = 0; + uassert_int_equal(poll(&poll_fd, 1, 0), 1); + uassert_true((poll_fd.revents & POLLOUT) != 0); + uassert_true((poll_fd.revents & POLLIN) == 0); + + uassert_int_equal(send(sockets[0], payload, sizeof(payload), 0), + sizeof(payload)); + poll_fd.revents = 0; + uassert_int_equal(poll(&poll_fd, 1, 0), 1); + uassert_true((poll_fd.revents & POLLIN) != 0); + uassert_int_equal(recv(sockets[1], buffer, sizeof(buffer), 0), + sizeof(payload)); + + uassert_int_equal(shutdown(sockets[0], SHUT_WR), 0); + poll_fd.revents = 0; + uassert_int_equal(poll(&poll_fd, 1, 0), 1); + uassert_true((poll_fd.revents & POLLIN) != 0); + uassert_int_equal(recv(sockets[1], buffer, sizeof(buffer), 0), 0); + + closesocket(sockets[0]); + closesocket(sockets[1]); +} + +static void af_unix_test_pending_close(void) +{ + int client = -1; + int error; + int listener = -1; + int result; + const char payload[] = "pending"; + struct sockaddr_un address; + + (void)unlink(AF_UNIX_PENDING_PATH); + af_unix_make_address(&address, AF_UNIX_PENDING_PATH); + + listener = socket(AF_UNIX, SOCK_STREAM, 0); + client = socket(AF_UNIX, SOCK_STREAM, 0); + uassert_true(listener >= 0); + uassert_true(client >= 0); + if (listener < 0 || client < 0) + { + goto __exit; + } + + uassert_int_equal(bind(listener, (struct sockaddr *)&address, + sizeof(address)), 0); + uassert_int_equal(listen(listener, 1), 0); + uassert_int_equal(connect(client, (struct sockaddr *)&address, + sizeof(address)), 0); + closesocket(listener); + listener = -1; + + result = send(client, payload, sizeof(payload), 0); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_true(error == ENOTCONN || error == EPIPE); + +__exit: + if (client >= 0) + { + closesocket(client); + } + if (listener >= 0) + { + closesocket(listener); + } + (void)unlink(AF_UNIX_PENDING_PATH); +} + +static void af_unix_test_socketpair(void) +{ + int type_index; + int types[2] = {SOCK_DGRAM, SOCK_STREAM}; + int sockets[2]; + char buffer[8]; + char first_part[3]; + char second_part[3]; + const char payload[] = "pair"; + struct iovec receive_iov[2]; + struct iovec send_iov[2]; + struct msghdr receive_message; + struct msghdr send_message; + + for (type_index = 0; type_index < 2; type_index++) + { + uassert_int_equal(socketpair(AF_UNIX, types[type_index], 0, + sockets), 0); + uassert_int_equal(send(sockets[0], payload, sizeof(payload), 0), + sizeof(payload)); + uassert_int_equal(recv(sockets[1], buffer, sizeof(buffer), 0), + sizeof(payload)); + uassert_buf_equal(buffer, payload, sizeof(payload)); + + rt_memset(&send_message, 0, sizeof(send_message)); + send_iov[0].iov_base = (void *)payload; + send_iov[0].iov_len = 2; + send_iov[1].iov_base = (void *)(payload + 2); + send_iov[1].iov_len = sizeof(payload) - 2; + send_message.msg_iov = send_iov; + send_message.msg_iovlen = 2; + uassert_int_equal(sendmsg(sockets[0], &send_message, 0), + sizeof(payload)); + + rt_memset(&receive_message, 0, sizeof(receive_message)); + receive_iov[0].iov_base = first_part; + receive_iov[0].iov_len = sizeof(first_part); + receive_iov[1].iov_base = second_part; + receive_iov[1].iov_len = sizeof(second_part); + receive_message.msg_iov = receive_iov; + receive_message.msg_iovlen = 2; + uassert_int_equal(recvmsg(sockets[1], &receive_message, 0), + sizeof(payload)); + uassert_buf_equal(first_part, payload, sizeof(first_part)); + uassert_buf_equal(second_part, payload + sizeof(first_part), + sizeof(payload) - sizeof(first_part)); + closesocket(sockets[0]); + closesocket(sockets[1]); + } +} + +static void af_unix_test_rights_transfer(void) +{ + char data; + char payload; + int received_fds[2] = {-1, -1}; + int pipe_fds[2][2] = {{-1, -1}, {-1, -1}}; + int send_fds[2]; + int sockets[2] = {-1, -1}; + int type_index; + int types[2] = {SOCK_DGRAM, SOCK_STREAM}; + size_t fd_count; + int message_flags; + + for (type_index = 0; type_index < 2; type_index++) + { + received_fds[0] = -1; + received_fds[1] = -1; + pipe_fds[0][0] = -1; + pipe_fds[0][1] = -1; + pipe_fds[1][0] = -1; + pipe_fds[1][1] = -1; + sockets[0] = -1; + sockets[1] = -1; + + uassert_int_equal(socketpair(AF_UNIX, types[type_index], 0, + sockets), 0); + uassert_int_equal(pipe(pipe_fds[0]), 0); + uassert_int_equal(pipe(pipe_fds[1]), 0); + if (sockets[0] < 0 || pipe_fds[0][0] < 0 || pipe_fds[1][0] < 0) + { + goto __iteration_exit; + } + + uassert_int_equal(write(pipe_fds[0][1], "a", 1), 1); + uassert_int_equal(write(pipe_fds[1][1], "b", 1), 1); + send_fds[0] = pipe_fds[0][0]; + send_fds[1] = pipe_fds[1][0]; + uassert_int_equal(af_unix_send_rights(sockets[0], send_fds, 2, + 'r'), 1); + close(pipe_fds[0][0]); + pipe_fds[0][0] = -1; + close(pipe_fds[1][0]); + pipe_fds[1][0] = -1; + + fd_count = 0; + message_flags = 0; + uassert_int_equal(af_unix_receive_rights( + sockets[1], 0, + CMSG_SPACE(2 * sizeof(int)), received_fds, + &fd_count, &message_flags, &payload), 1); + uassert_int_equal(payload, 'r'); + uassert_int_equal(fd_count, 2); + uassert_int_equal(message_flags & MSG_CTRUNC, 0); + uassert_int_equal(read(received_fds[0], &data, 1), 1); + uassert_int_equal(data, 'a'); + uassert_int_equal(read(received_fds[1], &data, 1), 1); + uassert_int_equal(data, 'b'); + + __iteration_exit: + if (received_fds[0] >= 0) + { + close(received_fds[0]); + } + if (received_fds[1] >= 0) + { + close(received_fds[1]); + } + if (pipe_fds[0][0] >= 0) + { + close(pipe_fds[0][0]); + } + if (pipe_fds[0][1] >= 0) + { + close(pipe_fds[0][1]); + } + if (pipe_fds[1][0] >= 0) + { + close(pipe_fds[1][0]); + } + if (pipe_fds[1][1] >= 0) + { + close(pipe_fds[1][1]); + } + if (sockets[0] >= 0) + { + closesocket(sockets[0]); + } + if (sockets[1] >= 0) + { + closesocket(sockets[1]); + } + } +} + +static void af_unix_test_rights_truncation(void) +{ + char payload; + int message_flags = 0; + int pipe_fds[2][2] = {{-1, -1}, {-1, -1}}; + int received_fds[2] = {-1, -1}; + int send_fds[2]; + int sockets[2] = {-1, -1}; + size_t fd_count = 0; + + uassert_int_equal(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets), 0); + uassert_int_equal(pipe(pipe_fds[0]), 0); + uassert_int_equal(pipe(pipe_fds[1]), 0); + if (sockets[0] < 0 || pipe_fds[0][0] < 0 || pipe_fds[1][0] < 0) + { + goto __exit; + } + + send_fds[0] = pipe_fds[0][0]; + send_fds[1] = pipe_fds[1][0]; + uassert_int_equal(af_unix_send_rights(sockets[0], send_fds, 2, 't'), 1); + uassert_int_equal(af_unix_receive_rights( + sockets[1], 0, 0, + received_fds, &fd_count, &message_flags, &payload), 1); + uassert_int_equal(fd_count, 0); + uassert_true((message_flags & MSG_CTRUNC) != 0); + +__exit: + if (received_fds[0] >= 0) + { + close(received_fds[0]); + } + if (pipe_fds[0][0] >= 0) + { + close(pipe_fds[0][0]); + } + if (pipe_fds[0][1] >= 0) + { + close(pipe_fds[0][1]); + } + if (pipe_fds[1][0] >= 0) + { + close(pipe_fds[1][0]); + } + if (pipe_fds[1][1] >= 0) + { + close(pipe_fds[1][1]); + } + if (sockets[0] >= 0) + { + closesocket(sockets[0]); + } + if (sockets[1] >= 0) + { + closesocket(sockets[1]); + } +} + +static void af_unix_test_rights_peek_and_invalid(void) +{ + char payload; + int error; + int invalid_fd = -1; + int message_flags = 0; + int pipe_fds[2] = {-1, -1}; + int received_fds[2] = {-1, -1}; + int sockets[2] = {-1, -1}; + int result; + size_t fd_count = 0; + + uassert_int_equal(socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, + sockets), 0); + uassert_int_equal(pipe(pipe_fds), 0); + if (sockets[0] < 0 || pipe_fds[0] < 0) + { + goto __exit; + } + + result = af_unix_send_rights(sockets[0], &invalid_fd, 1, 'x'); + error = rt_get_errno(); + uassert_int_equal(result, -1); + uassert_int_equal(error, EBADF); + + uassert_int_equal(af_unix_send_rights(sockets[0], pipe_fds, 1, 'p'), 1); + fd_count = 0; + uassert_int_equal(af_unix_receive_rights( + sockets[1], MSG_PEEK, CMSG_SPACE(sizeof(int)), + received_fds, &fd_count, &message_flags, &payload), 1); + uassert_int_equal(payload, 'p'); + uassert_int_equal(fd_count, 0); + + fd_count = 0; + message_flags = 0; + uassert_int_equal(af_unix_receive_rights( + sockets[1], 0, CMSG_SPACE(sizeof(int)), + received_fds, &fd_count, &message_flags, &payload), 1); + uassert_int_equal(fd_count, 1); + +__exit: + if (received_fds[0] >= 0) + { + close(received_fds[0]); + } + if (pipe_fds[0] >= 0) + { + close(pipe_fds[0]); + } + if (pipe_fds[1] >= 0) + { + close(pipe_fds[1]); + } + if (sockets[0] >= 0) + { + closesocket(sockets[0]); + } + if (sockets[1] >= 0) + { + closesocket(sockets[1]); + } +} + +static void af_unix_test_rights_socket(void) +{ + char buffer = 0; + char payload = 0; + int carrier[2] = {-1, -1}; + int message_flags = 0; + int passed[2] = {-1, -1}; + int received_fds[2] = {-1, -1}; + size_t fd_count = 0; + + uassert_int_equal(socketpair(AF_UNIX, SOCK_STREAM, 0, carrier), 0); + uassert_int_equal(socketpair(AF_UNIX, SOCK_DGRAM, 0, passed), 0); + if (carrier[0] < 0 || passed[0] < 0) + { + goto __exit; + } + + uassert_int_equal(af_unix_send_rights(carrier[0], &passed[1], 1, 's'), 1); + closesocket(passed[1]); + passed[1] = -1; + uassert_int_equal(af_unix_receive_rights( + carrier[1], 0, CMSG_SPACE(sizeof(int)), + received_fds, &fd_count, &message_flags, &payload), 1); + uassert_int_equal(fd_count, 1); + uassert_int_equal(send(passed[0], "q", 1, 0), 1); + uassert_int_equal(recv(received_fds[0], &buffer, 1, 0), 1); + uassert_int_equal(buffer, 'q'); + +__exit: + if (received_fds[0] >= 0) + { + closesocket(received_fds[0]); + } + if (passed[0] >= 0) + { + closesocket(passed[0]); + } + if (passed[1] >= 0) + { + closesocket(passed[1]); + } + if (carrier[0] >= 0) + { + closesocket(carrier[0]); + } + if (carrier[1] >= 0) + { + closesocket(carrier[1]); + } +} + +static void af_unix_testcase(void) +{ + UTEST_UNIT_RUN(af_unix_test_dgram); + UTEST_UNIT_RUN(af_unix_test_stream); + UTEST_UNIT_RUN(af_unix_test_dgram_readiness); + UTEST_UNIT_RUN(af_unix_test_stream_readiness); + UTEST_UNIT_RUN(af_unix_test_pending_close); + UTEST_UNIT_RUN(af_unix_test_socketpair); + UTEST_UNIT_RUN(af_unix_test_pathname_lifetime); + UTEST_UNIT_RUN(af_unix_test_rights_transfer); + UTEST_UNIT_RUN(af_unix_test_rights_truncation); + UTEST_UNIT_RUN(af_unix_test_rights_peek_and_invalid); + UTEST_UNIT_RUN(af_unix_test_rights_socket); +} + +UTEST_TC_EXPORT(af_unix_testcase, "components.net.af_unix", RT_NULL, + RT_NULL, 20); From f46416365904bacbadabde8c321aad5742413bbc Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 3 Aug 2026 09:49:16 +0800 Subject: [PATCH 5/5] Fix AF_UNIX CI checks Apply the repository clang-format rules to the affected source lines. Suppress the cppcheck false positive for the devtmpfs list iterator. No functional behavior is changed. --- .../dfs/dfs_v2/filesystems/devfs/devtmpfs.c | 1 + components/dfs/dfs_v2/src/dfs_file.c | 2 +- components/net/af_unix/src/af_unix_core.c | 12 +-- components/net/af_unix/src/af_unix_rights.c | 2 +- .../net/af_unix/testcases/af_unix_test.c | 86 +++++++++++-------- components/net/sal/include/sal_socket.h | 2 +- components/net/sal/src/sal_socket.c | 52 ++++++----- 7 files changed, 85 insertions(+), 72 deletions(-) diff --git a/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c b/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c index 50882746cf76..b60e5c5d0f1c 100644 --- a/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c +++ b/components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c @@ -224,6 +224,7 @@ static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock if (rt_strcmp(file->name, filename) == 0) { rt_spin_unlock(&superblock->lock); + /* cppcheck-suppress uninitvar */ return file; } } diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c index 4c259f2662cf..a49d0e37a443 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -901,7 +901,7 @@ int dfs_file_mknod(const char *path, int type, mode_t mode) if (dfs_is_mounted(mnt) == 0) { vnode = mnt->fs_ops->create_vnode(dentry, create_type, - create_mode); + create_mode); } if (vnode != RT_NULL) { diff --git a/components/net/af_unix/src/af_unix_core.c b/components/net/af_unix/src/af_unix_core.c index 9efb1a2c6791..0e8e016323fb 100644 --- a/components/net/af_unix/src/af_unix_core.c +++ b/components/net/af_unix/src/af_unix_core.c @@ -748,8 +748,7 @@ static int af_unix_getsockopt(int handle, int level, int option, result = af_unix_error(EINVAL); break; } - af_unix_timeval_from_timeout(option == SO_RCVTIMEO ? - sock->receive_timeout : sock->send_timeout, + af_unix_timeval_from_timeout(option == SO_RCVTIMEO ? sock->receive_timeout : sock->send_timeout, &time_value); rt_memcpy(value, &time_value, sizeof(time_value)); *length = sizeof(time_value); @@ -772,8 +771,7 @@ static int af_unix_getsockopt(int handle, int level, int option, break; case SO_SNDBUF: case SO_RCVBUF: - int_value = sock->type == SOCK_DGRAM ? AF_UNIX_DGRAM_MAX_SIZE : - AF_UNIX_STREAM_BUFFER_SIZE; + int_value = sock->type == SOCK_DGRAM ? AF_UNIX_DGRAM_MAX_SIZE : AF_UNIX_STREAM_BUFFER_SIZE; break; default: result = af_unix_error(ENOPROTOOPT); @@ -1085,8 +1083,7 @@ static int af_unix_poll(struct dfs_file *file, struct rt_pollreq *request) return mask; } -static const struct sal_socket_ops af_unix_socket_ops = -{ +static const struct sal_socket_ops af_unix_socket_ops = { .socket = af_unix_socket_create, .closesocket = af_unix_close, .bind = af_unix_bind, @@ -1107,8 +1104,7 @@ static const struct sal_socket_ops af_unix_socket_ops = .poll = af_unix_poll, }; -static const struct sal_proto_family af_unix_family = -{ +static const struct sal_proto_family af_unix_family = { .family = AF_UNIX, .sec_family = AF_UNIX, .skt_ops = &af_unix_socket_ops, diff --git a/components/net/af_unix/src/af_unix_rights.c b/components/net/af_unix/src/af_unix_rights.c index 56ccdd5a80ec..8cf30f45e1d3 100644 --- a/components/net/af_unix/src/af_unix_rights.c +++ b/components/net/af_unix/src/af_unix_rights.c @@ -88,7 +88,7 @@ int af_unix_rights_create(const struct msghdr *message, } next = af_unix_cmsg_next(offset, cmsg->cmsg_len, - message->msg_controllen); + message->msg_controllen); if (next <= offset || next > message->msg_controllen) { return af_unix_error(EINVAL); diff --git a/components/net/af_unix/testcases/af_unix_test.c b/components/net/af_unix/testcases/af_unix_test.c index 8efde7b7aee3..fbd46a2d4a02 100644 --- a/components/net/af_unix/testcases/af_unix_test.c +++ b/components/net/af_unix/testcases/af_unix_test.c @@ -118,11 +118,14 @@ static void af_unix_test_dgram(void) } uassert_int_equal(bind(server, (struct sockaddr *)&server_address, - sizeof(server_address)), 0); + sizeof(server_address)), + 0); uassert_int_equal(bind(client, (struct sockaddr *)&client_address, - sizeof(client_address)), 0); + sizeof(client_address)), + 0); uassert_int_equal(connect(client, (struct sockaddr *)&server_address, - sizeof(server_address)), 0); + sizeof(server_address)), + 0); uassert_int_equal(send(client, payload, sizeof(payload), 0), sizeof(payload)); @@ -172,7 +175,8 @@ static void af_unix_test_pathname_lifetime(void) goto __exit; } uassert_int_equal(bind(first, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); uassert_int_equal(stat(AF_UNIX_PERSIST_PATH, &file_stat), 0); uassert_true(S_ISSOCK(file_stat.st_mode)); @@ -194,7 +198,8 @@ static void af_unix_test_pathname_lifetime(void) uassert_int_equal(unlink(AF_UNIX_PERSIST_PATH), 0); uassert_int_equal(bind(second, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); __exit: if (second >= 0) @@ -231,10 +236,12 @@ static void af_unix_test_stream(void) } uassert_int_equal(bind(listener, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); uassert_int_equal(listen(listener, 2), 0); uassert_int_equal(connect(client, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); accepted = accept(listener, RT_NULL, RT_NULL); uassert_true(accepted >= 0); if (accepted < 0) @@ -277,7 +284,7 @@ static void af_unix_test_dgram_readiness(void) int error; int index; int result; - int sockets[2] = {-1, -1}; + int sockets[2] = { -1, -1 }; char buffer[2]; const char payload[] = "x"; struct pollfd poll_fd; @@ -324,7 +331,7 @@ static void af_unix_test_dgram_readiness(void) static void af_unix_test_stream_readiness(void) { int result; - int sockets[2] = {-1, -1}; + int sockets[2] = { -1, -1 }; char buffer[8]; const char payload[] = "poll"; struct pollfd poll_fd; @@ -383,10 +390,12 @@ static void af_unix_test_pending_close(void) } uassert_int_equal(bind(listener, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); uassert_int_equal(listen(listener, 1), 0); uassert_int_equal(connect(client, (struct sockaddr *)&address, - sizeof(address)), 0); + sizeof(address)), + 0); closesocket(listener); listener = -1; @@ -410,7 +419,7 @@ static void af_unix_test_pending_close(void) static void af_unix_test_socketpair(void) { int type_index; - int types[2] = {SOCK_DGRAM, SOCK_STREAM}; + int types[2] = { SOCK_DGRAM, SOCK_STREAM }; int sockets[2]; char buffer[8]; char first_part[3]; @@ -424,7 +433,8 @@ static void af_unix_test_socketpair(void) for (type_index = 0; type_index < 2; type_index++) { uassert_int_equal(socketpair(AF_UNIX, types[type_index], 0, - sockets), 0); + sockets), + 0); uassert_int_equal(send(sockets[0], payload, sizeof(payload), 0), sizeof(payload)); uassert_int_equal(recv(sockets[1], buffer, sizeof(buffer), 0), @@ -462,12 +472,12 @@ static void af_unix_test_rights_transfer(void) { char data; char payload; - int received_fds[2] = {-1, -1}; - int pipe_fds[2][2] = {{-1, -1}, {-1, -1}}; + int received_fds[2] = { -1, -1 }; + int pipe_fds[2][2] = { { -1, -1 }, { -1, -1 } }; int send_fds[2]; - int sockets[2] = {-1, -1}; + int sockets[2] = { -1, -1 }; int type_index; - int types[2] = {SOCK_DGRAM, SOCK_STREAM}; + int types[2] = { SOCK_DGRAM, SOCK_STREAM }; size_t fd_count; int message_flags; @@ -483,7 +493,8 @@ static void af_unix_test_rights_transfer(void) sockets[1] = -1; uassert_int_equal(socketpair(AF_UNIX, types[type_index], 0, - sockets), 0); + sockets), + 0); uassert_int_equal(pipe(pipe_fds[0]), 0); uassert_int_equal(pipe(pipe_fds[1]), 0); if (sockets[0] < 0 || pipe_fds[0][0] < 0 || pipe_fds[1][0] < 0) @@ -496,7 +507,8 @@ static void af_unix_test_rights_transfer(void) send_fds[0] = pipe_fds[0][0]; send_fds[1] = pipe_fds[1][0]; uassert_int_equal(af_unix_send_rights(sockets[0], send_fds, 2, - 'r'), 1); + 'r'), + 1); close(pipe_fds[0][0]); pipe_fds[0][0] = -1; close(pipe_fds[1][0]); @@ -507,7 +519,8 @@ static void af_unix_test_rights_transfer(void) uassert_int_equal(af_unix_receive_rights( sockets[1], 0, CMSG_SPACE(2 * sizeof(int)), received_fds, - &fd_count, &message_flags, &payload), 1); + &fd_count, &message_flags, &payload), + 1); uassert_int_equal(payload, 'r'); uassert_int_equal(fd_count, 2); uassert_int_equal(message_flags & MSG_CTRUNC, 0); @@ -556,10 +569,10 @@ static void af_unix_test_rights_truncation(void) { char payload; int message_flags = 0; - int pipe_fds[2][2] = {{-1, -1}, {-1, -1}}; - int received_fds[2] = {-1, -1}; + int pipe_fds[2][2] = { { -1, -1 }, { -1, -1 } }; + int received_fds[2] = { -1, -1 }; int send_fds[2]; - int sockets[2] = {-1, -1}; + int sockets[2] = { -1, -1 }; size_t fd_count = 0; uassert_int_equal(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets), 0); @@ -575,7 +588,8 @@ static void af_unix_test_rights_truncation(void) uassert_int_equal(af_unix_send_rights(sockets[0], send_fds, 2, 't'), 1); uassert_int_equal(af_unix_receive_rights( sockets[1], 0, 0, - received_fds, &fd_count, &message_flags, &payload), 1); + received_fds, &fd_count, &message_flags, &payload), + 1); uassert_int_equal(fd_count, 0); uassert_true((message_flags & MSG_CTRUNC) != 0); @@ -616,14 +630,15 @@ static void af_unix_test_rights_peek_and_invalid(void) int error; int invalid_fd = -1; int message_flags = 0; - int pipe_fds[2] = {-1, -1}; - int received_fds[2] = {-1, -1}; - int sockets[2] = {-1, -1}; + int pipe_fds[2] = { -1, -1 }; + int received_fds[2] = { -1, -1 }; + int sockets[2] = { -1, -1 }; int result; size_t fd_count = 0; uassert_int_equal(socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, - sockets), 0); + sockets), + 0); uassert_int_equal(pipe(pipe_fds), 0); if (sockets[0] < 0 || pipe_fds[0] < 0) { @@ -639,7 +654,8 @@ static void af_unix_test_rights_peek_and_invalid(void) fd_count = 0; uassert_int_equal(af_unix_receive_rights( sockets[1], MSG_PEEK, CMSG_SPACE(sizeof(int)), - received_fds, &fd_count, &message_flags, &payload), 1); + received_fds, &fd_count, &message_flags, &payload), + 1); uassert_int_equal(payload, 'p'); uassert_int_equal(fd_count, 0); @@ -647,7 +663,8 @@ static void af_unix_test_rights_peek_and_invalid(void) message_flags = 0; uassert_int_equal(af_unix_receive_rights( sockets[1], 0, CMSG_SPACE(sizeof(int)), - received_fds, &fd_count, &message_flags, &payload), 1); + received_fds, &fd_count, &message_flags, &payload), + 1); uassert_int_equal(fd_count, 1); __exit: @@ -677,10 +694,10 @@ static void af_unix_test_rights_socket(void) { char buffer = 0; char payload = 0; - int carrier[2] = {-1, -1}; + int carrier[2] = { -1, -1 }; int message_flags = 0; - int passed[2] = {-1, -1}; - int received_fds[2] = {-1, -1}; + int passed[2] = { -1, -1 }; + int received_fds[2] = { -1, -1 }; size_t fd_count = 0; uassert_int_equal(socketpair(AF_UNIX, SOCK_STREAM, 0, carrier), 0); @@ -695,7 +712,8 @@ static void af_unix_test_rights_socket(void) passed[1] = -1; uassert_int_equal(af_unix_receive_rights( carrier[1], 0, CMSG_SPACE(sizeof(int)), - received_fds, &fd_count, &message_flags, &payload), 1); + received_fds, &fd_count, &message_flags, &payload), + 1); uassert_int_equal(fd_count, 1); uassert_int_equal(send(passed[0], "q", 1, 0), 1); uassert_int_equal(recv(received_fds[0], &buffer, 1, 0), 1); diff --git a/components/net/sal/include/sal_socket.h b/components/net/sal/include/sal_socket.h index dc0cef0ebf49..7d74310094e8 100644 --- a/components/net/sal/include/sal_socket.h +++ b/components/net/sal/include/sal_socket.h @@ -120,7 +120,7 @@ typedef uint16_t in_port_t; #define MSG_MORE 0x10 /* Sender will send more */ /* Output-only flags returned through struct msghdr. */ -#define MSG_CTRUNC 0x08 /* Control data was discarded due to truncation */ +#define MSG_CTRUNC 0x08 /* Control data was discarded due to truncation */ #define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ #define MSG_CONFIRM 0x0800 /* Confirm path validity */ diff --git a/components/net/sal/src/sal_socket.c b/components/net/sal/src/sal_socket.c index 4c9d876254e7..b420eb29573f 100644 --- a/components/net/sal/src/sal_socket.c +++ b/components/net/sal/src/sal_socket.c @@ -44,16 +44,14 @@ #include #define VALID_PROTOCOL(protocol) ((protocol) >= 0 && (protocol) <= IPPROTO_RAW) -#define VALID_COMBO(domain, type, protocol) \ - ( \ - (((domain) == AF_INET || (domain) == AF_INET6) && \ - (((type) == SOCK_STREAM && ((protocol) == 0 || (protocol) == IPPROTO_TCP)) || \ - ((type) == SOCK_DGRAM && ((protocol) == 0 || (protocol) == IPPROTO_UDP)) || \ - ((type) == SOCK_RAW && ((protocol) == IPPROTO_RAW)) \ - )) || \ - ((domain) == AF_UNIX && ((type) == SOCK_STREAM || (type) == SOCK_DGRAM) && (protocol) == 0) || \ - ((domain) == AF_NETLINK && (type) == SOCK_RAW && (protocol) == 0) \ - ) +#define VALID_COMBO(domain, type, protocol) \ + ( \ + (((domain) == AF_INET || (domain) == AF_INET6) && \ + (((type) == SOCK_STREAM && ((protocol) == 0 || (protocol) == IPPROTO_TCP)) || \ + ((type) == SOCK_DGRAM && ((protocol) == 0 || (protocol) == IPPROTO_UDP)) || \ + ((type) == SOCK_RAW && ((protocol) == IPPROTO_RAW)))) || \ + ((domain) == AF_UNIX && ((type) == SOCK_STREAM || (type) == SOCK_DGRAM) && (protocol) == 0) || \ + ((domain) == AF_NETLINK && (type) == SOCK_RAW && (protocol) == 0)) /* the socket table used to dynamic allocate sockets */ struct sal_socket_table @@ -91,8 +89,8 @@ static rt_bool_t init_ok = RT_FALSE; static struct sal_netdev_res_table sal_dev_res_tbl[SAL_SOCKETS_NUM]; static const struct sal_proto_family *local_proto_families[SAL_PROTO_FAMILIES_NUM]; -#define IS_SOCKET_PROTO_TLS(sock) (((sock)->protocol == PROTOCOL_TLS) || \ - ((sock)->protocol == PROTOCOL_DTLS)) +#define IS_SOCKET_PROTO_TLS(sock) (((sock)->protocol == PROTOCOL_TLS) || \ + ((sock)->protocol == PROTOCOL_DTLS)) #define SAL_SOCKOPS_PROTO_TLS_VALID(sock, name) (proto_tls && (proto_tls->ops->name) && IS_SOCKET_PROTO_TLS(sock)) #define SAL_SOCKOPT_PROTO_TLS_EXEC(sock, name, optval, optlen) \ @@ -135,21 +133,21 @@ static const struct sal_proto_family *local_proto_families[SAL_PROTO_FAMILIES_NU } \ } while (0) -#define SAL_NETDEV_SOCKETOPS_VALID(netdev, pf, ops) \ - do \ - { \ - if ((netdev) == RT_NULL) \ - { \ - rt_set_errno(EOPNOTSUPP); \ - return -1; \ - } \ - (pf) = (struct sal_proto_family *)(netdev)->sal_user_data; \ - if ((pf) == RT_NULL || (pf)->skt_ops == RT_NULL || \ - (pf)->skt_ops->ops == RT_NULL) \ - { \ - rt_set_errno(EOPNOTSUPP); \ - return -1; \ - } \ +#define SAL_NETDEV_SOCKETOPS_VALID(netdev, pf, ops) \ + do \ + { \ + if ((netdev) == RT_NULL) \ + { \ + rt_set_errno(EOPNOTSUPP); \ + return -1; \ + } \ + (pf) = (struct sal_proto_family *)(netdev)->sal_user_data; \ + if ((pf) == RT_NULL || (pf)->skt_ops == RT_NULL || \ + (pf)->skt_ops->ops == RT_NULL) \ + { \ + rt_set_errno(EOPNOTSUPP); \ + return -1; \ + } \ } while (0) #define SAL_NETDEV_NETDBOPS_VALID(netdev, pf, ops) \