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);
	}
}
示例#2
0
/*
 * 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;
}
示例#3
0
/*
 * 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);
}
示例#4
0
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);
}
示例#5
0
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);
}
示例#6
0
/*
 * 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;
}