Free (GPLv2) TCP/IP stack developed by TASS Belgium
Fork of PicoTCP by
Diff: modules/pico_tcp.c
- Revision:
- 31:d3b2dfcc358f
- Parent:
- 10:dd7111d4279f
--- a/modules/pico_tcp.c Tue Jun 11 23:28:50 2013 +0000 +++ b/modules/pico_tcp.c Wed Jun 12 13:35:01 2013 +0000 @@ -61,6 +61,7 @@ #endif + static inline int seq_compare(uint32_t a, uint32_t b) { uint32_t thresh = ((uint32_t)(-1))>>1; @@ -213,8 +214,11 @@ uint8_t x_mode; uint8_t dupacks; uint8_t backoff; + /* Close wait flag */ + uint8_t closing; +}; -}; +static void checkIfQueueEmptyAndFin(struct pico_socket_tcp * t); /* Queues */ static struct pico_queue tcp_in = {}; @@ -710,7 +714,7 @@ if (in_frame_len > f->payload_len - in_frame_off) in_frame_len = f->payload_len - in_frame_off; - memcpy(buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); + memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); tot_rd_len += in_frame_len; t->rcv_processed += in_frame_len; @@ -1041,6 +1045,44 @@ t->snd_nxt++; } +/*****/ +static inline void checkIfQueueEmptyAndFin(struct pico_socket_tcp * t) +{ + struct pico_socket *s =(struct pico_socket *)&t->sock; + if(t->closing && t->tcpq_out.frames==0) + { + s->state &= 0x00FFU; + /* set SHUT_REMOTE */ + s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; + s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; + tcp_dbg("TCP> Close-wait\n"); + if (s->wakeup) + { + s->wakeup(PICO_SOCK_EV_CLOSE, s); + } + t->closing = 0; + } + + if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replacled !f by tcpq check */ + if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { + tcp_dbg("TCP> buffer empty, shutdown established ...\n"); + /* send fin if queue empty and in state shut local (write) */ + tcp_send_fin(t); + /* change tcp state to FIN_WAIT1 */ + s->state &= 0x00FFU; + s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; + } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { + /* send fin if queue empty and in state shut local (write) */ + tcp_send_fin(t); + /* change tcp state to LAST_ACK */ + s->state &= 0x00FFU; + s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; + tcp_dbg("TCP> STATE: LAST_ACK.\n"); + } + } +} +/*****/ + static void tcp_sack_prepare(struct pico_socket_tcp *t) { struct pico_frame *pkt; @@ -1280,6 +1322,7 @@ add_retransmission_timer(t, 0); if (t->tcpq_out.size < t->tcpq_out.max_size) t->sock.ev_pending |= PICO_SOCK_EV_WR; + checkIfQueueEmptyAndFin(t); return; } } @@ -1739,19 +1782,31 @@ if (f->flags & PICO_TCP_ACK) tcp_ack(s,f); if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - tcp_dbg("TCP> Close-wait\n"); - if (s->wakeup){ - if(f->payload_len>0){ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->sock.ev_pending |=PICO_SOCK_EV_CLOSE; - }else - s->wakeup(PICO_SOCK_EV_CLOSE, s); + if(t->tcpq_out.frames == 0) + { + /* received FIN, increase ACK nr */ + t->rcv_nxt = long_be(hdr->seq) + 1; + s->state &= 0x00FFU; + s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; + /* set SHUT_REMOTE */ + s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; + tcp_dbg("TCP> Close-wait\n"); + if (s->wakeup){ + if(f->payload_len>0){ + struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; + t->sock.ev_pending |=PICO_SOCK_EV_CLOSE; + }else + s->wakeup(PICO_SOCK_EV_CLOSE, s); + } + } + else + { + if(!t->closing) + { + /* Update ACK for the first FIN */ + t->rcv_nxt = long_be(hdr->seq) + 1; + } + t->closing = 1; } } else { tcp_send_ack(t); /* return ACK */ @@ -2032,23 +2087,9 @@ // no packets in queue ?? } - if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replacled !f by tcpq check */ - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { - tcp_dbg("TCP> buffer empty, shutdown established ...\n"); - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to FIN_WAIT1 */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; - } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to LAST_ACK */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; - tcp_dbg("TCP> STATE: LAST_ACK.\n"); - } - } + // check to see if we are in the case where FIN was received + // but we still had data in the queue (tcpq_out) + checkIfQueueEmptyAndFin(t); return loop_score; }