diff --git a/ChangeLog b/ChangeLog index 9c9386b0c9b187283906dcec863f345bcd628bdc..05b8b3f1ae06196f465363a7018401839122a547 100644 --- a/ChangeLog +++ b/ChangeLog @@ -265,3 +265,4 @@ * Fix UDP recvfrom timeout bug * Correct processing of input UDP broadcast packets. * Verfied basic DHCP client functionality (netutils/dhcpc) + * Implemented send() timeout logic diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index e6fd36bddeea5942d3fa060233aecc6b08db5454..a0546ee630de6911371db4a6208faf8816cf35d4 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -753,6 +753,7 @@ Other memory: * Fix UDP recvfrom timeout bug * Correct processing of input UDP broadcast packets. * Verfied basic DHCP client functionality (netutils/dhcpc) + * Implemented send() timeout logic </pre></ul> <table width ="100%"> diff --git a/TODO b/TODO index 500013d146fa78c31050f417e8f082f50d88c5a0..a41b5f59d842e1f9160b6513ca781546d4fab6a0 100644 --- a/TODO +++ b/TODO @@ -29,10 +29,8 @@ o C++ Support - Need to call static constructors o Network -- Did not implement send() and sendto() timeouts. Option is setable via setsockopt, - but is not implemented. -- uIP's netutils/smtp, dpcpc, resolv, webclient -- untested -- Should implement SOCK_RAW +- uIP's netutils/smtp, resolv, webclient -- untested +- Should implement SOCK_RAW, SOCK_PACKET - uIP polling issues: (1) Current logic will not support multiple ethernet drivers. Each driver should poll on TCP connections connect on the network supported by the driver; UDP @@ -44,6 +42,7 @@ o Network - uIP/Socket callback logic is not thread safe. This means that a socket cannot be used concurrently by two threads. Minimal fix: Add mutex to support exclusion. - IPv6 support is incomplete +- Incoming UDP broadcast should only be accepted if listening on INADDR_ANY(?) o USB - Implement USB device support diff --git a/net/accept.c b/net/accept.c index 8c32eac3a888cc146e8a91f0bb5ffecc34ce18bb..0541fa0617ab33fb813b38428eabc9859a321f7b 100644 --- a/net/accept.c +++ b/net/accept.c @@ -111,12 +111,7 @@ static inline void accept_tcpsender(struct uip_conn *conn, struct accept_s *psta { addr->sin_family = AF_INET; addr->sin_port = conn->rport; - -#ifdef CONFIG_NET_IPv6 uip_ipaddr_copy(addr->sin_addr.s_addr, conn->ripaddr); -#else - uip_ipaddr_copy(addr->sin_addr.s_addr, conn->ripaddr); -#endif } } #endif @@ -400,4 +395,4 @@ errout: return ERROR; } -#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && CONFIG_NET_TCP*/ +#endif /* CONFIG_NET && CONFIG_NSOCKET_DESCRIPTORS && CONFIG_NET_TCP */ diff --git a/net/send.c b/net/send.c index 67acc62856bcd1d862c161237b0bbbd661035969..15a7adc0b544ac7c96becad11d20ddc6c59cefcf 100644 --- a/net/send.c +++ b/net/send.c @@ -75,6 +75,9 @@ struct send_s ssize_t snd_sent; /* The number of bytes sent */ uint32 snd_isn; /* Initial sequence number */ uint32 snd_acked; /* The number of bytes acked */ +#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) + uint32 snd_time; /* last send time for determining timeout */ +#endif }; /**************************************************************************** @@ -129,6 +132,46 @@ static uint32 send_getackno(struct uip_driver_s *dev) return ntohl(tmp); } +/**************************************************************************** + * Function: send_timeout + * + * Description: + * Check for send timeout. + * + * Parameters: + * pstate send state structure + * + * Returned Value: + * TRUE:timeout FALSE:no timeout + * + * Assumptions: + * Running at the interrupt level + * + ****************************************************************************/ + +#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) +static inline int send_timeout(struct send_s *pstate) +{ + FAR struct socket *psock = 0; + + /* Check for a timeout configured via setsockopts(SO_SNDTIMEO). + * If none... we well let the send wait forever. + */ + + psock = pstate->snd_sock; + if (psock && psock->s_sndtimeo != 0) + { + /* Check if the configured timeout has elapsed */ + + return net_timeo(pstate->snd_time, psock->s_sndtimeo); + } + + /* No timeout */ + + return FALSE; +} +#endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ + /**************************************************************************** * Function: send_interrupt * @@ -149,7 +192,8 @@ static uint32 send_getackno(struct uip_driver_s *dev) * ****************************************************************************/ -static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags) +static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, + uint8 flags) { struct send_s *pstate = (struct send_s *)conn->data_private; @@ -161,10 +205,10 @@ static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uin if ((flags & UIP_ACKDATA) != 0) { - /* The current acknowledgement number number is the (relative) offset of - * the of the next byte needed by the receiver. The snd_isn is the offset - * of the first byte to send to the receiver. The difference is the number - * of bytes to be acknowledged. + /* The current acknowledgement number number is the (relative) offset + * of the of the next byte needed by the receiver. The snd_isn is the + * offset of the first byte to send to the receiver. The difference + * is the number of bytes to be acknowledged. */ pstate->snd_acked = send_getackno(dev) - pstate->snd_isn; @@ -175,23 +219,14 @@ static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uin if ( pstate->snd_acked >= pstate->snd_buflen) { - /* Yes. Then pstate->snd_len should hold the number of bytes actually - * sent. - * - * Don't allow any further call backs. - */ - - conn->data_flags = 0; - conn->data_private = NULL; - conn->data_event = NULL; - - /* Wake up the waiting thread, returning the number of bytes + /* Yes. Then pstate->snd_len should hold the number of bytes * actually sent. */ - sem_post(&pstate->snd_sem); - return flags; + goto end_wait; } + + /* No.. fall through to send more data if necessary */ } /* Check if we are being asked to retransmit data */ @@ -203,25 +238,19 @@ static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uin */ 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) { - /* Stop further callbacks */ - - conn->data_flags = 0; - conn->data_private = NULL; - conn->data_event = NULL; - /* Report not connected */ + nvdbg("Lost connection\n"); pstate->snd_sent = -ENOTCONN; - - /* Wake up the waiting thread */ - - sem_post(&pstate->snd_sem); + goto end_wait; } /* We get here if (1) not all of the data has been ACKed, (2) we have been @@ -250,6 +279,35 @@ static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uin pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); } + /* All data has been send and we are just waiting for ACK or re-tranmist + * indications to complete the send. Check for a timeout. + */ + +#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) + else if (send_timeout(pstate)) + { + /* Yes.. report the timeout */ + + nvdbg("TCP timeout\n"); + pstate->snd_sent = -EAGAIN; + goto end_wait; + } +#endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ + + /* Continue waiting */ + + return flags; + +end_wait: + /* Do not allow any further callbacks */ + + conn->data_flags = 0; + conn->data_private = NULL; + conn->data_event = NULL; + + /* Wake up the waiting thread */ + + sem_post(&pstate->snd_sem); return flags; }