/* * 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; }
/* * sonewconn: accept a new connection. * * When an attempt at a new connection is noted on a socket which accepts * connections, sonewconn(9) 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. * * => If 'soready' is true, then socket will become ready for accept() i.e. * inserted into the so_q queue, SS_ISCONNECTED set and waiters awoken. * => May be called from soft-interrupt context. * => Listening socket should be locked. * => Returns the new socket locked. */ struct socket * sonewconn(struct socket *head, bool soready) { struct socket *so; int soqueue, error; KASSERT(solocked(head)); if (head->so_qlen + head->so_q0len > 3 * head->so_qlimit / 2) { /* Listen queue overflow. */ return NULL; } if ((head->so_options & SO_ACCEPTFILTER) != 0) { soready = false; } soqueue = soready ? 1 : 0; if ((so = soget(false)) == 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_send = head->so_send; so->so_receive = head->so_receive; so->so_uidinfo = head->so_uidinfo; so->so_cpid = head->so_cpid; /* * Share the lock with the listening-socket, it may get unshared * once the connection is complete. */ mutex_obj_hold(head->so_lock); so->so_lock = head->so_lock; /* * Reserve the space for socket buffers. */ #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)) { 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); /* * Finally, perform the protocol attach. Note: a new socket * lock may be assigned at this point (if so, it will be held). */ error = (*so->so_proto->pr_usrreqs->pr_attach)(so, 0); if (error) { out: KASSERT(solocked(so)); KASSERT(so->so_accf == NULL); soput(so); /* Note: the listening socket shall stay locked. */ KASSERT(solocked(head)); return NULL; } KASSERT(solocked2(head, so)); /* * Insert into the queue. If ready, update the connection status * and wake up any waiters, e.g. processes blocking on accept(). */ soqinsque(head, so, soqueue); if (soready) { so->so_state |= SS_ISCONNECTED; sorwakeup(head); cv_broadcast(&head->so_cv); } return so; }