Ejemplo n.º 1
0
errno_t
sock_accept(socket_t sock, struct sockaddr *from, int fromlen, int flags,
            sock_upcall callback, void *cookie, socket_t *new_sock)
{
    struct sockaddr *sa;
    struct socket *new_so;
    lck_mtx_t *mutex_held;
    int dosocklock;
    errno_t	error = 0;

    if (sock == NULL || new_sock == NULL)
        return (EINVAL);

    socket_lock(sock, 1);
    if ((sock->so_options & SO_ACCEPTCONN) == 0) {
        socket_unlock(sock, 1);
        return (EINVAL);
    }
    if ((flags & ~(MSG_DONTWAIT)) != 0) {
        socket_unlock(sock, 1);
        return (ENOTSUP);
    }
    if (((flags & MSG_DONTWAIT) != 0 || (sock->so_state & SS_NBIO) != 0) &&
            sock->so_comp.tqh_first == NULL) {
        socket_unlock(sock, 1);
        return (EWOULDBLOCK);
    }

    if (sock->so_proto->pr_getlock != NULL)  {
        mutex_held = (*sock->so_proto->pr_getlock)(sock, 0);
        dosocklock = 1;
    } else {
        mutex_held = sock->so_proto->pr_domain->dom_mtx;
        dosocklock = 0;
    }

    while (TAILQ_EMPTY(&sock->so_comp) && sock->so_error == 0) {
        if (sock->so_state & SS_CANTRCVMORE) {
            sock->so_error = ECONNABORTED;
            break;
        }
        error = msleep((caddr_t)&sock->so_timeo, mutex_held,
                       PSOCK | PCATCH, "sock_accept", NULL);
        if (error != 0) {
            socket_unlock(sock, 1);
            return (error);
        }
    }
    if (sock->so_error != 0) {
        error = sock->so_error;
        sock->so_error = 0;
        socket_unlock(sock, 1);
        return (error);
    }

    new_so = TAILQ_FIRST(&sock->so_comp);
    TAILQ_REMOVE(&sock->so_comp, new_so, so_list);
    sock->so_qlen--;

    /*
     * Pass the pre-accepted socket to any interested socket filter(s).
     * Upon failure, the socket would have been closed by the callee.
     */
    if (new_so->so_filt != NULL) {
        /*
         * Temporarily drop the listening socket's lock before we
         * hand off control over to the socket filter(s), but keep
         * a reference so that it won't go away.  We'll grab it
         * again once we're done with the filter(s).
         */
        socket_unlock(sock, 0);
        if ((error = soacceptfilter(new_so)) != 0) {
            /* Drop reference on listening socket */
            sodereference(sock);
            return (error);
        }
        socket_lock(sock, 0);
    }

    if (dosocklock)	{
        lck_mtx_assert(new_so->so_proto->pr_getlock(new_so, 0),
                       LCK_MTX_ASSERT_NOTOWNED);
        socket_lock(new_so, 1);
    }

    new_so->so_state &= ~SS_COMP;
    new_so->so_head = NULL;
    (void) soacceptlock(new_so, &sa, 0);

    socket_unlock(sock, 1);	/* release the head */

    /* see comments in sock_setupcall() */
    if (callback != NULL) {
        sock_setupcalls_common(new_so, callback, cookie, NULL, NULL);
    }

    if (sa != NULL && from != NULL) {
        if (fromlen > sa->sa_len)
            fromlen = sa->sa_len;
        memcpy(from, sa, fromlen);
    }
    if (sa != NULL)
        FREE(sa, M_SONAME);

    /*
     * If the socket has been marked as inactive by sosetdefunct(),
     * disallow further operations on it.
     */
    if (new_so->so_flags & SOF_DEFUNCT) {
        (void) sodefunct(current_proc(), new_so,
                         SHUTDOWN_SOCKET_LEVEL_DISCONNECT_INTERNAL);
    }
    *new_sock = new_so;
    if (dosocklock)
        socket_unlock(new_so, 1);
    return (error);
}
Ejemplo n.º 2
0
static int
shutdown_sockets_on_interface_proc_callout(proc_t p, void *arg)
{
	struct filedesc *fdp;
	int i;
	struct ifnet *ifp = (struct ifnet *)arg;

	if (ifp == NULL)
		return (PROC_RETURNED);

	proc_fdlock(p);
	fdp = p->p_fd;
	for (i = 0; i < fdp->fd_nfiles; i++) {
		struct fileproc	*fp = fdp->fd_ofiles[i];
		struct fileglob *fg;
		struct socket *so;
		struct inpcb *inp;
		struct ifnet *inp_ifp;
		int error;

		if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0) {
			continue;
		}

		fg = fp->f_fglob;
		if (FILEGLOB_DTYPE(fg) != DTYPE_SOCKET)
			continue;

		so = (struct socket *)fp->f_fglob->fg_data;
		if (SOCK_DOM(so) != PF_INET && SOCK_DOM(so) != PF_INET6)
			continue;

		inp = (struct inpcb *)so->so_pcb;

		if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) == WNT_STOPUSING)
			continue;

		socket_lock(so, 1);

		if (in_pcb_checkstate(inp, WNT_RELEASE, 1) == WNT_STOPUSING) {
			socket_unlock(so, 1);
			continue;
		}

		if (inp->inp_boundifp != NULL) {
			inp_ifp = inp->inp_boundifp;
		} else if (inp->inp_last_outifp != NULL) {
			inp_ifp = inp->inp_last_outifp;
		} else {
			socket_unlock(so, 1);
			continue;
		}

		if (inp_ifp != ifp && inp_ifp->if_delegated.ifp != ifp) {
			socket_unlock(so, 1);
			continue;
		}
		error = sosetdefunct(p, so, 0, TRUE);
		if (error != 0) {
			log(LOG_ERR, "%s: sosetdefunct() error %d",
			    __func__, error);
		} else {
			error = sodefunct(p, so, 0);
			if (error != 0) {
				log(LOG_ERR, "%s: sodefunct() error %d",
				    __func__, error);
			}
		}

		socket_unlock(so, 1);
	}
	proc_fdunlock(p);

	return (PROC_RETURNED);
}