static int amqp_openssl_bio_should_retry(int res) { if (res == -1) { int err = amqp_os_socket_error(); if ( #ifdef EWOULDBLOCK err == EWOULDBLOCK || #endif #ifdef WSAEWOULDBLOCK err == WSAEWOULDBLOCK || #endif #ifdef ENOTCONN err == ENOTCONN || #endif #ifdef EINTR err == EINTR || #endif #ifdef EAGAIN err == EAGAIN || #endif #ifdef EPROTO err == EPROTO || #endif #ifdef EINPROGRESS err == EINPROGRESS || #endif #ifdef EALREADY err == EALREADY || #endif 0) { return 1; } } return 0; }
static ssize_t amqp_tcp_socket_send(void *base, const void *buf, size_t len) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t res; int flags = 0; if (-1 == self->sockfd) { return AMQP_STATUS_SOCKET_CLOSED; } #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; #endif start: #ifdef _WIN32 res = send(self->sockfd, buf, (int)len, flags); #else res = send(self->sockfd, buf, len, flags); #endif if (res < 0) { self->internal_error = amqp_os_socket_error(); switch (self->internal_error) { case EINTR: goto start; case EWOULDBLOCK: #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK case EAGAIN: #endif res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE; break; default: res = AMQP_STATUS_SOCKET_ERROR; } } else { self->internal_error = 0; } return res; }
static ssize_t amqp_tcp_socket_recv(void *base, void *buf, size_t len, int flags) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t ret; if (-1 == self->sockfd) { return AMQP_STATUS_SOCKET_CLOSED; } start: #ifdef _WIN32 ret = recv(self->sockfd, buf, (int)len, flags); #else ret = recv(self->sockfd, buf, len, flags); #endif if (0 > ret) { self->internal_error = amqp_os_socket_error(); switch (self->internal_error) { case EINTR: goto start; #ifdef _WIN32 case WSAEWOULDBLOCK: #else case EWOULDBLOCK: #endif #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK case EAGAIN: #endif ret = AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD; break; default: ret = AMQP_STATUS_SOCKET_ERROR; } } else if (0 == ret) { ret = AMQP_STATUS_CONNECTION_CLOSED; } return ret; }
static ssize_t amqp_tcp_socket_recv(void *base, void *buf, size_t len, int flags) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t ret; start: ret = recv(self->sockfd, buf, len, flags); if (0 > ret) { self->internal_error = amqp_os_socket_error(); if (EINTR == self->internal_error) { goto start; } else { ret = AMQP_STATUS_SOCKET_ERROR; } } else if (0 == ret) { ret = AMQP_STATUS_CONNECTION_CLOSED; } return ret; }
static ssize_t amqp_tcp_socket_send_inner(void *base, const void *buf, size_t len, int flags) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t res; const char *buf_left = buf; ssize_t len_left = len; #ifdef MSG_NOSIGNAL flags |= MSG_NOSIGNAL; #endif start: RABBIT_INFO("Calling send on: %d", self->sockfd); res = send(self->sockfd, buf_left, len_left, flags); if (res < 0) { self->internal_error = amqp_os_socket_error(); if (EINTR == self->internal_error) { goto start; } else { res = AMQP_STATUS_SOCKET_ERROR; } } else { if (res == len_left) { self->internal_error = 0; res = AMQP_STATUS_OK; } else { buf_left += res; len_left -= res; goto start; } } return res; }
static ssize_t amqp_tcp_socket_writev(void *base, struct iovec *iov, int iovcnt) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t ret; #if defined(_WIN32) DWORD res; /* Making the assumption here that WSAsend won't do a partial send * unless an error occured, in which case we're hosed so it doesn't matter */ if (WSASend(self->sockfd, (LPWSABUF)iov, iovcnt, &res, 0, NULL, NULL) == 0) { self->internal_error = 0; ret = AMQP_STATUS_OK; } else { self->internal_error = WSAGetLastError(); ret = AMQP_STATUS_SOCKET_ERROR; } return ret; #elif defined(MSG_MORE) int i; for (i = 0; i < iovcnt - 1; ++i) { ret = amqp_tcp_socket_send_inner(self, iov[i].iov_base, iov[i].iov_len, MSG_MORE); if (ret != AMQP_STATUS_OK) { goto exit; } } ret = amqp_tcp_socket_send_inner(self, iov[i].iov_base, iov[i].iov_len, 0); exit: return ret; #elif defined(SO_NOSIGPIPE) || !defined(MSG_NOSIGNAL) int i; ssize_t len_left = 0; struct iovec *iov_left = iov; int iovcnt_left = iovcnt; for (i = 0; i < iovcnt; ++i) { len_left += iov[i].iov_len; } start: ret = writev(self->sockfd, iov_left, iovcnt_left); if (ret < 0) { self->internal_error = amqp_os_socket_error(); if (EINTR == self->internal_error) { goto start; } else { self->internal_error = amqp_os_socket_error(); ret = AMQP_STATUS_SOCKET_ERROR; } } else { if (ret == len_left) { self->internal_error = 0; ret = AMQP_STATUS_OK; } else { len_left -= ret; for (i = 0; i < iovcnt_left; ++i) { if (ret < (ssize_t)iov_left[i].iov_len) { iov_left[i].iov_base = ((char*)iov_left[i].iov_base) + ret; iov_left[i].iov_len -= ret; iovcnt_left -= i; iov_left += i; break; } else { ret -= iov_left[i].iov_len; } } goto start; } } return ret; #else int i; size_t bytes = 0; void *bufferp; for (i = 0; i < iovcnt; ++i) { bytes += iov[i].iov_len; } if (self->buffer_length < bytes) { self->buffer = realloc(self->buffer, bytes); if (NULL == self->buffer) { self->buffer_length = 0; self->internal_error = 0; ret = AMQP_STATUS_NO_MEMORY; goto exit; } self->buffer_length = bytes; } bufferp = self->buffer; for (i = 0; i < iovcnt; ++i) { memcpy(bufferp, iov[i].iov_base, iov[i].iov_len); bufferp += iov[i].iov_len; } ret = amqp_tcp_socket_send_inner(self, self->buffer, bytes, 0); exit: return ret; #endif }
static ssize_t amqp_tcp_socket_send(void *base, const void *buf, size_t len, int flags) { struct amqp_tcp_socket_t *self = (struct amqp_tcp_socket_t *)base; ssize_t res; int flagz = 0; if (-1 == self->sockfd) { return AMQP_STATUS_SOCKET_CLOSED; } #ifdef MSG_NOSIGNAL flagz |= MSG_NOSIGNAL; #endif #if defined(MSG_MORE) if (flags & AMQP_SF_MORE) { flagz |= MSG_MORE; } #elif defined(TCP_NOPUSH) if (flags & AMQP_SF_MORE && !(self->state & AMQP_SF_MORE)) { int one = 1; res = setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &one, sizeof(one)); if (0 != res) { self->internal_error = res; return AMQP_STATUS_SOCKET_ERROR; } self->state |= AMQP_SF_MORE; } else if (!(flags & AMQP_SF_MORE) && self->state & AMQP_SF_MORE) { int zero = 0; res = setsockopt(self->sockfd, IPPROTO_TCP, TCP_NOPUSH, &zero, sizeof(&zero)); if (0 != res) { self->internal_error = res; res = AMQP_STATUS_SOCKET_ERROR; } else { self->state &= ~AMQP_SF_MORE; } } #endif start: #ifdef _WIN32 res = send(self->sockfd, buf, (int)len, flagz); #else res = send(self->sockfd, buf, len, flagz); #endif if (res < 0) { self->internal_error = amqp_os_socket_error(); switch (self->internal_error) { case EINTR: goto start; #ifdef _WIN32 case WSAEWOULDBLOCK: #else case EWOULDBLOCK: #endif #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK case EAGAIN: #endif res = AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE; break; default: res = AMQP_STATUS_SOCKET_ERROR; } } else { self->internal_error = 0; } return res; }
static int amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout) { struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; long result; int status; ERR_clear_error(); self->ssl = SSL_new(self->ctx); if (!self->ssl) { self->internal_error = ERR_peek_error(); status = AMQP_STATUS_SSL_ERROR; goto exit; } SSL_set_mode(self->ssl, SSL_MODE_AUTO_RETRY); self->sockfd = amqp_open_socket_noblock(host, port, timeout); if (0 > self->sockfd) { status = self->sockfd; self->internal_error = amqp_os_socket_error(); self->sockfd = -1; goto error_out1; } status = SSL_set_fd(self->ssl, self->sockfd); if (!status) { self->internal_error = SSL_get_error(self->ssl, status); status = AMQP_STATUS_SSL_ERROR; goto error_out2; } status = SSL_connect(self->ssl); if (!status) { self->internal_error = SSL_get_error(self->ssl, status); status = AMQP_STATUS_SSL_CONNECTION_FAILED; goto error_out2; } result = SSL_get_verify_result(self->ssl); if (X509_V_OK != result) { self->internal_error = result; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out3; } if (self->verify) { int status = amqp_ssl_socket_verify_hostname(self, host); if (status) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out3; } } self->internal_error = 0; status = AMQP_STATUS_OK; exit: return status; error_out3: SSL_shutdown(self->ssl); error_out2: amqp_os_socket_close(self->sockfd); self->sockfd = -1; error_out1: SSL_free(self->ssl); self->ssl = NULL; goto exit; }
static int amqp_ssl_socket_open(void *base, const char *host, int port, struct timeval *timeout) { struct amqp_ssl_socket_t *self = (struct amqp_ssl_socket_t *)base; long result; int status; amqp_time_t deadline; X509 *cert; BIO *bio; if (-1 != self->sockfd) { return AMQP_STATUS_SOCKET_INUSE; } ERR_clear_error(); self->ssl = SSL_new(self->ctx); if (!self->ssl) { self->internal_error = ERR_peek_error(); status = AMQP_STATUS_SSL_ERROR; goto exit; } status = amqp_time_from_now(&deadline, timeout); if (AMQP_STATUS_OK != status) { return status; } self->sockfd = amqp_open_socket_inner(host, port, deadline); if (0 > self->sockfd) { status = self->sockfd; self->internal_error = amqp_os_socket_error(); self->sockfd = -1; goto error_out1; } bio = BIO_new(amqp_openssl_bio()); if (!bio) { status = AMQP_STATUS_NO_MEMORY; goto error_out2; } BIO_set_fd(bio, self->sockfd, BIO_NOCLOSE); SSL_set_bio(self->ssl, bio, bio); start_connect: status = SSL_connect(self->ssl); if (status != 1) { self->internal_error = SSL_get_error(self->ssl, status); switch (self->internal_error) { case SSL_ERROR_WANT_READ: status = amqp_poll(self->sockfd, AMQP_SF_POLLIN, deadline); break; case SSL_ERROR_WANT_WRITE: status = amqp_poll(self->sockfd, AMQP_SF_POLLOUT, deadline); break; default: status = AMQP_STATUS_SSL_CONNECTION_FAILED; } if (AMQP_STATUS_OK == status) { goto start_connect; } goto error_out2; } cert = SSL_get_peer_certificate(self->ssl); if (self->verify_peer) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out3; } result = SSL_get_verify_result(self->ssl); if (X509_V_OK != result) { self->internal_error = result; status = AMQP_STATUS_SSL_PEER_VERIFY_FAILED; goto error_out4; } } if (self->verify_hostname) { if (!cert) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out3; } if (AMQP_HVR_MATCH_FOUND != amqp_ssl_validate_hostname(host, cert)) { self->internal_error = 0; status = AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED; goto error_out4; } } X509_free(cert); self->internal_error = 0; status = AMQP_STATUS_OK; exit: return status; error_out4: X509_free(cert); error_out3: SSL_shutdown(self->ssl); error_out2: amqp_os_socket_close(self->sockfd); self->sockfd = -1; error_out1: SSL_free(self->ssl); self->ssl = NULL; goto exit; }