summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Sokolovsky <pfalcon@users.sourceforge.net>2016-03-25 18:38:13 +0200
committerPaul Sokolovsky <pfalcon@users.sourceforge.net>2016-03-25 18:38:13 +0200
commitde0c84ebf1e18a5de4e1adb39cf33499b66d27b4 (patch)
tree7550d26745fbb9cef372876ba7439732175f98ec
parent5e75f335e6df01cddfc2cd8db24d5807e73c13a6 (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.c29
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);