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); }
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; }
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); }
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); }