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);
	}
}
Beispiel #2
0
/*
 * 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);
}
Beispiel #3
0
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;
}
Beispiel #5
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;
}