#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 */
struct socket_info_fd *prev, *next;
int fd;
- /* Points to list of socket_info structures */
- struct socket_info *si;
+ /*
+ * Points to corresponding index in array of
+ * socket_info structures
+ */
+ int si_index;
};
struct socket_info
} io;
};
+static struct socket_info *sockets;
+static size_t max_sockets = 0;
+
/*
* While socket file descriptors are passed among different processes, the
* numerical value gets changed. So its better to store it locally to each
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)
+{
+
+ 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);
+ }
+}
+
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)
return 1;/* 127.0.0.1 */
}
+static int socket_wrapper_first_free_index(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < max_sockets; ++i) {
+ if (sockets[i].refcount == 0) {
+ ZERO_STRUCT(sockets[i]);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, socklen_t *len)
{
unsigned int iface;
return NULL;
}
-static struct socket_info *find_socket_info(int fd)
+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 fi->si;
+ return &sockets[idx];
}
#if 0 /* FIXME */
}
for (f = socket_fds; f; f = f->next) {
- struct socket_info *s = f->si;
+ struct socket_info *s = &sockets[f->si_index];
if (s == last_s) {
continue;
return;
}
- si = fi->si;
+ si = &sockets[fi->si_index];
SWRAP_LOG(SWRAP_LOG_TRACE, "remove stale wrapper for %d", fd);
SWRAP_DLIST_REMOVE(socket_fds, fi);
if (si->un_addr.sun_path[0] != '\0') {
unlink(si->un_addr.sun_path);
}
- free(si);
}
static int sockaddr_convert_to_un(struct socket_info *si,
struct socket_info *si;
struct socket_info_fd *fi;
int fd;
+ int idx;
int real_type = type;
/*
/* 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
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;
fi->fd = fd;
- fi->si = si;
+ fi->si_index = idx;
SWRAP_DLIST_ADD(socket_fds, fi);
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),
};
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;
&un_my_addr.sa_socklen);
if (ret == -1) {
free(child_fi);
- free(child_si);
close(fd);
return ret;
}
&in_my_addr.sa_socklen);
if (ret == -1) {
free(child_fi);
- free(child_si);
close(fd);
return ret;
}
memcpy(&child_si->myname.sa.ss, &in_my_addr.sa.ss, in_my_addr.sa_socklen);
child_si->refcount = 1;
- child_fi->si = child_si;
+ child_fi->si_index = idx;
SWRAP_DLIST_ADD(socket_fds, child_fi);
return libc_close(fd);
}
- si = fi->si;
+ si = &sockets[fi->si_index];
SWRAP_DLIST_REMOVE(socket_fds, fi);
free(fi);
if (si->un_addr.sun_path[0] != '\0') {
unlink(si->un_addr.sun_path);
}
- free(si);
return ret;
}
return libc_dup(fd);
}
- si = src_fi->si;
+ si = &sockets[src_fi->si_index];
fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
if (fi == NULL) {
}
si->refcount++;
- fi->si = si;
+ fi->si_index = src_fi->si_index;
/* Make sure we don't have an entry for the fd */
swrap_remove_stale(fi->fd);
return libc_dup2(fd, newfd);
}
- si = src_fi->si;
+ si = &sockets[src_fi->si_index];
if (fd == newfd) {
/*
}
si->refcount++;
- fi->si = si;
+ fi->si_index = src_fi->si_index;
/* Make sure we don't have an entry for the fd */
swrap_remove_stale(fi->fd);
return libc_vfcntl(fd, cmd, va);
}
- si = src_fi->si;
+ si = &sockets[src_fi->si_index];
switch (cmd) {
case F_DUPFD:
}
si->refcount++;
- fi->si = si;
+ fi->si_index = src_fi->si_index;
/* Make sure we don't have an entry for the fd */
swrap_remove_stale(fi->fd);
s = socket_fds;
}
+ free(sockets);
+
if (swrap.libc_handle != NULL) {
dlclose(swrap.libc_handle);
}