From b38468d49f77c3ef4cadf6b0d24c70699cce67b4 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 17 Oct 2013 09:54:48 -0600 Subject: [PATCH] net_sendfile: Let the ACK callback handle the REXMIT flag and don't return until all data has been ACK'd. From Max Holtzberg --- ChangeLog | 6 ++++-- net/net_sendfile.c | 47 +++++++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7760eecbfd..ac87c9a833 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5787,5 +5787,7 @@ Max Holtzberg (2013-10-17). * net/uip/uip_tcpinput.c: Move tcp connection into SYN_RCVD state after aception instead of bypassing and moving directly into ESTABLISHED. - From Max Holtzber (2013-10-17). - + From Max Holtzberg (2013-10-17). + * net/net_sendfile.c: Let the ACK callback handle the REXMIT flag and + don't return until all data has been ACK'd. From Max Holtzberg + (2013-10-17). diff --git a/net/net_sendfile.c b/net/net_sendfile.c index 2b5f6b2116..17189ae0f1 100644 --- a/net/net_sendfile.c +++ b/net/net_sendfile.c @@ -170,12 +170,18 @@ static uint16_t ack_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn, dev->d_sndlen = 0; - /* Wake up the waiting thread */ - - sem_post(&pstate->snd_sem); - flags &= ~UIP_ACKDATA; } + else if ((flags & UIP_REXMIT) != 0) + { + nlldbg("REXMIT\n"); + + /* Yes.. in this case, reset the number of bytes that have been sent + * to the number of bytes that have been ACKed. + */ + + pstate->snd_sent = pstate->snd_acked; + } /* Check for a loss of connection */ @@ -187,10 +193,12 @@ static uint16_t ack_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn, net_lostconnection(pstate->snd_sock, flags); pstate->snd_sent = -ENOTCONN; - - sem_post(&pstate->snd_sem); } + /* Wake up the waiting thread */ + + sem_post(&pstate->snd_sem); + return flags; } @@ -224,20 +232,9 @@ static uint16_t sendfile_interrupt(FAR struct uip_driver_s *dev, FAR void *pvcon nllvdbg("flags: %04x acked: %d sent: %d\n", flags, pstate->snd_acked, pstate->snd_sent); - if ((flags & UIP_REXMIT) != 0) - { - /* Yes.. in this case, reset the number of bytes that have been sent - * to the number of bytes that have been ACKed. - */ - - pstate->snd_sent = pstate->snd_acked; - - /* Fall through to re-send data from the last that was ACKed */ - } - /* Check for a loss of connection */ - else if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0) + if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0) { /* Report not connected */ @@ -356,6 +353,14 @@ static uint16_t sendfile_interrupt(FAR struct uip_driver_s *dev, FAR void *pvcon } #endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ + if (pstate->snd_sent >= pstate->snd_flen + && pstate->snd_acked < pstate->snd_flen) + { + /* All data has been sent, but there are outstanding ACK's */ + + goto wait; + } + end_wait: /* Do not allow any further callbacks */ @@ -521,7 +526,7 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, /* Set up the ACK callback in the connection */ - state.snd_ackcb->flags = UIP_ACKDATA|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT; + state.snd_ackcb->flags = UIP_ACKDATA|UIP_REXMIT|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT; state.snd_ackcb->priv = (void*)&state; state.snd_ackcb->event = ack_interrupt; @@ -529,7 +534,7 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, do { - state.snd_datacb->flags = UIP_REXMIT|UIP_POLL; + state.snd_datacb->flags = UIP_POLL; state.snd_datacb->priv = (void*)&state; state.snd_datacb->event = sendfile_interrupt; @@ -539,7 +544,7 @@ ssize_t net_sendfile(int outfd, struct file *infile, off_t *offset, uip_lockedwait(&state.snd_sem); } - while (state.snd_sent > 0 && state.snd_acked < state.snd_flen); + while (state.snd_sent >= 0 && state.snd_acked < state.snd_flen); /* Set the socket state to idle */