From fad2787f2394bad3cf105ca5b4cf411db6d34aa6 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sun, 22 Jul 2018 13:19:01 +0200 Subject: [PATCH] Allow utcp_send() before a connection has been fully established. This will put the data in the send buffer, and it will be sent when possible. This also allows the socket to be shut down for writing before it has reached the ESTABLISHED state. --- utcp.c | 36 ++++++++++++++++++++++++++++++------ utcp_priv.h | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/utcp.c b/utcp.c index 49b89ab..7c4e563 100644 --- a/utcp.c +++ b/utcp.c @@ -580,12 +580,12 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { switch(c->state) { case CLOSED: case LISTEN: - case SYN_SENT: - case SYN_RECEIVED: debug("Error: send() called on unconnected connection %p\n", c); errno = ENOTCONN; return -1; + case SYN_SENT: + case SYN_RECEIVED: case ESTABLISHED: case CLOSE_WAIT: break; @@ -621,6 +621,12 @@ ssize_t utcp_send(struct utcp_connection *c, const void *data, size_t len) { } c->snd.last += len; + + // Don't send anything yet if the connection has not fully established yet + + if (c->state == SYN_SENT || c->state == SYN_RECEIVED) + return len; + ack(c, false); if(!is_reliable(c)) { @@ -1350,7 +1356,12 @@ skip_ack: c->rcv.irs = hdr.seq; c->rcv.nxt = hdr.seq; - set_state(c, ESTABLISHED); + if(c->shut_wr) { + c->snd.last++; + set_state(c, FIN_WAIT_1); + } else { + set_state(c, ESTABLISHED); + } // TODO: notify application of this somehow. break; @@ -1538,6 +1549,12 @@ int utcp_shutdown(struct utcp_connection *c, int dir) { return 0; } + // Only process shutting down writes once. + if (c->shut_wr) + return 0; + + c->shut_wr = true; + switch(c->state) { case CLOSED: case LISTEN: @@ -1545,7 +1562,6 @@ int utcp_shutdown(struct utcp_connection *c, int dir) { return -1; case SYN_SENT: - set_state(c, CLOSED); return 0; case SYN_RECEIVED: @@ -1823,9 +1839,17 @@ size_t utcp_get_sndbuf(struct utcp_connection *c) { } size_t utcp_get_sndbuf_free(struct utcp_connection *c) { - if(c && (c->state == ESTABLISHED || c->state == CLOSE_WAIT)) { + if (!c) + return 0; + + switch(c->state) { + case SYN_SENT: + case SYN_RECEIVED: + case ESTABLISHED: + case CLOSE_WAIT: return buffer_free(&c->sndbuf); - } else { + + default: return 0; } } diff --git a/utcp_priv.h b/utcp_priv.h index 437941f..6c5c1f8 100644 --- a/utcp_priv.h +++ b/utcp_priv.h @@ -152,6 +152,7 @@ struct utcp_connection { bool nodelay; bool keepalive; + bool shut_wr; // Congestion avoidance state -- 2.39.5