diff --git a/src/devices/tap_user.c b/src/devices/tap_user.c index 50df34ab3..85d5e1dff 100644 --- a/src/devices/tap_user.c +++ b/src/devices/tap_user.c @@ -577,6 +577,7 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a tap_sock_t* ts = tap_tcp_lookup(tap, dst, src); if (ts) { tcp_ctx_t* tcp = ts->tcp; + bool reset = !!(flags & TCP_FLAG_RST); bool resp_ack = seq != tcp->ack; // Respond with ACK on keepalive bool cleanup = false; tcp->window = window; // Scale the window @@ -591,7 +592,7 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a } if (tcp->win_full && (tcp->state & TCP_STATE_RECV_OPEN) && tcp_window_avail(tcp)) { // Window became available - if (!tap_tcp_arm_poll(tap, ts)) cleanup = true; + if (!tap_tcp_arm_poll(tap, ts)) reset = true; tcp->win_full = false; } if (tcp->seq == tcp->seq_ack + 1 && ack == tcp->seq) { @@ -609,7 +610,7 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a if (tap_tcp_arm_poll(tap, ts)) { tcp->state |= TCP_STATE_ESTABLISHED; tcp->seq_ack++; - } else cleanup = true; + } else reset = true; } if (tcp->state == TCP_STATE_RECV_OPEN && (flags & TCP_FLAG_SYN)) { // Guest SYN ACKed an inbound connection @@ -618,7 +619,7 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a tcp->ack = seq + 1; tcp->seq_ack++; resp_ack = true; - } else cleanup = true; + } else reset = true; } } } @@ -629,7 +630,13 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a size_t send_len = size - data_off; size_t seq_off = tcp->ack - seq; if (send_len > seq_off) { - tcp->ack += net_tcp_send(ts->sock, buffer + data_off + seq_off, send_len - seq_off); + int32_t result = net_tcp_send(ts->sock, buffer + data_off + seq_off, send_len - seq_off); + if (result >= 0) { + tcp->ack += result; + } else if (result != NET_ERR_BLOCK) { + // Connection is reset + reset = true; + } } // Acknowledge the bytes actually sent // TODO: Reduce amount of response ACKs @@ -649,16 +656,15 @@ static void handle_tcp(tap_dev_t* tap, const uint8_t* buffer, size_t size, net_a } resp_ack = true; } - if (flags & TCP_FLAG_RST) { + if (reset) { // Reset the connection - if ((tcp->state & TCP_STATE_ESTABLISHED) && !(tcp->state & TCP_STATE_RECV_OPEN)) { + if (!(flags & TCP_FLAG_RST)) tap_tcp_segment(tap, ts, TCP_FLAG_RST); + if (!!(tcp->state & TCP_STATE_ESTABLISHED) != !!(tcp->state & TCP_STATE_RECV_OPEN)) { // Closed completely cleanup = true; } tcp->state = TCP_STATE_CLOSED; - resp_ack = false; - } - if (resp_ack) { + } else if (resp_ack) { // Handle keepalive, ACKs tap_tcp_segment(tap, ts, TCP_FLAG_ACK); } @@ -842,8 +848,9 @@ static void tap_udp_recv(tap_dev_t* tap, tap_sock_t* ts) size_t size = sizeof(buffer) - offset; if (ts->timeout != BOUND_INF) ts->timeout = 0; - size = net_udp_recv(ts->sock, buffer + offset, size, &addr); - if (size) { + int32_t result = net_udp_recv(ts->sock, buffer + offset, size, &addr); + if (result >= 0) { + size = result; tap_addr_convert(&addr); uint8_t* ipv4 = create_eth_frame(tap, buffer, ETH2_IPv4); uint8_t* udp = create_ipv4_frame(ipv4, size + UDP_HDR_SIZE, IP_PROTO_UDP, ts->addr.ip, addr.ip); @@ -864,10 +871,10 @@ static void tap_tcp_recv(tap_dev_t* tap, tap_sock_t* ts) tcp_segment_t* seg = safe_new_obj(tcp_segment_t); size_t size = sizeof(seg->buffer) - TCP_WRAP_SIZE; - uint32_t error = 0; - seg->size = net_tcp_recv(ts->sock, seg->buffer + TCP_WRAP_SIZE, size, &error); - if (seg->size) { + int32_t result = net_tcp_recv(ts->sock, seg->buffer + TCP_WRAP_SIZE, size); + if (result > 0) { // Push a segment and buffer it for retransmit + seg->size = result; uint8_t* ipv4 = create_eth_frame(tap, seg->buffer, ETH2_IPv4); uint8_t* tcp = create_ipv4_frame(ipv4, seg->size + TCP_HDR_SIZE, IP_PROTO_TCP, ts->addr.ip, net_sock_addr(ts->sock)->ip); create_tcp_segment(tcp, TCP_FLAG_PSH | TCP_FLAG_ACK, ts->tcp->seq, ts->tcp->ack, ts->addr.port, net_sock_addr(ts->sock)->port); @@ -885,14 +892,14 @@ static void tap_tcp_recv(tap_dev_t* tap, tap_sock_t* ts) eth_send(tap, seg->buffer, seg->size + TCP_WRAP_SIZE); } else { free(seg); - if (error == NET_ERR_DISCONNECT) { + if (result == NET_ERR_DISCONNECT) { // Receiving side closed ts->tcp->state &= ~TCP_STATE_RECV_OPEN; ts->tcp->seq++; tap_tcp_segment(tap, ts, TCP_FLAG_FIN | TCP_FLAG_ACK); net_poll_remove(tap->poll, ts->sock); - } else if (error != NET_ERR_BLOCK) { + } else if (result != NET_ERR_BLOCK) { // Connection reset tap_tcp_segment(tap, ts, TCP_FLAG_RST); diff --git a/src/networking.c b/src/networking.c index 6d636ac23..6ba802c50 100644 --- a/src/networking.c +++ b/src/networking.c @@ -389,7 +389,7 @@ static net_sock_t* net_init_localaddr(net_sock_t* sock, const net_addr_t* addr) return sock; } -static uint32_t net_last_error() +static int32_t net_last_error() { #ifdef _WIN32 int err = WSAGetLastError(); @@ -519,21 +519,21 @@ bool net_tcp_shutdown(net_sock_t* sock) return sock && shutdown(sock->fd, 1) == 0; } -size_t net_tcp_send(net_sock_t* sock, const void* buffer, size_t size) +int32_t net_tcp_send(net_sock_t* sock, const void* buffer, size_t size) { - int ret = sock ? send(sock->fd, buffer, size, 0) : 0; - return ret > 0 ? ret : 0; + if (sock == NULL) return NET_ERR_RESET; + int ret = send(sock->fd, buffer, size, 0); + if (ret < 0) return net_last_error(); + return ret; } -size_t net_tcp_recv(net_sock_t* sock, void* buffer, size_t size, uint32_t* error) +int32_t net_tcp_recv(net_sock_t* sock, void* buffer, size_t size) { - int ret = sock ? recv(sock->fd, buffer, size, 0) : 0; - if (error) { - if (ret > 0) *error = NET_ERR_NONE; - if (ret == 0) *error = NET_ERR_DISCONNECT; - if (ret < 0) *error = net_last_error(); - } - return ret > 0 ? ret : 0; + if (sock == NULL) return NET_ERR_RESET; + int ret = recv(sock->fd, buffer, size, 0); + if (ret > 0) return ret; + if (ret == 0) return NET_ERR_DISCONNECT; + return net_last_error(); } net_sock_t* net_udp_bind(const net_addr_t* addr) @@ -567,10 +567,10 @@ size_t net_udp_send(net_sock_t* sock, const void* buffer, size_t size, const net return ret > 0 ? ret : 0; } -size_t net_udp_recv(net_sock_t* sock, void* buffer, size_t size, net_addr_t* addr) +int32_t net_udp_recv(net_sock_t* sock, void* buffer, size_t size, net_addr_t* addr) { int ret = 0; - if (sock == NULL) return 0; + if (sock == NULL) return NET_ERR_RESET; if (sock->addr.type == NET_TYPE_IPV4) { struct sockaddr_in sock_addr = {0}; net_addrlen_t addr_len = sizeof(struct sockaddr_in); @@ -584,7 +584,8 @@ size_t net_udp_recv(net_sock_t* sock, void* buffer, size_t size, net_addr_t* add net_addr_from_sockaddr6(addr, &sock_addr); #endif } - return ret > 0 ? ret : 0; + if (ret < 0) return net_last_error(); + return ret; } // Generic socket operations diff --git a/src/networking.h b/src/networking.h index 933928092..6258a4750 100644 --- a/src/networking.h +++ b/src/networking.h @@ -51,11 +51,11 @@ extern const net_addr_t net_ipv6_local_addr; #define NET_IPV6_ANY (&net_ipv6_any_addr) #define NET_IPV6_LOCAL (&net_ipv6_local_addr) -#define NET_ERR_NONE 0x0 -#define NET_ERR_BLOCK 0x1 -#define NET_ERR_DISCONNECT 0x2 -#define NET_ERR_RESET 0x3 -#define NET_ERR_UNKNOWN 0xFFFF +#define NET_ERR_NONE 0 +#define NET_ERR_UNKNOWN (-1) +#define NET_ERR_BLOCK (-2) +#define NET_ERR_DISCONNECT (-3) +#define NET_ERR_RESET (-4) // TCP Sockets @@ -66,15 +66,15 @@ bool net_tcp_sockpair(net_sock_t* pair[2]); bool net_tcp_status(net_sock_t* sock); // Connected & not yet closed on both sides bool net_tcp_shutdown(net_sock_t* sock); // Send EOF (FIN), only recv() works afterwards -size_t net_tcp_send(net_sock_t* sock, const void* buffer, size_t size); -size_t net_tcp_recv(net_sock_t* sock, void* buffer, size_t size, uint32_t* error); +int32_t net_tcp_send(net_sock_t* sock, const void* buffer, size_t size); +int32_t net_tcp_recv(net_sock_t* sock, void* buffer, size_t size); // UDP Sockets net_sock_t* net_udp_bind(const net_addr_t* addr); size_t net_udp_send(net_sock_t* sock, const void* buffer, size_t size, const net_addr_t* addr); -size_t net_udp_recv(net_sock_t* sock, void* buffer, size_t size, net_addr_t* addr); +int32_t net_udp_recv(net_sock_t* sock, void* buffer, size_t size, net_addr_t* addr); // Generic socket operations