Skip to content

Commit de0c84e

Browse files
committed
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]."
1 parent 5e75f33 commit de0c84e

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

extmod/modlwip.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,35 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
365365
// Helper function for send/sendto to handle TCP packets
366366
STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
367367
u16_t available = tcp_sndbuf(socket->pcb.tcp);
368+
369+
if (available == 0) {
370+
// Non-blocking socket
371+
if (socket->timeout == 0) {
372+
*_errno = EAGAIN;
373+
return -1;
374+
}
375+
376+
mp_uint_t start = mp_hal_ticks_ms();
377+
// Assume that STATE_PEER_CLOSED may mean half-closed connection, where peer closed it
378+
// sending direction, but not receiving. Consequently, check for both STATE_CONNECTED
379+
// and STATE_PEER_CLOSED as normal conditions and still waiting for buffers to be sent.
380+
// If peer fully closed socket, we would have socket->state set to ERR_RST (connection
381+
// reset) by error callback.
382+
// Avoid sending too small packets, so wait until at least 16 bytes available
383+
while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
384+
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
385+
*_errno = ETIMEDOUT;
386+
return -1;
387+
}
388+
poll_sockets();
389+
}
390+
391+
if (socket->state < 0) {
392+
*_errno = error_lookup_table[-socket->state];
393+
return -1;
394+
}
395+
}
396+
368397
u16_t write_len = MIN(available, len);
369398

370399
err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);

0 commit comments

Comments
 (0)