summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-04-29 22:00:55 +0200
committerAnton Kling <anton@kling.gg>2024-04-29 22:00:55 +0200
commit231301a6190605bd3ced4d961ee0d5d3fcd49d65 (patch)
tree8af67c28f9b638393f700fbaf2c9e33fd97a8b46 /kernel
parent7d2ab3a71f4bda9d8ee997764d98b29e13a902c5 (diff)
Kernel/IRC: Add setsockopt and move IRC client to use new socket interface
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cpu/syscall.c6
-rw-r--r--kernel/socket.c51
-rw-r--r--kernel/socket.h4
-rw-r--r--kernel/syscalls/lseek.c34
4 files changed, 86 insertions, 9 deletions
diff --git a/kernel/cpu/syscall.c b/kernel/cpu/syscall.c
index 84faa16..b72beff 100644
--- a/kernel/cpu/syscall.c
+++ b/kernel/cpu/syscall.c
@@ -145,6 +145,11 @@ int syscall_connect(int sockfd, const struct sockaddr *addr,
return connect(sockfd, addr, addrlen);
}
+int syscall_setsockopt(int socket, int level, int option_name,
+ const void *option_value, socklen_t option_len) {
+ return setsockopt(socket, level, option_name, option_value, option_len);
+}
+
int (*syscall_functions[])() = {
(void(*))syscall_open,
(void(*))syscall_mread,
@@ -198,6 +203,7 @@ int (*syscall_functions[])() = {
(void(*))syscall_open_process,
(void(*))syscall_lseek,
(void(*))syscall_connect,
+ (void(*))syscall_setsockopt,
};
void int_syscall(reg_t *r);
diff --git a/kernel/socket.c b/kernel/socket.c
index fbc0648..d952052 100644
--- a/kernel/socket.c
+++ b/kernel/socket.c
@@ -8,6 +8,7 @@
#include <poll.h>
#include <sched/scheduler.h>
#include <socket.h>
+#include <sys/socket.h>
struct list open_tcp_connections;
struct list open_tcp_listen;
@@ -70,6 +71,7 @@ struct TcpConnection *internal_tcp_incoming(u32 src_ip, u16 src_port,
con->outgoing_port = src_port;
con->incoming_ip = dst_ip;
con->incoming_port = dst_port;
+ con->no_delay = 0;
ringbuffer_init(&con->incoming_buffer, 8192);
ringbuffer_init(&con->outgoing_buffer, 8192);
@@ -126,6 +128,11 @@ int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {
return -EBADF; // TODO: Check if this is correct.
}
+ if (con->no_delay) {
+ send_tcp_packet(con, buffer, len);
+ return len;
+ }
+
struct ringbuffer *rb = &con->outgoing_buffer;
if (ringbuffer_unused(rb) < len) {
tcp_sync_buffer(fd);
@@ -144,10 +151,8 @@ int tcp_has_data(vfs_inode_t *inode) {
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
vfs_fd_t *fd = get_vfs_fd(sockfd, NULL);
- assert(fd);
-
- if (fd->inode->internal_object) {
- return -EISCONN;
+ if (!fd) {
+ return -EBADF;
}
assert(AF_INET == addr->sa_family);
@@ -159,7 +164,7 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
con->incoming_port = 1337; // TODO
con->outgoing_ip = in_addr->sin_addr.s_addr;
- con->outgoing_port = in_addr->sin_port;
+ con->outgoing_port = ntohs(in_addr->sin_port);
ringbuffer_init(&con->incoming_buffer, 8192);
ringbuffer_init(&con->outgoing_buffer, 8192);
@@ -185,6 +190,35 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
return 0;
}
+int setsockopt(int socket, int level, int option_name, const void *option_value,
+ socklen_t option_len) {
+ vfs_fd_t *fd = get_vfs_fd(socket, NULL);
+ if (!fd) {
+ return -EBADF;
+ }
+ // TODO: Check that it is actually a TCP socket
+ if (IPPROTO_TCP == level) {
+ struct TcpConnection *tcp_connection = fd->inode->internal_object;
+ switch (option_name) {
+ case TCP_NODELAY: {
+ if (sizeof(int) != option_len) {
+ return -EINVAL;
+ }
+ if (!mmu_is_valid_userpointer(option_value, option_len)) {
+ return -EPERM; // TODO: Check if this is correct
+ }
+ int value = *(int *)option_value;
+ tcp_connection->no_delay = value;
+ } break;
+ default:
+ return -ENOPROTOOPT;
+ break;
+ }
+ return 0;
+ }
+ return -ENOPROTOOPT;
+}
+
int uds_open(const char *path) {
// FIXME: This is super ugly
@@ -268,10 +302,9 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) {
stack_pop(&tcp_listen->incoming_connections);
assert(connection);
vfs_inode_t *inode = vfs_create_inode(
- 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, tcp_has_data,
- always_can_write, 1, connection, 0 /*file_size*/, NULL /*open*/,
- NULL /*create_file*/, tcp_read, tcp_write,
- tcp_close /*close*/, NULL /*create_directory*/,
+ 0 /*inode_num*/, FS_TYPE_UNIX_SOCKET, tcp_has_data, always_can_write, 1,
+ connection, 0 /*file_size*/, NULL /*open*/, NULL /*create_file*/,
+ tcp_read, tcp_write, tcp_close /*close*/, NULL /*create_directory*/,
NULL /*get_vm_object*/, NULL /*truncate*/, NULL /*stat*/,
NULL /*send_signal*/);
assert(inode);
diff --git a/kernel/socket.h b/kernel/socket.h
index b542c87..3d1025d 100644
--- a/kernel/socket.h
+++ b/kernel/socket.h
@@ -38,6 +38,8 @@ struct TcpConnection {
struct ringbuffer incoming_buffer;
struct ringbuffer outgoing_buffer;
+ int no_delay;
+
u32 seq;
u32 ack;
@@ -116,4 +118,6 @@ struct INCOMING_TCP_CONNECTION *get_incoming_tcp_connection(u8 ip[4],
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
void global_socket_init(void);
u16 tcp_get_free_port(void);
+int setsockopt(int socket, int level, int option_name, const void *option_value,
+ socklen_t option_len);
#endif
diff --git a/kernel/syscalls/lseek.c b/kernel/syscalls/lseek.c
new file mode 100644
index 0000000..3e38822
--- /dev/null
+++ b/kernel/syscalls/lseek.c
@@ -0,0 +1,34 @@
+#include <assert.h>
+#include <errno.h>
+#include <fs/vfs.h>
+
+// FIXME: These should be in a shared header file with libc
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+off_t syscall_lseek(int fd, off_t offset, int whence) {
+ vfs_fd_t *fd_ptr = get_vfs_fd(fd, NULL);
+ if (!fd_ptr) {
+ return -EBADF;
+ }
+
+ off_t ret_offset = fd_ptr->offset;
+ switch (whence) {
+ case SEEK_SET:
+ ret_offset = offset;
+ break;
+ case SEEK_CUR:
+ ret_offset += offset;
+ break;
+ case SEEK_END:
+ assert(fd_ptr->inode);
+ ret_offset = fd_ptr->inode->file_size + offset;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ fd_ptr->offset = ret_offset;
+ return ret_offset;
+}