aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTest_User <hax@andrewyu.org>2024-06-19 03:41:14 -0400
committerTest_User <hax@andrewyu.org>2024-06-19 03:41:14 -0400
commit991d1d37474726ae5dc910da9705485f7b193e18 (patch)
treee6d01a7a65dd8f916f400f1b083909c58a304d71
parent9c16070679fea6ac5625546d4ba5af0f638e6636 (diff)
downloadhaxircd-991d1d37474726ae5dc910da9705485f7b193e18.tar.gz
haxircd-991d1d37474726ae5dc910da9705485f7b193e18.zip
Some improvements and openssl send buffering
-rw-r--r--Makefile78
-rw-r--r--config.h14
-rw-r--r--general_network.c48
-rw-r--r--general_network.h8
-rw-r--r--networks/gnutls_buffered.c436
-rw-r--r--networks/gnutls_buffered.h45
-rw-r--r--networks/openssl_buffered.c600
-rw-r--r--networks/openssl_buffered.h45
-rw-r--r--networks/plaintext_buffered.c27
-rw-r--r--protocols/inspircd2.c37
-rw-r--r--real_main.c24
-rw-r--r--server_network.c16
12 files changed, 1347 insertions, 31 deletions
diff --git a/Makefile b/Makefile
index c2bce49..4994a14 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/config.h b/config.h
index a80de42..65a8511 100644
--- a/config.h
+++ b/config.h
@@ -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++) {