From 3e1a7441420847c24cb4fcf02bb4907be22c4d8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joan=20Lled=C3=B3?= <jlledom@member.fsf.org>
Date: Tue, 8 Aug 2017 19:28:12 +0200
Subject: [PATCH] New option LWIP_SOCKET_OPEN_COUNT in opts.h

---
 src/api/sockets.c                    | 79 +++++++++++++++++++++++++++++++++++-
 src/core/init.c                      |  3 ++
 src/include/lwip/opt.h               | 10 +++++
 src/include/lwip/priv/sockets_priv.h |  6 +++
 4 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/src/api/sockets.c b/src/api/sockets.c
index a50faf5..e4ec97f 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -258,8 +258,13 @@ static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr,
 static void lwip_socket_drop_registered_memberships(int s);
 #endif /* LWIP_IGMP */
 
+#if LWIP_SOCKET_OPEN_COUNT
+/** The global linked list of available sockets */
+static struct lwip_sock *sockets = NULL;
+#else /* LWIP_SOCKET_OPEN_COUNT */
 /** The global array of available sockets */
 static struct lwip_sock sockets[NUM_SOCKETS];
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 
 #if LWIP_SOCKET_SELECT
 #if LWIP_TCPIP_CORE_LOCKING
@@ -377,11 +382,20 @@ static struct lwip_sock *
 tryget_socket_unconn_nouse(int fd)
 {
   int s = fd - LWIP_SOCKET_OFFSET;
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock *sock;
+  for(sock = sockets; sock != NULL; sock = sock->next) {
+    if(sock->count == s)
+      break;
+  }
+  return sock;
+#else /* LWIP_SOCKET_OPEN_COUNT */
   if ((s < 0) || (s >= NUM_SOCKETS)) {
     LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd));
     return NULL;
   }
   return &sockets[s];
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 }
 
 struct lwip_sock*
@@ -431,9 +445,11 @@ get_socket(int fd)
 {
   struct lwip_sock *sock = tryget_socket(fd);
   if (!sock) {
+#if !LWIP_SOCKET_OPEN_COUNT
     if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) {
       LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd));
     }
+#endif /* !LWIP_SOCKET_OPEN_COUNT */
     set_errno(EBADF);
     return NULL;
   }
@@ -452,9 +468,59 @@ static int
 alloc_socket(struct netconn *newconn, int accepted)
 {
   int i;
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock *newsock, **it;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
   SYS_ARCH_DECL_PROTECT(lev);
   LWIP_UNUSED_ARG(accepted);
 
+#if LWIP_SOCKET_OPEN_COUNT
+    newsock = (struct lwip_sock*)mem_malloc(sizeof(struct lwip_sock));
+    if(newsock == NULL) {
+      return -1;
+    }
+#if LWIP_NETCONN_FULLDUPLEX
+    if (newsock->fd_used) {
+      SYS_ARCH_UNPROTECT(lev);
+      continue;
+    }
+    newsock->fd_used    = 1;
+    newsock->fd_free_pending = 0;
+#endif
+    newsock->conn       = newconn;
+    newsock->lastdata   = NULL;
+    newsock->lastoffset = 0;
+    newsock->rcvevent   = 0;
+    /* TCP sendbuf is empty, but the socket is not yet writable until connected
+     * (unless it has been created by accept()). */
+     newsock->lastdata.pbuf = NULL;
+#if LWIP_SOCKET_SELECT
+    LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0);
+    newsock->rcvevent   = 0;
+    /* TCP sendbuf is empty, but the socket is not yet writable until connected
+     * (unless it has been created by accept()). */
+    newsock->sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
+    newsock->errevent   = 0;
+#endif /* LWIP_SOCKET_SELECT */
+    /* Protect socket list */
+    SYS_ARCH_PROTECT(lev);
+    it = &sockets;
+    i = LWIP_SOCKET_OFFSET;
+    while(*it) {
+      if((*it)->count != i) {
+        /* There's a gap in the list, fill it */
+        break;
+      }
+      i++;
+      it = &(*it)->next;
+    }
+    /* Add the new socket in the first gap found or in the end */
+    newsock->count = i;
+    newsock->next = (*it);
+    (*it) = newsock;
+    SYS_ARCH_UNPROTECT(lev);
+    return i;
+#else /* LWIP_SOCKET_OPEN_COUNT */
   /* allocate a new socket identifier */
   for (i = 0; i < NUM_SOCKETS; ++i) {
     /* Protect socket array */
@@ -486,6 +552,7 @@ alloc_socket(struct netconn *newconn, int accepted)
     SYS_ARCH_UNPROTECT(lev);
   }
   return -1;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 }
 
 /** Free a socket. The socket's netconn must have been
@@ -513,10 +580,18 @@ free_socket(struct lwip_sock *sock, int is_tcp)
 #endif
 
   lastdata = sock->lastdata;
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock **it = &sockets;
+
+  while(*it != sock) it = &(*it)->next;
+  *it = (*it)->next;
+  mem_free(sock);
+#else /* LWIP_SOCKET_OPEN_COUNT */
   sock->lastdata.pbuf = NULL;
   sock->conn = NULL;
-  SYS_ARCH_UNPROTECT(lev);
   /* don't use 'sock' after this line, as another task might have allocated it */
+#endif /* LWIP_SOCKET_OPEN_COUNT */
+SYS_ARCH_UNPROTECT(lev);
 
   if (lastdata.pbuf != NULL) {
     if (is_tcp) {
@@ -574,7 +649,9 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
     done_socket(sock);
     return -1;
   }
+#if !LWIP_SOCKET_OPEN_COUNT
   LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
+#endif /* !LWIP_SOCKET_OPEN_COUNT */
   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
 
   /* See event_callback: If data comes in right away after an accept, even
diff --git a/src/core/init.c b/src/core/init.c
index 9a73034..e799cd6 100644
--- a/src/core/init.c
+++ b/src/core/init.c
@@ -176,6 +176,9 @@ PACK_STRUCT_END
 #if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
   #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
 #endif
+#if (LWIP_SOCKET_OPEN_COUNT && !MEMP_MEM_MALLOC)
+  #error "LWIP_SOCKET_OPEN_COUNT requires MEMP_MEM_MALLOC=1 in your lwipopts.h"
+#endif
 #if (LWIP_PPP_API && (NO_SYS==1))
   #error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h"
 #endif
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index bd7bd08..e239e36 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1880,6 +1880,16 @@
 #endif
 
 /**
+ * LWIP_SOCKET_OPEN_COUNT==1: Number of sockets is not limited to MEMP_NUM_NETCONN.
+ * When enabled, sockets are allocated in the heap and the amount of sockets is
+ * only limited by the heap size. Handle with care regarding execution speed.
+ * To use this, MEMP_MEM_MALLOC also has to be enabled.
+ */
+#if !defined LWIP_SOCKET_OPEN_COUNT || defined __DOXYGEN__
+#define LWIP_SOCKET_OPEN_COUNT              0
+#endif
+
+/**
  * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
  * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
  * in seconds. (does not require sockets.c, and will affect tcp.c)
diff --git a/src/include/lwip/priv/sockets_priv.h b/src/include/lwip/priv/sockets_priv.h
index d2ec917..aaaecea 100644
--- a/src/include/lwip/priv/sockets_priv.h
+++ b/src/include/lwip/priv/sockets_priv.h
@@ -64,6 +64,12 @@ union lwip_sock_lastdata {
 
 /** Contains all internal pointers and states used for a socket */
 struct lwip_sock {
+#if LWIP_SOCKET_OPEN_COUNT
+  /** Next element in the linked list */
+  struct lwip_sock *next;
+  /** Socket number*/
+  int count;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
   /** sockets currently are built on netconns, each socket has one netconn */
   struct netconn *conn;
   /** data that was left from the previous read */
-- 
2.1.4

