+static struct socket *sockpair(int dgram)
+{
+ struct socket *s1, *s2;
+
+ s1 = newsock1(dgram);
+ s2 = newsock1(dgram);
+ s1->back = s2;
+ s2->back = s1;
+ putsock(s2);
+ return(s1);
+}
+
+static void sksetstate(struct socket *sk, int state)
+{
+ sk->state = state;
+ sk->back->state = state;
+}
+
+struct socket *netsockpipe(void)
+{
+ struct socket *sk;
+
+ sk = sockpair(0);
+ sksetstate(sk, SOCK_EST);
+ return(sk);
+}
+
+static void closeufd(struct ufd *ufd)
+{
+ if(ufd->fd != -1)
+ close(ufd->fd);
+ ufd->fd = -1;
+}
+
+static void freeufd(struct ufd *ufd)
+{
+ if(ufd->next != NULL)
+ ufd->next->prev = ufd->prev;
+ if(ufd->prev != NULL)
+ ufd->prev->next = ufd->next;
+ if(ufd == ufds)
+ ufds = ufd->next;
+ closeufd(ufd);
+ if(ufd->sk != NULL)
+ putsock(ufd->sk);
+ if(ufd->type == UFD_SOCK) {
+ if(ufd->d.s.remote != NULL)
+ free(ufd->d.s.remote);
+ }
+ free(ufd);
+}
+
+static struct ufd *mkufd(int fd, int type, struct socket *sk)
+{
+ struct ufd *ufd;
+
+ ufd = memset(smalloc(sizeof(*ufd)), 0, sizeof(*ufd));
+ ufd->fd = fd;
+ ufd->type = type;
+ if(sk != NULL) {
+ getsock(ufd->sk = sk);
+ sk->ufd = ufd;
+ }
+ if(type == UFD_SOCK) {
+ ufd->d.s.ucred.uid = -1;
+ ufd->d.s.ucred.gid = -1;
+ }
+ ufd->next = ufds;
+ if(ufds)
+ ufds->prev = ufd;
+ ufds = ufd;
+ return(ufd);
+}
+
+static struct ufd *dupufd(struct ufd *ufd)
+{
+ struct ufd *nufd;
+ struct socket *nsk;
+
+ if(ufd->sk != NULL)
+ nsk = sockpair(ufd->sk->dgram);
+ else
+ nsk = NULL;
+ nufd = mkufd(ufd->fd, ufd->type, nsk);
+ if(nsk != NULL)
+ putsock(nsk);
+ if((nufd->fd = dup(ufd->fd)) < 0)
+ {
+ flog(LOG_WARNING, "could not dup() fd: %s", strerror(errno));
+ freeufd(nufd);
+ return(NULL);
+ }
+ sksetstate(nsk, SOCK_EST);
+ if(ufd->type == UFD_SOCK) {
+ nufd->d.s.family = ufd->d.s.family;
+ nufd->d.s.type = ufd->d.s.type;
+ nufd->d.s.ucred.uid = ufd->d.s.ucred.uid;
+ nufd->d.s.ucred.gid = ufd->d.s.ucred.gid;
+ if(ufd->d.s.remote != NULL)
+ nufd->d.s.remote = memcpy(smalloc(ufd->d.s.remotelen), ufd->d.s.remote, nufd->d.s.remotelen = ufd->d.s.remotelen);
+ } else if(ufd->type == UFD_LISTEN) {
+ nufd->d.l.family = ufd->d.l.family;
+ }
+ return(nufd);
+}
+