aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore7
-rw-r--r--LICENSE.c27
-rw-r--r--LICENSE.h27
-rw-r--r--Makefile271
-rw-r--r--config.h78
-rw-r--r--general_network.c138
-rw-r--r--general_network.h72
-rw-r--r--gnutls_network.c234
-rw-r--r--gnutls_network.h44
-rw-r--r--haxstring.h43
-rw-r--r--haxstring_utils.c75
-rw-r--r--haxstring_utils.h34
-rw-r--r--main.c125
-rw-r--r--main.h34
-rw-r--r--openssl_network.c379
-rw-r--r--openssl_network.h44
-rw-r--r--plaintext_network.c168
-rw-r--r--plaintext_network.h44
-rw-r--r--protocols.c42
-rw-r--r--protocols.h43
-rw-r--r--protocols/inspircd2.c341
-rw-r--r--protocols/inspircd2.h41
-rw-r--r--server_network.c162
-rw-r--r--server_network.h51
-rw-r--r--table.c185
-rw-r--r--table.h48
26 files changed, 2757 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8c4fba9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+config.c
+*.o
+.*.swp
+haxserv
+core
+.makeopts
+output
diff --git a/LICENSE.c b/LICENSE.c
new file mode 100644
index 0000000..708783d
--- /dev/null
+++ b/LICENSE.c
@@ -0,0 +1,27 @@
+// 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.
diff --git a/LICENSE.h b/LICENSE.h
new file mode 100644
index 0000000..a10cafb
--- /dev/null
+++ b/LICENSE.h
@@ -0,0 +1,27 @@
+// 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
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4bc5184
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,271 @@
+# Makefile 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.
+
+INCLUDEFLAGS =
+
+CFLAGS += $(INCLUDEFLAGS) -D_REENTRANT -ggdb3 -Wall -Wextra -Wsign-conversion -Wno-unused-parameter -std=gnu99
+
+LDFLAGS = -lpthread
+
+.makeopts:
+ > .makeopts
+
+include .makeopts
+
+rebuild = 0
+
+# tabs not allowed :(
+ifneq ($(PLAINTEXT_CLIENT),)
+ifneq ($(PLAINTEXT_CLIENT),$(LAST_PLAINTEXT_CLIENT))
+rebuild = 1
+endif
+else
+PLAINTEXT_CLIENT = $(LAST_PLAINTEXT_CLIENT)
+endif
+
+ifneq ($(PLAINTEXT_SERVER),)
+ifneq ($(PLAINTEXT_SERVER),$(LAST_PLAINTEXT_SERVER))
+rebuild = 1
+endif
+else
+PLAINTEXT_SERVER = $(LAST_PLAINTEXT_SERVER)
+endif
+
+ifneq ($(GNUTLS_CLIENT),)
+ifneq ($(GNUTLS_CLIENT),$(LAST_GNUTLS_CLIENT))
+rebuild = 1
+endif
+else
+GNUTLS_CLIENT = $(LAST_GNUTLS_CLIENT)
+endif
+
+ifneq ($(GNUTLS_SERVER),)
+ifneq ($(GNUTLS_SERVER),$(LAST_GNUTLS_SERVER))
+rebuild = 1
+endif
+else
+GNUTLS_SERVER = $(LAST_GNUTLS_SERVER)
+endif
+
+ifneq ($(OPENSSL_CLIENT),)
+ifneq ($(OPENSSL_CLIENT),$(LAST_OPENSSL_CLIENT))
+rebuild = 1
+endif
+else
+OPENSSL_CLIENT = $(LAST_OPENSSL_CLIENT)
+endif
+
+ifneq ($(OPENSSL_SERVER),)
+ifneq ($(OPENSSL_SERVER),$(LAST_OPENSSL_SERVER))
+rebuild = 1
+endif
+else
+OPENSSL_SERVER = $(LAST_OPENSSL_SERVER)
+endif
+
+ifneq ($(INSPIRCD2_PROTOCOL),)
+ifneq ($(INSPIRCD2_PROTOCOL),$(LAST_INSPIRCD2_PROTOCOL))
+rebuild = 1
+endif
+else
+INSPIRCD2_PROTOCOL = $(LAST_INSPIRCD2_PROTOCOL)
+endif
+
+ifneq ($(SAFE_STACK),)
+ifneq ($(SAFE_STACK),$(LAST_SAFE_STACK))
+rebuild = 1
+endif
+else
+SAFE_STACK = $(LAST_SAFE_STACK)
+endif
+
+ifneq ($(CFLAGS),)
+ifneq ($(CFLAGS),$(LAST_CFLAGS))
+rebuild = 1
+endif
+else
+CFLAGS = $(LAST_CFLAGS)
+endif
+
+ifneq ($(CC),)
+ifneq ($(CC),$(LAST_CC))
+rebuild = 1
+endif
+else
+CC = $(LAST_CC)
+endif
+
+ifeq ($(rebuild),1)
+$(shell printf '%s\n' 'LAST_PLAINTEXT_CLIENT = $(PLAINTEXT_CLIENT)' > .makeopts)
+$(shell printf '%s\n' 'LAST_PLAINTEXT_SERVER = $(PLAINTEXT_SERVER)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_GNUTLS_CLIENT = $(GNUTLS_CLIENT)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_GNUTLS_SERVER = $(GNUTLS_SERVER)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_OPENSSL_CLIENT = $(OPENSSL_CLIENT)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_OPENSSL_SERVER = $(OPENSSL_SERVER)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_INSPIRCD2_PROTOCOL = $(INSPIRCD2_PROTOCOL)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_SAFE_STACK = $(SAFE_STACK)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_CFLAGS = $(CFLAGS)' >> .makeopts)
+$(shell printf '%s\n' 'LAST_CC = $(CC)' >> .makeopts)
+endif
+
+USE_PLAINTEXT = 0
+USE_CLIENT = 0
+USE_GNUTLS = 0
+USE_SERVER = 0
+
+ifeq ($(PLAINTEXT_CLIENT),1)
+CFLAGS += -DUSE_PLAINTEXT_CLIENT
+USE_CLIENT = 1
+USE_PLAINTEXT = 1
+endif
+
+ifeq ($(PLAINTEXT_SERVER),1)
+CFLAGS += -DUSE_PLAINTEXT_SERVER
+USE_SERVER = 1
+USE_PLAINTEXT = 1
+endif
+
+ifeq ($(GNUTLS_CLIENT),1)
+CFLAGS += -DUSE_GNUTLS_CLIENT
+USE_CLIENT = 1
+USE_GNUTLS = 1
+endif
+
+ifeq ($(GNUTLS_SERVER),1)
+CFLAGS += -DUSE_GNUTLS_SERVER
+USE_SERVER = 1
+USE_GNUTLS = 1
+endif
+
+ifeq ($(OPENSSL_CLIENT),1)
+CFLAGS += -DUSE_OPENSSL_CLIENT
+USE_CLIENT = 1
+USE_OPENSSL = 1
+endif
+
+ifeq ($(OPENSSL_SERVER),1)
+CFLAGS += -DUSE_OPENSSL_SERVER
+USE_SERVER = 1
+USE_OPENSSL = 1
+endif
+
+
+OFILES = config.o general_network.o haxstring_utils.o main.o protocols.o table.o
+
+ifeq ($(USE_CLIENT),1)
+OFILES += client_network.o
+CFLAGS += -DUSE_CLIENT
+endif
+
+ifeq ($(USE_SERVER),1)
+OFILES += server_network.o
+CFLAGS += -DUSE_SERVER
+endif
+
+ifeq ($(USE_PLAINTEXT),1)
+OFILES += plaintext_network.o
+CFLAGS += -DUSE_PLAINTEXT
+endif
+
+ifeq ($(USE_GNUTLS),1)
+OFILES += gnutls_network.o
+CFLAGS += -DUSE_GNUTLS $(shell pkg-config gnutls --cflags)
+LDFLAGS += $(shell pkg-config gnutls --libs)
+endif
+
+ifeq ($(USE_OPENSSL),1)
+OFILES += openssl_network.o
+CFLAGS += -DUSE_OPENSSL $(shell pkg-config openssl --cflags)
+LDFLAGS += $(shell pkg-config openssl --libs)
+endif
+
+ifeq ($(SAFE_STACK),1)
+CFLAGS += -fstack-check
+endif
+
+
+
+ifeq ($(INSPIRCD2_PROTOCOL),1)
+ifneq ($(USE_SERVER),1)
+$(error You must have some form of server transport layer enabled if you hope to use the inspircd2 protocol)
+endif
+OFILES += protocols/inspircd2.o
+CFLAGS += -DUSE_INSPIRCD2_PROTOCOL
+endif
+
+
+DEPS = $(shell $(CC) $(CFLAGS) -M -MT $(1).o $(1).c | sed -z 's/\\\n //g') .makeopts Makefile
+
+
+.PHONY: all clean
+all: haxserv
+
+haxserv: $(OFILES) .makeopts Makefile
+ $(CC) $(OFILES) -o $@ $(LDFLAGS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(call DEPS,config)
+
+$(call DEPS,general_network)
+
+$(call DEPS,haxstring_utils)
+
+$(call DEPS,main)
+
+$(call DEPS,protocols)
+
+$(call DEPS,table)
+
+ifeq ($(USE_PLAINTEXT),1)
+$(call DEPS,plaintext_network)
+endif
+
+ifeq ($(USE_GNUTLS),1)
+$(call DEPS,gnutls_network)
+endif
+
+ifeq ($(USE_OPENSSL),1)
+$(call DEPS,openssl_network)
+endif
+
+ifeq ($(USE_CLIENT),1)
+$(call DEPS,client_network)
+endif
+
+ifeq ($(USE_SERVER),1)
+$(call DEPS,server_network)
+endif
+
+ifeq ($(INSPIRCD2_PROTOCOL),1)
+$(call DEPS,protocols/inspircd2)
+endif
+
+clean:
+ $(RM) -r haxserv *.o protocols/*.o
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..d80357c
--- /dev/null
+++ b/config.h
@@ -0,0 +1,78 @@
+// 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 <time.h>
+
+#include "general_network.h"
+#include "protocols.h"
+
+#ifdef USE_SERVER
+struct server_config {
+ struct string name; // = STRING("hax.example.org"),
+ struct string sid; // = STRING("100"),
+
+ struct string in_pass; // = STRING("blah blah blah"),
+ struct string out_pass; // = STRING("some other thing"),
+
+ size_t protocol; // = HAXIRCD_PROTOCOL,
+
+ char autoconnect; // = 1;
+ size_t autoconnect_type; // = NET_TYPE_GNUTLS,
+
+ // autoconnect only
+ struct string address; // = "haxnet.org",
+ struct string port; // = "4321",
+};
+extern struct server_config server_config[]; // = {{...}, ...};
+extern size_t server_config_len; // = sizeof(server_config)/sizeof(*server_config);
+#endif
+
+extern struct string SID; // = STRING("200");
+extern struct string SERVER_NAME; // = STRING("me.example.org");
+extern struct string SERVER_FULLNAME; // = STRING("My random server");
+
+extern time_t PING_INTERVAL; // = 60;
+
+#ifdef USE_GNUTLS
+extern char GNUTLS_USE_SYSTEM_TRUST; // = 1;
+extern char *GNUTLS_CERT_PATH; // = "/etc/keys/crt.pem"
+extern char *GNUTLS_KEY_PATH; // = "/etc/keys/key.pem"
+#endif
+
+#ifdef USE_OPENSSL
+extern char OPENSSL_USE_SYSTEM_TRUST; // = 1;
+extern char *OPENSSL_CERT_PATH; // = "/etc/keys/crt.pem"
+extern char *OPENSSL_KEY_PATH; // = "/etc/keys/key.pem"
+#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
+#endif
diff --git a/general_network.c b/general_network.c
new file mode 100644
index 0000000..f6375d9
--- /dev/null
+++ b/general_network.c
@@ -0,0 +1,138 @@
+// 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 <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "general_network.h"
+
+#ifdef USE_PLAINTEXT
+#include "plaintext_network.h"
+#endif
+#ifdef USE_GNUTLS
+#include "gnutls_network.h"
+#endif
+#ifdef USE_OPENSSL
+#include "openssl_network.h"
+#endif
+
+char casemap[UCHAR_MAX+1] = {
+ ['a'] = 'A',
+ ['b'] = 'B',
+ ['c'] = 'C',
+ ['d'] = 'D',
+ ['e'] = 'E',
+ ['f'] = 'F',
+ ['g'] = 'G',
+ ['h'] = 'H',
+ ['i'] = 'I',
+ ['j'] = 'J',
+ ['k'] = 'K',
+ ['l'] = 'L',
+ ['m'] = 'M',
+ ['n'] = 'N',
+ ['o'] = 'O',
+ ['p'] = 'P',
+ ['q'] = 'Q',
+ ['r'] = 'R',
+ ['s'] = 'S',
+ ['t'] = 'Y',
+ ['u'] = 'U',
+ ['v'] = 'V',
+ ['w'] = 'W',
+ ['x'] = 'X',
+ ['y'] = 'Y',
+ ['z'] = 'Z',
+ ['{'] = '[',
+ ['}'] = ']',
+ ['|'] = '\\',
+ ['^'] = '~',
+};
+
+struct network networks[NUM_NET_TYPES] = {
+#ifdef USE_PLAINTEXT
+ [NET_TYPE_PLAINTEXT] = {
+ .send = plaintext_send,
+ .recv = plaintext_recv,
+ .connect = plaintext_connect,
+ .accept = plaintext_accept,
+ .close = plaintext_close,
+ },
+#endif
+#ifdef USE_GNUTLS
+ [NET_TYPE_GNUTLS] = {
+ .send = gnutls_send,
+ .recv = gnutls_recv,
+ .connect = gnutls_connect,
+ .accept = gnutls_accept,
+ .close = gnutls_close,
+ },
+#endif
+#ifdef USE_OPENSSL
+ [NET_TYPE_OPENSSL] = {
+ .send = openssl_send,
+ .recv = openssl_recv,
+ .connect = openssl_connect,
+ .accept = openssl_accept,
+ .close = openssl_close,
+ },
+#endif
+};
+
+// TODO: Proper string handling
+int resolve(struct string address, struct string port, struct sockaddr *sockaddr) {
+ int success;
+ struct addrinfo hints = {
+ .ai_family = AF_INET,
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ .ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG,
+ };
+ struct addrinfo *info;
+
+ success = getaddrinfo(address.data, port.data, &hints, &info);
+
+ if (success == 0) {
+ *sockaddr = *(info->ai_addr);
+ freeaddrinfo(info);
+ }
+
+ return success;
+}
+
+int init_general_network(void) {
+ for (size_t i = 1; i < UCHAR_MAX + 1; i++) {
+ if (casemap[i] == 0) {
+ casemap[i] = i;
+ }
+ }
+
+ return 0;
+}
diff --git a/general_network.h b/general_network.h
new file mode 100644
index 0000000..cb3e9a7
--- /dev/null
+++ b/general_network.h
@@ -0,0 +1,72 @@
+// 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 <limits.h>
+#include <stddef.h>
+#include <sys/socket.h>
+
+#include "haxstring.h"
+#include "table.h"
+
+struct network {
+ int (*send)(void *handle, struct string msg);
+ size_t (*recv)(void *handle, char *data, size_t len, char *err);
+
+ int (*connect)(void **handle, struct string address, struct string port, struct string *addr_out);
+ int (*accept)(int listen_fd, void **handle, struct string *addr);
+
+ void (*close)(int fd, void *handle);
+};
+
+struct server_info {
+ struct string sid;
+
+ struct table user_list;
+};
+
+int resolve(struct string address, struct string port, struct sockaddr *sockaddr);
+
+int init_general_network(void);
+
+extern char casemap[UCHAR_MAX+1];
+#define CASEMAP(x) (casemap[(unsigned char)x])
+
+#ifdef USE_PLAINTEXT
+#define NET_TYPE_PLAINTEXT 0
+#endif
+#ifdef USE_GNUTLS
+#define NET_TYPE_GNUTLS 1
+#endif
+#ifdef USE_OPENSSL
+#define NET_TYPE_OPENSSL 2
+#endif
+
+#define NUM_NET_TYPES 3
+extern struct network networks[NUM_NET_TYPES];
diff --git a/gnutls_network.c b/gnutls_network.c
new file mode 100644
index 0000000..5105ce1
--- /dev/null
+++ b/gnutls_network.c
@@ -0,0 +1,234 @@
+// 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 <gnutls/gnutls.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "general_network.h"
+#include "gnutls_network.h"
+
+gnutls_certificate_credentials_t gnutls_cert_creds;
+
+int init_gnutls_network(void) {
+ if (gnutls_global_init() < 0)
+ return 1;
+
+ if (gnutls_certificate_allocate_credentials(&gnutls_cert_creds) != GNUTLS_E_SUCCESS)
+ return 2;
+
+ if (GNUTLS_USE_SYSTEM_TRUST && (gnutls_certificate_set_x509_system_trust(gnutls_cert_creds) < 0))
+ return 3;
+
+ if (gnutls_certificate_set_x509_key_file(gnutls_cert_creds, GNUTLS_CERT_PATH, GNUTLS_KEY_PATH, GNUTLS_X509_FMT_PEM) < 0)
+ return 4;
+
+ return 0;
+}
+
+int gnutls_send(void *session, struct string msg) {
+ do {
+ ssize_t res;
+ do {
+ res = gnutls_record_send(*((gnutls_session_t*)session), msg.data, msg.len);
+ } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+
+ if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error
+ return 1;
+ } else if (res > 0) {
+ msg.len -= (size_t)res;
+ msg.data += (size_t)res;
+ }
+ } while (msg.len > 0);
+
+ return 0;
+}
+
+size_t gnutls_recv(void *session, char *data, size_t len, char *err) {
+ ssize_t res;
+ do {
+ res = gnutls_record_recv(*((gnutls_session_t*)session), data, len);
+ } while (res < 0 && (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN));
+
+ if (res < 0) {
+ if (res == -GNUTLS_E_TIMEDOUT) {
+ *err = 1;
+ } else {
+ *err = 3;
+ }
+ return 0;
+ } else if (res == 0) {
+ *err = 2;
+ return 0;
+ }
+ *err = 0;
+
+ return (size_t)res;
+}
+
+int gnutls_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 gnutls_connect_close;
+
+ gnutls_session_t *session;
+ session = malloc(sizeof(*session));
+ if (session == 0)
+ goto gnutls_connect_close;
+ *handle = session;
+
+ if (gnutls_init(session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS)
+ goto gnutls_connect_free_session;
+
+ if (gnutls_server_name_set(*session, GNUTLS_NAME_DNS, address.data, address.len) != GNUTLS_E_SUCCESS)
+ goto gnutls_connect_deinit_session;
+
+ if (gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, gnutls_cert_creds) != GNUTLS_E_SUCCESS)
+ goto gnutls_connect_deinit_session;
+
+ if (gnutls_set_default_priority(*session) != GNUTLS_E_SUCCESS)
+ goto gnutls_connect_deinit_session;
+
+ gnutls_transport_set_int(*session, fd);
+
+ gnutls_handshake_set_timeout(*session, PING_INTERVAL * 1000);
+ gnutls_record_set_timeout(*session, PING_INTERVAL * 1000);
+
+ do {
+ res = gnutls_handshake(*session);
+ } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+ if (res < 0)
+ goto gnutls_connect_deinit_session;
+
+ 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(*session);
+ gnutls_connect_free_session:
+ free(session);
+ gnutls_connect_close:
+ close(fd);
+ return -1;
+}
+
+int gnutls_accept(int listen_fd, void **handle, struct string *addr) {
+ 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;
+
+ addr->data = malloc(address_len);
+ if (addr->data == 0 && address_len != 0)
+ goto gnutls_accept_close;
+
+ memcpy(addr->data, &address, address_len);
+ addr->len = address_len;
+
+ gnutls_session_t *session;
+ session = malloc(sizeof(*session));
+ if (!session)
+ goto gnutls_accept_free_addr_data;
+ *handle = session;
+
+ if (gnutls_init(session, GNUTLS_SERVER) != GNUTLS_E_SUCCESS)
+ goto gnutls_accept_free_session;
+
+ if (gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, gnutls_cert_creds) != GNUTLS_E_SUCCESS)
+ goto gnutls_accept_deinit_session;
+
+ if (gnutls_set_default_priority(*session) != GNUTLS_E_SUCCESS)
+ goto gnutls_accept_deinit_session;
+
+ gnutls_transport_set_int(*session, con_fd);
+
+ gnutls_handshake_set_timeout(*session, PING_INTERVAL * 1000);
+ gnutls_record_set_timeout(*session, PING_INTERVAL * 1000);
+
+ int res;
+ do {
+ res = gnutls_handshake(*session);
+ } while (res == -GNUTLS_E_INTERRUPTED || res == -GNUTLS_E_AGAIN);
+ if (res != GNUTLS_E_SUCCESS)
+ goto gnutls_accept_deinit_session;
+
+ return con_fd;
+
+ gnutls_accept_deinit_session:
+ gnutls_deinit(*session);
+ gnutls_accept_free_session:
+ free(session);
+ gnutls_accept_free_addr_data:
+ free(addr->data);
+ gnutls_accept_close:
+ close(con_fd);
+ return -1;
+}
+
+void gnutls_close(int fd, void *handle) {
+ gnutls_deinit(*((gnutls_session_t*)handle));
+ free(handle);
+ close(fd);
+}
diff --git a/gnutls_network.h b/gnutls_network.h
new file mode 100644
index 0000000..c70f2e3
--- /dev/null
+++ b/gnutls_network.h
@@ -0,0 +1,44 @@
+// 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_network(void);
+
+int gnutls_send(void *fd, struct string msg);
+size_t gnutls_recv(void *fd, char *data, size_t len, char *err);
+
+int gnutls_connect(void **handle, struct string address, struct string port, struct string *addr_out);
+int gnutls_accept(int listen_fd, void **handle, struct string *addr);
+
+void gnutls_close(int fd, void *handle);
diff --git a/haxstring.h b/haxstring.h
new file mode 100644
index 0000000..f78c343
--- /dev/null
+++ b/haxstring.h
@@ -0,0 +1,43 @@
+// Hax's strings
+//
+// 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>
+
+struct string {
+ char *data;
+ size_t len;
+};
+
+#define STRING(x) (struct string){x, sizeof(x)-1}
+#define NULSTR(x) (struct string){x, strlen(x)}
+
+#define STRING_EQ(x, y) (x.len == y.len && memcmp(x.data, y.data, x.len) == 0)
+
+#define WRITES(x, y) write(x, y.data, y.len)
diff --git a/haxstring_utils.c b/haxstring_utils.c
new file mode 100644
index 0000000..2fed747
--- /dev/null
+++ b/haxstring_utils.c
@@ -0,0 +1,75 @@
+// Hax's string utils
+//
+// 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 <stddef.h>
+
+#include "haxstring.h"
+#include "haxstring_utils.h"
+
+size_t str_to_unsigned(struct string str, char *err) {
+ if (str.len == 0) {
+ *err = 1;
+ return 0;
+ }
+
+ size_t val = 0;
+ while (str.len > 0) {
+ switch(str.data[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (val > ((size_t)-1)/10) {
+ *err = 1;
+ return 0;
+ }
+ val *= 10;
+ if (val > (-((size_t)((unsigned char)str.data[0] - 0x30) + 1))) {
+ *err = 1;
+ return 0;
+ }
+ val += (unsigned char)str.data[0] - 0x30;
+ break;
+ default:
+ *err = 1;
+ return 0;
+ }
+
+ str.data++;
+ str.len--;
+ }
+
+ *err = 0;
+ return val;
+}
diff --git a/haxstring_utils.h b/haxstring_utils.h
new file mode 100644
index 0000000..5023141
--- /dev/null
+++ b/haxstring_utils.h
@@ -0,0 +1,34 @@
+// Header for hax's string utils
+//
+// 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"
+
+size_t str_to_unsigned(struct string str, char *err);
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..51f40b7
--- /dev/null
+++ b/main.c
@@ -0,0 +1,125 @@
+// "Main" file 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 <signal.h>
+#include <pthread.h>
+
+#include "config.h"
+#include "general_network.h"
+#include "main.h"
+
+#ifdef USE_PLAINTEXT
+#include "plaintext_network.h"
+#endif
+#ifdef USE_GNUTLS
+#include "gnutls_network.h"
+#endif
+#ifdef USE_OPENSSL
+#include "openssl_network.h"
+#endif
+
+#ifdef USE_SERVER
+#include "server_network.h"
+#endif
+#ifdef USE_CLIENT
+#include "client_network.h"
+#endif
+
+#ifdef USE_INSPIRCD2_PROTOCOL
+#include "protocols/inspircd2.h"
+#endif
+
+pthread_attr_t pthread_attr;
+pthread_mutexattr_t pthread_mutexattr;
+
+pthread_mutex_t state_lock = PTHREAD_MUTEX_INITIALIZER;
+
+int main(void) {
+ if (init_general_network() != 0)
+ return 1;
+
+#ifdef USE_SERVER
+ if (init_server_network() != 0)
+ return 1;
+#endif
+
+#ifdef USE_CLIENT
+ if (init_client_network() != 0)
+ return 1;
+#endif
+
+#ifdef USE_PLAINTEXT
+ if (init_plaintext_network() != 0) // there's not really anything to do ahead of time with plain tcp networking, this is just here for consistency (and will probably be optimized out by the compiler)
+ return 1;
+#endif
+
+#ifdef USE_GNUTLS
+ if (init_gnutls_network() != 0)
+ return 1;
+#endif
+
+#ifdef USE_OPENSSL
+ if (init_openssl_network() != 0)
+ return 1;
+#endif
+
+#ifdef USE_INSPIRCD2_PROTOCOL
+ if (init_inspircd2_protocol() != 0)
+ return 1;
+#endif
+
+ {
+ struct sigaction tmp = {
+ .sa_handler = SIG_IGN,
+ };
+ sigaction(SIGPIPE, &tmp, 0);
+ }
+
+ if (pthread_attr_init(&pthread_attr) != 0)
+ return 1;
+
+ if (pthread_mutexattr_init(&pthread_mutexattr) != 0)
+ return 1;
+
+ if (pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED) != 0) // shouldn't actually happen
+ return 1;
+
+#ifdef USE_CLIENT
+ if (start_client_network() != 0)
+ return 1;
+#endif
+
+#ifdef USE_SERVER
+ if (start_server_network() != 0)
+ return 1;
+#endif
+
+ pthread_exit(0);
+
+ return 0;
+}
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..44e05e1
--- /dev/null
+++ b/main.h
@@ -0,0 +1,34 @@
+// 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
+
+extern pthread_attr_t pthread_attr;
+extern pthread_mutexattr_t pthread_mutexattr;
+
+extern pthread_mutex_t state_lock;
+
+int main(void);
diff --git a/openssl_network.c b/openssl_network.c
new file mode 100644
index 0000000..60b2189
--- /dev/null
+++ b/openssl_network.c
@@ -0,0 +1,379 @@
+// 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>
+
+#include "config.h"
+#include "main.h"
+#include "openssl_network.h"
+
+struct openssl_handle {
+ SSL *ssl;
+ pthread_mutex_t mutex;
+ int fd;
+};
+
+SSL_CTX *openssl_ctx;
+
+int init_openssl_network(void) {
+ SSL_library_init();
+
+ openssl_ctx = SSL_CTX_new(TLS_method());
+ if (SSL_CTX_use_certificate_file(openssl_ctx, OPENSSL_CERT_PATH, SSL_FILETYPE_PEM) != 1)
+ return 1;
+ if (SSL_CTX_use_PrivateKey_file(openssl_ctx, OPENSSL_KEY_PATH, SSL_FILETYPE_PEM) != 1)
+ return 1;
+
+ if (OPENSSL_USE_SYSTEM_TRUST) {
+ if (SSL_CTX_set_default_verify_paths(openssl_ctx) != 1) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int openssl_send(void *handle, struct string msg) {
+ struct openssl_handle *openssl_handle = handle;
+
+ pthread_mutex_lock(&(openssl_handle->mutex));
+
+ struct pollfd pollfd = {
+ .fd = openssl_handle->fd,
+ };
+ int res;
+ do {
+ res = SSL_write(openssl_handle->ssl, msg.data, msg.len);
+ 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_send_error_unlock;
+ }
+ } else {
+ break;
+ }
+
+ res = poll(&pollfd, 1, -1); // TODO: What if the buffer is never ready? But openssl demands that the send buffer remain unchanged...
+ if (res < 0) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ goto openssl_send_error_unlock;
+ }
+ }
+ if (res == 0) // Shouldn't actually happen, but checking anyways
+ goto openssl_send_error_unlock;
+ if ((pollfd.revents & (POLLIN | POLLOUT)) == 0) // Only errors returned
+ goto openssl_send_error_unlock;
+ } while (1);
+
+ pthread_mutex_unlock(&(openssl_handle->mutex));
+ return 0;
+
+ openssl_send_error_unlock:
+ pthread_mutex_unlock(&(openssl_handle->mutex));
+ return 1;
+}
+
+size_t openssl_recv(void *handle, char *data, size_t len, char *err) {
+ struct openssl_handle *openssl_handle = handle;
+
+ struct pollfd pollfd = {
+ .fd = openssl_handle->fd,
+ };
+ int res;
+ do {
+ pthread_mutex_lock(&(openssl_handle->mutex));
+ res = SSL_read(openssl_handle->ssl, data, len);
+ pthread_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_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_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_ctx);
+ if (!openssl_handle->ssl)
+ goto openssl_connect_free_openssl_handle;
+ SSL_set_fd(openssl_handle->ssl, fd);
+
+ res = pthread_mutex_init(&(openssl_handle->mutex), &(pthread_mutexattr));
+ 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);
+
+ return fd;
+
+ openssl_connect_destroy_mutex:
+ pthread_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_accept(int listen_fd, void **handle, struct string *addr) {
+ 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_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_ctx);
+ if (!openssl_handle->ssl)
+ goto openssl_accept_free_openssl_handle;
+
+ SSL_set_fd(openssl_handle->ssl, con_fd);
+
+ int res = pthread_mutex_init(&(openssl_handle->mutex), &(pthread_mutexattr));
+ 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);
+
+ return con_fd;
+
+ openssl_accept_destroy_mutex:
+ pthread_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_close(int fd, void *handle) {
+ struct openssl_handle *openssl_handle = handle;
+ pthread_mutex_destroy(&(openssl_handle->mutex));
+ SSL_free(openssl_handle->ssl);
+ free(openssl_handle);
+ close(fd);
+}
diff --git a/openssl_network.h b/openssl_network.h
new file mode 100644
index 0000000..83f0432
--- /dev/null
+++ b/openssl_network.h
@@ -0,0 +1,44 @@
+// 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_network(void);
+
+int openssl_send(void *handle, struct string msg);
+size_t openssl_recv(void *handle, char *data, size_t len, char *err);
+
+int openssl_connect(void **handle, struct string address, struct string port, struct string *addr_out);
+int openssl_accept(int listen_fd, void **handle, struct string *addr);
+
+void openssl_close(int fd, void *handle);
diff --git a/plaintext_network.c b/plaintext_network.c
new file mode 100644
index 0000000..ce040ce
--- /dev/null
+++ b/plaintext_network.c
@@ -0,0 +1,168 @@
+// 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "general_network.h"
+#include "haxstring.h"
+#include "plaintext_network.h"
+
+int init_plaintext_network(void) {
+ return 0;
+}
+
+int plaintext_send(void *fd, struct string msg) {
+ do {
+ ssize_t res;
+ do {
+ res = send(*((int*)fd), msg.data, msg.len, 0);
+ } while (res == -1 && (errno == EINTR));
+
+ if (res < 0 || (size_t)res > msg.len) { // res > len shouldn't be possible, but is still an error
+ return 1;
+ } else if (res > 0) {
+ msg.len -= (size_t)res;
+ msg.data += (size_t)res;
+ }
+ } while (msg.len > 0);
+
+ return 0;
+}
+
+size_t plaintext_recv(void *fd, char *data, size_t len, char *err) {
+ ssize_t res;
+ do {
+ res = recv(*((int*)fd), data, len, 0);
+ } while (res == -1 && (errno == EINTR));
+
+ if (res == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ *err = 1;
+ } else {
+ *err = 3;
+ }
+ return 0;
+ } else if (res == 0) {
+ *err = 2;
+ return 0;
+ }
+ *err = 0;
+
+ return (size_t)res;
+}
+
+int plaintext_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) {
+ close(fd);
+ return -1;
+ }
+
+ *handle = malloc(sizeof(fd));
+ if (!handle) {
+ close(fd);
+ return -1;
+ }
+ *((int*)*handle) = fd;
+
+ addr_out->data = malloc(sizeof(sockaddr));
+ if (!addr_out->data) {
+ free(handle);
+ close(fd);
+ return -1;
+ }
+ memcpy(addr_out->data, &sockaddr, sizeof(sockaddr));
+ addr_out->len = sizeof(sockaddr);
+
+ return fd;
+}
+
+int plaintext_accept(int listen_fd, void **handle, struct string *addr) {
+ 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;
+
+ addr->data = malloc(address_len);
+ if (addr->data == 0 && address_len != 0) {
+ close(con_fd);
+ return -1;
+ }
+
+ memcpy(addr->data, &address, address_len);
+ addr->len = address_len;
+
+ *handle = malloc(sizeof(con_fd));
+ if (!handle) {
+ free(addr->data);
+ close(con_fd);
+ return -1;
+ }
+ *((int*)*handle) = con_fd;
+
+ return con_fd;
+}
+
+void plaintext_close(int fd, void *handle) {
+ free(handle);
+ close(fd);
+}
diff --git a/plaintext_network.h b/plaintext_network.h
new file mode 100644
index 0000000..e30e5ca
--- /dev/null
+++ b/plaintext_network.h
@@ -0,0 +1,44 @@
+// 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_plaintext_network(void);
+
+int plaintext_send(void *fd, struct string msg);
+size_t plaintext_recv(void *fd, char *data, size_t len, char *err);
+
+int plaintext_connect(void **handle, struct string address, struct string port, struct string *addr_out);
+int plaintext_accept(int listen_fd, void **handle, struct string *addr);
+
+void plaintext_close(int fd, void *handle);
diff --git a/protocols.c b/protocols.c
new file mode 100644
index 0000000..eb1e6f4
--- /dev/null
+++ b/protocols.c
@@ -0,0 +1,42 @@
+// 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 "protocols.h"
+
+#ifdef USE_INSPIRCD2_PROTOCOL
+#include "protocols/inspircd2.h"
+#endif
+
+struct protocol protocols[NUM_PROTOCOLS] = {
+#ifdef USE_INSPIRCD2_PROTOCOL
+ [INSPIRCD2_PROTOCOL] = {
+ .handle_connection = inspircd2_protocol_handle_connection,
+ .autoconnect = inspircd2_protocol_autoconnect,
+ },
+#endif
+};
diff --git a/protocols.h b/protocols.h
new file mode 100644
index 0000000..ae06ebf
--- /dev/null
+++ b/protocols.h
@@ -0,0 +1,43 @@
+// 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
+
+struct protocol {
+ void * (*handle_connection)(void *info);
+ void * (*autoconnect)(void *config);
+};
+
+#ifdef USE_HAXIRCD_PROTOCOL
+#define HAXIRCD_PROTOCOL 0
+#endif
+#ifdef USE_INSPIRCD2_PROTOCOL
+#define INSPIRCD2_PROTOCOL 1
+#endif
+
+#define NUM_PROTOCOLS 2
+
+extern struct protocol protocols[NUM_PROTOCOLS];
diff --git a/protocols/inspircd2.c b/protocols/inspircd2.c
new file mode 100644
index 0000000..4bb79c8
--- /dev/null
+++ b/protocols/inspircd2.c
@@ -0,0 +1,341 @@
+// 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 <pthread.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../config.h"
+#include "../general_network.h"
+#include "../haxstring.h"
+#include "../main.h"
+#include "../server_network.h"
+#include "inspircd2.h"
+
+struct table inspircd2_protocol_init_commands = {0};
+struct table inspircd2_protocol_commands = {0};
+
+int init_inspircd2_protocol(void) {
+ inspircd2_protocol_commands.array = malloc(0);
+
+ set_table_index(&inspircd2_protocol_init_commands, STRING("SERVER"), &inspircd2_protocol_init_handle_server);
+// set_table_index(&inspircd2_protocol_commands, STRING("PING"), &inspircd2_protocol_handle_ping);
+
+ return 0;
+}
+
+void * inspircd2_protocol_handle_connection(void *type) {
+ struct string address;
+ size_t net;
+ char is_incoming;
+ int fd;
+ void *handle;
+ struct server_config *config;
+
+ char ready = 0;
+
+ {
+ struct server_connection_info *t = type;
+ address = t->address;
+ fd = t->fd;
+ handle = t->handle;
+ config = t->config;
+ net = t->type->net_type;
+ is_incoming = t->type->is_incoming;
+ if (is_incoming)
+ free(type);
+ }
+
+ struct string full_msg = {.data = malloc(0), .len = 0}; // TODO: move this down below after incoming connections are handled
+
+ if (is_incoming) {
+ WRITES(2, STRING("InspIRCd v2 protocol handling does not yet support incoming connections!\r\n"));
+ goto inspircd2_protocol_handle_connection_close;
+ } else {
+ networks[net].send(handle, STRING("CAPAB START 1202\nCAPAB END\n"));
+
+ networks[net].send(handle, STRING("SERVER "));
+ networks[net].send(handle, SERVER_NAME);
+ networks[net].send(handle, STRING(" "));
+ networks[net].send(handle, config->out_pass);
+ networks[net].send(handle, STRING(" 0 "));
+ networks[net].send(handle, SID);
+ networks[net].send(handle, STRING(" :"));
+ networks[net].send(handle, SERVER_FULLNAME);
+ networks[net].send(handle, STRING("\n"));
+ }
+
+ while (1) {
+ size_t msg_len;
+ size_t old_len;
+ {
+ char data[512];
+ unsigned char timeout = 0;
+ size_t new_len;
+ while (1) {
+ char err;
+ new_len = networks[net].recv(handle, data, sizeof(data), &err);
+ if (err >= 2) { // Connection closed, or some uncorrected error
+ goto inspircd2_protocol_handle_connection_close;
+ } else if (err == 1) { // Timed out
+ if (timeout > 0)
+ goto inspircd2_protocol_handle_connection_close;
+ timeout++;
+ // TODO: Ping the server
+ } else {
+ break;
+ }
+ }
+ old_len = full_msg.len;
+ full_msg.len += new_len;
+ void *tmp = realloc(full_msg.data, full_msg.len);
+ if (!tmp && full_msg.len + new_len != 0)
+ goto inspircd2_protocol_handle_connection_close;
+ full_msg.data = tmp;
+ memcpy(full_msg.data + old_len, data, new_len);
+ }
+
+ while (1) {
+ char found = 0;
+ for (size_t i = old_len; i < full_msg.len; i++) {
+ if (full_msg.data[i] == '\n') {
+ found = 1;
+ msg_len = i;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ old_len = 0;
+
+ struct string line = {.data = full_msg.data, .len = msg_len};
+
+ WRITES(2, STRING("[inspircd2] [server -> us] Got `"));
+ WRITES(2, line);
+ WRITES(2, STRING("'\r\n"));
+
+ size_t offset = 0;
+ while (offset < msg_len && full_msg.data[offset] == ' ')
+ offset++;
+
+ if (msg_len == offset) {
+ WRITES(2, STRING("Protocol violation: empty message.\r\n\n"));
+ goto inspircd2_protocol_handle_connection_close;
+ }
+
+ struct string source;
+ if (full_msg.data[offset] == ':') {
+ source.data = full_msg.data + offset + 1;
+ found = 0;
+ source.len = 0;
+ for (size_t i = offset + 1; i < msg_len; i++) {
+ if (full_msg.data[i] == ' ') {
+ found = 1;
+ source.len = i - offset - 1;
+ offset = i + 1;
+ while (offset < msg_len && full_msg.data[offset] == ' ')
+ offset++;
+ break;
+ }
+ source.len++;
+ }
+ if (source.len == 0) {
+ WRITES(2, STRING("Protocol violation: source prefix but no source.\r\n\n"));
+ goto inspircd2_protocol_handle_connection_close;
+ }
+ if (!found || offset >= msg_len) {
+ WRITES(2, STRING("Protocol violation: source but no command.\r\n\n"));
+ goto inspircd2_protocol_handle_connection_close;
+ }
+ } else {
+ source = (struct string){0};
+ }
+
+ struct string command;
+ command.data = full_msg.data + offset;
+ found = 0;
+ for (size_t i = offset; i < msg_len; i++) {
+ if (full_msg.data[i] == ' ') {
+ found = 1;
+ command.len = i - offset;
+ offset = i + 1;
+ while (offset < msg_len && full_msg.data[offset] == ' ')
+ offset++;
+ break;
+ }
+ }
+ if (!found) {
+ command.len = msg_len - offset;
+ offset = msg_len;
+ }
+
+ size_t argc = 0;
+ size_t old_offset = offset;
+ while (offset < msg_len) {
+ if (full_msg.data[offset] == ':') {
+ argc++;
+ break;
+ }
+
+ while (offset < msg_len && full_msg.data[offset] != ' ')
+ offset++;
+
+ argc++;
+
+ while (offset < msg_len && full_msg.data[offset] == ' ')
+ offset++;
+ }
+ offset = old_offset;
+
+ struct string argv[argc]; // TODO: Maybe dynamically allocate this if it exceeds some number that probably shouldn't be put on the stack
+ for (size_t i = 0; offset < msg_len;) {
+ if (full_msg.data[offset] == ':') {
+ argv[i].data = full_msg.data + offset + 1;
+ argv[i].len = msg_len - offset - 1;
+ break;
+ }
+
+ argv[i].data = full_msg.data + offset;
+ size_t start = offset;
+
+ while (offset < msg_len && full_msg.data[offset] != ' ')
+ offset++;
+
+ argv[i].len = offset - start;
+
+ while (offset < msg_len && full_msg.data[offset] == ' ')
+ offset++;
+
+ i++;
+ }
+
+ WRITES(2, STRING("Source: `"));
+ WRITES(2, source);
+ WRITES(2, STRING("'\r\nCommand: `"));
+ WRITES(2, command);
+ WRITES(2, STRING("'\r\n"));
+ if (argc > 0) {
+ WRITES(2, STRING("Args:\r\n"));
+ for (size_t i = 0; i < argc; i++) {
+ WRITES(2, STRING("\t`"));
+ WRITES(2, argv[i]);
+ WRITES(2, STRING("'\r\n"));
+ }
+ }
+
+ pthread_mutex_lock(&state_lock);
+
+ int (*func)(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming);
+ if (!ready)
+ func = get_table_index(inspircd2_protocol_init_commands, command);
+ else
+ func = get_table_index(inspircd2_protocol_commands, command);
+
+ if (!func) {
+ WRITES(2, STRING("WARNING: Command is unknown, ignoring.\r\n\n"));
+ goto inspircd2_protocol_handle_connection_unlock_next;
+ }
+
+ int res = func(source, argc, argv, handle, is_incoming);
+ if (res < 0) // Disconnect
+ goto inspircd2_protocol_handle_connection_unlock_close;
+ else if (res > 0) // Connection is now "ready"
+ ready = 1;
+
+ inspircd2_protocol_handle_connection_unlock_next:
+ pthread_mutex_unlock(&state_lock);
+ inspircd2_protocol_handle_connection_next:
+ memmove(full_msg.data, full_msg.data + msg_len + 1, full_msg.len - msg_len - 1);
+ full_msg.len -= msg_len + 1;
+ void *tmp = realloc(full_msg.data, full_msg.len);
+ if (tmp || full_msg.len == 0)
+ full_msg.data = tmp;
+ }
+ }
+
+ inspircd2_protocol_handle_connection_unlock_close:
+ pthread_mutex_unlock(&state_lock);
+ inspircd2_protocol_handle_connection_close:
+ free(full_msg.data);
+
+ networks[net].close(fd, handle);
+ free(address.data);
+
+ return 0;
+}
+
+void * inspircd2_protocol_autoconnect(void *tmp) {
+ struct server_config *config = tmp;
+
+ struct server_connection_info *info;
+ info = malloc(sizeof(*info));
+ if (!info)
+ return 0;
+
+ struct server_network_info *type;
+ type = malloc(sizeof(*type));
+ if (!type) {
+ free(info);
+ return 0;
+ }
+
+ type->net_type = config->autoconnect_type;
+ type->protocol = INSPIRCD2_PROTOCOL;
+ type->is_incoming = 0;
+ info->type = type;
+ info->config = config;
+
+ time_t last_time = 0;
+ while (1) {
+ for (time_t current = time(NULL); current < last_time + 60; current = time(NULL))
+ sleep(60 - (current - last_time));
+ last_time = time(NULL);
+
+ info->fd = networks[type->net_type].connect(&(info->handle), config->address, config->port, &(info->address));
+ if (info->fd == -1)
+ continue;
+
+ inspircd2_protocol_handle_connection(info);
+ }
+}
+
+int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming) {
+ if (argc < 5) {
+ WRITES(2, STRING("Invalid SERVER recieved! (Missing parameters)\r\n"));
+ return -1;
+ }
+
+ if (is_incoming) {
+ // TODO: set SID
+ } else {
+ }
+
+ return 0;
+}
diff --git a/protocols/inspircd2.h b/protocols/inspircd2.h
new file mode 100644
index 0000000..45cac84
--- /dev/null
+++ b/protocols/inspircd2.h
@@ -0,0 +1,41 @@
+// 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"
+
+extern struct table inspircd2_protocol_init_commands;
+extern struct table inspircd2_protocol_commands;
+
+int init_inspircd2_protocol(void);
+
+void * inspircd2_protocol_handle_connection(void *type);
+void * inspircd2_protocol_autoconnect(void *type);
+
+int inspircd2_protocol_init_handle_server(struct string source, size_t argc, struct string *argv, void *handle, char is_incoming);
diff --git a/server_network.c b/server_network.c
new file mode 100644
index 0000000..aed6a41
--- /dev/null
+++ b/server_network.c
@@ -0,0 +1,162 @@
+// 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 <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "main.h"
+#include "protocols.h"
+#include "server_network.h"
+
+#ifdef USE_PLAINTEXT_SERVER
+#include "plaintext_network.h"
+#endif
+#ifdef USE_GNUTLS_SERVER
+#include "gnutls_network.h"
+#endif
+
+int init_server_network(void) {
+ return 0;
+}
+
+int start_server_network(void) {
+#ifdef USE_PLAINTEXT_SERVER
+ if (start_server_network_threads(NET_TYPE_PLAINTEXT) != 0)
+ return 1;
+#endif
+#ifdef USE_GNUTLS_SERVER
+ if (start_server_network_threads(NET_TYPE_GNUTLS) != 0)
+ return 1;
+#endif
+#ifdef USE_OPENSSL_SERVER
+ if (start_server_network_threads(NET_TYPE_OPENSSL) != 0)
+ return 1;
+#endif
+
+ pthread_t trash;
+ for (size_t i = 0; i < server_config_len; i++) {
+ if (server_config[i].autoconnect) {
+ if (pthread_create(&trash, &pthread_attr, protocols[server_config[i].protocol].autoconnect, &(server_config[i])) != 0) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int start_server_network_threads(size_t net) {
+ pthread_t trash; // Not actually used, so discard
+ struct server_network_info *type;
+#ifdef USE_INSPIRCD2_PROTOCOL
+ type = malloc(sizeof(*type));
+ if (!type)
+ return 1;
+ type->net_type = net;
+ type->protocol = INSPIRCD2_PROTOCOL;
+ type->is_incoming = 1;
+ if (pthread_create(&trash, &pthread_attr, server_accept_thread, type) != 0) {
+ free(type);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+void * server_accept_thread(void *type) {
+ size_t net;
+ size_t protocol;
+ {
+ struct server_network_info *t = type;
+ net = t->net_type;
+ protocol = t->protocol;
+ }
+
+ // Check if there is actually an incoming server connection configured using this net+protocol, and if not just return from this thread; some excess may have been spawned
+ {
+ char found = 0;
+ for (size_t i = 0; i < server_config_len; i++) {
+ if (server_config[i].protocol == protocol && !(server_config[i].autoconnect)) { // TODO: Don't make autoconnect conflict with incoming connections
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return 0;
+ }
+
+ int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_fd < 0)
+ return 0;
+
+ {
+ int one = 1;
+ setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+ }
+
+ {
+ struct sockaddr_in sockaddr = {
+ .sin_family = AF_INET,
+ };
+
+ sockaddr.sin_port = htons(SERVER_PORTS[net][protocol]);
+ size_t listen_number = SERVER_LISTEN[net][protocol];
+
+ if (bind(listen_fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) != 0)
+ return 0;
+
+ listen(listen_fd, listen_number);
+ }
+
+ while (1) {
+ struct string address;
+ void *con_handle;
+ int con_fd = networks[net].accept(listen_fd, &con_handle, &address);
+ if (con_fd == -1)
+ continue; // TODO: Handle error
+
+ pthread_t trash;
+ struct server_connection_info *info;
+ info = malloc(sizeof(*info));
+ if (!info) {
+ networks[net].close(con_fd, con_handle);
+ continue;
+ }
+ info->address = address;
+ info->type = type;
+ info->fd = con_fd;
+ info->handle = con_handle;
+ if (pthread_create(&trash, &pthread_attr, protocols[protocol].handle_connection, info) != 0) {
+ free(info);
+ networks[net].close(con_fd, con_handle);
+ }
+ }
+}
diff --git a/server_network.h b/server_network.h
new file mode 100644
index 0000000..b07424d
--- /dev/null
+++ b/server_network.h
@@ -0,0 +1,51 @@
+// 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>
+
+struct server_network_info {
+ size_t net_type;
+ size_t protocol;
+ char is_incoming;
+};
+
+struct server_connection_info {
+ struct string address;
+ struct server_config *config;
+ struct server_network_info *type;
+ int fd;
+ void *handle;
+};
+
+int init_server_network(void);
+int start_server_network(void);
+int start_server_network_threads(size_t net);
+
+void * server_accept_thread(void *type);
+
+void * handle_server_thread(void *type);
diff --git a/table.c b/table.c
new file mode 100644
index 0000000..4dc4940
--- /dev/null
+++ b/table.c
@@ -0,0 +1,185 @@
+// My table library thing
+//
+// 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 <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "haxstring.h"
+#include "table.h"
+
+// currently going with a binary lookup...
+
+static inline int compare(struct string a, struct string b) {
+ size_t len;
+ if (a.len > b.len)
+ len = b.len;
+ else
+ len = a.len;
+
+ int val = memcmp(a.data, b.data, len);
+
+ if (val == 0 && a.len != b.len)
+ return 1;
+ else
+ return val;
+}
+
+static inline size_t search(struct table tbl, struct string name, char *exists) {
+ if (tbl.len == 0) {
+ *exists = 0;
+ return 0;
+ }
+
+ size_t low = 0, high = tbl.len - 1;
+
+ size_t mid = high/2;
+
+ while (low != high) {
+ int val = compare(tbl.array[mid].name, name);
+
+ if (val == 0) {
+ *exists = 1;
+ return mid;
+ } else if (val > 0) {
+ low = mid + 1;
+ if (mid > low)
+ break;
+ if (low > high)
+ low = high;
+ } else {
+ high = mid - 1;
+ if (mid < high)
+ break;
+ if (high < low)
+ high = low;
+ }
+
+ mid = low + ((high-low)/2);
+ }
+
+ int val = compare(tbl.array[mid].name, name);
+ if (val > 0) {
+ *exists = 0;
+ return mid+1;
+ } else if (val == 0) {
+ *exists = 1;
+ return mid;
+ } else {
+ *exists = 0;
+ return mid;
+ }
+}
+
+int set_table_index(struct table *tbl, struct string name, void *ptr) {
+ char exists;
+ size_t index = search(*tbl, name, &exists);
+
+ if (index == tbl->len) {
+ void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * (tbl->len+1));
+ if (tmp == 0)
+ return 1;
+
+ tbl->array = tmp;
+
+ tbl->len++;
+ } else if (!exists) {
+ void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * (tbl->len+1));
+ if (tmp == 0)
+ return 1;
+
+ tbl->array = tmp;
+
+ memmove(&(tbl->array[index+1]), &(tbl->array[index]), (tbl->len - index) * sizeof(*(tbl->array)));
+ tbl->len++;
+ } else {
+ tbl->array[index].ptr = ptr;
+
+ return 0; // don't overwrite old allocated name
+ }
+
+ char *data = malloc(name.len);
+ if (data == 0)
+ return 1;
+
+ memcpy(data, name.data, name.len);
+
+ tbl->array[index] = (struct table_index){{data, name.len}, ptr};
+
+ return 0;
+}
+
+void * get_table_index(struct table tbl, struct string name) {
+ char exists;
+ size_t index = search(tbl, name, &exists);
+ if (!exists)
+ return 0;
+
+ return tbl.array[index].ptr;
+}
+
+char has_table_index(struct table tbl, struct string name) {
+ char exists;
+ search(tbl, name, &exists);
+ return exists;
+}
+
+void * remove_table_index(struct table *tbl, struct string name) {
+ char exists;
+ size_t index = search(*tbl, name, &exists);
+
+ if (!exists)
+ return 0;
+
+ void *ptr = tbl->array[index].ptr;
+ free(tbl->array[index].name.data);
+
+ memmove(&(tbl->array[index]), &(tbl->array[index+1]), (tbl->len - index - 1) * sizeof(*(tbl->array)));
+ tbl->len--;
+
+ void *tmp = realloc(tbl->array, sizeof(*(tbl->array)) * tbl->len);
+ if (tmp || (tbl->len == 0))
+ tbl->array = tmp;
+ // else: realloc failed on shrinking... so now we have a table that's allocated a bit too big, not much of an issue
+
+ return ptr;
+}
+
+void clear_table(struct table *tbl) {
+ for (size_t i = 0; i < tbl->len; i++)
+ free(tbl->array[i].name.data);
+
+ tbl->array = realloc(tbl->array, 0);
+ tbl->len = 0;
+}
+
+size_t get_table_offset(struct table tbl, struct string name, char *exists) {
+ return search(tbl, name, exists);
+}
diff --git a/table.h b/table.h
new file mode 100644
index 0000000..5281e5d
--- /dev/null
+++ b/table.h
@@ -0,0 +1,48 @@
+// Header for my table library thing
+//
+// 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 "haxstring.h"
+
+struct table_index {
+ struct string name;
+ void *ptr;
+};
+
+struct table {
+ struct table_index *array;
+ size_t len;
+};
+
+extern int set_table_index(struct table *tbl, struct string name, void *ptr);
+extern void * get_table_index(struct table tbl, struct string name);
+extern char has_table_index(struct table tbl, struct string name);
+extern void * remove_table_index(struct table *tbl, struct string name); // returns same as get_table_index
+extern void clear_table(struct table *tbl);
+extern size_t get_table_offset(struct table tbl, struct string name, char *exists);