int sys_socketpair(struct lwp *l, const struct sys_socketpair_args *uap, register_t *retval) { /* { syscallarg(int) domain; syscallarg(int) type; syscallarg(int) protocol; syscallarg(int *) rsv; } */ file_t *fp1, *fp2; struct socket *so1, *so2; int fd, error, sv[2]; proc_t *p = curproc; int flags = SCARG(uap, type) & SOCK_FLAGS_MASK; int type = SCARG(uap, type) & ~SOCK_FLAGS_MASK; int domain = SCARG(uap, domain); int proto = SCARG(uap, protocol); error = makesocket(l, &fp1, &fd, flags, type, domain, proto, NULL); if (error) return error; so1 = fp1->f_socket; sv[0] = fd; error = makesocket(l, &fp2, &fd, flags, type, domain, proto, so1); if (error) goto out; so2 = fp2->f_socket; sv[1] = fd; solock(so1); error = soconnect2(so1, so2); if (error == 0 && type == SOCK_DGRAM) { /* * Datagram socket connection is asymmetric. */ error = soconnect2(so2, so1); } sounlock(so1); if (error == 0) error = copyout(sv, SCARG(uap, rsv), sizeof(sv)); if (error == 0) { fd_affix(p, fp2, sv[1]); fd_affix(p, fp1, sv[0]); return 0; } fd_abort(p, fp2, sv[1]); (void)soclose(so2); out: fd_abort(p, fp1, sv[0]); (void)soclose(so1); return error; }
int sys_socketpair(struct proc *p, void *v, register_t *retval) { struct sys_socketpair_args /* { syscallarg(int) domain; syscallarg(int) type; syscallarg(int) protocol; syscallarg(int *) rsv; } */ *uap = v; struct filedesc *fdp = p->p_fd; struct file *fp1, *fp2; struct socket *so1, *so2; int fd, error, sv[2]; error = socreate(SCARG(uap, domain), &so1, SCARG(uap, type), SCARG(uap, protocol)); if (error) return (error); error = socreate(SCARG(uap, domain), &so2, SCARG(uap, type), SCARG(uap, protocol)); if (error) goto free1; fdplock(fdp); if ((error = falloc(p, &fp1, &fd)) != 0) goto free2; sv[0] = fd; fp1->f_flag = FREAD|FWRITE; fp1->f_type = DTYPE_SOCKET; fp1->f_ops = &socketops; fp1->f_data = so1; if ((error = falloc(p, &fp2, &fd)) != 0) goto free3; fp2->f_flag = FREAD|FWRITE; fp2->f_type = DTYPE_SOCKET; fp2->f_ops = &socketops; fp2->f_data = so2; sv[1] = fd; if ((error = soconnect2(so1, so2)) != 0) goto free4; if (SCARG(uap, type) == SOCK_DGRAM) { /* * Datagram socket connection is asymmetric. */ if ((error = soconnect2(so2, so1)) != 0) goto free4; } error = copyout(sv, SCARG(uap, rsv), 2 * sizeof (int)); if (error == 0) { FILE_SET_MATURE(fp1, p); FILE_SET_MATURE(fp2, p); fdpunlock(fdp); return (0); } free4: fdremove(fdp, sv[1]); closef(fp2, p); so2 = NULL; free3: fdremove(fdp, sv[0]); closef(fp1, p); so1 = NULL; free2: if (so2 != NULL) (void)soclose(so2); fdpunlock(fdp); free1: if (so1 != NULL) (void)soclose(so1); return (error); }
/* ARGSUSED */ int fifo_open(struct vnop_open_args *ap) { struct vnode *vp = ap->a_vp; struct fifoinfo *fip; struct socket *rso, *wso; int error; vnode_lock(vp); retry: fip = vp->v_fifoinfo; if (fip == (struct fifoinfo *)0) panic("fifo_open with no fifoinfo"); if ((fip->fi_flags & FIFO_CREATED) == 0) { if (fip->fi_flags & FIFO_INCREATE) { fip->fi_flags |= FIFO_CREATEWAIT; error = msleep(&fip->fi_flags, &vp->v_lock, PRIBIO | PCATCH, "fifocreatewait", NULL); if (error) { vnode_unlock(vp); return(error); } goto retry; } else { fip->fi_flags |= FIFO_INCREATE; vnode_unlock(vp); if ( (error = socreate(AF_LOCAL, &rso, SOCK_STREAM, 0)) ) { goto bad1; } if ( (error = socreate(AF_LOCAL, &wso, SOCK_STREAM, 0)) ) { (void)soclose(rso); goto bad1; } if ( (error = soconnect2(wso, rso)) ) { (void)soclose(wso); (void)soclose(rso); goto bad1; } fip->fi_readers = fip->fi_writers = 0; /* Lock ordering between wso and rso does not matter here * because they are just created and no one has a reference to them */ socket_lock(wso, 1); wso->so_state |= SS_CANTRCVMORE; wso->so_snd.sb_lowat = PIPE_BUF; socket_unlock(wso, 1); socket_lock(rso, 1); rso->so_state |= SS_CANTSENDMORE; socket_unlock(rso, 1); vnode_lock(vp); fip->fi_readsock = rso; fip->fi_writesock = wso; fip->fi_flags |= FIFO_CREATED; fip->fi_flags &= ~FIFO_INCREATE; if ((fip->fi_flags & FIFO_CREATEWAIT)) { fip->fi_flags &= ~FIFO_CREATEWAIT; wakeup(&fip->fi_flags); } /* vnode lock is held to process further */ } } /* vnode is locked at this point */ /* fifo in created already */ if (ap->a_mode & FREAD) { fip->fi_readers++; if (fip->fi_readers == 1) { socket_lock(fip->fi_writesock, 1); fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; socket_unlock(fip->fi_writesock, 1); if (fip->fi_writers > 0) wakeup((caddr_t)&fip->fi_writers); } } if (ap->a_mode & FWRITE) { fip->fi_writers++; if (fip->fi_writers == 1) { socket_lock(fip->fi_readsock, 1); fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; socket_unlock(fip->fi_readsock, 1); if (fip->fi_readers > 0) wakeup((caddr_t)&fip->fi_readers); } } if ((ap->a_mode & FREAD) && (ap->a_mode & O_NONBLOCK) == 0) { if (fip->fi_writers == 0) { error = msleep((caddr_t)&fip->fi_readers, &vp->v_lock, PCATCH | PSOCK, "fifoor", NULL); if (error) goto bad; if (fip->fi_readers == 1) { if (fip->fi_writers > 0) wakeup((caddr_t)&fip->fi_writers); } } } if (ap->a_mode & FWRITE) { if (ap->a_mode & O_NONBLOCK) { if (fip->fi_readers == 0) { error = ENXIO; goto bad; } } else { if (fip->fi_readers == 0) { error = msleep((caddr_t)&fip->fi_writers,&vp->v_lock, PCATCH | PSOCK, "fifoow", NULL); if (error) goto bad; if (fip->fi_writers == 1) { if (fip->fi_readers > 0) wakeup((caddr_t)&fip->fi_readers); } } } } vnode_unlock(vp); return (0); bad: fifo_close_internal(vp, ap->a_mode, ap->a_context, 1); vnode_unlock(vp); return (error); bad1: vnode_lock(vp); fip->fi_flags &= ~FIFO_INCREATE; if ((fip->fi_flags & FIFO_CREATEWAIT)) { fip->fi_flags &= ~FIFO_CREATEWAIT; wakeup(&fip->fi_flags); } vnode_unlock(vp); return (error); }