diff options
author | Test_User <hax@andrewyu.org> | 2024-06-19 03:41:14 -0400 |
---|---|---|
committer | Test_User <hax@andrewyu.org> | 2024-06-19 03:41:14 -0400 |
commit | 991d1d37474726ae5dc910da9705485f7b193e18 (patch) | |
tree | e6d01a7a65dd8f916f400f1b083909c58a304d71 | |
parent | 9c16070679fea6ac5625546d4ba5af0f638e6636 (diff) | |
download | haxircd-991d1d37474726ae5dc910da9705485f7b193e18.tar.gz haxircd-991d1d37474726ae5dc910da9705485f7b193e18.zip |
Some improvements and openssl send buffering
-rw-r--r-- | Makefile | 78 | ||||
-rw-r--r-- | config.h | 14 | ||||
-rw-r--r-- | general_network.c | 48 | ||||
-rw-r--r-- | general_network.h | 8 | ||||
-rw-r--r-- | networks/gnutls_buffered.c | 436 | ||||
-rw-r--r-- | networks/gnutls_buffered.h | 45 | ||||
-rw-r--r-- | networks/openssl_buffered.c | 600 | ||||
-rw-r--r-- | networks/openssl_buffered.h | 45 | ||||
-rw-r--r-- | networks/plaintext_buffered.c | 27 | ||||
-rw-r--r-- | protocols/inspircd2.c | 37 | ||||
-rw-r--r-- | real_main.c | 24 | ||||
-rw-r--r-- | server_network.c | 16 |
12 files changed, 1347 insertions, 31 deletions
@@ -41,6 +41,10 @@ LDFLAGS = -lpthread printf '%s\n' 'LAST_OPENSSL_SERVER = $(OPENSSL_SERVER)' >> .makeopts printf '%s\n' 'LAST_PLAINTEXT_BUFFERED_CLIENT = $(PLAINTEXT_BUFFERED_CLIENT)' >> .makeopts printf '%s\n' 'LAST_PLAINTEXT_BUFFERED_SERVER = $(PLAINTEXT_BUFFERED_SERVER)' >> .makeopts + printf '%s\n' 'LAST_GNUTLS_BUFFERED_CLIENT = $(GNUTLS_BUFFERED_CLIENT)' >> .makeopts + printf '%s\n' 'LAST_GNUTLS_BUFFERED_SERVER = $(GNUTLS_BUFFERED_SERVER)' >> .makeopts + printf '%s\n' 'LAST_OPENSSL_BUFFERED_CLIENT = $(OPENSSL_BUFFERED_CLIENT)' >> .makeopts + printf '%s\n' 'LAST_OPENSSL_BUFFERED_SERVER = $(OPENSSL_BUFFERED_SERVER)' >> .makeopts printf '%s\n' 'LAST_INSPIRCD2_PROTOCOL = $(INSPIRCD2_PROTOCOL)' >> .makeopts printf '%s\n' 'LAST_INSPIRCD3_PROTOCOL = $(INSPIRCD3_PROTOCOL)' >> .makeopts printf '%s\n' 'LAST_HAXSERV_PSEUDOCLIENT = $(HAXSERV_PSEUDOCLIENT)' >> .makeopts @@ -120,6 +124,38 @@ else PLAINTEXT_BUFFERED_SERVER := $(LAST_PLAINTEXT_BUFFERED_SERVER) endif +ifneq ($(GNUTLS_BUFFERED_CLIENT),) +ifneq ($(GNUTLS_BUFFERED_CLIENT),$(LAST_GNUTLS_BUFFERED_CLIENT)) +rebuild = 1 +endif +else +GNUTLS_BUFFERED_CLIENT := $(LAST_GNUTLS_BUFFERED_CLIENT) +endif + +ifneq ($(GNUTLS_BUFFERED_SERVER),) +ifneq ($(GNUTLS_BUFFERED_SERVER),$(LAST_GNUTLS_BUFFERED_SERVER)) +rebuild = 1 +endif +else +GNUTLS_BUFFERED_SERVER := $(LAST_GNUTLS_BUFFERED_SERVER) +endif + +ifneq ($(OPENSSL_BUFFERED_CLIENT),) +ifneq ($(OPENSSL_BUFFERED_CLIENT),$(LAST_OPENSSL_BUFFERED_CLIENT)) +rebuild = 1 +endif +else +OPENSSL_BUFFERED_CLIENT := $(LAST_OPENSSL_BUFFERED_CLIENT) +endif + +ifneq ($(OPENSSL_BUFFERED_SERVER),) +ifneq ($(OPENSSL_BUFFERED_SERVER),$(LAST_OPENSSL_BUFFERED_SERVER)) +rebuild = 1 +endif +else +OPENSSL_BUFFERED_SERVER := $(LAST_OPENSSL_BUFFERED_SERVER) +endif + ifneq ($(INSPIRCD2_PROTOCOL),) ifneq ($(INSPIRCD2_PROTOCOL),$(LAST_INSPIRCD2_PROTOCOL)) rebuild = 1 @@ -239,6 +275,30 @@ USE_SERVER = 1 USE_PLAINTEXT_BUFFERED = 1 endif +ifeq ($(GNUTLS_BUFFERED_CLIENT),1) +CFLAGS += -DUSE_GNUTLS_BUFFERED_CLIENT +USE_CLIENT = 1 +USE_GNUTLS_BUFFERED = 1 +endif + +ifeq ($(GNUTLS_BUFFERED_SERVER),1) +CFLAGS += -DUSE_GNUTLS_BUFFERED_SERVER +USE_SERVER = 1 +USE_GNUTLS_BUFFERED = 1 +endif + +ifeq ($(OPENSSL_BUFFERED_CLIENT),1) +CFLAGS += -DUSE_OPENSSL_BUFFERED_CLIENT +USE_CLIENT = 1 +USE_OPENSSL_BUFFERED = 1 +endif + +ifeq ($(OPENSSL_BUFFERED_SERVER),1) +CFLAGS += -DUSE_OPENSSL_BUFFERED_SERVER +USE_SERVER = 1 +USE_OPENSSL_BUFFERED = 1 +endif + ifeq ($(INSPIRCD2_PROTOCOL),1) @@ -298,6 +358,16 @@ OFILES += networks/plaintext_buffered.o CFLAGS += -DUSE_PLAINTEXT_BUFFERED endif +ifeq ($(USE_GNUTLS_BUFFERED),1) +OFILES += networks/gnutls_buffered.o +CFLAGS += -DUSE_GNUTLS_BUFFERED +endif + +ifeq ($(USE_OPENSSL_BUFFERED),1) +OFILES += networks/openssl_buffered.o +CFLAGS += -DUSE_OPENSSL_BUFFERED +endif + ifeq ($(USE_PROTOCOLS),1) @@ -378,6 +448,14 @@ ifeq ($(USE_PLAINTEXT_BUFFERED),1) $(call DEPS,networks/plaintext_buffered,o) endif +ifeq ($(USE_GNUTLS_BUFFERED),1) +$(call DEPS,networks/gnutls_buffered,o) +endif + +ifeq ($(USE_OPENSSL_BUFFERED),1) +$(call DEPS,networks/openssl_buffered,o) +endif + ifeq ($(USE_CLIENT),1) $(call DEPS,client_network,o) endif @@ -33,9 +33,9 @@ #include "general_network.h" #include "protocols.h" -// #define K 1024 -// #define M (1024 * K) -// #define G (1024 * M) +// #define K * 1024 +// #define M * (1024 K) +// #define G * (1024 M) #ifdef USE_SERVER struct server_config { @@ -84,6 +84,14 @@ extern char *OPENSSL_KEY_PATH; // = "/etc/keys/key.pem", or 0 extern size_t PLAINTEXT_BUFFERED_LEN; // = 1 M #endif +#ifdef USE_GNUTLS_BUFFERED +extern size_t GNUTLS_BUFFERED_LEN; // = 1 M +#endif + +#ifdef USE_OPENSSL_BUFFERED +extern size_t OPENSSL_BUFFERED_LEN; // = 1 M +#endif + #ifdef USE_SERVER extern unsigned short SERVER_PORTS[NUM_NET_TYPES][NUM_PROTOCOLS]; // = {7000, ...}; extern size_t SERVER_LISTEN[NUM_NET_TYPES][NUM_PROTOCOLS]; // = {16, ...}; diff --git a/general_network.c b/general_network.c index a400a5a..2cdbb43 100644 --- a/general_network.c +++ b/general_network.c @@ -52,6 +52,12 @@ #ifdef USE_PLAINTEXT_BUFFERED #include "networks/plaintext_buffered.h" #endif +#ifdef USE_GNUTLS_BUFFERED +#include "networks/gnutls_buffered.h" +#endif +#ifdef USE_OPENSSL_BUFFERED +#include "networks/openssl_buffered.h" +#endif #ifdef USE_PROTOCOLS #include "protocols.h" @@ -105,16 +111,6 @@ struct network networks[NUM_NET_TYPES] = { .close = plaintext_close, }, #endif -#ifdef USE_PLAINTEXT_BUFFERED - [NET_TYPE_PLAINTEXT_BUFFERED] = { - .send = plaintext_buffered_send, - .recv = plaintext_buffered_recv, - .connect = plaintext_buffered_connect, - .accept = plaintext_buffered_accept, - .shutdown = plaintext_buffered_shutdown, - .close = plaintext_buffered_close, - }, -#endif #ifdef USE_GNUTLS [NET_TYPE_GNUTLS] = { .send = gnutls_send, @@ -135,6 +131,36 @@ struct network networks[NUM_NET_TYPES] = { .close = openssl_close, }, #endif +#ifdef USE_PLAINTEXT_BUFFERED + [NET_TYPE_PLAINTEXT_BUFFERED] = { + .send = plaintext_buffered_send, + .recv = plaintext_buffered_recv, + .connect = plaintext_buffered_connect, + .accept = plaintext_buffered_accept, + .shutdown = plaintext_buffered_shutdown, + .close = plaintext_buffered_close, + }, +#endif +#ifdef USE_GNUTLS_BUFFERED + [NET_TYPE_GNUTLS_BUFFERED] = { + .send = gnutls_buffered_send, + .recv = gnutls_buffered_recv, + .connect = gnutls_buffered_connect, + .accept = gnutls_buffered_accept, + .shutdown = gnutls_buffered_shutdown, + .close = gnutls_buffered_close, + }, +#endif +#ifdef USE_OPENSSL_BUFFERED + [NET_TYPE_OPENSSL_BUFFERED] = { + .send = openssl_buffered_send, + .recv = openssl_buffered_recv, + .connect = openssl_buffered_connect, + .accept = openssl_buffered_accept, + .shutdown = openssl_buffered_shutdown, + .close = openssl_buffered_close, + }, +#endif }; struct table server_list = {0}; @@ -470,6 +496,7 @@ int set_channel(struct string from, struct string name, size_t timestamp, size_t return -1; channel->channel_ts = timestamp; + channel->channel_ts_str = (struct string){.data = malloc(0), .len = 0}; if (set_table_index(&channel_list, name, channel) != 0) goto set_channel_free_channel; @@ -504,6 +531,7 @@ int set_channel(struct string from, struct string name, size_t timestamp, size_t goto set_channel_free_ts_str; #endif + free(channel->channel_ts_str.data); channel->channel_ts_str = ts_str; channel->channel_ts = timestamp; diff --git a/general_network.h b/general_network.h index dd9b692..d75e4f6 100644 --- a/general_network.h +++ b/general_network.h @@ -160,8 +160,14 @@ extern char casemap[UCHAR_MAX+1]; #ifdef USE_PLAINTEXT_BUFFERED #define NET_TYPE_PLAINTEXT_BUFFERED 3 #endif +#ifdef USE_GNUTLS_BUFFERED +#define NET_TYPE_GNUTLS_BUFFERED 4 +#endif +#ifdef USE_OPENSSL_BUFFERED +#define NET_TYPE_OPENSSL_BUFFERED 5 +#endif -#define NUM_NET_TYPES 4 +#define NUM_NET_TYPES 6 #define MODE_TYPE_UNKNOWN 0 #define MODE_TYPE_NOARGS 1 diff --git a/networks/gnutls_buffered.c b/networks/gnutls_buffered.c new file mode 100644 index 0000000..28a50ca --- /dev/null +++ b/networks/gnutls_buffered.c @@ -0,0 +1,436 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <gnutls/gnutls.h> +#include <poll.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "../config.h" +#include "../general_network.h" +#include "../main.h" +#include "../mutex.h" +#include "gnutls_buffered.h" + +struct gnutls_buffered_handle { + gnutls_session_t session; + MUTEX_TYPE mutex; + int fd; + char valid; +}; + +gnutls_certificate_credentials_t gnutls_buffered_cert_creds; + +int init_gnutls_buffered_network(void) { + if (gnutls_global_init() < 0) + return 1; + + if (gnutls_certificate_allocate_credentials(&gnutls_buffered_cert_creds) != GNUTLS_E_SUCCESS) + return 2; + + if (GNUTLS_USE_SYSTEM_TRUST && (gnutls_certificate_set_x509_system_trust(gnutls_buffered_cert_creds) < 0)) + return 3; + + if (GNUTLS_KEY_PATH && GNUTLS_CERT_PATH && gnutls_certificate_set_x509_key_file(gnutls_buffered_cert_creds, GNUTLS_CERT_PATH, GNUTLS_KEY_PATH, GNUTLS_X509_FMT_PEM) < 0) + return 4; + + return 0; +} + +int gnutls_buffered_send(void *handle, struct string msg) { + if (msg.len == 0) + return 0; + + struct gnutls_buffered_handle *gnutls_handle = handle; + + mutex_lock(&(gnutls_handle->mutex)); + + if (!gnutls_handle->valid) + goto gnutls_send_error_unlock; + + struct pollfd pollfd = { + .fd = gnutls_handle->fd, + }; + do { + ssize_t gnutls_res; + int poll_res; + gnutls_res = gnutls_record_send(gnutls_handle->session, msg.data, msg.len); + if (gnutls_res <= 0) { + if (gnutls_res == GNUTLS_E_INTERRUPTED) { + continue; + } else if (gnutls_res == GNUTLS_E_AGAIN) { + pollfd.events = POLLIN | POLLOUT; + do { + poll_res = poll(&pollfd, 1, 0); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_send_error_unlock; + + if ((pollfd.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT)) + continue; + else if (pollfd.revents & (~(POLLIN | POLLOUT))) + goto gnutls_send_error_unlock; + else + pollfd.events = (pollfd.revents & (POLLIN | POLLOUT)) ^ (POLLIN | POLLOUT); + } else { + goto gnutls_send_error_unlock; + } + } else { + break; + } + + do { + poll_res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_send_error_unlock; + if (poll_res == 0) // Timed out + goto gnutls_send_error_unlock; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) + goto gnutls_send_error_unlock; + } while (1); + + mutex_unlock(&(gnutls_handle->mutex)); + return 0; + + gnutls_send_error_unlock: + if (gnutls_handle->valid) { + mutex_unlock(&(gnutls_handle->mutex)); + gnutls_buffered_shutdown(gnutls_handle); + } else { + mutex_unlock(&(gnutls_handle->mutex)); + } + return 1; +} + +size_t gnutls_buffered_recv(void *handle, char *data, size_t len, char *err) { + struct gnutls_buffered_handle *gnutls_handle = handle; + + struct pollfd pollfd = { + .fd = gnutls_handle->fd, + }; + ssize_t gnutls_res; + do { + int poll_res; + mutex_lock(&(gnutls_handle->mutex)); + if (!gnutls_handle->valid) { + mutex_unlock(&(gnutls_handle->mutex)); + *err = 3; + return 0; + } + do { + gnutls_res = gnutls_record_recv(gnutls_handle->session, data, len); + } while (gnutls_res == GNUTLS_E_INTERRUPTED); + mutex_unlock(&(gnutls_handle->mutex)); + if (gnutls_res < 0) { + if (gnutls_res == GNUTLS_E_AGAIN) { + pollfd.events = POLLIN | POLLOUT; + do { + poll_res = poll(&pollfd, 1, 0); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) { + *err = 3; + return 0; + } + + if ((pollfd.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT)) + continue; + else + pollfd.events = (pollfd.revents & (POLLIN | POLLOUT)) ^ (POLLIN | POLLOUT); + } else { + *err = 3; + return 0; + } + } else if (gnutls_res == 0) { + *err = 2; + return 0; + } else { + break; + } + + do { + poll_res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) { + *err = 3; + return 0; + } if (poll_res == 0) { // Timed out + *err = 1; + return 0; + } if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) { + *err = 3; + return 0; + } + } while (1); + + *err = 0; + + return (size_t)gnutls_res; +} + +int gnutls_buffered_connect(void **handle, struct string address, struct string port, struct string *addr_out) { + struct gnutls_buffered_handle *gnutls_handle; + gnutls_handle = malloc(sizeof(*gnutls_handle)); + if (!gnutls_handle) + return -1; + + *handle = gnutls_handle; + + int res = mutex_init(&(gnutls_handle->mutex)); + if (res != 0) + goto gnutls_connect_free_gnutls_handle; + + struct sockaddr sockaddr; + if (resolve(address, port, &sockaddr) != 0) + goto gnutls_connect_destroy_mutex; + + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + goto gnutls_connect_destroy_mutex; + + gnutls_handle->fd = fd; + gnutls_handle->valid = 1; + + do { + res = connect(fd, &sockaddr, sizeof(sockaddr)); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto gnutls_connect_close; + + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + goto gnutls_connect_close; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto gnutls_connect_close; + + if (gnutls_init(&(gnutls_handle->session), GNUTLS_CLIENT | GNUTLS_NONBLOCK) != GNUTLS_E_SUCCESS) + goto gnutls_connect_close; + + if (gnutls_server_name_set(gnutls_handle->session, GNUTLS_NAME_DNS, address.data, address.len) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + if (gnutls_credentials_set(gnutls_handle->session, GNUTLS_CRD_CERTIFICATE, gnutls_buffered_cert_creds) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + if (gnutls_set_default_priority(gnutls_handle->session) != GNUTLS_E_SUCCESS) + goto gnutls_connect_deinit_session; + + gnutls_transport_set_int(gnutls_handle->session, fd); + + struct pollfd pollfd = { + .fd = fd, + }; + ssize_t gnutls_res; + do { + int poll_res; + do { + gnutls_res = gnutls_handshake(gnutls_handle->session); + } while (res == GNUTLS_E_INTERRUPTED); + if (gnutls_res < 0) { + if (gnutls_res == GNUTLS_E_AGAIN) { + pollfd.events = POLLIN | POLLOUT; + do { + poll_res = poll(&pollfd, 1, 0); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_connect_deinit_session; + + if ((pollfd.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT)) + continue; + else if (pollfd.revents & (~(POLLIN | POLLOUT))) + goto gnutls_connect_deinit_session; + else + pollfd.events = pollfd.revents ^ (POLLIN | POLLOUT); + } + } else { + break; + } + + do { + poll_res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_connect_deinit_session; + if (poll_res == 0) // Timed out + goto gnutls_connect_deinit_session; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) + goto gnutls_connect_deinit_session; + } while (1); + + addr_out->data = malloc(sizeof(sockaddr)); + if (!addr_out->data) + goto gnutls_connect_deinit_session; + + memcpy(addr_out->data, &sockaddr, sizeof(sockaddr)); + addr_out->len = sizeof(sockaddr); + + return fd; + + gnutls_connect_deinit_session: + gnutls_deinit(gnutls_handle->session); + gnutls_connect_close: + close(fd); + gnutls_connect_destroy_mutex: + mutex_destroy(&(gnutls_handle->mutex)); + gnutls_connect_free_gnutls_handle: + free(gnutls_handle); + + return -1; +} + +int gnutls_buffered_accept(int listen_fd, void **handle, struct string *addr) { + if (!GNUTLS_CERT_PATH || !GNUTLS_KEY_PATH) + return -1; + + struct sockaddr address; + socklen_t address_len = sizeof(address); + + int con_fd; + do { + con_fd = accept(listen_fd, &address, &address_len); + } while (con_fd == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN || errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)); + + if (con_fd == -1) + return -1; + + int flags = fcntl(con_fd, F_GETFL); + if (flags == -1) + goto gnutls_accept_close; + if (fcntl(con_fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto gnutls_accept_close; + + struct gnutls_buffered_handle *gnutls_handle; + gnutls_handle = malloc(sizeof(*gnutls_handle)); + if (!gnutls_handle) + goto gnutls_accept_close; + + *handle = gnutls_handle; + gnutls_handle->valid = 1; + gnutls_handle->fd = con_fd; + + int res = mutex_init(&(gnutls_handle->mutex)); + if (res != 0) + goto gnutls_accept_free_gnutls_handle; + + addr->data = malloc(address_len); + if (addr->data == 0 && address_len != 0) + goto gnutls_accept_destroy_mutex; + + memcpy(addr->data, &address, address_len); + addr->len = address_len; + + if (gnutls_init(&(gnutls_handle->session), GNUTLS_SERVER | GNUTLS_NONBLOCK) != GNUTLS_E_SUCCESS) + goto gnutls_accept_free_addr_data; + + if (gnutls_credentials_set(gnutls_handle->session, GNUTLS_CRD_CERTIFICATE, gnutls_buffered_cert_creds) != GNUTLS_E_SUCCESS) + goto gnutls_accept_deinit_session; + + if (gnutls_set_default_priority(gnutls_handle->session) != GNUTLS_E_SUCCESS) + goto gnutls_accept_deinit_session; + + gnutls_transport_set_int(gnutls_handle->session, con_fd); + + gnutls_handshake_set_timeout(gnutls_handle->session, PING_INTERVAL * 1000); + gnutls_record_set_timeout(gnutls_handle->session, PING_INTERVAL * 1000); + + struct pollfd pollfd = { + .fd = con_fd, + }; + ssize_t gnutls_res; + do { + int poll_res; + do { + gnutls_res = gnutls_handshake(gnutls_handle->session); + } while (res == GNUTLS_E_INTERRUPTED); + if (gnutls_res < 0) { + if (gnutls_res == GNUTLS_E_AGAIN) { + pollfd.events = POLLIN | POLLOUT; + do { + poll_res = poll(&pollfd, 1, 0); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_accept_deinit_session; + + if ((pollfd.revents & (POLLIN | POLLOUT)) == (POLLIN | POLLOUT)) + continue; + else if (pollfd.revents & (~(POLLIN | POLLOUT))) + goto gnutls_accept_deinit_session; + else + pollfd.events = pollfd.revents ^ (POLLIN | POLLOUT); + } + } else { + break; + } + + do { + poll_res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (poll_res < 0 && errno == EINTR); + if (poll_res < 0) + goto gnutls_accept_deinit_session; + if (poll_res == 0) // Timed out + goto gnutls_accept_deinit_session; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) + goto gnutls_accept_deinit_session; + } while (1); + + return con_fd; + + gnutls_accept_deinit_session: + gnutls_deinit(gnutls_handle->session); + gnutls_accept_free_addr_data: + free(addr->data); + gnutls_accept_destroy_mutex: + mutex_destroy(&(gnutls_handle->mutex)); + gnutls_accept_free_gnutls_handle: + free(gnutls_handle); + gnutls_accept_close: + close(con_fd); + return -1; +} + +void gnutls_buffered_shutdown(void *handle) { + struct gnutls_buffered_handle *gnutls_handle = handle; + mutex_lock(&(gnutls_handle->mutex)); + shutdown(gnutls_handle->fd, SHUT_RDWR); + gnutls_handle->valid = 0; + mutex_unlock(&(gnutls_handle->mutex)); +} + +void gnutls_buffered_close(int fd, void *handle) { + struct gnutls_buffered_handle *gnutls_handle = handle; + mutex_destroy(&(gnutls_handle->mutex)); + gnutls_deinit(gnutls_handle->session); + free(gnutls_handle); + close(fd); +} diff --git a/networks/gnutls_buffered.h b/networks/gnutls_buffered.h new file mode 100644 index 0000000..a12d4cd --- /dev/null +++ b/networks/gnutls_buffered.h @@ -0,0 +1,45 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "../haxstring.h" +#include "../general_network.h" + +int init_gnutls_buffered_network(void); + +int gnutls_buffered_send(void *fd, struct string msg); +size_t gnutls_buffered_recv(void *fd, char *data, size_t len, char *err); + +int gnutls_buffered_connect(void **handle, struct string address, struct string port, struct string *addr_out); +int gnutls_buffered_accept(int listen_fd, void **handle, struct string *addr); + +void gnutls_buffered_shutdown(void *handle); +void gnutls_buffered_close(int fd, void *handle); diff --git a/networks/openssl_buffered.c b/networks/openssl_buffered.c new file mode 100644 index 0000000..f929145 --- /dev/null +++ b/networks/openssl_buffered.c @@ -0,0 +1,600 @@ +// One of the code files for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <openssl/ssl.h> +#include <openssl/tls1.h> +#include <poll.h> +#include <pthread.h> +#include <unistd.h> + +#ifdef USE_FUTEX +#else +#include <semaphore.h> +#endif + +#include "../config.h" +#include "../main.h" +#include "../mutex.h" +#include "openssl_buffered.h" + +struct openssl_buffered_handle { + SSL *ssl; + MUTEX_TYPE mutex; + int fd; + char valid; + char close; +#ifdef USE_FUTEX + MUTEX_TYPE release_read; + MUTEX_TYPE release_write; +#else + sem_t release_read; + sem_t release_write; +#endif + char *buffer; + size_t write_buffer_index; + size_t buffer_len; +}; + +SSL_CTX *openssl_buffered_ctx; + +int init_openssl_buffered_network(void) { + SSL_library_init(); + + openssl_buffered_ctx = SSL_CTX_new(TLS_method()); + if (OPENSSL_CERT_PATH && OPENSSL_KEY_PATH) { + if (SSL_CTX_use_certificate_file(openssl_buffered_ctx, OPENSSL_CERT_PATH, SSL_FILETYPE_PEM) != 1) + return 1; + if (SSL_CTX_use_PrivateKey_file(openssl_buffered_ctx, OPENSSL_KEY_PATH, SSL_FILETYPE_PEM) != 1) + return 1; + } + + if (OPENSSL_USE_SYSTEM_TRUST) { + if (SSL_CTX_set_default_verify_paths(openssl_buffered_ctx) != 1) { + return 1; + } + } + + return 0; +} + +void * openssl_buffered_send_thread(void *handle) { + struct openssl_buffered_handle *info = handle; + + size_t read_buffer_index = 0; + mutex_lock(&(info->mutex)); + while (1) { + if (!info->valid) + goto openssl_buffered_send_thread_error_unlock; + + size_t len; + len = info->buffer_len; + +#ifdef USE_FUTEX + mutex_unlock(&(info->release_write)); + if (len == 0) + info->release_read = 1; +#else + sem_trywait(&(info->release_write)); + sem_post(&(info->release_write)); +#endif + + mutex_unlock(&(info->mutex)); + +#ifdef USE_FUTEX + if (len == 0) { + mutex_lock(&(info->release_read)); + mutex_lock(&(info->mutex)); + continue; + } +#else + if (len == 0) { + sem_wait(&(info->release_read)); + mutex_lock(&(info->mutex)); + continue; + } +#endif + + if (read_buffer_index + len > OPENSSL_BUFFERED_LEN) + len = OPENSSL_BUFFERED_LEN - read_buffer_index; + + struct pollfd pollfd = { + .fd = info->fd, + }; + int res; + do { + mutex_lock(&(info->mutex)); + res = SSL_write(info->ssl, &(info->buffer[read_buffer_index]), len); + if (res <= 0) { + switch(SSL_get_error(info->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_buffered_send_thread_error_unlock; + } + } else { + break; + } + mutex_unlock(&(info->mutex)); + + do { + res = poll(&pollfd, 1, PING_INTERVAL*1000); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto openssl_buffered_send_thread_error; + if (res == 0) // Timed out... maybe handle differently later + goto openssl_buffered_send_thread_error; + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_buffered_send_thread_error; + } while (1); + + read_buffer_index += len; + if (read_buffer_index >= OPENSSL_BUFFERED_LEN) + read_buffer_index = 0; + + info->buffer_len -= len; + } + + openssl_buffered_send_thread_error: + mutex_lock(&(info->mutex)); + openssl_buffered_send_thread_error_unlock: + info->valid = 0; + mutex_unlock(&(info->mutex)); + +#ifdef USE_FUTEX + mutex_unlock(&(info->release_write)); +#else + sem_trywait(&(info->release_write)); + sem_post(&(info->release_write)); +#endif + while (1) { + mutex_lock(&(info->mutex)); + if (info->close) { + mutex_unlock(&(info->mutex)); + mutex_destroy(&(info->mutex)); + SSL_free(info->ssl); + close(info->fd); + free(info->buffer); +#ifdef USE_FUTEX +#else + sem_destroy(&(info->release_read)); + sem_destroy(&(info->release_write)); +#endif + free(info); + return 0; + } else { +#ifdef USE_FUTEX + info->release_read = 1; + mutex_unlock(&(info->mutex)); + mutex_lock(&(info->release_read)); + continue; +#else + mutex_unlock(&(info->mutex)); + sem_wait(&(info->release_read)); + continue; +#endif + } + mutex_unlock(&(info->mutex)); + } +} + +int openssl_buffered_send(void *handle, struct string msg) { + struct openssl_buffered_handle *openssl_handle = handle; + while (msg.len > 0) { + size_t len = msg.len; + if (len > OPENSSL_BUFFERED_LEN - openssl_handle->write_buffer_index) + len = OPENSSL_BUFFERED_LEN - openssl_handle->write_buffer_index; + mutex_lock(&(openssl_handle->mutex)); + if (!openssl_handle->valid) { + mutex_unlock(&(openssl_handle->mutex)); + return 1; + } + if (len > OPENSSL_BUFFERED_LEN - openssl_handle->buffer_len) + len = OPENSSL_BUFFERED_LEN - openssl_handle->buffer_len; +#ifdef USE_FUTEX + if (len == 0) { + openssl_handle->release_write = 1; + mutex_unlock(&(openssl_handle->mutex)); + mutex_lock(&(openssl_handle->release_write)); + continue; + } +#else + if (len == 0) { + mutex_unlock(&(openssl_hndle->mutex)); + sem_wait(&(openssl_handle->release_write)); + continue; + } +#endif + memcpy(&(openssl_handle->buffer[openssl_handle->write_buffer_index]), msg.data, len); + openssl_handle->buffer_len += len; +#ifdef USE_FUTEX + mutex_unlock(&(openssl_handle->release_read)); +#else + sem_trywait(&(openssl_handle->release_read)); + sem_post(&(openssl_handle->release_read)); +#endif + mutex_unlock(&(openssl_handle->mutex)); + openssl_handle->write_buffer_index += len; + if (openssl_handle->write_buffer_index >= OPENSSL_BUFFERED_LEN) + openssl_handle->write_buffer_index = 0; + msg.len -= len; + msg.data += len; + } + + return 0; +} + +size_t openssl_buffered_recv(void *handle, char *data, size_t len, char *err) { + struct openssl_buffered_handle *openssl_handle = handle; + + struct pollfd pollfd = { + .fd = openssl_handle->fd, + }; + int res; + do { + mutex_lock(&(openssl_handle->mutex)); + if (!openssl_handle->valid) { + mutex_unlock(&(openssl_handle->mutex)); + *err = 3; + return 0; + } + res = SSL_read(openssl_handle->ssl, data, len); + mutex_unlock(&(openssl_handle->mutex)); + if (res <= 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + *err = 3; + return 0; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) { // Timeout + *err = 1; + return 0; + } + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + *err = 3; + return 0; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) { // Only errors returned + if (pollfd.revents & POLLHUP) { + *err = 2; + } else { + *err = 3; + } + + return 0; + } + } while (1); + + *err = 0; + return (size_t)res; +} + +int openssl_buffered_connect(void **handle, struct string address, struct string port, struct string *addr_out) { + struct sockaddr sockaddr; + if (resolve(address, port, &sockaddr) != 0) + return -1; + + int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fd == -1) + return -1; + + { + struct timeval timeout = { + .tv_sec = PING_INTERVAL, + .tv_usec = 0, + }; + + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } + + int res; + do { + res = connect(fd, &sockaddr, sizeof(sockaddr)); + } while (res < 0 && errno == EINTR); + if (res < 0) + goto openssl_connect_close; + + int flags = fcntl(fd, F_GETFL); + if (flags == -1) + goto openssl_connect_close; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto openssl_connect_close; + + addr_out->data = malloc(sizeof(sockaddr)); + if (!addr_out->data) + goto openssl_connect_close; + memcpy(addr_out->data, &sockaddr, sizeof(sockaddr)); + addr_out->len = sizeof(sockaddr); + + struct openssl_buffered_handle *openssl_handle; + openssl_handle = malloc(sizeof(*openssl_handle)); + if (!openssl_handle) + goto openssl_connect_free_addr_data; + *handle = openssl_handle; + + openssl_handle->fd = fd; + + openssl_handle->ssl = SSL_new(openssl_buffered_ctx); + if (!openssl_handle->ssl) + goto openssl_connect_free_openssl_handle; + SSL_set_fd(openssl_handle->ssl, fd); + + res = mutex_init(&(openssl_handle->mutex)); + if (res != 0) + goto openssl_connect_free_ssl; + + struct pollfd pollfd = { + .fd = fd, + }; + do { + res = SSL_connect(openssl_handle->ssl); + if (res == 0) + goto openssl_connect_destroy_mutex; + if (res < 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_connect_destroy_mutex; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) // Timeout + goto openssl_connect_destroy_mutex; + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + goto openssl_connect_destroy_mutex; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_connect_destroy_mutex; + } while (1); + + openssl_handle->valid = 1; + openssl_handle->close = 0; + openssl_handle->write_buffer_index = 0; + openssl_handle->buffer_len = 0; + + openssl_handle->buffer = malloc(OPENSSL_BUFFERED_LEN); + if (!openssl_handle->buffer) + goto openssl_connect_destroy_mutex; + +#ifdef USE_FUTEX + openssl_handle->release_read = 0; + openssl_handle->release_write = 0; +#else + sem_init(&(openssl_handle->release_read), 0, 0); + sem_init(&(openssl_handle->release_write), 0, 0); +#endif + + pthread_t trash; + if (pthread_create(&trash, &pthread_attr, openssl_buffered_send_thread, openssl_handle) != 0) + goto openssl_connect_destroy_releases; + + return fd; + + openssl_connect_destroy_releases: +#ifdef USE_FUTEX +#else + sem_destroy(&(openssl_handle->release_read)); + sem_destroy(&(openssl_handle->release_write)); +#endif + openssl_connect_destroy_mutex: + mutex_destroy(&(openssl_handle->mutex)); + openssl_connect_free_ssl: + SSL_free(openssl_handle->ssl); + openssl_connect_free_openssl_handle: + free(openssl_handle); + openssl_connect_free_addr_data: + free(addr_out->data); + openssl_connect_close: + close(fd); + + return -1; +} + +int openssl_buffered_accept(int listen_fd, void **handle, struct string *addr) { + if (!OPENSSL_CERT_PATH || !OPENSSL_KEY_PATH) + return -1; + + struct sockaddr address; + socklen_t address_len = sizeof(address); + + int con_fd; + do { + con_fd = accept(listen_fd, &address, &address_len); + } while (con_fd == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENETDOWN || errno == EPROTO || errno == ENOPROTOOPT || errno == EHOSTDOWN || errno == ENONET || errno == EHOSTUNREACH || errno == EOPNOTSUPP || errno == ENETUNREACH)); + + if (con_fd == -1) + return -1; + + int flags = fcntl(con_fd, F_GETFL); + if (flags == -1) + goto openssl_accept_close; + if (fcntl(con_fd, F_SETFL, flags | O_NONBLOCK) == -1) + goto openssl_accept_close; + + addr->data = malloc(address_len); + if (addr->data == 0 && address_len != 0) + goto openssl_accept_close; + + memcpy(addr->data, &address, address_len); + addr->len = address_len; + + struct openssl_buffered_handle *openssl_handle; + openssl_handle = malloc(sizeof(*openssl_handle)); + if (!openssl_handle) + goto openssl_accept_free_addr_data; + + *handle = openssl_handle; + + openssl_handle->fd = con_fd; + + openssl_handle->ssl = SSL_new(openssl_buffered_ctx); + if (!openssl_handle->ssl) + goto openssl_accept_free_openssl_handle; + + SSL_set_fd(openssl_handle->ssl, con_fd); + + int res = mutex_init(&(openssl_handle->mutex)); + if (res != 0) + goto openssl_accept_free_ssl; + + struct pollfd pollfd = { + .fd = con_fd, + }; + do { + res = SSL_accept(openssl_handle->ssl); + if (res == 0) + goto openssl_accept_destroy_mutex; + if (res < 0) { + switch(SSL_get_error(openssl_handle->ssl, res)) { + case SSL_ERROR_WANT_READ: + pollfd.events = POLLIN; + break; + case SSL_ERROR_WANT_WRITE: + pollfd.events = POLLOUT; + break; + default: + goto openssl_accept_destroy_mutex; + } + } else { + break; + } + + res = poll(&pollfd, 1, PING_INTERVAL*1000); + if (res == 0) // Timeout + goto openssl_accept_destroy_mutex; + if (res == -1) { + if (errno != EINTR) { + continue; + } else { + goto openssl_accept_destroy_mutex; + } + } + if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned + goto openssl_accept_destroy_mutex; + } while (1); + + openssl_handle->valid = 1; + + openssl_handle->buffer = malloc(OPENSSL_BUFFERED_LEN); + if (!openssl_handle->buffer) + goto openssl_accept_destroy_mutex; + +#ifdef USE_FUTEX + openssl_handle->release_read = 0; + openssl_handle->release_write = 0; +#else + sem_init(&(openssl_handle->release_read), 0, 0); + sem_init(&(openssl_handle->release_write), 0, 0); +#endif + + pthread_t trash; + if (pthread_create(&trash, &pthread_attr, openssl_buffered_send_thread, openssl_handle) != 0) + goto openssl_accept_destroy_releases; + + return con_fd; + + openssl_accept_destroy_releases: +#ifdef USE_FUTEX +#else + sem_destroy(&(openssl_handle->release_read)); + sem_destroy(&(openssl_handle->release_write)); +#endif + openssl_accept_destroy_mutex: + mutex_destroy(&(openssl_handle->mutex)); + openssl_accept_free_ssl: + SSL_free(openssl_handle->ssl); + openssl_accept_free_openssl_handle: + free(openssl_handle); + openssl_accept_free_addr_data: + free(addr->data); + openssl_accept_close: + close(con_fd); + + return -1; +} + +void openssl_buffered_shutdown(void *handle) { + struct openssl_buffered_handle *openssl_handle = handle; + mutex_lock(&(openssl_handle->mutex)); + openssl_handle->valid = 0; +#ifdef USE_FUTEX + mutex_unlock(&(openssl_handle->release_read)); +#else + sem_trywait(&(openssl_handle->release_read)); + sem_post(&(openssl_handle->release_read)); +#endif + mutex_unlock(&(openssl_handle->mutex)); + shutdown(openssl_handle->fd, SHUT_RDWR); +} + +void openssl_buffered_close(int fd, void *handle) { + struct openssl_buffered_handle *openssl_handle = handle; + mutex_lock(&(openssl_handle->mutex)); + openssl_handle->valid = 0; +#ifdef USE_FUTEX + mutex_unlock(&(openssl_handle->release_read)); +#else + sem_trywait(&(openssl_handle->release_read)); + sem_post(&(openssl_handle->release_read)); +#endif + openssl_handle->close = 1; + mutex_unlock(&(openssl_handle->mutex)); +} diff --git a/networks/openssl_buffered.h b/networks/openssl_buffered.h new file mode 100644 index 0000000..def2ec7 --- /dev/null +++ b/networks/openssl_buffered.h @@ -0,0 +1,45 @@ +// One of the headers for HaxServ +// +// Written by: Test_User <hax@andrewyu.org> +// +// This is free and unencumbered software released into the public +// domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include <stddef.h> + +#include "../haxstring.h" +#include "../general_network.h" + +int init_openssl_buffered_network(void); + +int openssl_buffered_send(void *handle, struct string msg); +size_t openssl_buffered_recv(void *handle, char *data, size_t len, char *err); + +int openssl_buffered_connect(void **handle, struct string address, struct string port, struct string *addr_out); +int openssl_buffered_accept(int listen_fd, void **handle, struct string *addr); + +void openssl_buffered_shutdown(void *handle); +void openssl_buffered_close(int fd, void *handle); diff --git a/networks/plaintext_buffered.c b/networks/plaintext_buffered.c index 6ac3e1c..99bd085 100644 --- a/networks/plaintext_buffered.c +++ b/networks/plaintext_buffered.c @@ -65,27 +65,31 @@ struct plaintext_buffered_handle { size_t buffer_len; }; +int init_plaintext_buffered_network(void) { + return 0; +} + void * plaintext_buffered_send_thread(void *handle) { struct plaintext_buffered_handle *info = handle; size_t read_buffer_index = 0; mutex_lock(&(info->mutex)); while (1) { + if (!info->valid) + goto plaintext_buffered_send_thread_error_unlock; + size_t len; len = info->buffer_len; #ifdef USE_FUTEX + mutex_unlock(&(info->release_write)); if (len == 0) info->release_read = 1; - mutex_unlock(&(info->release_write)); #else sem_trywait(&(info->release_write)); sem_post(&(info->release_write)); #endif - if (!info->valid) - goto plaintext_buffered_send_thread_error_unlock; - mutex_unlock(&(info->mutex)); #ifdef USE_FUTEX @@ -132,7 +136,6 @@ void * plaintext_buffered_send_thread(void *handle) { sem_trywait(&(info->release_write)); sem_post(&(info->release_write)); #endif - // TODO: Sane solution that works with ptread mutexes while (1) { mutex_lock(&(info->mutex)); if (info->close) { @@ -165,10 +168,6 @@ void * plaintext_buffered_send_thread(void *handle) { return 0; } -int init_plaintext_buffered_network(void) { - return 0; -} - int plaintext_buffered_send(void *handle, struct string msg) { struct plaintext_buffered_handle *plaintext_handle = handle; while (msg.len > 0) { @@ -197,9 +196,6 @@ int plaintext_buffered_send(void *handle, struct string msg) { } #endif memcpy(&(plaintext_handle->buffer[plaintext_handle->write_buffer_index]), msg.data, len); - plaintext_handle->write_buffer_index += len; - if (plaintext_handle->write_buffer_index >= PLAINTEXT_BUFFERED_LEN) - plaintext_handle->write_buffer_index = 0; plaintext_handle->buffer_len += len; #ifdef USE_FUTEX mutex_unlock(&(plaintext_handle->release_read)); @@ -208,7 +204,11 @@ int plaintext_buffered_send(void *handle, struct string msg) { sem_post(&(plaintext_handle->release_read)); #endif mutex_unlock(&(plaintext_handle->mutex)); + plaintext_handle->write_buffer_index += len; + if (plaintext_handle->write_buffer_index >= PLAINTEXT_BUFFERED_LEN) + plaintext_handle->write_buffer_index = 0; msg.len -= len; + msg.data += len; } return 0; @@ -268,6 +268,7 @@ int plaintext_buffered_connect(void **handle, struct string address, struct stri goto plaintext_buffered_connect_close; *handle = plaintext_handle; plaintext_handle->valid = 1; + plaintext_handle->close = 0; plaintext_handle->fd = fd; addr_out->data = malloc(sizeof(sockaddr)); @@ -335,7 +336,7 @@ int plaintext_buffered_accept(int listen_fd, void **handle, struct string *addr) goto plaintext_buffered_accept_close; *handle = plaintext_handle; plaintext_handle->valid = 1; - plaintext_handle->close = 1; + plaintext_handle->close = 0; plaintext_handle->fd = con_fd; addr->data = malloc(address_len); diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c index 6c16598..fb1873b 100644 --- a/protocols/inspircd2.c +++ b/protocols/inspircd2.c @@ -213,8 +213,12 @@ void * inspircd2_protocol_connection(void *type) { goto inspircd2_protocol_handle_connection_close; } else if (err == 1) { // Timed out if (ready) { - if (timeout > 0) + if (timeout > 0) { + WRITES(2, STRING("[InspIRCd v2] [")); + WRITES(2, config->name); + WRITES(2, STRING("] Disconnected: Ping timeout.\r\n\n")); goto inspircd2_protocol_handle_connection_close; + } timeout++; mutex_lock(&(state_lock)); @@ -232,6 +236,7 @@ void * inspircd2_protocol_connection(void *type) { mutex_unlock(&(state_lock)); } else { + WRITES(2, STRING("[InspIRCd v2] [unidentified server] Disconnected: Ping timeout.\r\n\n")); goto inspircd2_protocol_handle_connection_close; } } else { @@ -403,10 +408,12 @@ void * inspircd2_protocol_connection(void *type) { } int res = func(source, argc, argv, net, handle, &config, is_incoming); - if (res < 0) // Disconnect + if (res < 0) { // Disconnect + WRITES(2, STRING("[InspIRCd v2] [unidentified server] Disconnected: Command handler returned < 0.\r\n\n")); goto inspircd2_protocol_handle_connection_unlock_close; - else if (res > 0) // Connection is now "ready" + } else if (res > 0) { // Connection is now "ready" ready = 1; + } } else { int (*func)(struct string source, size_t argc, struct string *argv, size_t net, void *handle, struct server_config *config, char is_incoming); func = get_table_index(inspircd2_protocol_commands, command); @@ -416,8 +423,12 @@ void * inspircd2_protocol_connection(void *type) { } int res = func(source, argc, argv, net, handle, config, is_incoming); - if (res < 0) // Disconnect + if (res < 0) { // Disconnect + WRITES(2, STRING("[InspIRCd v2] [")); + WRITES(2, config->name); + WRITES(2, STRING("] Disconnected: Command handler returned < 0.\r\n\n")); goto inspircd2_protocol_handle_connection_unlock_close; + } } inspircd2_protocol_handle_connection_unlock_next: @@ -1016,6 +1027,8 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str return -1; } + WRITES(2, STRING("0\n")); + if (source.len != 0) { WRITES(2, STRING("[InspIRCd v2] Server attempting to use a source without having introduced itself!\r\n")); return -1; @@ -1051,6 +1064,8 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str networks[net].send(handle, STRING("\n")); } + WRITES(2, STRING("1\n")); + time_t now = time(0); if (now < 0) { WRITES(2, STRING("ERROR: Negative clock!\r\n")); @@ -1069,28 +1084,42 @@ int inspircd2_protocol_init_handle_server(struct string source, size_t argc, str networks[net].send(handle, time); networks[net].send(handle, STRING("\n")); + WRITES(2, STRING("2\n")); + inspircd2_protocol_introduce_servers_to(net, handle); + WRITES(2, STRING("3\n")); + for (size_t i = 0; i < user_list.len; i++) inspircd2_protocol_introduce_user_to(net, handle, user_list.array[i].ptr, 0); + WRITES(2, STRING("4\n")); + for (size_t i = 0; i < channel_list.len; i++) inspircd2_protocol_introduce_channel_to(net, handle, channel_list.array[i].ptr); + WRITES(2, STRING("5\n")); + networks[net].send(handle, STRING(":")); networks[net].send(handle, SID); networks[net].send(handle, STRING(" ENDBURST\n")); free(time.data); + WRITES(2, STRING("6\n")); + if (add_server((*config)->sid, SID, argv[3], argv[0], argv[4], INSPIRCD2_PROTOCOL, net, handle) != 0) { WRITES(2, STRING("ERROR: Unable to add server!\r\n")); return -1; } + WRITES(2, STRING("7\n")); + struct server_info *server = get_table_index(server_list, (*config)->sid); server->awaiting_pong = 0; + WRITES(2, STRING("8\n")); + return 1; } diff --git a/real_main.c b/real_main.c index 3990feb..15f665a 100644 --- a/real_main.c +++ b/real_main.c @@ -43,6 +43,15 @@ #ifdef USE_OPENSSL #include "networks/openssl.h" #endif +#ifdef USE_PLAINTEXT_BUFFERED +#include "networks/plaintext_buffered.h" +#endif +#ifdef USE_GNUTLS_BUFFERED +#include "networks/gnutls_buffered.h" +#endif +#ifdef USE_OPENSSL_BUFFERED +#include "networks/openssl_buffered.h" +#endif #ifdef USE_SERVER #include "server_network.h" @@ -85,6 +94,21 @@ int real_main(void) { return 1; #endif +#ifdef USE_PLAINTEXT_BUFFERED + if (init_plaintext_buffered_network() != 0) + return 1; +#endif + +#ifdef USE_GNUTLS_BUFFERED + if (init_gnutls_buffered_network() != 0) + return 1; +#endif + +#ifdef USE_OPENSSL_BUFFERED + if (init_openssl_buffered_network() != 0) + return 1; +#endif + #ifdef USE_SERVER if (init_server_network() != 0) return 1; diff --git a/server_network.c b/server_network.c index dfbc6f6..29639fd 100644 --- a/server_network.c +++ b/server_network.c @@ -51,6 +51,12 @@ #ifdef USE_PLAINTEXT_BUFFERED_SERVER #include "networks/plaintext_buffered.h" #endif +#ifdef USE_GNUTLS_BUFFERED_SERVER +#include "networks/gnutls_buffered.h" +#endif +#ifdef USE_OPENSSL_BUFFERED_SERVER +#include "networks/openssl_buffered.h" +#endif struct table server_config = {0}; @@ -86,6 +92,16 @@ int start_server_network(void) { if (start_server_network_threads(NET_TYPE_PLAINTEXT_BUFFERED) != 0) return 1; #endif +#ifdef USE_GNUTLS_BUFFERED_SERVER + if (GNUTLS_CERT_PATH && GNUTLS_KEY_PATH) + if (start_server_network_threads(NET_TYPE_GNUTLS_BUFFERED) != 0) + return 1; +#endif +#ifdef USE_OPENSSL_BUFFERED_SERVER + if (OPENSSL_CERT_PATH && OPENSSL_KEY_PATH) + if (start_server_network_threads(NET_TYPE_OPENSSL_BUFFERED) != 0) + return 1; +#endif pthread_t trash; for (size_t i = 0; i < SERVER_CONFIG_LEN; i++) { |