return 0;
}
-
+struct socket_info_fd {
+ struct socket_info_fd *prev, *next;
+ int fd;
+};
struct socket_info
{
- int fd;
+ struct socket_info_fd *fds;
int family;
int type;
{
struct socket_info *i;
for (i = sockets; i; i = i->next) {
- if (i->fd == fd)
- return i;
+ struct socket_info_fd *f;
+ for (f = i->fds; f; f = f->next) {
+ if (f->fd == fd) {
+ return i;
+ }
+ }
}
return NULL;
_PUBLIC_ int swrap_socket(int family, int type, int protocol)
{
struct socket_info *si;
+ struct socket_info_fd *fi;
int fd;
int real_type = type;
#ifdef SOCK_CLOEXEC
if (fd == -1) return -1;
si = (struct socket_info *)calloc(1, sizeof(struct socket_info));
+ if (si == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
si->family = family;
* the type, not the flags */
si->type = real_type;
si->protocol = protocol;
- si->fd = fd;
+ fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+ if (fi == NULL) {
+ free(si);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ fi->fd = fd;
+
+ SWRAP_DLIST_ADD(si->fds, fi);
SWRAP_DLIST_ADD(sockets, si);
- return si->fd;
+ return fd;
}
_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
struct socket_info *parent_si, *child_si;
+ struct socket_info_fd *child_fi;
int fd;
struct sockaddr_un un_addr;
socklen_t un_addrlen = sizeof(un_addr);
child_si = (struct socket_info *)malloc(sizeof(struct socket_info));
memset(child_si, 0, sizeof(*child_si));
- child_si->fd = fd;
+ child_fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+ if (child_fi == NULL) {
+ free(child_si);
+ free(my_addr);
+ close(fd);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ child_fi->fd = fd;
+
+ SWRAP_DLIST_ADD(child_si->fds, child_fi);
+
child_si->family = parent_si->family;
child_si->type = parent_si->type;
child_si->protocol = parent_si->protocol;
ret = real_getsockname(fd, (struct sockaddr *)(void *)&un_my_addr,
&un_my_addrlen);
if (ret == -1) {
+ free(child_fi);
free(child_si);
close(fd);
return ret;
ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen,
child_si->family, my_addr, &len);
if (ret == -1) {
+ free(child_fi);
free(child_si);
free(my_addr);
close(fd);
_PUBLIC_ int swrap_close(int fd)
{
struct socket_info *si = find_socket_info(fd);
+ struct socket_info_fd *fi;
int ret;
if (!si) {
return real_close(fd);
}
+ for (fi = si->fds; fi; fi = fi->next) {
+ if (fi->fd == fd) {
+ SWRAP_DLIST_REMOVE(si->fds, fi);
+ free(fi);
+ break;
+ }
+ }
+
+ if (si->fds) {
+ /* there are still references left */
+ return real_close(fd);
+ }
+
SWRAP_DLIST_REMOVE(sockets, si);
if (si->myname && si->peername) {
_PUBLIC_ int swrap_dup(int fd)
{
- struct socket_info *si, *si2;
- int fd2;
+ struct socket_info *si;
+ struct socket_info_fd *fi;
si = find_socket_info(fd);
return real_dup(fd);
}
- if (si->tmp_path) {
- /* we would need reference counting to handle this */
- errno = EINVAL;
- return -1;
- }
-
- fd2 = real_dup(fd);
- if (fd2 == -1) {
- return -1;
- }
-
- si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
- if (si2 == NULL) {
- real_close(fd2);
+ fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+ if (fi == NULL) {
errno = ENOMEM;
return -1;
}
- /* copy the whole structure, then duplicate pointer elements */
- *si2 = *si;
-
- si2->fd = fd2;
-
- if (si2->myname) {
- si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
- if (si2->myname == NULL) {
- real_close(fd2);
- errno = ENOMEM;
- return -1;
- }
- }
-
- if (si2->peername) {
- si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
- if (si2->peername == NULL) {
- real_close(fd2);
- errno = ENOMEM;
- return -1;
- }
+ fi->fd = real_dup(fd);
+ if (fi->fd == -1) {
+ int saved_errno = errno;
+ free(fi);
+ errno = saved_errno;
+ return -1;
}
- SWRAP_DLIST_ADD(sockets, si2);
- return fd2;
+ SWRAP_DLIST_ADD(si->fds, fi);
+ return fi->fd;
}
_PUBLIC_ int swrap_dup2(int fd, int newfd)
{
- struct socket_info *si, *si2;
- int fd2;
+ struct socket_info *si;
+ struct socket_info_fd *fi;
si = find_socket_info(fd);
return real_dup2(fd, newfd);
}
- if (si->tmp_path) {
- /* we would need reference counting to handle this */
- errno = EINVAL;
- return -1;
- }
-
if (find_socket_info(newfd)) {
/* dup2() does an implicit close of newfd, which we
* need to emulate */
swrap_close(newfd);
}
- fd2 = real_dup2(fd, newfd);
- if (fd2 == -1) {
- return -1;
- }
-
- si2 = (struct socket_info *)malloc(sizeof(struct socket_info));
- if (si2 == NULL) {
- real_close(fd2);
+ fi = (struct socket_info_fd *)calloc(1, sizeof(struct socket_info_fd));
+ if (fi == NULL) {
errno = ENOMEM;
return -1;
}
- /* copy the whole structure, then duplicate pointer elements */
- *si2 = *si;
-
- si2->fd = fd2;
-
- if (si2->myname) {
- si2->myname = sockaddr_dup(si2->myname, si2->myname_len);
- if (si2->myname == NULL) {
- real_close(fd2);
- errno = ENOMEM;
- return -1;
- }
- }
-
- if (si2->peername) {
- si2->peername = sockaddr_dup(si2->peername, si2->peername_len);
- if (si2->peername == NULL) {
- real_close(fd2);
- errno = ENOMEM;
- return -1;
- }
+ fi->fd = real_dup2(fd, newfd);
+ if (fi->fd == -1) {
+ int saved_errno = errno;
+ free(fi);
+ errno = saved_errno;
+ return -1;
}
- SWRAP_DLIST_ADD(sockets, si2);
- return fd2;
+ SWRAP_DLIST_ADD(si->fds, fi);
+ return fi->fd;
}