summaryrefslogtreecommitdiff
path: root/kernel/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/socket.c')
-rw-r--r--kernel/socket.c69
1 files changed, 56 insertions, 13 deletions
diff --git a/kernel/socket.c b/kernel/socket.c
index fbccac5..cc5a645 100644
--- a/kernel/socket.c
+++ b/kernel/socket.c
@@ -48,12 +48,30 @@ void tcp_remove_connection(struct TcpConnection *con) {
}
if (c == con) {
relist_remove(&open_tcp_connections, i);
+ ringbuffer_free(&c->incoming_buffer);
+ ringbuffer_free(&c->outgoing_buffer);
kfree(con);
break;
}
}
}
+int num_open_connections(void) {
+ int f = 0;
+ for (int i = 0;; i++) {
+ struct TcpConnection *c;
+ int end;
+ if (!relist_get(&open_tcp_connections, i, (void **)&c, &end)) {
+ if (end) {
+ break;
+ }
+ continue;
+ }
+ f++;
+ }
+ return f;
+}
+
struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port,
ipv4_t dst_ip, u16 dst_port) {
for (int i = 0;; i++) {
@@ -74,7 +92,11 @@ struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port,
if (c->incoming_port == dst_port) {
struct TcpConnection *new_connection =
kmalloc(sizeof(struct TcpConnection));
- memcpy(new_connection, c, sizeof(struct TcpConnection));
+ new_connection->incoming_port = c->incoming_port;
+ new_connection->incoming_ip = c->incoming_ip;
+
+ new_connection->no_delay = c->no_delay;
+
new_connection->outgoing_port = src_port;
new_connection->outgoing_ip = src_ip.d;
new_connection->state = TCP_STATE_LISTEN;
@@ -94,10 +116,7 @@ struct TcpConnection *tcp_connect_to_listen(ipv4_t src_ip, u16 src_port,
new_connection->snd_wnd = 0;
new_connection->sent_ack = 0;
- new_connection->snd_wnd =
- ringbuffer_unused(&new_connection->outgoing_buffer);
- u32 index;
- assert(relist_add(&open_tcp_connections, new_connection, &index));
+ assert(relist_add(&open_tcp_connections, new_connection, NULL));
assert(relist_add(&c->incoming_connections, new_connection, NULL));
return new_connection;
}
@@ -137,9 +156,24 @@ void tcp_flush_buffers(void) {
}
continue;
}
+ if (TCP_STATE_TIME_WAIT == c->state) {
+ // TODO: It should actually wait
+ c->state = TCP_STATE_CLOSED;
+ tcp_remove_connection(c);
+ continue;
+ }
+ if (TCP_STATE_FIN_WAIT2 == c->state) {
+ // TODO: It should actually wait
+ c->state = TCP_STATE_CLOSED;
+ tcp_remove_connection(c);
+ continue;
+ }
if (TCP_STATE_CLOSED == c->state) {
continue;
}
+ if (TCP_STATE_ESTABLISHED != c->state) {
+ continue;
+ }
tcp_sync_buffer(c);
}
}
@@ -233,9 +267,12 @@ void tcp_strip_connection(struct TcpConnection *con) {
void tcp_close(vfs_fd_t *fd) {
struct TcpConnection *con = fd->inode->internal_object;
+ if (TCP_STATE_CLOSED == con->state) {
+ return;
+ }
assert(con);
- tcp_sync_buffer(con);
if (TCP_STATE_ESTABLISHED == con->state) {
+ tcp_sync_buffer(con);
tcp_strip_connection(con);
}
tcp_close_connection(con);
@@ -256,12 +293,16 @@ int tcp_read(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {
int tcp_has_data(vfs_inode_t *inode) {
struct TcpConnection *con = inode->internal_object;
+ if (TCP_STATE_ESTABLISHED != con->state) {
+ inode->is_open = 0;
+ }
return !(ringbuffer_isempty(&con->incoming_buffer));
}
int tcp_can_write(vfs_inode_t *inode) {
struct TcpConnection *con = inode->internal_object;
if (TCP_STATE_ESTABLISHED != con->state) {
+ inode->is_open = 0;
return 0;
}
if (con->no_delay) {
@@ -271,6 +312,11 @@ int tcp_can_write(vfs_inode_t *inode) {
(0 != tcp_can_send(con));
}
+int tcp_is_open(vfs_inode_t *inode) {
+ struct TcpConnection *con = inode->internal_object;
+ return (TCP_STATE_ESTABLISHED == con->state);
+}
+
int tcp_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {
(void)offset;
struct TcpConnection *con = fd->inode->internal_object;
@@ -462,6 +508,7 @@ int tcp_connect(vfs_fd_t *fd, const struct sockaddr *addr, socklen_t addrlen) {
fd->inode->_has_data = tcp_has_data;
fd->inode->_can_write = tcp_can_write;
+ fd->inode->_is_open = tcp_is_open;
fd->inode->write = tcp_write;
fd->inode->read = tcp_read;
fd->inode->close = tcp_close;
@@ -535,12 +582,6 @@ int uds_open(const char *path) {
return fd[0];
}
-int tcp_listen_has_data(vfs_inode_t *inode) {
- const SOCKET *s = (SOCKET *)inode->internal_object;
- const struct TcpListen *tcp_listen = s->object;
- return !stack_isempty(&tcp_listen->incoming_connections);
-}
-
int accept(int socket, struct sockaddr *address, socklen_t *address_len) {
(void)address;
(void)address_len;
@@ -587,6 +628,7 @@ int accept(int socket, struct sockaddr *address, socklen_t *address_len) {
NULL /*create_file*/, tcp_read, tcp_write, tcp_close /*close*/,
NULL /*create_directory*/, NULL /*get_vm_object*/, NULL /*truncate*/,
NULL /*stat*/, NULL /*send_signal*/, NULL /*connect*/);
+ inode->_is_open = tcp_is_open;
assert(inode);
return vfs_create_fd(O_RDWR, 0, 0 /*is_tty*/, inode, NULL);
}
@@ -618,7 +660,7 @@ struct TcpConnection *tcp_get_incoming_connection(struct TcpConnection *con,
if (!c) {
continue;
}
- if (TCP_STATE_ESTABLISHED == c->state) {
+ if (TCP_STATE_LISTEN != c->state) {
if (remove) {
assert(relist_remove(&con->incoming_connections, i));
}
@@ -739,6 +781,7 @@ int tcp_create_fd(int is_nonblock) {
kfree(con);
return -ENOMEM;
}
+ inode->_is_open = tcp_is_open;
int fd = vfs_create_fd(O_RDWR | (is_nonblock ? O_NONBLOCK : 0), 0,
0 /*is_tty*/, inode, NULL);
if (fd < 0) {