示例#1
0
文件: ssl.c 项目: neshema/openconnect
static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
                               const struct sockaddr *addr, socklen_t addrlen)
{
    struct sockaddr_storage peer;
    socklen_t peerlen = sizeof(peer);
    fd_set wr_set, rd_set;
    int maxfd = sockfd;

    set_sock_nonblock(sockfd);
    if (vpninfo->protect_socket)
        vpninfo->protect_socket(vpninfo->cbdata, sockfd);

    if (connect(sockfd, addr, addrlen) < 0 && !connect_pending())
        return -1;

    do {
        FD_ZERO(&wr_set);
        FD_ZERO(&rd_set);
        FD_SET(sockfd, &wr_set);
        cmd_fd_set(vpninfo, &rd_set, &maxfd);

        select(maxfd + 1, &rd_set, &wr_set, NULL, NULL);
        if (is_cancel_pending(vpninfo, &rd_set)) {
            vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
            errno = EINTR;
            return -1;
        }
    } while (!FD_ISSET(sockfd, &wr_set) && !vpninfo->got_pause_cmd);

    /* Check whether connect() succeeded or failed by using
       getpeername(). See http://cr.yp.to/docs/connect.html */
    return getpeername(sockfd, (void *)&peer, &peerlen);
}
int zmq::socket_base_t::bind (const char *addr_)
{
    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1;
    }

    //  Process pending commands, if any.
    int rc = process_commands (0, false);
    if (unlikely (rc != 0))
        return -1;

    //  Parse addr_ string.
    std::string protocol;
    std::string address;
    rc = parse_uri (addr_, protocol, address);
    if (rc != 0)
        return -1;

    rc = check_protocol (protocol);
    if (rc != 0)
        return -1;

    if (protocol == "inproc") {
        endpoint_t endpoint = {this, options};
        int rc = register_endpoint (addr_, endpoint);
        if (rc == 0) {
            connect_pending(addr_, this);
            last_endpoint.assign (addr_);
        }
        return rc;
    }

    if (protocol == "pgm" || protocol == "epgm" || protocol == "norm") {
        //  For convenience's sake, bind can be used interchageable with
        //  connect for PGM, EPGM and NORM transports.
        return connect (addr_);
    }

    //  Remaining trasnports require to be run in an I/O thread, so at this
    //  point we'll choose one.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    if (!io_thread) {
        errno = EMTHREAD;
        return -1;
    }

    if (protocol == "tcp") {
        tcp_listener_t *listener = new (std::nothrow) tcp_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        int rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            delete listener;
            event_bind_failed (address, zmq_errno());
            return -1;
        }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (addr_, (own_t *) listener, NULL);
        return 0;
    }

#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
    if (protocol == "ipc") {
        ipc_listener_t *listener = new (std::nothrow) ipc_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        int rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            delete listener;
            event_bind_failed (address, zmq_errno());
            return -1;
        }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (addr_, (own_t *) listener, NULL);
        return 0;
    }
#endif
#if defined ZMQ_HAVE_TIPC
    if (protocol == "tipc") {
        tipc_listener_t *listener = new (std::nothrow) tipc_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        int rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            delete listener;
            event_bind_failed (address, zmq_errno());
            return -1;
        }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (addr_, (own_t *) listener, NULL);
        return 0;
    }
#endif

    zmq_assert (false);
    return -1;
}
示例#3
0
int zmq::socket_base_t::bind (const char *addr_)
{
    scoped_optional_lock_t sync_lock(thread_safe ? &sync : NULL);

    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1;
    }

    //  Process pending commands, if any.
    int rc = process_commands (0, false);
    if (unlikely (rc != 0)) {
        return -1;
    }

    //  Parse addr_ string.
    std::string protocol;
    std::string address;
    if (parse_uri (addr_, protocol, address) || check_protocol (protocol)) {
        return -1;
    }

    if (protocol == "inproc") {
        const endpoint_t endpoint = { this, options };
        rc = register_endpoint (addr_, endpoint);
        if (rc == 0) {
            connect_pending (addr_, this);
            last_endpoint.assign (addr_);
            options.connected = true;
        }
        return rc;
    }

    if (protocol == "pgm" || protocol == "epgm" || protocol == "norm") {
        //  For convenience's sake, bind can be used interchangeable with
        //  connect for PGM, EPGM, NORM transports.
        rc = connect (addr_);
        if (rc != -1)
            options.connected = true;
        return rc;
    }

    if (protocol == "udp") {
        if (!(options.type == ZMQ_DGRAM || options.type == ZMQ_DISH)) {
            errno = ENOCOMPATPROTO;
            return -1;
        }

        //  Choose the I/O thread to run the session in.
        io_thread_t *io_thread = choose_io_thread (options.affinity);
        if (!io_thread) {
            errno = EMTHREAD;
            return -1;
        }

        address_t *paddr = new (std::nothrow) address_t (protocol, address, this->get_ctx ());
        alloc_assert (paddr);

        paddr->resolved.udp_addr = new (std::nothrow) udp_address_t ();
        alloc_assert (paddr->resolved.udp_addr);
        rc = paddr->resolved.udp_addr->resolve (address.c_str(), true);
        if (rc != 0) {
            LIBZMQ_DELETE(paddr);
            return -1;
        }

        session_base_t *session = session_base_t::create (io_thread, true, this,
            options, paddr);
        errno_assert (session);

        pipe_t *newpipe = NULL;

        //  Create a bi-directional pipe.
        object_t *parents [2] = {this, session};
        pipe_t *new_pipes [2] = {NULL, NULL};

        int hwms [2] = {options.sndhwm, options.rcvhwm};
        bool conflates [2] = {false, false};
        rc = pipepair (parents, new_pipes, hwms, conflates);
        errno_assert (rc == 0);

        //  Attach local end of the pipe to the socket object.
        attach_pipe (new_pipes [0], true);
        newpipe = new_pipes [0];

        //  Attach remote end of the pipe to the session object later on.
        session->attach_pipe (new_pipes [1]);

        //  Save last endpoint URI
        paddr->to_string (last_endpoint);

        add_endpoint (addr_, (own_t *) session, newpipe);

        return 0;
    }

    //  Remaining transports require to be run in an I/O thread, so at this
    //  point we'll choose one.
    io_thread_t *io_thread = choose_io_thread (options.affinity);
    if (!io_thread) {
        errno = EMTHREAD;
        return -1;
    }

    if (protocol == "tcp") {
        tcp_listener_t *listener = new (std::nothrow) tcp_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            LIBZMQ_DELETE(listener);
            event_bind_failed (address, zmq_errno());
            return -1;
        }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL);
        options.connected = true;
        return 0;
    }

#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
    if (protocol == "ipc") {
        ipc_listener_t *listener = new (std::nothrow) ipc_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        int rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            LIBZMQ_DELETE(listener);
            event_bind_failed (address, zmq_errno());
            return -1;
        }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (last_endpoint.c_str (), (own_t *) listener, NULL);
        options.connected = true;
        return 0;
    }
#endif
#if defined ZMQ_HAVE_TIPC
    if (protocol == "tipc") {
         tipc_listener_t *listener = new (std::nothrow) tipc_listener_t (
              io_thread, this, options);
         alloc_assert (listener);
         int rc = listener->set_address (address.c_str ());
         if (rc != 0) {
             LIBZMQ_DELETE(listener);
             event_bind_failed (address, zmq_errno());
             return -1;
         }

        // Save last endpoint URI
        listener->get_address (last_endpoint);

        add_endpoint (addr_, (own_t *) listener, NULL);
        options.connected = true;
        return 0;
    }
#endif
#if defined ZMQ_HAVE_VMCI
    if (protocol == "vmci") {
        vmci_listener_t *listener = new (std::nothrow) vmci_listener_t (
            io_thread, this, options);
        alloc_assert (listener);
        int rc = listener->set_address (address.c_str ());
        if (rc != 0) {
            LIBZMQ_DELETE(listener);
            event_bind_failed (address, zmq_errno ());
            return -1;
        }

        listener->get_address (last_endpoint);

        add_endpoint (last_endpoint.c_str(), (own_t *) listener, NULL);
        options.connected = true;
        return 0;
    }
#endif

    zmq_assert (false);
    return -1;
}
示例#4
0
/* Windows is interminably horrid, and has disjoint errno spaces.
 * So if we return a positive value, that's a WSA Error and should
 * be handled with openconnect__win32_strerror(). But if we return a
 * negative value, that's a normal errno and should be handled with
 * strerror(). No, you can't just pass the latter value (negated) to
 * openconnect__win32_strerror() because it gives nonsense results. */
static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd,
			       const struct sockaddr *addr, socklen_t addrlen)
{
	struct sockaddr_storage peer;
	socklen_t peerlen = sizeof(peer);
	fd_set wr_set, rd_set, ex_set;
	int maxfd = sockfd;
	int err;

	set_sock_nonblock(sockfd);
	if (vpninfo->protect_socket)
		vpninfo->protect_socket(vpninfo->cbdata, sockfd);

	if (connect(sockfd, addr, addrlen) < 0 && !connect_pending()) {
#ifdef _WIN32
		return WSAGetLastError();
#else
		return -errno;
#endif
	}

	do {
		FD_ZERO(&wr_set);
		FD_ZERO(&rd_set);
		FD_ZERO(&ex_set);
		FD_SET(sockfd, &wr_set);
#ifdef _WIN32 /* Windows indicates failure this way, not in wr_set */
		FD_SET(sockfd, &ex_set);
#endif
		cmd_fd_set(vpninfo, &rd_set, &maxfd);
		select(maxfd + 1, &rd_set, &wr_set, &ex_set, NULL);
		if (is_cancel_pending(vpninfo, &rd_set)) {
			vpn_progress(vpninfo, PRG_ERR, _("Socket connect cancelled\n"));
			return -EINTR;
		}
	} while (!FD_ISSET(sockfd, &wr_set) && !FD_ISSET(sockfd, &ex_set) &&
		 !vpninfo->got_pause_cmd);

	/* Check whether connect() succeeded or failed by using
	   getpeername(). See http://cr.yp.to/docs/connect.html */
	if (!getpeername(sockfd, (void *)&peer, &peerlen))
		return 0;

#ifdef _WIN32 /* On Windows, use getsockopt() to determine the error.
	       * We don't ddo this on Windows because it just reports
	       * -ENOTCONN, which we already knew. */

	err = WSAGetLastError();
	if (err == WSAENOTCONN) {
		socklen_t errlen = sizeof(err);

		getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
			   (void *)&err, &errlen);
	}
#else
	err = -errno;
	if (err == -ENOTCONN) {
		int ch;

		if (read(sockfd, &ch, 1) < 0)
			err = -errno;
		/* It should *always* fail! */
	}
#endif
	return err;
}