aboutsummaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorTest_User <hax@andrewyu.org>2024-06-09 23:03:09 -0400
committerTest_User <hax@andrewyu.org>2024-06-09 23:03:09 -0400
commit6cd6ee27e7dcd80b033186f3b18cd593b75d7403 (patch)
tree8f7639fbb51a08571738c7df340881a2b1fc8ce1 /protocols
downloadhaxircd-6cd6ee27e7dcd80b033186f3b18cd593b75d7403.tar.gz
haxircd-6cd6ee27e7dcd80b033186f3b18cd593b75d7403.zip
In-progress mesh haxserv; still has a lot to write up before it's usable
Diffstat (limited to 'protocols')
-rw-r--r--protocols/inspircd2.c341
-rw-r--r--protocols/inspircd2.h41
2 files changed, 382 insertions, 0 deletions
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);