void soisconnected(struct socket *so) { struct socket *head; head = so->so_head; KASSERT(solocked(so)); KASSERT(head == NULL || solocked2(so, head)); so->so_state &= ~(SS_ISCONNECTING | SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTED; if (head && so->so_onq == &head->so_q0) { if ((so->so_options & SO_ACCEPTFILTER) == 0) { soqremque(so, 0); soqinsque(head, so, 1); sorwakeup(head); cv_broadcast(&head->so_cv); } else { so->so_upcall = head->so_accf->so_accept_filter->accf_callback; so->so_upcallarg = head->so_accf->so_accept_filter_arg; so->so_rcv.sb_flags |= SB_UPCALL; so->so_options &= ~SO_ACCEPTFILTER; (*so->so_upcall)(so, so->so_upcallarg, POLLIN|POLLRDNORM, M_DONTWAIT); } } else { cv_broadcast(&so->so_cv); sorwakeup(so); sowwakeup(so); } }
struct socket* acceptfrom(struct socket* server) { // if ((so->so_options & SO_ACCEPTCONN) == 0) // return (EINVAL); // if ((so->so_state & SS_NBIO) && so->so_qlen == 0) // return (EWOULDBLOCK); // if (so->so_error): // error = so->so_error; // so->so_error = 0; // return (error); int s = splnet(); struct socket *so = server->so_q; if (!so) goto done; if (soqremque(so, 1) == 0) panic("accept"); struct mbuf *nam = m_get(M_WAIT, MT_SONAME); (void) soaccept(so, nam); m_freem(nam); done: splx(s); return so; }
/* * When an attempt at a new connection is noted on a socket * which accepts connections, sonewconn is called. If the * connection is possible (subject to space constraints, etc.) * then we allocate a new structure, properly linked into the * data structure of the original socket, and return this. * Connstatus may be 0 or SS_ISCONNECTED. * * Must be called at splsoftnet() */ struct socket * sonewconn(struct socket *head, int connstatus) { struct socket *so; int soqueue = connstatus ? 1 : 0; splsoftassert(IPL_SOFTNET); if (mclpools[0].pr_nout > mclpools[0].pr_hardlimit * 95 / 100) return (NULL); if (head->so_qlen + head->so_q0len > head->so_qlimit * 3) return (NULL); so = pool_get(&socket_pool, PR_NOWAIT|PR_ZERO); if (so == NULL) return (NULL); so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_pgid = head->so_pgid; so->so_euid = head->so_euid; so->so_ruid = head->so_ruid; so->so_egid = head->so_egid; so->so_rgid = head->so_rgid; so->so_cpid = head->so_cpid; so->so_siguid = head->so_siguid; so->so_sigeuid = head->so_sigeuid; /* * Inherit watermarks but those may get clamped in low mem situations. */ if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) { pool_put(&socket_pool, so); return (NULL); } so->so_snd.sb_wat = head->so_snd.sb_wat; so->so_snd.sb_lowat = head->so_snd.sb_lowat; so->so_snd.sb_timeo = head->so_snd.sb_timeo; so->so_rcv.sb_wat = head->so_rcv.sb_wat; so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; soqinsque(head, so, soqueue); if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL, curproc)) { (void) soqremque(so, soqueue); pool_put(&socket_pool, so); return (NULL); } if (connstatus) { sorwakeup(head); wakeup(&head->so_timeo); so->so_state |= connstatus; } return (so); }
void sofree(struct socket * so) { INET_TRACE (INETM_SOCKET|INETM_CLOSE, ("INET: sofree, so %lx so_pcb %lx so_state %x so_head %lx\n", so, so->so_pcb, so->so_state, so->so_head)); if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; if (so->so_head) { if (!soqremque(so, 0) && !soqremque(so, 1)) panic("sofree"); so->so_head = 0; } sbrelease(&so->so_snd); sorflush(so); #ifdef SAVE_SOCK_ENDPOINTS if (so->so_endpoint) _socket_free_entry (so); #endif /* SAVE_SOCK_ENDPOINTS */ #ifdef IP_MULTICAST /* multicast opts? */ if (so->inp_moptions) ip_freemoptions(so->inp_moptions); #endif /* IP_MULTICAST */ /* IP_TOS opts? */ if (so->so_optsPack) SOCOPT_FREE(so->so_optsPack); qdel(&soq, so); /* Delete the socket entry from the queue */ if (so_evtmap) (*so_evtmap_delete) (so); SOC_FREE(so); }
void soisconnected(struct socket *so) { struct socket *head = so->so_head; so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING); so->so_state |= SS_ISCONNECTED; if (head && soqremque(so, 0)) { soqinsque(head, so, 1); sorwakeup(head); wakeup_one(&head->so_timeo); } else { wakeup(&so->so_timeo); sorwakeup(so); sowwakeup(so); } }
/* * When an attempt at a new connection is noted on a socket * which accepts connections, sonewconn is called. If the * connection is possible (subject to space constraints, etc.) * then we allocate a new structure, propoerly linked into the * data structure of the original socket, and return this. * Connstatus may be 0, SS_ISCONFIRMING, or SS_ISCONNECTED. */ struct socket * sonewconn(struct socket *head, int connstatus) { struct socket *so; int soqueue, error; KASSERT(connstatus == 0 || connstatus == SS_ISCONFIRMING || connstatus == SS_ISCONNECTED); KASSERT(solocked(head)); if ((head->so_options & SO_ACCEPTFILTER) != 0) connstatus = 0; soqueue = connstatus ? 1 : 0; if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) return NULL; so = soget(false); if (so == NULL) return NULL; mutex_obj_hold(head->so_lock); // so->so_lock = head->so_lock; so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; so->so_linger = head->so_linger; so->so_state = head->so_state | SS_NOFDREF; so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; #if 0 /* VADIM */ so->so_pgid = head->so_pgid; so->so_send = head->so_send; so->so_receive = head->so_receive; so->so_uidinfo = head->so_uidinfo; so->so_cpid = head->so_cpid; #else so->glueing_block = NULL; #endif #ifdef MBUFTRACE so->so_mowner = head->so_mowner; so->so_rcv.sb_mowner = head->so_rcv.sb_mowner; so->so_snd.sb_mowner = head->so_snd.sb_mowner; #endif if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) != 0) goto out; so->so_snd.sb_lowat = head->so_snd.sb_lowat; so->so_rcv.sb_lowat = head->so_rcv.sb_lowat; so->so_rcv.sb_timeo = head->so_rcv.sb_timeo; so->so_snd.sb_timeo = head->so_snd.sb_timeo; so->so_rcv.sb_flags |= head->so_rcv.sb_flags & (SB_AUTOSIZE | SB_ASYNC); so->so_snd.sb_flags |= head->so_snd.sb_flags & (SB_AUTOSIZE | SB_ASYNC); soqinsque(head, so, soqueue); error = (*so->so_proto->pr_usrreq)(so, PRU_ATTACH, NULL, NULL, NULL); KASSERT(solocked(so)); if (error != 0) { (void) soqremque(so, soqueue); out: /* * Remove acccept filter if one is present. * XXX Is this really needed? */ #if 0 /*VADIM*/ if (so->so_accf != NULL) (void)accept_filt_clear(so); #endif soput(so); return NULL; } if (connstatus) { sorwakeup(head); #if 0 cv_broadcast(&head->so_cv); #endif so->so_state |= connstatus; } return so; }
long t_accept(long s, struct sockaddr * addr, int * addrlen) { #ifdef SOCKDEBUG char logbuf[10]; #endif struct socket * so; struct mbuf * nam; so = LONG2SO(s); SOC_CHECK(so); DOMAIN_CHECK(so, *addrlen); so->so_error = 0; INET_TRACE (INETM_SOCKET, ("INET:accept:so %x so_qlen %d so_state %x\n", so, so->so_qlen, so->so_state)); if ((so->so_options & SO_ACCEPTCONN) == 0) { so->so_error = EINVAL; #ifdef SOCKDEBUG sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error); glog_with_type(LOG_TYPE_DEBUG, logbuf, 1); #endif return SOCKET_ERROR; } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { so->so_error = EWOULDBLOCK; #ifdef SOCKDEBUG sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error); glog_with_type(LOG_TYPE_DEBUG, logbuf, 1); #endif return SOCKET_ERROR; } LOCK_NET_RESOURCE(NET_RESID); while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; UNLOCK_NET_RESOURCE(NET_RESID); return SOCKET_ERROR; } tcp_sleep ((char *)&so->so_timeo); } if (so->so_error) { #ifdef SOCKDEBUG sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error); glog_with_type(LOG_TYPE_DEBUG, logbuf, 1); #endif UNLOCK_NET_RESOURCE(NET_RESID); return SOCKET_ERROR; } nam = m_getwithdata (MT_SONAME, sizeof (struct sockaddr)); if (nam == NULL) { UNLOCK_NET_RESOURCE(NET_RESID); so->so_error = ENOMEM; #ifdef SOCKDEBUG sprintf(logbuf, "t_accept[%d]: %d", __LINE__, so->so_error); glog_with_type(LOG_TYPE_DEBUG, logbuf, 1); #endif return SOCKET_ERROR; } { struct socket *aso = so->so_q; if (soqremque (aso, 1) == 0) panic("accept"); so = aso; } (void)soaccept (so, nam); #ifdef TRACE_DEBUG { struct sockaddr_in *sin; sin = mtod(nam, struct sockaddr_in *); INET_TRACE (INETM_SOCKET, ("INET:accept:done so %lx port %d addr %lx\n", so, sin->sin_port, sin->sin_addr.s_addr)); } #endif /* TRACE_INET */ /* return the addressing info in the passed structure */ if (addr != NULL) MEMCPY(addr, nam->m_data, *addrlen); m_freem (nam); UNLOCK_NET_RESOURCE(NET_RESID); SOC_RANGE(so); return SO2LONG(so); }
int do_sys_accept(struct lwp *l, int sock, struct mbuf **name, register_t *new_sock, const sigset_t *mask, int flags, int clrflags) { file_t *fp, *fp2; struct mbuf *nam; int error, fd; struct socket *so, *so2; short wakeup_state = 0; if ((fp = fd_getfile(sock)) == NULL) return EBADF; if (fp->f_type != DTYPE_SOCKET) { fd_putfile(sock); return ENOTSOCK; } if ((error = fd_allocfile(&fp2, &fd)) != 0) { fd_putfile(sock); return error; } nam = m_get(M_WAIT, MT_SONAME); *new_sock = fd; so = fp->f_socket; solock(so); if (__predict_false(mask)) sigsuspendsetup(l, mask); if (!(so->so_proto->pr_flags & PR_LISTEN)) { error = EOPNOTSUPP; goto bad; } if ((so->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto bad; } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { error = EWOULDBLOCK; goto bad; } while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } if (wakeup_state & SS_RESTARTSYS) { error = ERESTART; goto bad; } error = sowait(so, true, 0); if (error) { goto bad; } wakeup_state = so->so_state; } if (so->so_error) { error = so->so_error; so->so_error = 0; goto bad; } /* connection has been removed from the listen queue */ KNOTE(&so->so_rcv.sb_sel.sel_klist, NOTE_SUBMIT); so2 = TAILQ_FIRST(&so->so_q); if (soqremque(so2, 1) == 0) panic("accept"); fp2->f_type = DTYPE_SOCKET; fp2->f_flag = (fp->f_flag & ~clrflags) | ((flags & SOCK_NONBLOCK) ? FNONBLOCK : 0)| ((flags & SOCK_NOSIGPIPE) ? FNOSIGPIPE : 0); fp2->f_ops = &socketops; fp2->f_socket = so2; if (fp2->f_flag & FNONBLOCK) so2->so_state |= SS_NBIO; else so2->so_state &= ~SS_NBIO; error = soaccept(so2, nam); so2->so_cred = kauth_cred_dup(so->so_cred); sounlock(so); if (error) { /* an error occurred, free the file descriptor and mbuf */ m_freem(nam); mutex_enter(&fp2->f_lock); fp2->f_count++; mutex_exit(&fp2->f_lock); closef(fp2); fd_abort(curproc, NULL, fd); } else { fd_set_exclose(l, fd, (flags & SOCK_CLOEXEC) != 0); fd_affix(curproc, fp2, fd); *name = nam; } fd_putfile(sock); if (__predict_false(mask)) sigsuspendteardown(l); return error; bad: sounlock(so); m_freem(nam); fd_putfile(sock); fd_abort(curproc, fp2, fd); if (__predict_false(mask)) sigsuspendteardown(l); return error; }
static int bsd_accept ( cyg_file *fp, cyg_file *new_fp, struct sockaddr *name, socklen_t *anamelen ) { struct mbuf *nam; socklen_t namelen = 0; int error = 0, s; register struct socket *so; if( anamelen != NULL ) namelen = *anamelen; s = splsoftnet(); so = (struct socket *)fp->f_data; if ((so->so_options & SO_ACCEPTCONN) == 0) { splx(s); return (EINVAL); } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { splx(s); return (EWOULDBLOCK); } while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, netcon, 0); if (error) { splx(s); return (error); } } if (so->so_error) { error = so->so_error; so->so_error = 0; splx(s); return (error); } { struct socket *aso = so->so_q; if (soqremque(aso, 1) == 0) panic("accept"); so = aso; } cyg_selinit(&so->so_rcv.sb_sel); cyg_selinit(&so->so_snd.sb_sel); new_fp->f_type = DTYPE_SOCKET; new_fp->f_flag |= FREAD|FWRITE; new_fp->f_offset = 0; new_fp->f_ops = &bsd_sock_fileops; new_fp->f_data = (CYG_ADDRWORD)so; new_fp->f_xops = (CYG_ADDRWORD)&bsd_sockops; nam = m_get(M_WAIT, MT_SONAME); (void) soaccept(so, nam); if (name) { if (namelen > nam->m_len) namelen = nam->m_len; /* SHOULD COPY OUT A CHAIN HERE */ if ((error = copyout(mtod(nam, caddr_t), (caddr_t)name, namelen)) == 0) *anamelen = namelen; } m_freem(nam); splx(s); return (error); }
int sys_accept(struct proc *p, void *v, register_t *retval) { struct sys_accept_args /* { syscallarg(int) s; syscallarg(struct sockaddr *) name; syscallarg(socklen_t *) anamelen; } */ *uap = v; struct file *fp, *headfp; struct mbuf *nam; socklen_t namelen; int error, s, tmpfd; struct socket *head, *so; int nflag; if (SCARG(uap, name) && (error = copyin(SCARG(uap, anamelen), &namelen, sizeof (namelen)))) return (error); if ((error = getsock(p->p_fd, SCARG(uap, s), &fp)) != 0) return (error); headfp = fp; s = splsoftnet(); head = fp->f_data; redo: if ((head->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto bad; } if ((head->so_state & SS_NBIO) && head->so_qlen == 0) { if (head->so_state & SS_CANTRCVMORE) error = ECONNABORTED; else error = EWOULDBLOCK; goto bad; } while (head->so_qlen == 0 && head->so_error == 0) { if (head->so_state & SS_CANTRCVMORE) { head->so_error = ECONNABORTED; break; } error = tsleep(&head->so_timeo, PSOCK | PCATCH, "netcon", 0); if (error) { goto bad; } } if (head->so_error) { error = head->so_error; head->so_error = 0; goto bad; } /* Take note if socket was non-blocking. */ nflag = (headfp->f_flag & FNONBLOCK); fdplock(p->p_fd); error = falloc(p, &fp, &tmpfd); fdpunlock(p->p_fd); if (error != 0) { /* * Probably ran out of file descriptors. Wakeup * so some other process might have a chance at it. */ wakeup_one(&head->so_timeo); goto bad; } nam = m_get(M_WAIT, MT_SONAME); /* * Check whether the queue emptied while we slept: falloc() or * m_get() may have blocked, allowing the connection to be reset * or another thread or process to accept it. If so, start over. */ if (head->so_qlen == 0) { m_freem(nam); fdplock(p->p_fd); fdremove(p->p_fd, tmpfd); closef(fp, p); fdpunlock(p->p_fd); goto redo; } /* * Do not sleep after we have taken the socket out of the queue. */ so = TAILQ_FIRST(&head->so_q); if (soqremque(so, 1) == 0) panic("accept"); /* connection has been removed from the listen queue */ KNOTE(&head->so_rcv.sb_sel.si_note, 0); fp->f_type = DTYPE_SOCKET; fp->f_flag = FREAD | FWRITE | nflag; fp->f_ops = &socketops; fp->f_data = so; error = soaccept(so, nam); if (!error && SCARG(uap, name)) { error = copyaddrout(p, nam, SCARG(uap, name), namelen, SCARG(uap, anamelen)); } if (error) { /* if an error occurred, free the file descriptor */ fdplock(p->p_fd); fdremove(p->p_fd, tmpfd); closef(fp, p); fdpunlock(p->p_fd); } else { FILE_SET_MATURE(fp, p); *retval = tmpfd; } m_freem(nam); bad: splx(s); FRELE(headfp, p); return (error); }