diff options
author | Ian Moffett <ian@osmora.org> | 2025-07-28 02:52:34 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-07-28 03:31:26 -0400 |
commit | 275108db200f6303d84d5225b80081b58866fe22 (patch) | |
tree | 7c64eed1d7b7c4ce8098f194c9e93a19e8566545 | |
parent | 3b834839d2328dc8d1f069cddee32f80a236c349 (diff) |
kernel: net: Introduce initial socket impl
Introduce initial support for POSIX sockets. This commit currently
implements the AF_UNIX family for IPC.
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r-- | sys/include/sys/socket.h | 92 | ||||
-rw-r--r-- | sys/include/sys/socketvar.h | 53 | ||||
-rw-r--r-- | sys/include/sys/vnode.h | 1 | ||||
-rw-r--r-- | sys/kern/kern_socket.c | 345 |
4 files changed, 491 insertions, 0 deletions
diff --git a/sys/include/sys/socket.h b/sys/include/sys/socket.h new file mode 100644 index 0000000..7175da5 --- /dev/null +++ b/sys/include/sys/socket.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_SOCKET_H_ +#define _SYS_SOCKET_H_ + +#include <sys/socketvar.h> +#if defined(_KERNEL) +#include <sys/types.h> +#include <sys/syscall.h> +#include <sys/mutex.h> +#else +#include <stdint.h> +#include <stddef.h> +#endif /* _KERNEL */ + +#ifndef _SA_FAMILY_T_DEFINED_ +#define _SA_FAMILY_T_DEFINED_ +typedef uint32_t sa_family_t; +#endif /* _SA_FAMILY_T_DEFINED_ */ + +#ifndef _SOCKLEN_T_DEFINED_ +#define _SOCKLEN_T_DEFINED_ +typedef uint32_t socklen_t; +#endif /* !_SOCKLEN_T_DEFINED_ */ + +/* + * Address family defines + */ +#define AF_UNSPEC 0 +#define AF_UNIX 1 +#define AF_LOCAL AF_UNIX + +/* Socket types */ +#define SOCK_STREAM 1 + +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[108]; +}; + +struct sockaddr { + sa_family_t sa_family; + char sa_data[14]; +}; + +#if defined(_KERNEL) + +struct ksocket { + int sockfd; + union { + struct sockaddr sockaddr; + struct sockaddr_un un; + }; + struct sockbuf buf; + struct mutex *mtx; +}; +#endif /* _KERNEL */ + +int socket(int domain, int type, int protocol); +int bind(int sockfd, const struct sockaddr *addr, socklen_t len); + +ssize_t send(int sockfd, const void *buf, size_t size, int flags); +ssize_t recv(int sockfd, void *buf, size_t len, int flags); + +#endif /* !_SYS_SOCKET_H_ */ diff --git a/sys/include/sys/socketvar.h b/sys/include/sys/socketvar.h new file mode 100644 index 0000000..e090a70 --- /dev/null +++ b/sys/include/sys/socketvar.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_SOCKETVAR_H_ +#define _SYS_SOCKETVAR_H_ + +#include <sys/types.h> +#if defined(_KERNEL) +#include <net/netbuf.h> + +/* + * Socket buffer + * + * @buf: Actual data buffer + * @head: Buffer head + * @tail: Buffer tail + * @watermark: Max length + */ +struct sockbuf { + struct netbuf buf; + size_t head; + size_t tail; + size_t watermark; +}; + +#endif /* _KERNEL */ +#endif /* !_SYS_SOCKETVAR_H_ */ diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h index 3402b02..ff6f995 100644 --- a/sys/include/sys/vnode.h +++ b/sys/include/sys/vnode.h @@ -76,6 +76,7 @@ struct vcache { #define VDIR 0x02 /* Directory */ #define VCHR 0x03 /* Character device */ #define VBLK 0x04 /* Block device */ +#define VSOCK 0x05 /* Socket */ #define VNOVAL -1 diff --git a/sys/kern/kern_socket.c b/sys/kern/kern_socket.c new file mode 100644 index 0000000..7f58921 --- /dev/null +++ b/sys/kern/kern_socket.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/socket.h> +#include <sys/sio.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/filedesc.h> +#include <sys/vnode.h> +#include <vm/dynalloc.h> +#include <string.h> + +#define pr_trace(fmt, ...) kprintf("socket: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +static struct vops socket_vops; + +/* + * Get a kernel socket structure from a + * file descriptor. + * + * @sockfd: File descriptor to lookup + * @res: Result pointer + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +static int +get_ksock(int sockfd, struct ksocket **res) +{ + struct ksocket *ksock; + struct filedesc *fdesc; + struct vnode *vp; + + if (res == NULL) { + return -EINVAL; + } + + /* Grab the file descriptor */ + fdesc = fd_get(sockfd); + if (fdesc == NULL) { + return -EBADF; + } + + /* Is this even a socket? */ + if ((vp = fdesc->vp) == NULL) { + return -ENOTSOCK; + } + if (vp->type != VSOCK) { + return -ENOTSOCK; + } + + ksock = vp->data; + if (__unlikely(ksock == NULL)) { + return -EIO; + } + + *res = ksock; + return 0; +} + +/* + * VFS reclaim callback for the socket + * layer + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +static int +socket_reclaim(struct vnode *vp) +{ + struct ksocket *ksock; + + /* Is this even a socket? */ + if (vp->type != VSOCK) { + return -ENOTSOCK; + } + + /* Is there any data attached? */ + if ((ksock = vp->data) == NULL) { + return -EIO; + } + + fd_close(ksock->sockfd); + mutex_free(ksock->mtx); + dynfree(ksock); + return 0; +} + +/* + * Send data to socket - POSIX send(2) core + * + * @sockfd: File descriptor that backs this socket + * @buf: Buffer containing data to transmit + * @size: Size of the buffer + * @flags: Optional flags + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +ssize_t +send(int sockfd, const void *buf, size_t size, int flags) +{ + struct ksocket *ksock; + struct sockbuf *sbuf; + struct netbuf *netbuf; + size_t tail; + int error; + + /* Size cannot be zero */ + if (size == 0) { + return -EINVAL; + } + + if ((error = get_ksock(sockfd, &ksock)) < 0) { + return error; + } + + sbuf = &ksock->buf; + netbuf = &sbuf->buf; + mutex_acquire(ksock->mtx, 0); + + /* Make sure we dont overflow */ + if (netbuf->len > sbuf->watermark) { + mutex_release(ksock->mtx); + return -ENOBUFS; + } + + if (netbuf->len == 0) { + sbuf->head = 0; + sbuf->tail = 0; + } + + /* Clamp the size if needed */ + if ((netbuf->len + size) > sbuf->watermark) { + size = sbuf->watermark - netbuf->len; + } + if (size == 0) { + return -ENOBUFS; + } + + /* Copy the new data */ + tail = sbuf->tail; + memcpy(&netbuf->data[tail], buf, size); + + sbuf->tail += size; + netbuf->len += size; + mutex_release(ksock->mtx); + return size; +} + +/* + * Recv data from socket - POSIX recv(2) core + * + * @sockfd: File descriptor that backs this socket + * @buf: RX buffer + * @size: Size of the buffer + * @flags: Optional flags + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +ssize_t +recv(int sockfd, void *buf, size_t len, int flags) +{ + struct ksocket *ksock; + struct sockbuf *sbuf; + struct netbuf *netbuf; + size_t head; + int error; + + /* Length cannot be zero */ + if (len == 0) { + return -EINVAL; + } + + if ((error = get_ksock(sockfd, &ksock)) < 0) { + return error; + } + + sbuf = &ksock->buf; + netbuf = &sbuf->buf; + mutex_acquire(ksock->mtx, 0); + + /* Is it empty? */ + if (netbuf->len == 0) { + sbuf->head = 0; + sbuf->tail = 0; + return -EAGAIN; + } + + if (len > netbuf->len) { + len = netbuf->len; + } + + head = sbuf->head; + memcpy(buf, &netbuf->data[head], len); + + sbuf->head = (sbuf->head + len) % NETBUF_LEN; + mutex_release(ksock->mtx); + return len; +} + +/* + * POSIX socket(7) core + * + * @domain: Address family (see AF_*) + * @type: Socket type + * @protocol: Socket protocol + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +int +socket(int domain, int type, int protocol) +{ + struct vnode *vp = NULL; + struct ksocket *ksock = NULL; + struct filedesc *fdesc = NULL; + struct sockbuf *sbuf = NULL; + int fd, error = -1; + + if ((error = fd_alloc(&fdesc)) < 0) { + return error; + } + + fd = fdesc->fdno; + + /* Grab a new socket vnode */ + if ((error = vfs_alloc_vnode(&vp, VSOCK)) < 0) { + fd_close(fd); + return error; + } + + if (vp == NULL) { + error = -ENOBUFS; + goto fail; + } + + ksock = dynalloc(sizeof(*ksock)); + if (ksock == NULL) { + error = -ENOMEM; + goto fail; + } + + fdesc->vp = vp; + vp->vops = &socket_vops; + + sbuf = &ksock->buf; + sbuf->head = 0; + sbuf->tail = 0; + + switch (domain) { + case AF_UNIX: + { + struct sockaddr_un *un; + + un = &ksock->un; + sbuf->watermark = NETBUF_LEN; + + /* + * XXX: We could allow actual paths within the + * file system for sockets. + */ + un->sun_family = domain; + un->sun_path[0] = '\0'; + vp->data = ksock; + } + return fd; + default: + error = -EINVAL; + break; + } + +fail: + if (ksock != NULL) + dynfree(ksock); + if (vp != NULL) + vfs_release_vnode(vp); + + fd_close(fd); + return error; +} + +/* + * Bind address to socket - POSIX bind(2) core + * + * @sockfd: File descriptor + * @addr: Address to bind + * @len: Sockaddr len + * + * Returns zero on success, otherwise a less + * than zero errno. + */ +int +bind(int sockfd, const struct sockaddr *addr, socklen_t len) +{ + struct ksocket *ksock; + int error; + + if ((error = get_ksock(sockfd, &ksock)) < 0) { + kprintf("error=%d\n", error); + return error; + } + + /* Create the new mutex lock */ + ksock->mtx = mutex_new("ksocket"); + if (ksock->mtx == NULL) { + return -ENOMEM; + } + return 0; +} + +static struct vops socket_vops = { + .read = NULL, + .write = NULL, + .reclaim = socket_reclaim, +}; |