diff options
Diffstat (limited to 'libhw/host_net.c')
-rw-r--r-- | libhw/host_net.c | 118 |
1 files changed, 95 insertions, 23 deletions
diff --git a/libhw/host_net.c b/libhw/host_net.c index fcdac57..1563ced 100644 --- a/libhw/host_net.c +++ b/libhw/host_net.c @@ -22,6 +22,7 @@ #include <libcr/coroutine.h> #include <libmisc/vcall.h> +#include <libhw/generic/bootclock.h> #include <libhw/host_net.h> /* common *********************************************************************/ @@ -86,18 +87,20 @@ static inline ssize_t hostnet_map_errno(ssize_t v) { /* TCP init() ( AKA socket(3) + listen(3) )************************************/ static implements_net_stream_conn *hostnet_tcp_accept(implements_net_stream_listener *_listener); +static void hostnet_tcp_set_read_deadline(implements_net_stream_conn *conn, uint64_t ts_ns); static ssize_t hostnet_tcp_read(implements_net_stream_conn *conn, void *buf, size_t count); static ssize_t hostnet_tcp_write(implements_net_stream_conn *conn, void *buf, size_t count); -static int hostnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr); +static int hostnet_tcp_close(implements_net_stream_conn *conn, bool rd, bool wr); static struct net_stream_listener_vtable hostnet_tcp_listener_vtable = { .accept = hostnet_tcp_accept, }; static struct net_stream_conn_vtable hostnet_tcp_conn_vtable = { - .read = hostnet_tcp_read, - .write = hostnet_tcp_write, - .close = hostnet_tcp_close, + .set_read_deadline = hostnet_tcp_set_read_deadline, + .read = hostnet_tcp_read, + .write = hostnet_tcp_write, + .close = hostnet_tcp_close, }; void hostnet_tcp_listener_init(struct hostnet_tcp_listener *self, uint16_t port) { @@ -145,7 +148,7 @@ static void *hostnet_pthread_accept(void *_args) { *(args->ret_connfd) = -errno; WAKE_COROUTINE(args); return NULL; -}; +} static implements_net_stream_conn *hostnet_tcp_accept(implements_net_stream_listener *_listener) { struct hostnet_tcp_listener *listener = @@ -169,11 +172,20 @@ static implements_net_stream_conn *hostnet_tcp_accept(implements_net_stream_list /* TCP read() *****************************************************************/ +static void hostnet_tcp_set_read_deadline(implements_net_stream_conn *_conn, uint64_t ts_ns) { + struct _hostnet_tcp_conn *conn = + VCALL_SELF(struct _hostnet_tcp_conn, implements_net_stream_conn, _conn); + assert(conn); + + conn->read_deadline_ns = ts_ns; +} + struct hostnet_pthread_read_args { pthread_t cr_thread; cid_t cr_coroutine; int connfd; + struct timeval timeout; void *buf; size_t count; @@ -182,12 +194,22 @@ struct hostnet_pthread_read_args { static void *hostnet_pthread_read(void *_args) { struct hostnet_pthread_read_args *args = _args; + + *(args->ret) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, + &args->timeout, sizeof(args->timeout)); + if (*(args->ret) < 0) + goto end; + *(args->ret) = read(args->connfd, args->buf, args->count); if (*(args->ret) < 0) + goto end; + + end: + if (*(args->ret) < 0) *(args->ret) = hostnet_map_errno(-errno); WAKE_COROUTINE(args); return NULL; -}; +} static ssize_t hostnet_tcp_read(implements_net_stream_conn *_conn, void *buf, size_t count) { struct _hostnet_tcp_conn *conn = @@ -205,6 +227,20 @@ static ssize_t hostnet_tcp_read(implements_net_stream_conn *_conn, void *buf, si .ret = &ret, }; + if (conn->read_deadline_ns) { + uint64_t now_ns = bootclock_get_ns(); + if (conn->read_deadline_ns < now_ns) + return -NET_ETIMEDOUT; + uint64_t timeout_ns = conn->read_deadline_ns-now_ns; + args.timeout.tv_sec = timeout_ns + /NS_PER_S; + args.timeout.tv_usec = (timeout_ns - ((uint64_t)args.timeout.tv_sec)*NS_PER_S) + /(NS_PER_S/US_PER_S); + } else { + args.timeout.tv_sec = 0; + args.timeout.tv_usec = 0; + } + if (RUN_PTHREAD(hostnet_pthread_read, &args)) return -NET_ETHREAD; return ret; @@ -238,7 +274,7 @@ static void *hostnet_pthread_write(void *_args) { *(args->ret) = done; WAKE_COROUTINE(args); return NULL; -}; +} static ssize_t hostnet_tcp_write(implements_net_stream_conn *_conn, void *buf, size_t count) { struct _hostnet_tcp_conn *conn = @@ -282,6 +318,8 @@ static int hostnet_tcp_close(implements_net_stream_conn *_conn, bool rd, bool wr /* UDP init() *****************************************************************/ +static void hostnet_udp_set_read_deadline(implements_net_packet_conn *self, + uint64_t ts_ns); static ssize_t hostnet_udp_sendto(implements_net_packet_conn *self, void *buf, size_t len, struct net_ip4_addr addr, uint16_t port); static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *self, void *buf, size_t len, @@ -289,9 +327,10 @@ static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *self, void *buf, static int hostnet_udp_close(implements_net_packet_conn *self); static struct net_packet_conn_vtable hostnet_udp_conn_vtable = { - .sendto = hostnet_udp_sendto, - .recvfrom = hostnet_udp_recvfrom, - .close = hostnet_udp_close, + .set_read_deadline = hostnet_udp_set_read_deadline, + .sendto = hostnet_udp_sendto, + .recvfrom = hostnet_udp_recvfrom, + .close = hostnet_udp_close, }; void hostnet_udp_conn_init(struct hostnet_udp_conn *self, uint16_t port) { @@ -354,7 +393,7 @@ static void *hostnet_pthread_sendto(void *_args) { } static ssize_t hostnet_udp_sendto(implements_net_packet_conn *_conn, void *buf, size_t count, - struct net_ip4_addr node, uint16_t port) { + struct net_ip4_addr node, uint16_t port) { struct hostnet_udp_conn *conn = VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); assert(conn); @@ -379,11 +418,21 @@ static ssize_t hostnet_udp_sendto(implements_net_packet_conn *_conn, void *buf, /* UDP recvfrom() *************************************************************/ +static void hostnet_udp_set_read_deadline(implements_net_packet_conn *_conn, + uint64_t ts_ns) { + struct hostnet_udp_conn *conn = + VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); + assert(conn); + + conn->read_deadline_ns = ts_ns; +} + struct hostnet_pthread_recvfrom_args { pthread_t cr_thread; cid_t cr_coroutine; int connfd; + struct timeval timeout; void *buf; size_t count; @@ -402,26 +451,35 @@ static void *hostnet_pthread_recvfrom(void *_args) { } addr = { 0 }; socklen_t addr_size; + *(args->ret_size) = setsockopt(args->connfd, SOL_SOCKET, SO_RCVTIMEO, + &args->timeout, sizeof(args->timeout)); + if (*(args->ret_size) < 0) + goto end; + *(args->ret_size) = recvfrom(args->connfd, args->buf, args->count, 0, &addr.gen, &addr_size); if (*(args->ret_size) < 0) - *(args->ret_size) = hostnet_map_errno(-errno); - else { - assert(addr.in.sin_family == AF_INET); - if (args->ret_node) { - args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF; - args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF; - args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF; - args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF; - } - if (args->ret_port) - (*args->ret_port) = ntohs(addr.in.sin_port); + goto end; + + assert(addr.in.sin_family == AF_INET); + if (args->ret_node) { + args->ret_node->octets[0] = (addr.in.sin_addr.s_addr >> 24) & 0xFF; + args->ret_node->octets[1] = (addr.in.sin_addr.s_addr >> 16) & 0xFF; + args->ret_node->octets[2] = (addr.in.sin_addr.s_addr >> 8) & 0xFF; + args->ret_node->octets[3] = (addr.in.sin_addr.s_addr >> 0) & 0xFF; } + if (args->ret_port) { + (*args->ret_port) = ntohs(addr.in.sin_port); + } + + end: + if (*(args->ret_size) < 0) + *(args->ret_size) = hostnet_map_errno(-errno); WAKE_COROUTINE(args); return NULL; } static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *_conn, void *buf, size_t count, - struct net_ip4_addr *ret_node, uint16_t *ret_port) { + struct net_ip4_addr *ret_node, uint16_t *ret_port) { struct hostnet_udp_conn *conn = VCALL_SELF(struct hostnet_udp_conn, implements_net_packet_conn, _conn); assert(conn); @@ -439,6 +497,20 @@ static ssize_t hostnet_udp_recvfrom(implements_net_packet_conn *_conn, void *buf .ret_node = ret_node, .ret_port = ret_port, }; + if (conn->read_deadline_ns) { + uint64_t now_ns = bootclock_get_ns(); + if (conn->read_deadline_ns < now_ns) + return -NET_ETIMEDOUT; + uint64_t timeout_ns = conn->read_deadline_ns-now_ns; + args.timeout.tv_sec = timeout_ns + /NS_PER_S; + args.timeout.tv_usec = (timeout_ns - ((uint64_t)args.timeout.tv_sec)*NS_PER_S) + /(NS_PER_S/US_PER_S); + } else { + args.timeout.tv_sec = 0; + args.timeout.tv_usec = 0; + } + if (RUN_PTHREAD(hostnet_pthread_recvfrom, &args)) return -NET_ETHREAD; return ret; |