]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/commitdiff
Implemented timeout on send (TCP only, bug #33820)
authorSimon Goldschmidt <goldsimon@gmx.de>
Wed, 21 Sep 2011 17:36:09 +0000 (19:36 +0200)
committerSimon Goldschmidt <goldsimon@gmx.de>
Wed, 21 Sep 2011 17:36:09 +0000 (19:36 +0200)
CHANGELOG
src/api/api_lib.c
src/api/api_msg.c
src/api/sockets.c
src/include/lwip/api.h
src/include/lwip/api_msg.h
src/include/lwip/opt.h

index 82644b70f083727966f1e35b6e12eb3a525b1b60..a06c4817dc7cb727d28e3d38d46774820d5cd0db 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,10 @@ HISTORY
 
  ++ New features:
 
+  2011-09-21: Simon Goldschmidt
+  * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on
+    send (TCP only, bug #33820)
+
   2011-09-21: Simon Goldschmidt
   * init.c: Converted runtime-sanity-checks into compile-time checks that can
     be disabled (since runtime checks can often not be seen on embedded targets)
index f7375b0f1e49404b0b008c1b77da74910ca5e63c..e1018046bffb70f992085f4edbb758ec30a569dd 100644 (file)
@@ -611,12 +611,26 @@ netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
   msg.msg.msg.w.dataptr = dataptr;
   msg.msg.msg.w.apiflags = apiflags;
   msg.msg.msg.w.len = size;
+#if LWIP_SO_SNDTIMEO
+  if (conn->send_timeout != 0) {
+    /* get the time we started, which is later compared to
+        sys_now() + conn->send_timeout */
+    msg.msg.msg.w.time_started = sys_now();
+  } else {
+    msg.msg.msg.w.time_started = 0;
+  }
+#endif /* LWIP_SO_SNDTIMEO */
+
   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
      but if it is, this is done inside api_msg.c:do_write(), so we can use the
      non-blocking version here. */
   err = TCPIP_APIMSG(&msg);
   if ((err == ERR_OK) && (bytes_written != NULL)) {
-    if (dontblock) {
+    if (dontblock
+#if LWIP_SO_SNDTIMEO
+        || (conn->send_timeout != 0)
+#endif /* LWIP_SO_SNDTIMEO */
+       ) {
       /* nonblocking write: maybe the data has been sent partly */
       *bytes_written = msg.msg.msg.w.len;
     } else {
index fe97d3bcba762310b6803a8ba65d9afab40d9a72..4227a632b8e04ea594411b7c9bfaf5d70c40ec7c 100644 (file)
@@ -626,6 +626,9 @@ netconn_alloc(enum netconn_type t, netconn_callback callback)
   conn->current_msg  = NULL;
   conn->write_offset = 0;
 #endif /* LWIP_TCP */
+#if LWIP_SO_SNDTIMEO
+  conn->send_timeout = 0;
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
   conn->recv_timeout = 0;
 #endif /* LWIP_SO_RCVTIMEO */
@@ -1217,79 +1220,95 @@ do_writemore(struct netconn *conn)
   LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
     conn->write_offset < conn->current_msg->msg.w.len);
 
-  dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
-  diff = conn->current_msg->msg.w.len - conn->write_offset;
-  if (diff > 0xffffUL) { /* max_u16_t */
-    len = 0xffff;
-#if LWIP_TCPIP_CORE_LOCKING
-    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
-#endif
-    apiflags |= TCP_WRITE_FLAG_MORE;
-  } else {
-    len = (u16_t)diff;
-  }
-  available = tcp_sndbuf(conn->pcb.tcp);
-  if (available < len) {
-    /* don't try to write more than sendbuf */
-    len = available;
-    if (dontblock){ 
-      if (!len) {
-        err = ERR_WOULDBLOCK;
-        goto err_mem;
-      }
+#if LWIP_SO_SNDTIMEO
+  if ((conn->send_timeout != 0) &&
+      ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
+    write_finished = 1;
+    if (conn->write_offset == 0) {
+      /* nothing has been written */
+      err = ERR_WOULDBLOCK;
+      conn->current_msg->msg.w.len = 0;
     } else {
+      /* partial write */
+      err = ERR_OK;
+      conn->current_msg->msg.w.len = conn->write_offset;
+    }
+  } else
+#endif /* LWIP_SO_SNDTIMEO */
+  {
+    dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
+    diff = conn->current_msg->msg.w.len - conn->write_offset;
+    if (diff > 0xffffUL) { /* max_u16_t */
+      len = 0xffff;
 #if LWIP_TCPIP_CORE_LOCKING
       conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
 #endif
       apiflags |= TCP_WRITE_FLAG_MORE;
+    } else {
+      len = (u16_t)diff;
     }
-  }
-  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
-  err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
-  /* if OK or memory error, check available space */
-  if ((err == ERR_OK) || (err == ERR_MEM)) {
+    available = tcp_sndbuf(conn->pcb.tcp);
+    if (available < len) {
+      /* don't try to write more than sendbuf */
+      len = available;
+      if (dontblock){ 
+        if (!len) {
+          err = ERR_WOULDBLOCK;
+          goto err_mem;
+        }
+      } else {
+#if LWIP_TCPIP_CORE_LOCKING
+        conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+#endif
+        apiflags |= TCP_WRITE_FLAG_MORE;
+      }
+    }
+    LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
+    err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
+    /* if OK or memory error, check available space */
+    if ((err == ERR_OK) || (err == ERR_MEM)) {
 err_mem:
-    if (dontblock && (len < conn->current_msg->msg.w.len)) {
-      /* non-blocking write did not write everything: mark the pcb non-writable
-         and let poll_tcp check writable space to mark the pcb writable again */
-      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
-      conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
-    } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
-               (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
-      /* The queued byte- or pbuf-count exceeds the configured low-water limit,
-         let select mark this pcb as non-writable. */
-      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+      if (dontblock && (len < conn->current_msg->msg.w.len)) {
+        /* non-blocking write did not write everything: mark the pcb non-writable
+           and let poll_tcp check writable space to mark the pcb writable again */
+        API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+        conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
+      } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
+                 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
+        /* The queued byte- or pbuf-count exceeds the configured low-water limit,
+           let select mark this pcb as non-writable. */
+        API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
+      }
     }
-  }
 
-  if (err == ERR_OK) {
-    conn->write_offset += len;
-    if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
-      /* return sent length */
-      conn->current_msg->msg.w.len = conn->write_offset;
-      /* everything was written */
-      write_finished = 1;
-      conn->write_offset = 0;
-    }
-    tcp_output(conn->pcb.tcp);
-  } else if ((err == ERR_MEM) && !dontblock) {
-    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
-       we do NOT return to the application thread, since ERR_MEM is
-       only a temporary error! */
+    if (err == ERR_OK) {
+      conn->write_offset += len;
+      if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
+        /* return sent length */
+        conn->current_msg->msg.w.len = conn->write_offset;
+        /* everything was written */
+        write_finished = 1;
+        conn->write_offset = 0;
+      }
+      tcp_output(conn->pcb.tcp);
+    } else if ((err == ERR_MEM) && !dontblock) {
+      /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
+         we do NOT return to the application thread, since ERR_MEM is
+         only a temporary error! */
 
-    /* tcp_write returned ERR_MEM, try tcp_output anyway */
-    tcp_output(conn->pcb.tcp);
+      /* tcp_write returned ERR_MEM, try tcp_output anyway */
+      tcp_output(conn->pcb.tcp);
 
 #if LWIP_TCPIP_CORE_LOCKING
-    conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
+      conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
 #endif
-  } else {
-    /* On errors != ERR_MEM, we don't try writing any more but return
-       the error to the application thread. */
-    write_finished = 1;
-    conn->current_msg->msg.w.len = 0;
+    } else {
+      /* On errors != ERR_MEM, we don't try writing any more but return
+         the error to the application thread. */
+      write_finished = 1;
+      conn->current_msg->msg.w.len = 0;
+    }
   }
-
   if (write_finished) {
     /* everything was written: set back connection state
        and back to application task */
index 81cbf24ee36ef3bd9cb575b3c6ab687e93b9c1b7..1734d63d4235b74ade9c5628648772b815685552 100644 (file)
@@ -1535,7 +1535,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
     case SO_ERROR:
     case SO_KEEPALIVE:
     /* UNIMPL case SO_CONTIMEO: */
-    /* UNIMPL case SO_SNDTIMEO: */
+#if LWIP_SO_SNDTIMEO
+    case SO_SNDTIMEO:
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
     case SO_RCVTIMEO:
 #endif /* LWIP_SO_RCVTIMEO */
@@ -1780,6 +1782,11 @@ lwip_getsockopt_internal(void *arg)
                   s, *(int *)optval));
       break;
 
+#if LWIP_SO_SNDTIMEO
+    case SO_SNDTIMEO:
+      *(int *)optval = netconn_get_sendtimeout(sock->conn);
+      break;
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
     case SO_RCVTIMEO:
       *(int *)optval = netconn_get_recvtimeout(sock->conn);
@@ -1934,7 +1941,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
     /* UNIMPL case SO_DONTROUTE: */
     case SO_KEEPALIVE:
     /* UNIMPL case case SO_CONTIMEO: */
-    /* UNIMPL case case SO_SNDTIMEO: */
+#if LWIP_SO_SNDTIMEO
+    case SO_SNDTIMEO:
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
     case SO_RCVTIMEO:
 #endif /* LWIP_SO_RCVTIMEO */
@@ -2160,6 +2169,11 @@ lwip_setsockopt_internal(void *arg)
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
                   s, optname, (*(int*)optval?"on":"off")));
       break;
+#if LWIP_SO_SNDTIMEO
+    case SO_SNDTIMEO:
+      netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
+      break;
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
     case SO_RCVTIMEO:
       netconn_set_recvtimeout(sock->conn, *(int*)optval);
index 326528a23efd0885ab0dd560593c4c00a0f481e8..4c985800848923288b229a6c5bd70f073c998aa2 100644 (file)
@@ -180,6 +180,11 @@ struct netconn {
 #if LWIP_SOCKET
   int socket;
 #endif /* LWIP_SOCKET */
+#if LWIP_SO_SNDTIMEO
+  /** timeout to wait for sending data (which means enqueueing data for sending
+      in internal buffers) */
+  s32_t send_timeout;
+#endif /* LWIP_SO_RCVTIMEO */
 #if LWIP_SO_RCVTIMEO
   /** timeout to wait for new data to be received
       (or connections to arrive for listening netconns) */
@@ -299,6 +304,12 @@ err_t   netconn_gethostbyname(const char *name, ip_addr_t *addr);
 /** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
 #define netconn_get_noautorecved(conn)        (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
 
+#if LWIP_SO_SNDTIMEO
+/** Set the send timeout in milliseconds */
+#define netconn_set_sendtimeout(conn, timeout)      ((conn)->send_timeout = (timeout))
+/** Get the send timeout in milliseconds */
+#define netconn_get_sendtimeout(conn)               ((conn)->send_timeout)
+#endif /* LWIP_SO_SNDTIMEO */
 #if LWIP_SO_RCVTIMEO
 /** Set the receive timeout in milliseconds */
 #define netconn_set_recvtimeout(conn, timeout)      ((conn)->recv_timeout = (timeout))
index fca361d98c5d8474daa1c30a99de9c6b88825ad5..cadaa8cbdde96ad8cad57ec2c757e11f6374ade8 100644 (file)
@@ -89,6 +89,9 @@ struct api_msg_msg {
       const void *dataptr;
       size_t len;
       u8_t apiflags;
+#if LWIP_SO_SNDTIMEO
+      u32_t time_started;
+#endif /* LWIP_SO_SNDTIMEO */
     } w;
     /** used for do_recv */
     struct {
index cd1e47d61f441605f1d6e0b70c6351a3d915f0a9..aab3c8be108869d00d102a279fb1322d0b7b0494 100644 (file)
 #define LWIP_TCP_KEEPALIVE              0
 #endif
 
+/**
+ * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
+ * SO_SNDTIMEO processing.
+ */
+#ifndef LWIP_SO_SNDTIMEO
+#define LWIP_SO_SNDTIMEO                0
+#endif
+
 /**
  * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
  * SO_RCVTIMEO processing.