int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa,
	socklen_t len, int timeout)
{
	int   err;

	/*
	 * Sanity check. Just like with timed_wait(), the timeout must be a
	 * positive number.
	 */
	if (timeout < 0)
		acl_msg_panic("timed_connect: bad timeout: %d", timeout);

	/*
	 * Start the connection, and handle all possible results.
	 */
	if (acl_sane_connect(sock, sa, len) == 0)
		return (0);

	errno = acl_last_error();

#ifdef	ACL_UNIX
	if (errno != ACL_EINPROGRESS)
		return (-1);
#elif defined(ACL_WINDOWS)
	if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK)
		return (-1);
#endif

	/*
	 * A connection is in progress. Wait for a limited amount of time for
	 * something to happen. If nothing happens, report an error.
	 */
	if (acl_write_wait(sock, timeout) < 0)
		return (-1);

	/*
	 * Something happened. Some Solaris 2 versions have getsockopt() itself
	 * return the error, instead of returning it via the parameter list.
	 */
	len = sizeof(err);
	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) {
#ifdef  SUNOS5
	/*
	 * Solaris 2.4's socket emulation doesn't allow you
	 * to determine the error from a failed non-blocking
	 * connect and just returns EPIPE.  Create a fake
	 * error message for connect.   -- [email protected]
	 */
		if (errno == EPIPE)
			acl_set_error(ACL_ENOTCONN);
#endif
		return (-1);
	}

	if (err != 0) {
		acl_set_error(err);
		return (-1);
	} else
		return (0);
}
Exemple #2
0
int acl_write_buf(ACL_SOCKET fd, const char *buf, int len, int timeout)
{
	int     count;

	while (len > 0) {
		if (timeout > 0 && acl_write_wait(fd, timeout) < 0)
			return -1;
		count = acl_socket_write(fd, buf, len, 0, NULL, NULL);
		if (count < 0) {
			if (acl_last_error() == ACL_EAGAIN && timeout > 0)
				continue;
			return -1;
		}
		if (count == 0)
			acl_msg_fatal("write returned 0");
		buf += count;
		len -= count;
	}
	return len;
}
Exemple #3
0
static int vstream_client(void)
{
	const char *myname = "vstream_client";
	ACL_VSTREAM *client;
	char  ebuf[256], buf[4096];
	int   n, dlen = 0;

	printf("addr: %s, timeout: %d\n", addr, timeout);
	client = acl_vstream_connect(addr, ACL_NON_BLOCKING, timeout, timeout, 1024);
	if (client == NULL) {
		printf("%s(%d): connect addr %s error(%s)\n",
			myname, __LINE__, addr, acl_last_strerror(ebuf, sizeof(ebuf)));
		return (-1);
	}

	printf("%s: connect %s ok\r\n", myname, addr);
	acl_non_blocking(ACL_VSTREAM_SOCK(client), ACL_BLOCKING);

	n = acl_write_wait(ACL_VSTREAM_SOCK(client), 10);
	if (n < 0) {
		printf("connect timeout: %s\n", acl_last_serror());
		goto END;
	}
	acl_vstream_fprintf(client, "hello world\n");
	while (1) {
		n = acl_vstream_read(client, buf, sizeof(buf));
		if (n == ACL_VSTREAM_EOF) {
			printf("read over: %s\n", acl_last_serror());
			break;
		}
		dlen += n;
		buf[n] = 0;
		printf("read reply: %s\n", buf);
	}

END:
	acl_vstream_close(client);
	printf("%s: read %d\n", myname, dlen);
	return (0);
}
Exemple #4
0
static int network_biopair_interop(ACL_SOCKET fd, int timeout, BIO *network_bio)
{
    const char *myname = "network_biopair_interop";
    int     want_write;
    int     num_write;
    int     write_pos;
    int     from_bio;
    int     want_read;
    int     num_read;
    int     to_bio;
    char    buffer[NETLAYER_BUFFERSIZE];

    /*
     * To avoid deadlock, write all pending data to the network before
     * attempting to read from the network.
     */
    while ((want_write = (int) BIO_ctrl_pending(network_bio)) > 0) {
	if (want_write > (int) sizeof(buffer))
	    want_write = (int) sizeof(buffer);
	from_bio = BIO_read(network_bio, buffer, want_write);

	/*
	 * Write the complete buffer contents to the network.
	 */
	for (write_pos = 0; write_pos < from_bio; /* see below */ ) {
	    if (timeout > 0 && acl_write_wait(fd, timeout) < 0)
		return (-1);
	    num_write = acl_socket_write(fd, buffer + write_pos, from_bio - write_pos, 0, 0, 0);
	    if (num_write <= 0) {
		if ((num_write < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) {
		    acl_msg_warn("%s: write() returns EAGAIN on a writable file descriptor!", myname);
		    acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname);
		    sleep(1);
		} else {
		    acl_msg_warn("%s: error writing %d bytes to the network: %s",
			    myname, from_bio - write_pos, acl_last_serror());
		    return (-1);
		}
	    } else {
		write_pos += num_write;
	    }
	}
    }

    /*
     * Read data from the network into the BIO pair.
     */
    while ((want_read = (int) BIO_ctrl_get_read_request(network_bio)) > 0) {
	if (want_read > (int) sizeof(buffer))
	    want_read = (int) sizeof(buffer);
	if (timeout > 0 && acl_read_wait(fd, timeout) < 0)
	    return (-1);
	num_read = acl_socket_read(fd, buffer, want_read, 0, 0, 0);
	if (num_read == 0)
	    /* FIX 200412 Cannot return a zero read count. */
	    return (-1);
	if (num_read < 0) {
	    if ((num_read < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) {
		acl_msg_warn("%s: read() returns EAGAIN on a readable file descriptor!", myname);
		acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname);
		sleep(1);
	    } else {
		acl_msg_warn("%s: error reading %d bytes from the network: %s",
			myname, want_read, acl_last_serror());
		return (-1);
	    }
	} else {
	    to_bio = BIO_write(network_bio, buffer, num_read);
	    if (to_bio != num_read)
		acl_msg_panic("%s: BIO_write error: to_bio != num_read", myname);
	}
    }
    return (0);
}