swrap: Introduce a freelist in the socket_info array
authorMichael Adam <obnox@samba.org>
Wed, 14 Sep 2016 11:24:47 +0000 (13:24 +0200)
committerAndreas Schneider <asn@samba.org>
Thu, 20 Oct 2016 08:51:59 +0000 (10:51 +0200)
Signed-off-by: Michael Adam <obnox@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/socket_wrapper.c

index ad7f68293de5ed9d8db58614bb7be16dcb874eb5..84dfc07601ab163b10e8dd55dd96ab71e96d3cb6 100644 (file)
@@ -263,10 +263,14 @@ struct socket_info_fd {
        int si_index;
 };
 
+int first_free;
+
 struct socket_info
 {
        unsigned int refcount;
 
+       int next_free;
+
        int family;
        int type;
        int protocol;
@@ -1030,6 +1034,7 @@ done:
 
 static void socket_wrapper_init_sockets(void)
 {
+       size_t i;
 
        if (sockets != NULL) {
                return;
@@ -1045,6 +1050,14 @@ static void socket_wrapper_init_sockets(void)
                          "Failed to allocate sockets array.\n");
                exit(-1);
        }
+
+       first_free = 0;
+
+       for (i = 0; i < max_sockets; i++) {
+               sockets[i].next_free = i+1;
+       }
+
+       sockets[max_sockets-1].next_free = -1;
 }
 
 bool socket_wrapper_enabled(void)
@@ -1075,18 +1088,23 @@ static unsigned int socket_wrapper_default_iface(void)
        return 1;/* 127.0.0.1 */
 }
 
+/*
+ * Return the first free entry (if any) and make
+ * it re-usable again (by nulling it out)
+ */
 static int socket_wrapper_first_free_index(void)
 {
-       unsigned int i;
+       int next_free;
 
-       for (i = 0; i < max_sockets; ++i) {
-               if (sockets[i].refcount == 0) {
-                       ZERO_STRUCT(sockets[i]);
-                       return i;
-               }
+       if (first_free == -1) {
+               return -1;
        }
 
-       return -1;
+       next_free = sockets[first_free].next_free;
+       ZERO_STRUCT(sockets[first_free]);
+       sockets[first_free].next_free = next_free;
+
+       return first_free;
 }
 
 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
@@ -1607,6 +1625,9 @@ static void swrap_remove_stale(int fd)
        if (si->un_addr.sun_path[0] != '\0') {
                unlink(si->un_addr.sun_path);
        }
+
+       si->next_free = first_free;
+       first_free = fi->si_index;
 }
 
 static int sockaddr_convert_to_un(struct socket_info *si,
@@ -2629,6 +2650,9 @@ static int swrap_socket(int family, int type, int protocol)
        }
 
        si->refcount = 1;
+       first_free = si->next_free;
+       si->next_free = 0;
+
        fi->fd = fd;
        fi->si_index = idx;
 
@@ -2854,6 +2878,9 @@ static int swrap_accept(int s,
        memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
 
        child_si->refcount = 1;
+       first_free = child_si->next_free;
+       child_si->next_free = 0;
+
        child_fi->si_index = idx;
 
        SWRAP_DLIST_ADD(socket_fds, child_fi);
@@ -5239,6 +5266,9 @@ static int swrap_close(int fd)
                unlink(si->un_addr.sun_path);
        }
 
+       si->next_free = first_free;
+       first_free = fi->si_index;
+
        return ret;
 }