diff options
author | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2016-03-25 18:38:13 +0200 |
---|---|---|
committer | Paul Sokolovsky <pfalcon@users.sourceforge.net> | 2016-03-25 18:38:13 +0200 |
commit | de0c84ebf1e18a5de4e1adb39cf33499b66d27b4 (patch) | |
tree | 7550d26745fbb9cef372876ba7439732175f98ec | |
parent | 5e75f335e6df01cddfc2cd8db24d5807e73c13a6 (diff) |
extmod/modlwip: lwip_tcp_send: Handle properly send buffer full condition.
Per POSIX http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html :
"If space is not available at the sending socket to hold the message to be
transmitted, and the socket file descriptor does not have O_NONBLOCK set,
send() shall block until space is available. If space is not available at the
sending socket to hold the message to be transmitted, and the socket file
descriptor does have O_NONBLOCK set, send() shall fail [with EAGAIN]."
-rw-r--r-- | extmod/modlwip.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/extmod/modlwip.c b/extmod/modlwip.c index bce5d9f88..59216c5d8 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -365,6 +365,35 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ // Helper function for send/sendto to handle TCP packets STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { u16_t available = tcp_sndbuf(socket->pcb.tcp); + + if (available == 0) { + // Non-blocking socket + if (socket->timeout == 0) { + *_errno = EAGAIN; + return -1; + } + + mp_uint_t start = mp_hal_ticks_ms(); + // Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it + // sending direction, but not receiving. Consequently, check for both STATE_CONNECTED + // and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent. + // If peer fully closed socket, we would have socket->state set to ERR_RST (connection + // reset) by error callback. + // Avoid sending too small packets, so wait until at least 16 bytes available + while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) { + if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) { + *_errno = ETIMEDOUT; + return -1; + } + poll_sockets(); + } + + if (socket->state < 0) { + *_errno = error_lookup_table[-socket->state]; + return -1; + } + } + u16_t write_len = MIN(available, len); err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY); |