summaryrefslogtreecommitdiffstats
path: root/src/net.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/net.c500
1 files changed, 29 insertions, 471 deletions
diff --git a/src/net.c b/src/net.c
index 9c4a8e2..6bfe1fa 100644
--- a/src/net.c
+++ b/src/net.c
@@ -23,25 +23,28 @@
#include "log.h"
#include "opt.h"
-#include "os.h"
-#include "strerror.h"
#include <errno.h>
#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <errno.h>
#include <poll.h>
-#include <openssl/err.h>
#include <netdb.h>
#include <arpa/inet.h>
-#define TCP_RECV_BUF_SIZE (16 * 1024)
-#define TCP_SEND_BUF_SIZE (4 * 1024)
+enum perf_net_mode perf_net_parsemode(const char* mode)
+{
+ if (!strcmp(mode, "udp")) {
+ return sock_udp;
+ } else if (!strcmp(mode, "tcp")) {
+ return sock_tcp;
+ } else if (!strcmp(mode, "tls") || !strcmp(mode, "dot")) {
+ return sock_dot;
+ }
-static SSL_CTX* ssl_ctx = 0;
+ perf_log_warning("invalid socket mode");
+ perf_opt_usage();
+ exit(1);
+}
int perf_net_parsefamily(const char* family)
{
@@ -49,10 +52,8 @@ int perf_net_parsefamily(const char* family)
return AF_UNSPEC;
else if (strcmp(family, "inet") == 0)
return AF_INET;
-#ifdef AF_INET6
else if (strcmp(family, "inet6") == 0)
return AF_INET6;
-#endif
else {
fprintf(stderr, "invalid family %s\n", family);
perf_opt_usage();
@@ -82,9 +83,9 @@ in_port_t perf_sockaddr_port(const perf_sockaddr_t* sockaddr)
{
switch (sockaddr->sa.sa.sa_family) {
case AF_INET:
- return sockaddr->sa.sin.sin_port;
+ return ntohs(sockaddr->sa.sin.sin_port);
case AF_INET6:
- return sockaddr->sa.sin6.sin6_port;
+ return ntohs(sockaddr->sa.sin6.sin6_port);
default:
break;
}
@@ -95,10 +96,10 @@ void perf_sockaddr_setport(perf_sockaddr_t* sockaddr, in_port_t port)
{
switch (sockaddr->sa.sa.sa_family) {
case AF_INET:
- sockaddr->sa.sin.sin_port = port;
+ sockaddr->sa.sin.sin_port = htons(port);
break;
case AF_INET6:
- sockaddr->sa.sin6.sin6_port = port;
+ sockaddr->sa.sin6.sin6_port = htons(port);
break;
default:
break;
@@ -188,76 +189,15 @@ void perf_net_parselocal(int family, const char* name, unsigned int port,
exit(1);
}
-struct perf_net_socket perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, int bufsize)
+struct perf_net_socket* perf_net_opensocket(enum perf_net_mode mode, const perf_sockaddr_t* server, const perf_sockaddr_t* local, unsigned int offset, size_t bufsize)
{
- int family;
- perf_sockaddr_t tmp;
- int port;
- int ret;
- int flags;
- struct perf_net_socket sock = { .mode = mode, .is_ready = 1 };
-
- family = server->sa.sa.sa_family;
+ int port;
+ perf_sockaddr_t tmp;
- if (local->sa.sa.sa_family != family) {
+ if (server->sa.sa.sa_family != local->sa.sa.sa_family) {
perf_log_fatal("server and local addresses have different families");
}
- switch (mode) {
- case sock_udp:
- sock.fd = socket(family, SOCK_DGRAM, 0);
- break;
- case sock_tls:
- if (pthread_mutex_init(&sock.lock, 0)) {
- perf_log_fatal("pthread_mutex_init() failed");
- }
- if ((sock.fd = socket(family, SOCK_STREAM, 0)) < 0) {
- char __s[256];
- perf_log_fatal("socket: %s", perf_strerror_r(errno, __s, sizeof(__s)));
- }
- if (!ssl_ctx) {
-#ifdef HAVE_TLS_METHOD
- if (!(ssl_ctx = SSL_CTX_new(TLS_method()))) {
- perf_log_fatal("SSL_CTX_new(): %s", ERR_error_string(ERR_get_error(), 0));
- }
- if (!SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_2_VERSION)) {
- perf_log_fatal("SSL_CTX_set_min_proto_version(TLS1_2_VERSION): %s", ERR_error_string(ERR_get_error(), 0));
- }
-#else
- if (!(ssl_ctx = SSL_CTX_new(SSLv23_client_method()))) {
- perf_log_fatal("SSL_CTX_new(): %s", ERR_error_string(ERR_get_error(), 0));
- }
-#endif
- }
- if (!(sock.ssl = SSL_new(ssl_ctx))) {
- perf_log_fatal("SSL_new(): %s", ERR_error_string(ERR_get_error(), 0));
- }
- if (!(ret = SSL_set_fd(sock.ssl, sock.fd))) {
- perf_log_fatal("SSL_set_fd(): %s", ERR_error_string(SSL_get_error(sock.ssl, ret), 0));
- }
- break;
- case sock_tcp:
- sock.fd = socket(family, SOCK_STREAM, 0);
- break;
- default:
- perf_log_fatal("perf_net_opensocket(): invalid mode");
- }
-
- if (sock.fd == -1) {
- char __s[256];
- perf_log_fatal("socket: %s", perf_strerror_r(errno, __s, sizeof(__s)));
- }
-
-#if defined(AF_INET6) && defined(IPV6_V6ONLY)
- if (family == AF_INET6) {
- int on = 1;
-
- if (setsockopt(sock.fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) {
- perf_log_warning("setsockopt(IPV6_V6ONLY) failed");
- }
- }
-#endif
-
tmp = *local;
port = perf_sockaddr_port(&tmp);
if (port != 0 && offset != 0) {
@@ -267,398 +207,16 @@ struct perf_net_socket perf_net_opensocket(enum perf_net_mode mode, const perf_s
perf_sockaddr_setport(&tmp, port);
}
- if (bind(sock.fd, &tmp.sa.sa, tmp.length) == -1) {
- char __s[256];
- perf_log_fatal("bind: %s", perf_strerror_r(errno, __s, sizeof(__s)));
- }
-
- if (bufsize > 0) {
- bufsize *= 1024;
-
- ret = setsockopt(sock.fd, SOL_SOCKET, SO_RCVBUF,
- &bufsize, sizeof(bufsize));
- if (ret < 0)
- perf_log_warning("setsockbuf(SO_RCVBUF) failed");
-
- ret = setsockopt(sock.fd, SOL_SOCKET, SO_SNDBUF,
- &bufsize, sizeof(bufsize));
- if (ret < 0)
- perf_log_warning("setsockbuf(SO_SNDBUF) failed");
- }
-
- flags = fcntl(sock.fd, F_GETFL, 0);
- if (flags < 0)
- perf_log_fatal("fcntl(F_GETFL)");
- ret = fcntl(sock.fd, F_SETFL, flags | O_NONBLOCK);
- if (ret < 0)
- perf_log_fatal("fcntl(F_SETFL)");
-
- if (mode == sock_tcp || mode == sock_tls) {
- if (connect(sock.fd, &server->sa.sa, server->length)) {
- if (errno == EINPROGRESS) {
- sock.is_ready = 0;
- } else {
- char __s[256];
- perf_log_fatal("connect() failed: %s", perf_strerror_r(errno, __s, sizeof(__s)));
- }
- }
- sock.recvbuf = malloc(TCP_RECV_BUF_SIZE);
- sock.at = 0;
- sock.have_more = 0;
- sock.sendbuf = malloc(TCP_SEND_BUF_SIZE);
- if (!sock.recvbuf || !sock.sendbuf) {
- perf_log_fatal("perf_net_opensocket() failed: unable to allocate buffers");
- }
- }
-
- return sock;
-}
-
-ssize_t perf_net_recv(struct perf_net_socket* sock, void* buf, size_t len, int flags)
-{
- switch (sock->mode) {
- case sock_tls: {
- ssize_t n;
- uint16_t dnslen, dnslen2;
-
- if (!sock->have_more) {
- if (pthread_mutex_lock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_lock() failed");
- }
- if (!sock->is_ready) {
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- errno = EAGAIN;
- return -1;
- }
-
- n = SSL_read(sock->ssl, sock->recvbuf + sock->at, TCP_RECV_BUF_SIZE - sock->at);
- if (n < 0) {
- int err = SSL_get_error(sock->ssl, n);
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- if (err == SSL_ERROR_WANT_READ) {
- errno = EAGAIN;
- } else {
- errno = EBADF;
- }
- return -1;
- }
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
-
- sock->at += n;
- if (sock->at < 3) {
- errno = EAGAIN;
- return -1;
- }
- }
-
- memcpy(&dnslen, sock->recvbuf, 2);
- dnslen = ntohs(dnslen);
- if (sock->at < dnslen + 2) {
- errno = EAGAIN;
- return -1;
- }
- memcpy(buf, sock->recvbuf + 2, len < dnslen ? len : dnslen);
- memmove(sock->recvbuf, sock->recvbuf + 2 + dnslen, sock->at - 2 - dnslen);
- sock->at -= 2 + dnslen;
-
- if (sock->at > 2) {
- memcpy(&dnslen2, sock->recvbuf, 2);
- dnslen2 = ntohs(dnslen2);
- if (sock->at >= dnslen2 + 2) {
- sock->have_more = 1;
- return dnslen;
- }
- }
-
- sock->have_more = 0;
- return dnslen;
- }
- case sock_tcp: {
- ssize_t n;
- uint16_t dnslen, dnslen2;
-
- if (!sock->have_more) {
- n = recv(sock->fd, sock->recvbuf + sock->at, TCP_RECV_BUF_SIZE - sock->at, flags);
- if (n < 0) {
- if (errno == ECONNRESET) {
- // Treat connection reset like try again until reconnection features are in
- errno = EAGAIN;
- }
- return n;
- }
- sock->at += n;
- if (sock->at < 3) {
- errno = EAGAIN;
- return -1;
- }
- }
-
- memcpy(&dnslen, sock->recvbuf, 2);
- dnslen = ntohs(dnslen);
- if (sock->at < dnslen + 2) {
- errno = EAGAIN;
- return -1;
- }
- memcpy(buf, sock->recvbuf + 2, len < dnslen ? len : dnslen);
- memmove(sock->recvbuf, sock->recvbuf + 2 + dnslen, sock->at - 2 - dnslen);
- sock->at -= 2 + dnslen;
-
- if (sock->at > 2) {
- memcpy(&dnslen2, sock->recvbuf, 2);
- dnslen2 = ntohs(dnslen2);
- if (sock->at >= dnslen2 + 2) {
- sock->have_more = 1;
- return dnslen;
- }
- }
-
- sock->have_more = 0;
- return dnslen;
- }
- default:
- break;
- }
-
- return recv(sock->fd, buf, len, flags);
-}
-
-ssize_t perf_net_sendto(struct perf_net_socket* sock, const void* buf, size_t len, int flags,
- const struct sockaddr* dest_addr, socklen_t addrlen)
-{
- switch (sock->mode) {
- case sock_tls: {
- size_t send = len < TCP_SEND_BUF_SIZE - 2 ? len : (TCP_SEND_BUF_SIZE - 2);
- // TODO: We only send what we can send, because we can't continue sending
- uint16_t dnslen = htons(send);
- ssize_t n;
-
- memcpy(sock->sendbuf, &dnslen, 2);
- memcpy(sock->sendbuf + 2, buf, send);
- if (pthread_mutex_lock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_lock() failed");
- }
- n = SSL_write(sock->ssl, sock->sendbuf, send + 2);
- if (n < 0) {
- perf_log_warning("SSL_write(): %s", ERR_error_string(SSL_get_error(sock->ssl, n), 0));
- errno = EBADF;
- }
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
-
- if (n > 0 && n < send + 2) {
- sock->sending = n;
- sock->flags = flags;
- memcpy(&sock->dest_addr, dest_addr, addrlen);
- sock->addrlen = addrlen;
- sock->is_ready = 0;
- errno = EINPROGRESS;
- return -1;
- }
-
- return n > 0 ? n - 2 : n;
- }
- case sock_tcp: {
- size_t send = len < TCP_SEND_BUF_SIZE - 2 ? len : (TCP_SEND_BUF_SIZE - 2);
- // TODO: We only send what we can send, because we can't continue sending
- uint16_t dnslen = htons(send);
- ssize_t n;
-
- memcpy(sock->sendbuf, &dnslen, 2);
- memcpy(sock->sendbuf + 2, buf, send);
- n = sendto(sock->fd, sock->sendbuf, send + 2, flags, dest_addr, addrlen);
-
- if (n > 0 && n < send + 2) {
- sock->sending = n;
- sock->flags = flags;
- memcpy(&sock->dest_addr, dest_addr, addrlen);
- sock->addrlen = addrlen;
- sock->is_ready = 0;
- errno = EINPROGRESS;
- return -1;
- }
-
- return n > 0 ? n - 2 : n;
- }
- default:
- break;
- }
- return sendto(sock->fd, buf, len, flags, dest_addr, addrlen);
-}
-
-int perf_net_close(struct perf_net_socket* sock)
-{
- return close(sock->fd);
-}
-
-int perf_net_sockeq(struct perf_net_socket* sock_a, struct perf_net_socket* sock_b)
-{
- return sock_a->fd == sock_b->fd;
-}
-
-enum perf_net_mode perf_net_parsemode(const char* mode)
-{
- if (!strcmp(mode, "udp")) {
- return sock_udp;
- } else if (!strcmp(mode, "tcp")) {
- return sock_tcp;
- } else if (!strcmp(mode, "tls") || !strcmp(mode, "dot")) {
- return sock_tls;
- }
-
- perf_log_warning("invalid socket mode");
- perf_opt_usage();
- exit(1);
-}
-
-int perf_net_sockready(struct perf_net_socket* sock, int pipe_fd, int64_t timeout)
-{
- if (sock->is_ready) {
- return 1;
- }
-
- switch (sock->mode) {
- case sock_tls: {
- int ret;
-
- if (sock->sending) {
- uint16_t dnslen;
- ssize_t n;
-
- memcpy(&dnslen, sock->sendbuf, 2);
- dnslen = ntohs(dnslen);
- if (pthread_mutex_lock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_lock() failed");
- }
- n = SSL_write(sock->ssl, sock->sendbuf + sock->sending, dnslen + 2 - sock->sending);
- if (n < 1) {
- if (n < 0) {
- perf_log_warning("SSL_write(): %s", ERR_error_string(SSL_get_error(sock->ssl, n), 0));
- errno = EBADF;
- }
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- return -1;
- }
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- sock->sending += n;
- if (sock->sending < dnslen + 2) {
- errno = EINPROGRESS;
- return -1;
- }
- sock->sending = 0;
- sock->is_ready = 1;
- return 1;
- }
-
- if (!sock->is_ssl_ready) {
- switch (perf_os_waituntilanywritable(sock, 1, pipe_fd, timeout)) {
- case PERF_R_TIMEDOUT:
- return -1;
- case PERF_R_SUCCESS: {
- int error = 0;
- socklen_t len = (socklen_t)sizeof(error);
-
- getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
- if (error != 0) {
- if (error == EINPROGRESS
-#if EWOULDBLOCK != EAGAIN
- || error == EWOULDBLOCK
-#endif
- || error == EAGAIN) {
- return 0;
- }
- return -1;
- }
- }
- }
- sock->is_ssl_ready = 1;
- }
-
- if (pthread_mutex_lock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_lock() failed");
- }
- ret = SSL_connect(sock->ssl);
- if (!ret) {
- perf_log_warning("SSL_connect(): %s", ERR_error_string(SSL_get_error(sock->ssl, ret), 0));
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- return -1;
- }
- if (ret < 0) {
- int err = SSL_get_error(sock->ssl, ret);
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
- return 0;
- }
- perf_log_warning("SSL_connect(): %s", ERR_error_string(err, 0));
- return -1;
- }
- sock->is_ready = 1;
- if (pthread_mutex_unlock(&sock->lock)) {
- perf_log_fatal("pthread_mutex_unlock() failed");
- }
- return 1;
- }
+ switch (mode) {
+ case sock_udp:
+ return perf_net_udp_opensocket(server, &tmp, bufsize);
case sock_tcp:
- if (sock->sending) {
- uint16_t dnslen;
- ssize_t n;
-
- memcpy(&dnslen, sock->sendbuf, 2);
- dnslen = ntohs(dnslen);
- n = sendto(sock->fd, sock->sendbuf + sock->sending, dnslen + 2 - sock->sending, sock->flags, (struct sockaddr*)&sock->dest_addr, sock->addrlen);
- if (n < 1) {
- return -1;
- }
- sock->sending += n;
- if (sock->sending < dnslen + 2) {
- errno = EINPROGRESS;
- return -1;
- }
- sock->sending = 0;
- sock->is_ready = 1;
- return 1;
- }
-
- switch (perf_os_waituntilanywritable(sock, 1, pipe_fd, timeout)) {
- case PERF_R_TIMEDOUT:
- return -1;
- case PERF_R_SUCCESS: {
- int error = 0;
- socklen_t len = (socklen_t)sizeof(error);
-
- getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
- if (error != 0) {
- if (error == EINPROGRESS
-#if EWOULDBLOCK != EAGAIN
- || error == EWOULDBLOCK
-#endif
- || error == EAGAIN) {
- return 0;
- }
- return -1;
- }
- sock->is_ready = 1;
- return 1;
- }
- }
- break;
+ return perf_net_tcp_opensocket(server, &tmp, bufsize);
+ case sock_dot:
+ return perf_net_dot_opensocket(server, &tmp, bufsize);
default:
- break;
+ perf_log_fatal("perf_net_opensocket(): invalid mode");
}
- return -1;
+ return 0;
}