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); } }
/* * soqremque: remove socket from the specified queue. * * => Returns true if socket was removed from the specified queue. * => False if socket was not removed (because it was in other queue). */ bool soqremque(struct socket *so, int q) { struct socket *head = so->so_head; KASSERT(q == 0 || q == 1); KASSERT(solocked(so)); KASSERT(so->so_onq != NULL); KASSERT(head != NULL); if (q == 0) { if (so->so_onq != &head->so_q0) return false; head->so_q0len--; } else { if (so->so_onq != &head->so_q) return false; head->so_qlen--; } KASSERT(solocked2(so, head)); TAILQ_REMOVE(so->so_onq, so, so_qe); so->so_onq = NULL; so->so_head = NULL; return true; }
/* * soqinsque: insert socket of a new connection into the specified * accept queue of the listening socket (head). * * q = 0: queue of partial connections * q = 1: queue of incoming connections */ void soqinsque(struct socket *head, struct socket *so, int q) { KASSERT(q == 0 || q == 1); KASSERT(solocked2(head, so)); KASSERT(so->so_onq == NULL); KASSERT(so->so_head == NULL); so->so_head = head; if (q == 0) { head->so_q0len++; so->so_onq = &head->so_q0; } else { head->so_qlen++; so->so_onq = &head->so_q; } TAILQ_INSERT_TAIL(so->so_onq, so, so_qe); }
void soqinsque(struct socket *head, struct socket *so, int q) { KASSERT(solocked2(head, so)); #ifdef DIAGNOSTIC if (so->so_onq != NULL) panic("soqinsque"); #endif so->so_head = head; if (q == 0) { head->so_q0len++; so->so_onq = &head->so_q0; } else { head->so_qlen++; so->so_onq = &head->so_q; } TAILQ_INSERT_TAIL(so->so_onq, so, so_qe); }
int soqremque(struct socket *so, int q) { struct socket *head; head = so->so_head; KASSERT(solocked(so)); if (q == 0) { if (so->so_onq != &head->so_q0) return (0); head->so_q0len--; } else { if (so->so_onq != &head->so_q) return (0); head->so_qlen--; } KASSERT(solocked2(so, head)); TAILQ_REMOVE(so->so_onq, so, so_qe); so->so_onq = NULL; so->so_head = NULL; return (1); }
/* * 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; }