diff options
author | Marvin Borner | 2020-11-24 12:15:01 +0100 |
---|---|---|
committer | Marvin Borner | 2020-11-24 12:15:01 +0100 |
commit | 39f3538f7ee56dab414d62201235f8427b4a9592 (patch) | |
tree | f58a946b8db1e753bfa9d1123d39ba52f06b0770 | |
parent | 8babf8b26e23ffdd8094c810295061effde153dd (diff) |
Added userspace-based network timeout
The network in my whole city is down right now, so I've done some
error catching using timeouts etc without the kernel blocking
everything. Not having internet is exhausting though :(
-rw-r--r-- | apps/browser.c | 5 | ||||
-rw-r--r-- | apps/server.c | 7 | ||||
-rw-r--r-- | kernel/features/net.c | 28 | ||||
-rw-r--r-- | kernel/features/syscall.c | 13 | ||||
-rw-r--r-- | kernel/inc/net.h | 1 | ||||
-rw-r--r-- | libc/inc/sys.h | 2 | ||||
-rw-r--r-- | libnet/dns.c | 4 | ||||
-rw-r--r-- | libnet/inc/net.h | 46 |
8 files changed, 60 insertions, 46 deletions
diff --git a/apps/browser.c b/apps/browser.c index 7f4fc6e..157ddbd 100644 --- a/apps/browser.c +++ b/apps/browser.c @@ -148,11 +148,12 @@ void on_submit(void *event, struct element *box) struct element_label *c = code_label->data; struct socket *socket = net_open(S_TCP); - if (socket && net_connect(socket, ip, 80)) { + if (socket && net_connect(socket, ip, 80, NET_TIMEOUT)) { net_send(socket, query, strlen(query)); char buf[4096] = { 0 }; char parsed[4096] = { 0 }; - net_receive(socket, buf, 4096); + if (!net_receive(socket, buf, 4096, NET_TIMEOUT)) + return; parse(http_data(buf), 4096, parsed); l->text = parsed[0] ? parsed : http_data(buf); c->text = http_code(buf); diff --git a/apps/server.c b/apps/server.c index 4ab3369..6aca617 100644 --- a/apps/server.c +++ b/apps/server.c @@ -21,7 +21,8 @@ int main() socket->state = S_CONNECTED; char buf[4096] = { 0 }; - net_receive(socket, buf, 4096); + if (!net_receive(socket, buf, 4096, NET_NO_TIMEOUT)) + break; char path[128] = { 0 }; strcat(path, PATH); @@ -41,5 +42,7 @@ int main() net_close(socket); } - return 0; + print("Server closed!\n"); + + return 1; } diff --git a/kernel/features/net.c b/kernel/features/net.c index d2fa4b9..3fa28c9 100644 --- a/kernel/features/net.c +++ b/kernel/features/net.c @@ -504,6 +504,8 @@ static void tcp_handle_packet(struct tcp_packet *packet, u32 dst, int len) tcp->ack_no = recv_seq; tcp->seq_no = recv_ack; + proc_from_pid(socket->pid)->state = PROC_RUNNING; + socket->state = S_CONNECTED; tcp->state++; return; @@ -523,7 +525,6 @@ static void tcp_handle_packet(struct tcp_packet *packet, u32 dst, int len) // TODO: How many segments are going to be sent?! if ((flags & 0xff) == (TCP_FLAG_ACK | TCP_FLAG_PSH)) { - proc_from_pid(socket->pid)->state = PROC_RUNNING; tcp_send_packet(socket, TCP_FLAG_ACK, NULL, 0); tcp_send_packet(socket, TCP_FLAG_FIN | TCP_FLAG_ACK, NULL, 0); tcp->state++; @@ -764,22 +765,8 @@ int net_connect(struct socket *socket, u32 ip_addr, u16 dst_port) socket->prot.tcp.ack_no = 0; socket->prot.tcp.state = 0; socket->state = S_CONNECTING; - // TODO: Don't block kernel tcp_send_packet(socket, TCP_FLAG_SYN, NULL, 0); - scheduler_disable(); - sti(); - u32 time = timer_get(); - while ((socket->state != S_CONNECTED && timer_get() - time < 1000)) { - if (socket->state == S_FAILED) - break; - } - cli(); - scheduler_enable(); - if (socket->state != S_CONNECTED) { - socket->state = S_FAILED; - return 0; - } - return 1; + return 0; } else if (socket->type == S_UDP) { socket->state = S_CONNECTED; return 1; @@ -804,15 +791,6 @@ void net_send(struct socket *socket, void *data, u32 len) } } -int net_data_available(struct socket *socket) -{ - if (net_installed() && socket && socket->packets && socket->packets->head && - ((struct socket_data *)socket->packets->head->data)->length > 0) - return 1; - else - return 0; -} - int net_receive(struct socket *socket, void *buf, u32 len) { if (!net_installed() || !socket || !socket->packets) diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 3d70dbb..01720c5 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -111,7 +111,13 @@ void syscall_handler(struct regs *r) break; } case SYS_NET_CONNECT: { - r->eax = net_connect((void *)r->ebx, r->ecx, r->edx); + struct socket *s = (void *)r->ebx; + if (s->state == S_CONNECTED) + r->eax = 1; + else if (s->state == S_FAILED || s->state == S_CLOSED) + r->eax = 0; + else if (s->state == S_OPEN) + r->eax = net_connect(s, r->ecx, r->edx); break; } case SYS_NET_SEND: { @@ -119,11 +125,6 @@ void syscall_handler(struct regs *r) break; } case SYS_NET_RECEIVE: { - if (!net_data_available((void *)r->ebx)) { - proc_current()->state = PROC_SLEEPING; - proc_yield(r); - return; - } r->eax = net_receive((void *)r->ebx, (void *)r->ecx, r->edx); break; } diff --git a/kernel/inc/net.h b/kernel/inc/net.h index 2ad3d65..2852328 100644 --- a/kernel/inc/net.h +++ b/kernel/inc/net.h @@ -161,7 +161,6 @@ int net_close(struct socket *socket); int net_connect(struct socket *socket, u32 ip_addr, u16 dst_port); void net_send(struct socket *socket, void *data, u32 len); int net_receive(struct socket *socket, void *buf, u32 len); -int net_data_available(struct socket *socket); int net_installed(void); void net_install(void); diff --git a/libc/inc/sys.h b/libc/inc/sys.h index a9f7820..64ce7f5 100644 --- a/libc/inc/sys.h +++ b/libc/inc/sys.h @@ -80,7 +80,7 @@ int sysv(enum sys num, ...); } \ } #define yield() (int)sys0(SYS_YIELD) -#define time() (int)sys0(SYS_TIME) +#define time() (u32) sys0(SYS_TIME) #define event_register(id) sys1(SYS_REGISTER, (int)(id)) #define event_unregister(id) sys1(SYS_UNREGISTER, (int)(id)) diff --git a/libnet/dns.c b/libnet/dns.c index fe57cc4..0ca2f99 100644 --- a/libnet/dns.c +++ b/libnet/dns.c @@ -96,7 +96,7 @@ static u32 dns_handle_packet(struct dns_packet *packet) u32 dns_request(const char *name) { struct socket *socket = net_open(S_UDP); - if (!socket || !net_connect(socket, dns_ip_addr, 53) || part_count(name) == 1) + if (!socket || !net_connect(socket, dns_ip_addr, 53, NET_TIMEOUT) || part_count(name) == 1) return 0; u32 length = sizeof(struct dns_packet) + strlen(name) + part_count(name) + 4; @@ -107,7 +107,7 @@ u32 dns_request(const char *name) free(packet); u8 buf[1024] = { 0 }; - int l = net_receive(socket, buf, 1024); + int l = net_receive(socket, buf, 1024, NET_TIMEOUT); net_close(socket); if (l > 0) return dns_handle_packet((void *)buf); diff --git a/libnet/inc/net.h b/libnet/inc/net.h index 5dd4ee1..6884690 100644 --- a/libnet/inc/net.h +++ b/libnet/inc/net.h @@ -6,6 +6,7 @@ #include <dns.h> #include <http.h> #include <ip.h> +#include <print.h> #include <socket.h> #include <sys.h> @@ -18,10 +19,32 @@ #define ip(a, b, c, d) \ ((((a)&0xff) << 24) | (((b)&0xff) << 16) | (((c)&0xff) << 8) | (((d)&0xff) << 0)) +#define NET_TIMEOUT 500 +#define NET_NO_TIMEOUT 0 + +static inline int net_data_available(struct socket *socket) +{ + return (socket && socket->packets && socket->packets->head && socket->packets->head->data && + ((struct socket_data *)socket->packets->head->data)->length > 0); +} + #define net_open(type) (void *)sys1(SYS_NET_OPEN, (int)(type)) -#define net_connect(socket, ip_addr, dst_port) \ - (int)sys3(SYS_NET_CONNECT, (int)(socket), (int)(ip_addr), (int)(dst_port)) #define net_send(socket, data, len) (void)sys3(SYS_NET_SEND, (int)(socket), (int)(data), (int)(len)) + +static inline int net_connect(struct socket *socket, u32 ip_addr, u16 dst_port, u32 timeout) +{ + if (!socket || !ip_addr || !dst_port) + return 0; + sys3(SYS_NET_CONNECT, (int)(socket), (int)(ip_addr), (int)(dst_port)); + int time = time(); + while (socket->state != S_CONNECTED) { + if (socket->state == S_FAILED || (timeout && time() - time >= timeout)) + return 0; + yield(); + } + return 1; +} + static inline int net_close(struct socket *socket) { int res = 0; @@ -29,12 +52,21 @@ static inline int net_close(struct socket *socket) ; return res; } -static inline int net_receive(struct socket *socket, void *buf, u32 len) + +static inline int net_receive(struct socket *socket, void *buf, u32 len, u32 timeout) { - int res = 0; - while (!(res = (int)sys3(SYS_NET_RECEIVE, (int)(socket), (int)(buf), (int)(len)))) - ; - return res; + if (!socket || !buf || !len) + return 0; + + int time = time(); + while (!net_data_available(socket)) { + if (socket->state == S_FAILED || (timeout && time() - time >= timeout)) + return 0; + yield(); + } + + // TODO: Only return once all segments are received? + return (int)sys3(SYS_NET_RECEIVE, (int)(socket), (int)(buf), (int)(len)); } #endif |