From: Guo-Fu Tseng <coolda...@cooldavid.org> Michael suggested something like: =============================================================== struct list_head received = LIST_HEAD_INIT ( received ); ... while ( ! list_empty ( &tcp->rx_queue ) ) { ... tcp_rx_data ( tcp, seq, iob_disown ( iobuf ), &received ); ... }
list_for_each_entry_safe ( iobuf, tmp, &received, list ) { // deliver iobuf via xfer_deliver_iob() } if ( tcp->state & TCP_STATE_RCVD ( TCP_FIN ) ) tcp_close ( tcp, 0 ); =============================================================== But after some thought I think making the change like this commit can have same behavior, but simplified by not using extra queue. Which can also save some code size. In this patch: 1. We call xfer_deliver_iob() after fully updated/handled received TCP state. In which to have better timing that upper-layer protocol might call tcp_xfer_close() to initiate a shutdown, or sending extra data. 2. We move tcp_close() out from tcp_rx_fin() because tcp_close() nullified the xfer interface. It'll cause error to call xfer_deliver_iob() after tcp_rx_fin(). (So that I proposed an idea to clean up tcp_close(), I'll post it in later commit.) Signed-off-by: Guo-Fu Tseng <coolda...@cooldavid.org> --- src/net/tcp.c | 34 +++++++++++++++++++--------------- 1 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/net/tcp.c b/src/net/tcp.c index 637bfce..b30c91c 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -861,18 +861,17 @@ static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, * * This function takes ownership of the I/O buffer. */ -static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, +static struct io_buffer* tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, struct io_buffer *iobuf ) { uint32_t already_rcvd; uint32_t len; - int rc; /* Ignore duplicate or out-of-order data */ already_rcvd = ( tcp->rcv_ack - seq ); len = iob_len ( iobuf ); if ( already_rcvd >= len ) { free_iob ( iobuf ); - return 0; + return NULL; } iob_pull ( iobuf, already_rcvd ); len -= already_rcvd; @@ -880,14 +879,7 @@ static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, /* Acknowledge new data */ tcp_rx_seq ( tcp, len ); - /* Deliver data to application */ - if ( ( rc = xfer_deliver_iob ( &tcp->xfer, iobuf ) ) != 0 ) { - DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", - tcp, seq, ( seq + len ), strerror ( rc ) ); - return rc; - } - - return 0; + return iobuf; } /** @@ -909,9 +901,6 @@ static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) { /* Mark FIN as received */ tcp->tcp_state |= TCP_STATE_RCVD ( TCP_FIN ); - /* Close connection */ - tcp_close ( tcp, 0 ); - return 0; } @@ -1009,6 +998,7 @@ static void tcp_process_rx_queue ( struct tcp_connection *tcp ) { uint32_t seq; unsigned int flags; size_t len; + int rc; /* Process all applicable received buffers */ list_for_each_entry_safe ( iobuf, tmp, &tcp->rx_queue, list ) { @@ -1024,7 +1014,7 @@ static void tcp_process_rx_queue ( struct tcp_connection *tcp ) { len = iob_len ( iobuf ); /* Handle new data, if any */ - tcp_rx_data ( tcp, seq, iob_disown ( iobuf ) ); + iobuf = tcp_rx_data ( tcp, seq, iobuf ); seq += len; /* Handle FIN, if present */ @@ -1032,6 +1022,20 @@ static void tcp_process_rx_queue ( struct tcp_connection *tcp ) { tcp_rx_fin ( tcp, seq ); seq++; } + + /* Deliver data to application, if any */ + if ( iobuf && + ( rc = xfer_deliver_iob ( &tcp->xfer, + iob_disown ( iobuf ) ) ) != 0 ) { + DBGC ( tcp, "TCP %p could not deliver %08x..%08x: %s\n", + tcp, ( seq - len - ( flags & TCP_FIN ) ? 1 : 0 ), + seq, strerror ( rc ) ); + } + } + + if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_FIN ) ) { + /* Close connection */ + tcp_close ( tcp, 0 ); } } -- 1.7.1 _______________________________________________ gPXE-devel mailing list gPXE-devel@etherboot.org http://etherboot.org/mailman/listinfo/gpxe-devel