The branch, master has been updated via b61f5df tests: Add a test for max_sockets via f9fbda9 swrap: Introduce a freelist in the socket_info array via 69aee42 swrap: Replace linked list of socket_info with preallocated array of structures via c3e5f78 swrap: Optimization in (commented out) check_addr_port_in_use() via 1e7528c swrap: Improve vfcntl to add the dup'd fd after the source fd via d3d09e6 swrap: Improve dup2 to add the dup'd fd after the source fd via ebe5f15 swrap: Improve dup to add the dup'd fd after the source fd via 97d2372 swrap: Add SWRAP_DLIST_ADD_AFTER macro via 087f9ae swrap: Untangle socket_info_fd from socket_info structure. from f43d383 swrap: remove ununsed members from struct swrap.
https://git.samba.org/?p=socket_wrapper.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit b61f5df9f4a7c57cb9ad313a20d7dbe316f42072 Author: Michael Adam <ob...@samba.org> Date: Thu Sep 22 02:13:20 2016 +0200 tests: Add a test for max_sockets Signed-off-by: Michael Adam <ob...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit f9fbda9ef0f7b279e8e618a3888ab2e50884da1b Author: Michael Adam <ob...@samba.org> Date: Wed Sep 14 13:24:47 2016 +0200 swrap: Introduce a freelist in the socket_info array Signed-off-by: Michael Adam <ob...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 69aee42f1d4a0e563b9e85e899dc8b4f18303af0 Author: Anoop C S <anoo...@redhat.com> Date: Thu Aug 25 11:41:12 2016 +0530 swrap: Replace linked list of socket_info with preallocated array of structures Pair-Programmed-With: Michael Adam <ob...@samba.org> Signed-off-by: Anoop C S <anoo...@redhat.com> Signed-off-by: Michael Adam <ob...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit c3e5f78016f4319fb22126163d0ddbcac0bdeed5 Author: Michael Adam <ob...@samba.org> Date: Tue Aug 16 13:38:50 2016 +0200 swrap: Optimization in (commented out) check_addr_port_in_use() Pair-Programmed-With: Stefan Metzmacher <me...@samba.org> Signed-off-by: Michael Adam <ob...@samba.org> Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 1e7528c2b1a027538b54bd3576eba1206265ae8c Author: Michael Adam <ob...@samba.org> Date: Tue Aug 16 11:04:43 2016 +0200 swrap: Improve vfcntl to add the dup'd fd after the source fd Pair-Programmed-With: Stefan Metzmacher <me...@samba.org> Signed-off-by: Michael Adam <ob...@samba.org> Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit d3d09e631aa7f9b5ffe88a786ad21e7e51aee909 Author: Michael Adam <ob...@samba.org> Date: Tue Aug 16 11:04:12 2016 +0200 swrap: Improve dup2 to add the dup'd fd after the source fd Pair-Programmed-With: Stefan Metzmacher <me...@samba.org> Signed-off-by: Michael Adam <ob...@samba.org> Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit ebe5f15854866c225febe73c952356873b958305 Author: Michael Adam <ob...@samba.org> Date: Tue Aug 16 11:03:27 2016 +0200 swrap: Improve dup to add the dup'd fd after the source fd Pair-Programmed-With: Stefan Metzmacher <me...@samba.org> Signed-off-by: Michael Adam <ob...@samba.org> Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 97d23728cfc392fe5f2c33831f4c85aa31d083fc Author: Michael Adam <ob...@samba.org> Date: Tue Aug 16 11:00:50 2016 +0200 swrap: Add SWRAP_DLIST_ADD_AFTER macro Pair-Programmed-With: Stefan Metzmacher <me...@samba.org> Signed-off-by: Michael Adam <ob...@samba.org> Signed-off-by: Stefan Metzmacher <me...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> commit 087f9aea821cceffd3ced15b576106cace8a2c9d Author: Anoop C S <anoo...@redhat.com> Date: Wed Aug 10 16:32:19 2016 +0530 swrap: Untangle socket_info_fd from socket_info structure. This reverses the dependency of socket_info on socket_info_fd: Instead of maintaining the list of socket_info structures, and keeping a list of referencing fds (created by dup), we now maintain the list of fds with pointers to the corresponding socket_info structures, and count the references in the socket_info. This makes the treatment of the lists more obvious, especially seen in the removing part. This change is a preparatory step for implementing fd-passing in socket-wrapper. Pair-programmed-with: Michael Adam <ob...@samba.org> Signed-off-by: Anoop C S <anoo...@redhat.com> Signed-off-by: Michael Adam <ob...@samba.org> Reviewed-by: Andreas Schneider <a...@samba.org> ----------------------------------------------------------------------- Summary of changes: src/socket_wrapper.c | 330 +++++++++++++++++++++++++++++++++++------------ tests/CMakeLists.txt | 3 +- tests/test_max_sockets.c | 110 ++++++++++++++++ 3 files changed, 358 insertions(+), 85 deletions(-) create mode 100644 tests/test_max_sockets.c Changeset truncated at 500 lines: diff --git a/src/socket_wrapper.c b/src/socket_wrapper.c index 6c4ae3b..84dfc07 100644 --- a/src/socket_wrapper.c +++ b/src/socket_wrapper.c @@ -184,6 +184,20 @@ enum swrap_dbglvl_e { (item)->next = NULL; \ } while (0) +#define SWRAP_DLIST_ADD_AFTER(list, item, el) \ +do { \ + if ((list) != NULL || (el) != NULL) { \ + SWRAP_DLIST_ADD(list, item); \ + } else { \ + (item)->prev = (el); \ + (item)->next = (el)->next; \ + (el)->next = (item); \ + if ((item)->next != NULL) { \ + (item)->next->prev = (item); \ + } \ + } \ +} while (0) + #if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID) #define swrapGetTimeOfDay(tval) gettimeofday(tval,NULL) #else @@ -212,6 +226,14 @@ enum swrap_dbglvl_e { #define SOCKET_MAX_SOCKETS 1024 + +/* + * Maximum number of socket_info structures that can + * be used. Can be overriden by the environment variable + * SOCKET_WRAPPER_MAX_SOCKETS. + */ +#define SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT 65535 + /* This limit is to avoid broadcast sendto() needing to stat too many * files. It may be raised (with a performance cost) to up to 254 * without changing the format above */ @@ -233,11 +255,21 @@ struct swrap_address { struct socket_info_fd { struct socket_info_fd *prev, *next; int fd; + + /* + * Points to corresponding index in array of + * socket_info structures + */ + int si_index; }; +int first_free; + struct socket_info { - struct socket_info_fd *fds; + unsigned int refcount; + + int next_free; int family; int type; @@ -261,15 +293,17 @@ struct socket_info unsigned long pck_snd; unsigned long pck_rcv; } io; - - struct socket_info *prev, *next; }; +static struct socket_info *sockets; +static size_t max_sockets = 0; + /* - * File descriptors are shared between threads so we should share socket - * information too. + * While socket file descriptors are passed among different processes, the + * numerical value gets changed. So its better to store it locally to each + * process rather than including it within socket_info which will be shared. */ -struct socket_info *sockets; +static struct socket_info_fd *socket_fds; /* Function prototypes */ @@ -970,11 +1004,73 @@ done: return max_mtu; } +static size_t socket_wrapper_max_sockets(void) +{ + const char *s; + unsigned long tmp; + char *endp; + + if (max_sockets != 0) { + return max_sockets; + } + + max_sockets = SOCKET_WRAPPER_MAX_SOCKETS_DEFAULT; + + s = getenv("SOCKET_WRAPPER_MAX_SOCKETS"); + if (s == NULL || s[0] == '\0') { + goto done; + } + + tmp = strtoul(s, &endp, 10); + if (s == endp) { + goto done; + } + + max_sockets = tmp; + +done: + return max_sockets; +} + +static void socket_wrapper_init_sockets(void) +{ + size_t i; + + if (sockets != NULL) { + return; + } + + max_sockets = socket_wrapper_max_sockets(); + + sockets = (struct socket_info *)calloc(max_sockets, + sizeof(struct socket_info)); + + if (sockets == NULL) { + SWRAP_LOG(SWRAP_LOG_ERROR, + "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) { const char *s = socket_wrapper_dir(); - return s != NULL ? true : false; + if (s == NULL) { + return false; + } + + socket_wrapper_init_sockets(); + + return true; } static unsigned int socket_wrapper_default_iface(void) @@ -992,6 +1088,25 @@ 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) +{ + int next_free; + + if (first_free == -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) { unsigned int iface; @@ -1359,26 +1474,46 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in return 0; } -static struct socket_info *find_socket_info(int fd) +static struct socket_info_fd *find_socket_info_fd(int fd) { - struct socket_info *i; + struct socket_info_fd *f; - for (i = sockets; i; i = i->next) { - struct socket_info_fd *f; - for (f = i->fds; f; f = f->next) { - if (f->fd == fd) { - return i; - } + for (f = socket_fds; f; f = f->next) { + if (f->fd == fd) { + return f; } } return NULL; } +static int find_socket_info_index(int fd) +{ + struct socket_info_fd *fi = find_socket_info_fd(fd); + + if (fi == NULL) { + return -1; + } + + return fi->si_index; +} + +static struct socket_info *find_socket_info(int fd) +{ + int idx = find_socket_info_index(fd); + + if (idx == -1) { + return NULL; + } + + return &sockets[idx]; +} + #if 0 /* FIXME */ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) { - struct socket_info *s; + struct socket_info_fd *f; + const struct socket_info *last_s = NULL; /* first catch invalid input */ switch (sa->sa_family) { @@ -1399,7 +1534,14 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) break; } - for (s = sockets; s != NULL; s = s->next) { + for (f = socket_fds; f; f = f->next) { + struct socket_info *s = &sockets[f->si_index]; + + if (s == last_s) { + continue; + } + last_s = s; + if (s->myname == NULL) { continue; } @@ -1461,29 +1603,31 @@ static bool check_addr_port_in_use(const struct sockaddr *sa, socklen_t len) static void swrap_remove_stale(int fd) { - struct socket_info *si = find_socket_info(fd); - struct socket_info_fd *fi; + struct socket_info_fd *fi = find_socket_info_fd(fd); + struct socket_info *si; - if (si == NULL) { + if (fi == NULL) { return; } - for (fi = si->fds; fi; fi = fi->next) { - if (fi->fd == fd) { - SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd); - SWRAP_DLIST_REMOVE(si->fds, fi); - free(fi); - break; - } + si = &sockets[fi->si_index]; + + SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd); + SWRAP_DLIST_REMOVE(socket_fds, fi); + free(fi); + + si->refcount--; + + if (si->refcount > 0) { + return; } - if (si->fds == NULL) { - SWRAP_DLIST_REMOVE(sockets, si); - if (si->un_addr.sun_path[0] != '\0') { - unlink(si->un_addr.sun_path); - } - free(si); + 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, @@ -2377,6 +2521,7 @@ static int swrap_socket(int family, int type, int protocol) struct socket_info *si; struct socket_info_fd *fi; int fd; + int idx; int real_type = type; /* @@ -2455,12 +2600,14 @@ static int swrap_socket(int family, int type, int protocol) /* Check if we have a stale fd and remove it */ swrap_remove_stale(fd); - si = (struct socket_info *)calloc(1, sizeof(struct socket_info)); - if (si == NULL) { + idx = socket_wrapper_first_free_index(); + if (idx == -1) { errno = ENOMEM; return -1; } + si = &sockets[idx]; + si->family = family; /* however, the rest of the socket_wrapper code expects just @@ -2492,22 +2639,24 @@ static int swrap_socket(int family, int type, int protocol) break; } default: - free(si); errno = EINVAL; return -1; } fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { - free(si); errno = ENOMEM; return -1; } + si->refcount = 1; + first_free = si->next_free; + si->next_free = 0; + fi->fd = fd; + fi->si_index = idx; - SWRAP_DLIST_ADD(si->fds, fi); - SWRAP_DLIST_ADD(sockets, si); + SWRAP_DLIST_ADD(socket_fds, fi); SWRAP_LOG(SWRAP_LOG_TRACE, "Created %s socket for protocol %s", @@ -2601,6 +2750,7 @@ static int swrap_accept(int s, struct socket_info *parent_si, *child_si; struct socket_info_fd *child_fi; int fd; + int idx; struct swrap_address un_addr = { .sa_socklen = sizeof(struct sockaddr_un), }; @@ -2660,16 +2810,16 @@ static int swrap_accept(int s, return ret; } - child_si = (struct socket_info *)calloc(1, sizeof(struct socket_info)); - if (child_si == NULL) { - close(fd); + idx = socket_wrapper_first_free_index(); + if (idx == -1) { errno = ENOMEM; return -1; } + child_si = &sockets[idx]; + child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (child_fi == NULL) { - free(child_si); close(fd); errno = ENOMEM; return -1; @@ -2702,7 +2852,6 @@ static int swrap_accept(int s, &un_my_addr.sa_socklen); if (ret == -1) { free(child_fi); - free(child_si); close(fd); return ret; } @@ -2715,7 +2864,6 @@ static int swrap_accept(int s, &in_my_addr.sa_socklen); if (ret == -1) { free(child_fi); - free(child_si); close(fd); return ret; } @@ -2729,8 +2877,13 @@ static int swrap_accept(int s, }; memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen); - SWRAP_DLIST_ADD(child_si->fds, child_fi); - SWRAP_DLIST_ADD(sockets, child_si); + 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); if (addr != NULL) { swrap_pcap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0); @@ -5078,29 +5231,26 @@ ssize_t writev(int s, const struct iovec *vector, int count) static int swrap_close(int fd) { - struct socket_info *si = find_socket_info(fd); - struct socket_info_fd *fi; + struct socket_info_fd *fi = find_socket_info_fd(fd); + struct socket_info *si = NULL; int ret; - if (!si) { + if (fi == NULL) { return libc_close(fd); } - for (fi = si->fds; fi; fi = fi->next) { - if (fi->fd == fd) { - SWRAP_DLIST_REMOVE(si->fds, fi); - free(fi); - break; - } - } + si = &sockets[fi->si_index]; + + SWRAP_DLIST_REMOVE(socket_fds, fi); + free(fi); + + si->refcount--; - if (si->fds) { + if (si->refcount > 0) { /* there are still references left */ return libc_close(fd); } - SWRAP_DLIST_REMOVE(sockets, si); - if (si->myname.sa_socklen > 0 && si->peername.sa_socklen > 0) { swrap_pcap_dump_packet(si, NULL, SWRAP_CLOSE_SEND, NULL, 0); } @@ -5115,7 +5265,9 @@ static int swrap_close(int fd) if (si->un_addr.sun_path[0] != '\0') { unlink(si->un_addr.sun_path); } - free(si); + + si->next_free = first_free; + first_free = fi->si_index; return ret; } @@ -5132,14 +5284,15 @@ int close(int fd) static int swrap_dup(int fd) { struct socket_info *si; - struct socket_info_fd *fi; - - si = find_socket_info(fd); + struct socket_info_fd *src_fi, *fi; - if (!si) { + src_fi = find_socket_info_fd(fd); + if (src_fi == NULL) { return libc_dup(fd); } + si = &sockets[src_fi->si_index]; + fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd)); if (fi == NULL) { errno = ENOMEM; @@ -5154,10 +5307,13 @@ static int swrap_dup(int fd) return -1; } + si->refcount++; + fi->si_index = src_fi->si_index; + -- Socket Wrapper Repository