From fc99d4e88f4040240407dd460b8955933e954de9 Mon Sep 17 00:00:00 2001 From: Alex Denes Date: Tue, 8 Dec 2020 22:20:42 +0000 Subject: [PATCH] WIP: part 2 --- CMakeLists.txt | 39 +++-- config.test | 2 + src/buffer.c | 50 ++++++ src/buffer.h | 32 ++++ src/configuration.c | 45 +++-- src/configuration.h | 8 +- src/connection.c | 96 ++++------- src/connection.h | 35 ++-- src/filesystem.c | 10 +- src/filesystem.h | 11 ++ src/limits.h | 7 +- src/logging.h | 1 + src/main.c | 388 +++++++++++++++++++++++--------------------- src/main.h | 9 +- src/memory.c | 41 +++++ src/memory.h | 31 ++++ src/signal.h | 6 + 17 files changed, 504 insertions(+), 307 deletions(-) create mode 100644 config.test create mode 100644 src/buffer.c create mode 100644 src/buffer.h create mode 100644 src/memory.c create mode 100644 src/memory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 590638f..ad2ea96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,32 +1,37 @@ cmake_minimum_required(VERSION 3.16) project(microircd LANGUAGES C) +add_compile_definitions( + UIRCD_VERSION="2020.10.8-1-beta" +) + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") add_compile_options(-Wall -Wextra -Wformat-overflow=2 -Wformat-security -Winit-self -Wstrict-overflow=2 -Wstringop-overflow=2 -Walloc-zero -Wduplicated-branches -Wduplicated-cond -Wtrampolines -Wfloat-equal -Wshadow -Wunsafe-loop-optimizations -Wparentheses -pedantic -fanalyzer -fstack-check) elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") add_compile_options(-Weverything -pedantic -Wno-padded -Wno-disabled-macro-expansion) endif() -OPTION(CMAKE_BUILD_TYPE "Debug") - -if (CMAKE_BUILD_TYPE EQUAL "Debug") - add_compile_options(-Og) -elseif (CMAKE_BUILD_TYPE EQUAL "Release") - add_compile_options(-O2 -Werror) -endif() - add_executable(uircd - src/main.c - src/net.c + src/buffer.c + src/configuration.c + src/connection.c src/filesystem.c - src/misc.c - src/log.c - src/parsers.c - src/conns.c + src/logging.c + src/main.c + src/memory.c + src/signal.c ) -find_library(UIRC_PATH NAMES uirc libuirc REQUIRED) -find_library(LIBCONFIG_PATH NAMES config libconfig REQUIRED) -target_link_libraries(uircd ${UIRC_PATH} ${LIBCONFIG_PATH}) + +find_library(UIRC_PATH NAMES uirc REQUIRED) +find_library(LIBCONFIG_PATH NAMES config) +if(NOT LIBCONFIG_PATH) + message(WARNING "libconfig not found. uIRCd will not support configuration files") +else() + message(STATUS "Building with libconfig support") + add_compile_definitions(UIRCD_FEATURE_LIBCONFIG) + target_link_libraries(uircd ${LIBCONFIG_PATH}) +endif() +target_link_libraries(uircd ${UIRC_PATH}) set_property(TARGET uircd PROPERTY C_STANDARD 99) install(TARGETS uircd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/config.test b/config.test new file mode 100644 index 0000000..e649a68 --- /dev/null +++ b/config.test @@ -0,0 +1,2 @@ +address = "41.157.98.109"; +service = "9006"; diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..7e303b7 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,50 @@ +/* + * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) + * Copyright (c) 2019, 2020 Alex-David Denes + * + * uIRCd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * uIRCd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with uIRCd. If not, see . + */ + +#include "buffer.h" + +ssize_t get_buffer_line(char* buf, IRC_Message* parsed) +{ + if (buf == NULL || parsed == NULL) return -1; + char* ppoi; + if ((ppoi = strchr(buf, '\n')) != NULL) { + *ppoi = '\0'; + if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0'; + LOG(LOG_DEBUG, "Got IRC message: %s", buf); + if (Tok_mesg(buf, parsed) == 1) return ++ppoi - buf; + LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812)."); + return -1; + } + return 0; +} + +ssize_t flush_buffer(char* buf, size_t buflen, int fd) +{ + ssize_t res; + char* pos = buf; + for (;;) { + if ((size_t)(res = write(fd, pos, buflen - (size_t)(pos - buf))) != buflen - (size_t)(pos - buf)) { + if (res == -1 && errno != EINTR) + return -1; + else + pos += res; + } else + return res; + } +} + diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..8cdbb62 --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,32 @@ +/* + * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) + * Copyright (c) 2019, 2020 Alex-David Denes + * + * uIRCd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * uIRCd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with uIRCd. If not, see . + */ + +#include "logging.h" + +#include +#include +#include +#include + +#define UIRC_IRCV3 +#define UIRC_HELPERS +#include + +ssize_t get_buffer_line(char* buf, IRC_Message* parsed); +ssize_t flush_buffer(char* buf, size_t buflen, int fd); + diff --git a/src/configuration.c b/src/configuration.c index fd6b6c2..c64adf7 100644 --- a/src/configuration.c +++ b/src/configuration.c @@ -18,6 +18,7 @@ #include "configuration.h" +#ifdef UIRCD_FEATURE_LIBCONFIG int parse_configfile(char* config_path, Connection* conn) { config_t conf; @@ -25,21 +26,27 @@ int parse_configfile(char* config_path, Connection* conn) config_setting_t* setting; config_init(&conf); if (config_read_file(&conf, config_path)) { - // TODO: Confirm empty paths work - if ((setting = config_lookup(&conf, "")) != NULL) { + if ((setting = config_lookup(&conf, ".")) != NULL) { + // TODO: Add all options here struct maps { const char* str; - const char** save; + char** save; } maps[] = { - {"address", &conn->data.addr}, {"port", &conn->data.port}, {"password", &conn->data.pass}, - {"channels", &conn->data.chans}, {"name.nick", &conn->names.nick}, {"name.user", &conn->names.user}, - {"name.real", &conn->names.real}, + {"address", &conn->data.address}, + {"service", &conn->data.service}, + {"quitmsg", &conn->data.quitmsg}, + {"logdir", &conn->data.path}, }; for (unsigned long i = 0; i < sizeof(maps) / sizeof(*maps); i++) { const char* var = NULL; config_setting_lookup_string(setting, maps[i].str, &var); - *maps[i].save = var; - LOG(LOG_DEBUG, "Saved %s to %p", var, (void*)*maps[i].save); + if (var != NULL) { + if (allocate_copy(maps[i].save, var)) { + LOG(LOG_DEBUG, "Saved %s to %p", var, (const void*)maps[i].save); + } else { + LOG(LOG_WARN, "Failed to allocate memory to save config variable %s = %s", maps[i].str, var); + } + } } res = 1; } @@ -49,16 +56,20 @@ int parse_configfile(char* config_path, Connection* conn) config_destroy(&conf); return res; } +#endif -void set_conn_defaults(Connection* conn) +int set_config_defaults(Connection* conn) { - struct defaults { - const char** var; - const char* def; - } defs[] = { - {&conn->data.addr, UIRCD_DEFAULT_ADDR}, {&conn->data.port, UIRCD_DEFAULT_PORT}, {&conn->names.nick, UIRCD_DEFAULT_NICK}, - {&conn->names.user, UIRCD_DEFAULT_USER}, {&conn->names.real, UIRCD_DEFAULT_REAL}, + struct { + char** var; + char* def; + } defsalloc[] = { + {&conn->data.address, UIRCD_DEFAULT_ADDR}, {&conn->data.service, UIRCD_DEFAULT_PORT}, {&conn->data.quitmsg, UIRCD_DEFAULT_QUITMSG}, + {&conn->user.nickname, UIRCD_DEFAULT_NICK}, {&conn->user.username, UIRCD_DEFAULT_USER}, {&conn->user.realname, UIRCD_DEFAULT_REAL}, }; - for (unsigned int i = 0; i < sizeof(defs) / sizeof(*defs); i++) - if (defs[i].var == NULL) *defs[i].var = defs[i].def; + for (unsigned int i = 0; i < sizeof(defsalloc) / sizeof(*defsalloc); i++) { + if (!allocate_copy(defsalloc[i].var, defsalloc[i].def)) return 0; + } + return 1; } + diff --git a/src/configuration.h b/src/configuration.h index af25595..1a7ace8 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -18,6 +18,7 @@ #include "connection.h" #include "logging.h" +#include "memory.h" #include @@ -29,10 +30,13 @@ #define UIRCD_DEFAULT_NICK "uirc-user" #define UIRCD_DEFAULT_USER "uIRC-user" #define UIRCD_DEFAULT_REAL "uIRC user" +#define UIRCD_DEFAULT_QUITMSG "uIRCd " UIRCD_VERSION -void parse_cmdline_conn(char* arg, Connection* conn); +#ifdef UIRCD_FEATURE_LIBCONFIG int parse_configfile(char* config_path, Connection* conn); -void set_conn_defaults(Connection* conn); +#endif /* UIRCD_FEATURE_LIBCONFIG */ + +int set_config_defaults(Connection* conn); #endif /* UIRCD_GUARD_CONFIGURATION */ diff --git a/src/connection.c b/src/connection.c index 454e878..2249343 100644 --- a/src/connection.c +++ b/src/connection.c @@ -18,25 +18,24 @@ #include "connection.h" -signed int init_conn(Connection* info) +signed int init_connection(Connection* info) { int sockfd, getaddrres, connectres; - if (info->data.addr == NULL) return INIT_HARDFAIL; struct addrinfo* conn; - if ((getaddrres = getaddrinfo(info->data.addr, info->data.port, NULL, &conn)) != 0) { + if ((getaddrres = getaddrinfo(info->data.address, info->data.service, NULL, &conn)) != 0) { freeaddrinfo(conn); if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) { - LOG(LOG_ERROR, "Failed to get address info for " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, + LOG(LOG_ERROR, "Failed to get address info for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, gai_strerror(getaddrres), getaddrres); return INIT_HARDFAIL; } else { - LOG(LOG_WARN, "Failed to get address info for " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, + LOG(LOG_WARN, "Failed to get address info for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, gai_strerror(getaddrres), getaddrres); return INIT_SOFTFAIL; } } if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) { - LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, strerror(errno), errno); + LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno); freeaddrinfo(conn); return INIT_HARDFAIL; } @@ -44,10 +43,10 @@ signed int init_conn(Connection* info) close(sockfd); freeaddrinfo(conn); if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) { - LOG(LOG_ERROR, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, strerror(errno), errno); + LOG(LOG_ERROR, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno); return INIT_HARDFAIL; } else { - LOG(LOG_WARN, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, strerror(errno), errno); + LOG(LOG_WARN, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno); return INIT_SOFTFAIL; } } @@ -64,9 +63,9 @@ int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", message->args[0]); if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(message->args[0], NULL), sizeof(buf->buffer))) > 0) if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { - LOG(LOG_WARN, "Couldn't pong " ADDRFMT ". " ERRNOFMT, connection->data.addr, connection->data.port, + LOG(LOG_WARN, "Couldn't pong " ADDRFMT ". " ERRNOFMT, connection->data.address, connection->data.service, strerror(errno), errno); - connection->state = CONN_RECONNECTING; + connection->info.state = CONN_RECONNECTING; return 0; } break; @@ -74,26 +73,23 @@ int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* case (PONG): { if (message->trailing && message->args[1] != NULL) { LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]); - connection->lastpong = ctime; + connection->info.l_pong = ctime; } break; } - /* Autojoin channels from current connection on first response from the server - * TODO: Split channels and join X channels each - * This most likely is not required unless the user has loooots of channels. - * If you are that type of user, you are free to add that case - */ + /* Autojoin channels from current connection on first response from the server */ case (RPL_WELCOME): { - LOG(LOG_INFO, "Connection established to " ADDRFMT ".", connection->data.addr, connection->data.port); - connection->state = CONN_ACTIVE; - if (connection->data.chans != NULL) { - LOG(LOG_VERBOSE, "Auto-joining channels \"%s\" on " ADDRFMT ".", connection->data.chans, connection->data.addr, - connection->data.port); - if ((len = Assm_mesg(buf->buffer, Assm_cmd_JOIN(connection->data.chans, NULL), sizeof(buf->buffer))) > 0) { + LOG(LOG_INFO, "Connection established to " ADDRFMT ".", connection->data.address, connection->data.service); + connection->info.state = CONN_ACTIVE; + for (unsigned int i = 0; connection->data.channels != NULL && connection->data.channels[i] != NULL; i++) { + LOG(LOG_VERBOSE, "Auto-joining channel \"%s\" on " ADDRFMT ".", connection->data.channels[i]->name, connection->data.address, + connection->data.service); + if ((len = Assm_mesg(buf->buffer, Assm_cmd_JOIN(connection->data.channels[i]->name, NULL), sizeof(buf->buffer))) > 0) { if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { - LOG(LOG_WARN, "Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT, connection->data.chans, - connection->data.addr, connection->data.port, strerror(errno), errno); - connection->state = CONN_RECONNECTING; + LOG(LOG_WARN, "Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT, + connection->data.channels[i]->name, connection->data.address, connection->data.service, strerror(errno), + errno); + connection->info.state = CONN_RECONNECTING; return 0; } } @@ -103,21 +99,21 @@ int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* /* case (CAP): { if (message->args[1] != NULL && strcmp(message->args[1], "LS") == 0) { - LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], connection->data.addr, + LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], connection->data.address, connection->data.port); if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(message->args[2]), sizeof(buf->buffer))) > 0) { if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, message->args[2], - connection->data.addr, connection->data.port, strerror(errno), errno); + connection->data.address, connection->data.port, strerror(errno), errno); connection->state = CONN_RECONNECTING; return 0; } } } else if (message->args[1] != NULL && strcmp(message->args[1], "ACK") == 0) { - LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", connection->data.addr, connection->data.port); + LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", connection->data.address, connection->data.port); if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_END(), sizeof(buf->buffer))) > 0) { if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { - LOG(LOG_WARN, "Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT, connection->data.addr, + LOG(LOG_WARN, "Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT, connection->data.address, connection->data.port, strerror(errno), errno); connection->state = CONN_RECONNECTING; return 0; @@ -128,54 +124,26 @@ int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* } */ case (ERROR): { - LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", connection->data.addr, - connection->data.port, message->args[0]); + LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", connection->data.address, + connection->data.service, message->args[0]); break; } case (ERR_NICKNAMEINUSE): case (ERR_NICKCOLLISION): { - LOG(LOG_ERROR, "Nickname %s is already taken on " ADDRFMT ".", connection->names.nick, connection->data.addr, - connection->data.port); - connection->state = CONN_RECONNECTING; + LOG(LOG_ERROR, "Nickname %s is already taken on " ADDRFMT ".", connection->user.nickname, connection->data.address, + connection->data.service); + connection->info.state = CONN_RECONNECTING; break; } } return 1; } -ssize_t get_buffer_line(char* buf, IRC_Message* parsed) -{ - if (buf == NULL || parsed == NULL) return -1; - char* ppoi; - if ((ppoi = strchr(buf, '\n')) != NULL) { - *ppoi = '\0'; - if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0'; - LOG(LOG_DEBUG, "Got IRC message: %s", buf); - if (Tok_mesg(buf, parsed) == 1) return ++ppoi - buf; - LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812)."); - return -1; - } - return 0; -} - -ssize_t flush_buffer(char* buf, size_t buflen, int fd) -{ - ssize_t res; - char* pos = buf; - for (;;) { - if ((size_t)(res = write(fd, pos, buflen - (size_t)(pos - buf))) != buflen - (size_t)(pos - buf)) { - if (res == -1 && errno != EINTR) - return -1; - else - pos += res; - } else - return res; - } -} ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn) { int len = 0; - if ((len = snprintf(buf, maxlen, "%s.%s", conn->data.addr, conn->data.port)) <= 0) return -1; + LOG(LOG_DEBUG, "Preparing path: " ADDRFMT, conn->data.address, conn->data.service); + if ((len = snprintf(buf, maxlen, "%s.%s", conn->data.address, conn->data.service)) <= 0) return -1; return len; } diff --git a/src/connection.h b/src/connection.h index 63fd81f..78ecc86 100644 --- a/src/connection.h +++ b/src/connection.h @@ -16,11 +16,14 @@ * along with uIRCd. If not, see . */ +#include "buffer.h" #include "limits.h" #include "logging.h" #include +#include #include +#include #include #include #include @@ -44,28 +47,40 @@ #define CONN_CLOSED -3 typedef struct { - const char *addr, *port, *chans, *pass; -} Connection_Data; + char* name; + bool joined; +} Channel; + typedef struct { - const char *nick, *user, *real; + char *address, *service, *quitmsg, *path; + Channel** channels; + time_t timeout; +} Connection_Data; + +typedef struct { + char *nickname, *username, *realname, *password; } Connection_User; + +typedef struct { + time_t l_ping, l_pong, l_connect, l_message; + signed short state; +} Connection_Info; + typedef struct { char buffer[UIRCD_LIMITS_LINE + 1]; size_t append_pos; int fd; } Buffer_Info; + typedef struct { - Connection_User names; + Connection_User user; Connection_Data data; - const char *quitmsg, *path; - unsigned long timeout; - signed short state; - time_t lastping, lastpong, lastconnect, lastmessage; + Connection_Info info; } Connection; signed int init_connection(Connection* info); -ssize_t flush_buffer(char* buf, size_t buflen, int fd); -ssize_t get_buffer_line(char* buf, IRC_Message* parsed); +int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf); ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn); #endif /* UIRCD_GUARD_CONNECTION */ + diff --git a/src/filesystem.c b/src/filesystem.c index 6635883..2d70606 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -44,6 +44,7 @@ int makeinput(char* path) { if (path == NULL) return -1; int tmp; + LOG(LOG_DEBUG, "Creating FIFO at %s", path); if ((tmp = mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP)) == 0) { LOG(LOG_VERBOSE, "Created a FIFO pipe for input at %s.", path); } else if (errno != EEXIST) { @@ -101,20 +102,20 @@ bool add_socket_flags(int fd, int flags) ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf* buf) { + // TODO: Fix this if (buf == NULL || buf->elements[nth_elem].bufpos == NULL) return -1; size_t totallen = 0; - for (unsigned long i = 0; i < sizeof(buf->elements) / sizeof(PathBufElem) && buf->elements[i].len > 0; i++) totallen += buf->elements[i].len; + for (unsigned long i = 0; i < sizeof(buf->elements) / sizeof(*buf->elements) && buf->elements[i].len > 0; i++) totallen += buf->elements[i].len; ssize_t temp; if ((temp = snprintf(buf->elements[nth_elem].bufpos, sizeof(buf->buf) - totallen, (isdir) ? "%s/" : "%s", content)) == -1) return -2; buf->elements[nth_elem].len = (size_t)temp; - if (nth_elem < sizeof(buf->elements) / sizeof(PathBufElem)) { + if (nth_elem < sizeof(buf->elements) / sizeof(*buf->elements)) { buf->elements[nth_elem + 1].bufpos = buf->elements[nth_elem].bufpos + temp; buf->elements[nth_elem + 1].len = 0; } return temp; } -/* TODO: Put this somewhere else and improve it signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connection* conn) { if (message == NULL || pathbuffer == NULL) return -2; @@ -143,7 +144,7 @@ signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connectio elements[1].isdir = false; } else if (ISCMD(PRIVMSG) || ISCMD(NOTICE)) { if (message->args[0] == NULL) return -2; - if (strcmp(conn->names.nick, message->args[0]) == 0 && message->name.nick != NULL) { + if (strcmp(conn->user.nickname, message->args[0]) == 0 && message->name.nick != NULL) { elements[0].name = reused_strings[1]; strncpy(temp, message->name.nick, sizeof(temp)); } else if (*message->args[0] == '#' || *message->args[0] == '&' || *message->args[0] == '+' || *message->args[0] == '!') { @@ -170,5 +171,4 @@ signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connectio } return -1; } -*/ diff --git a/src/filesystem.h b/src/filesystem.h index 57e1578..348b4eb 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -35,6 +35,8 @@ #ifndef UIRCD_GUARD_FILESYSTEM #define UIRCD_GUARD_FILESYSTEM +#define ISCMD(CMD) (message->cmd == (CMD)) + typedef struct { char* bufpos; size_t len; @@ -44,4 +46,13 @@ typedef struct { PathBufElem elements[5]; } PathBuf; +int mkdir_bottomup(char* path); +int makeinput(char* path); +bool write_log(char* path, char* message); +bool cleanup_path_names(char* name); +bool add_socket_flags(int fd, int flags); +ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf* buf); +signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connection* conn); + #endif /* UIRCD_GUARD_FILESYSTEM */ + diff --git a/src/limits.h b/src/limits.h index 459997b..2d07525 100644 --- a/src/limits.h +++ b/src/limits.h @@ -19,9 +19,10 @@ #ifndef UIRCD_GUARD_LIMITS #define UIRCD_GUARD_LIMITS +/* Lenght limits */ +#define UIRCD_LIMITS_HOST HOST_NAME_MAX +#define UIRCD_LIMITS_PATH PATH_MAX #define UIRCD_LIMITS_LINE 512 -#define UIRCD_LIMITS_NICK 32 -#define UIRCD_LIMITS_USER 32 -#define UIRCD_LIMITS_REAL 32 #endif /* UIRCD_GUARD_LIMITS */ + diff --git a/src/logging.h b/src/logging.h index e63d56f..12c90d9 100644 --- a/src/logging.h +++ b/src/logging.h @@ -38,3 +38,4 @@ extern const char logchars[]; extern int loglevel; #endif /* UIRCD_GUARD_LOGGING */ + diff --git a/src/main.c b/src/main.c index 764fdd6..e43413a 100644 --- a/src/main.c +++ b/src/main.c @@ -18,138 +18,153 @@ #include "main.h" -int main(int argc, char* argv[]) +int parse_args(int argc, char** argv, Connection* conn) { - Connection connection; - /* Arguments: - * -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ] - * -l Starting directory for message tree - * -m Message sent on closing the bouncer gracefully - * -t Timeout duration (seconds) - * -V Log level: 0 being FATAL and 5 being DEBUG - * -C Configuration file path - * -v Version and license information - * -h Help/Usage - */ int c; - while ((c = getopt(argc, argv, "C:m:c:l:t:j:V:vh")) != -1) { + while ((c = getopt(argc, argv, + "V:d:a:p:t:N:U:R:P:q:c:" +#ifdef UIRCD_FEATURE_LIBCONFIG + "C:" +#endif /* UIRCD_FEATURE_LIBCONFIG */ + "vh")) + != -1) { switch (c) { - case 'c': { - /* NOTE: PASS and capabilities cannot be provided via the command line (per-connection). - * Consider using the configuration file. */ - parse_cmdline_conn(optarg, &connection); - break; - } - case 'l': { - int tmpres; - if ((tmpres = chdir(optarg)) != 0) { - LOG(LOG_FATAL, "Couldn't change log directory to %s. " ERRNOFMT, optarg, strerror(errno), errno); - return EXIT_FAILURE; - } - break; - } - case 'm': connection.quitmsg = optarg; break; - case 't': connection.timeout = (unsigned int)atoi(optarg); break; - case 'C': { - parse_configfile(optarg, &connection); - break; - } case 'V': loglevel = atoi(optarg); break; - case 'v': { - printf("uIRCd version " VERSION "\n"); - return EXIT_SUCCESS; - } - case 'h': { - // TODO: Fix this - struct help { - char arg; - char* desc; - char* def; - } arg_list[] = {{'c', "Define connection in format \"nick!user:real name@host/+port,#channel1,#channel2\"", NULL}, - {'l', "Directory for logs", "current dir"}, - {'m', "Quit message", "uIRC indev beta"}, - {'t', "Timeout duration", "30 seconds"}, - {'V', "Log level (0-5)", "0 [LOG_FATAL]"}, - {'C', "Configuration path", "${XDG_CONFIG_HOME:-~/.config}/uircd/main.conf"}, - {'v', "Print version information", NULL}, - {'h', "Print this help message", NULL}}; - printf("usage: uirc -c [connection] [options...]\n"); - for (size_t i = 0; i < sizeof(arg_list) / sizeof(*arg_list); i++) { - printf(" -%c\t%s", arg_list[i].arg, arg_list[i].desc); - if (arg_list[i].def != NULL) printf(" (default: %s)", arg_list[i].def); - putchar('\n'); - } - return EXIT_SUCCESS; + case 'd': allocate_copy(&conn->data.path, optarg); break; + case 'a': allocate_copy(&conn->data.address, optarg); break; + case 'p': allocate_copy(&conn->data.service, optarg); break; + case 't': conn->data.timeout = (unsigned int)atoi(optarg); break; + case 'N': allocate_copy(&conn->user.nickname, optarg); break; + case 'U': allocate_copy(&conn->user.username, optarg); break; + case 'R': allocate_copy(&conn->user.realname, optarg); break; + case 'P': allocate_copy(&conn->user.password, optarg); break; + case 'q': allocate_copy(&conn->data.quitmsg, optarg); break; + case 'c': { + // TODO: Parse channel arguments + break; } + case 'v': printf("uIRCd version " UIRCD_VERSION); return 0; + case 'h': print_help(); return 0; +#ifdef UIRCD_FEATURE_LIBCONFIG + case 'C': parse_configfile(optarg, conn); break; +#endif /* UIRCD_FEATURE_LIBCONFIG */ } } + return 1; +} - set_conn_defaults(&connection); +void print_help(void) +{ + struct help { + char arg; + char* type; + char* desc; + char* def; + } arg_list[] = {{'a', "host", "Host to connect to (IP/Hostname)", UIRCD_DEFAULT_ADDR}, + {'p', "serv", "Service (port for TCP/UDP)", UIRCD_DEFAULT_PORT}, + {'N', "str", "Nickname for registration", UIRCD_DEFAULT_NICK}, + {'U', "str", "Username for registration", UIRCD_DEFAULT_USER}, + {'R', "str", "Realname for registration", UIRCD_DEFAULT_REAL}, + {'P', "str", "Password for registration", NULL}, + {'d', "str", "Directory for logs", "current dir"}, + {'q', "str", "Quit message", UIRCD_DEFAULT_QUITMSG}, + {'t', "uint", "Timeout duration", "30 seconds"}, + {'V', "int", "Log level", "0 [LOG_FATAL]"}, +#ifdef UIRCD_FEATURE_LIBCONFIG + {'C', "path", "Configuration path", "${XDG_CONFIG_HOME:-~/.config}/uircd/main.conf"}, +#endif /* UIRCD_FEATURE_LIBCONFIG */ + {'v', NULL, "Print version information", NULL}, + {'h', NULL, "Print this help message", NULL}}; + printf("usage: uircd -a [ ... ]\n"); + for (size_t i = 0; i < sizeof(arg_list) / sizeof(*arg_list); i++) { + printf(" -%c", arg_list[i].arg); + if (arg_list[i].type != NULL) printf(" \t%s", arg_list[i].type); + if (arg_list[i].desc != NULL) printf(" \t%s", arg_list[i].desc); + if (arg_list[i].def != NULL) printf(" (default: %s)", arg_list[i].def); + putchar('\n'); + } +} + +int main(int argc, char* argv[]) +{ srand((unsigned int)time(NULL)); IRC_Message buffer; - Buffer_Info buffers[3]; /* Buffers */ + struct { + Buffer_Info recv, send, fifo; + } buf; PathBuf filebuf; signed int reconinter = 0; time_t ctime; bool active = true; struct timespec sleep = {0, 50000000L}; + Connection connection = {0}; + + if (!set_config_defaults(&connection)) { + LOG(LOG_FATAL, "Couldn't allocate memory for configuration variables. " ERRNOFMT, strerror(errno), errno); + return EXIT_FAILURE; + } + switch (parse_args(argc, argv, &connection)) { + case 0: return EXIT_SUCCESS; + case -1: return EXIT_FAILURE; + } + if (connection.data.path != NULL) { + int tmpres; + // TODO: Add chroot()/jail support by default where supported + if ((tmpres = chdir(connection.data.path)) != 0) { + LOG(LOG_ERROR, "Couldn't change log directory to %s. " ERRNOFMT, connection.data.path, strerror(errno), errno); + return EXIT_FAILURE; + } + LOG(LOG_VERBOSE, "Changed directory to %s.", connection.data.path); + } for (;;) { ctime = time(NULL); if (!active) nanosleep(&sleep, NULL); active = false; - if (!run || connection.state == CONN_CLOSING) { + if (!run || connection.info.state == CONN_CLOSING) { signed long temp; - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_QUIT(connection.quitmsg), sizeof(sendbuf.buffer))) > 0) { - sendbuf.append_pos = (unsigned long)temp; - LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", connection.data.addr, - connection.data.port, connection.quitmsg); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) - LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); + if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_QUIT(connection.data.quitmsg), sizeof(buf.send.buffer))) > 0) { + buf.send.append_pos = (unsigned long)temp; + LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", connection.data.address, + connection.data.service, connection.data.quitmsg); + if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) + LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); } - close(sendbuf.fd); - close(fifobuf.fd); - connection.state = CONN_CLOSED; - LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", connection.data.addr, connection.data.port); + close(buf.send.fd); + close(buf.fifo.fd); + connection.info.state = CONN_CLOSED; + LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", connection.data.address, connection.data.service); break; - } else if (connection.state == CONN_CLOSED) + } else if (connection.info.state == CONN_CLOSED) break; - else if (connection.state == CONN_RECONNECTING) { - close(sendbuf.fd); - close(fifobuf.fd); - connection.state = CONN_PENDING; - if (reconinter == 0) { - reconinter = 2; - } else if (reconinter > 300) { - reconinter = 300; - } else { - reconinter *= 2; - } + else if (connection.info.state == CONN_RECONNECTING) { + close(buf.send.fd); + close(buf.fifo.fd); + connection.info.state = CONN_PENDING; + if (reconinter <= 300) reconinter += 5; continue; - } else if (connection.state == CONN_PENDING) { - if (ctime - connection.lastconnect < reconinter) continue; - connection.lastconnect = ctime; + } else if (connection.info.state == CONN_PENDING) { + if (ctime - connection.info.l_connect < reconinter) continue; + connection.info.l_connect = ctime; filebuf.elements[0].bufpos = filebuf.buf; /* Reset all state-dependent values to empty */ - memset(&recvbuf, '\0', sizeof(recvbuf)); - recvbuf.fd = -1; - memset(&sendbuf, '\0', sizeof(sendbuf)); - sendbuf.fd = -1; - memset(&fifobuf, '\0', sizeof(fifobuf)); - fifobuf.fd = -1; - connection.lastping = 0; - connection.lastpong = 0; - connection.lastmessage = 0; + memset(&buf, '\0', sizeof(buf)); + buf.recv.fd = -1; + buf.send.fd = -1; + buf.fifo.fd = -1; + connection.info.l_ping = 0; + connection.info.l_pong = 0; + connection.info.l_message = 0; /* Prepare first part of path */ - char tempath[MAXPATH]; - if ((get_connstr(tempath, sizeof(tempath), conn)) >= 0) { + char tempath[PATH_MAX]; + if ((get_connstr(tempath, sizeof(tempath), &connection)) > 0) { cleanup_path_names(tempath); if (set_path_elem(tempath, 0, true, &filebuf) > 0 && set_path_elem("global", 1, true, &filebuf) > 0) { if (mkdir_bottomup(filebuf.buf)) { if (set_path_elem("in", 2, false, &filebuf)) - fifobuf.fd = makeinput(filebuf.buf); + buf.fifo.fd = makeinput(filebuf.buf); else LOG(LOG_WARN, "%s", "Couldn't append \"in\" to pathname."); } @@ -158,141 +173,145 @@ int main(int argc, char* argv[]) } else LOG(LOG_WARN, "%s", "Couldn't get connection string."); - if ((sendbuf.fd = init_conn(conn)) > 0) { - recvbuf.fd = sendbuf.fd; - add_socket_flags(sendbuf.fd, O_NONBLOCK); + if ((buf.send.fd = init_connection(&connection)) > 0) { + buf.recv.fd = buf.send.fd; + add_socket_flags(buf.send.fd, O_NONBLOCK); /* Registration process and CAP negotiation (TODO) */ signed long temp; /* - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_CAP_LS("302"), sizeof(sendbuf.buffer))) > 0) { - sendbuf.append_pos = (size_t)temp; - LOG(LOG_VERBOSE, "Sending a CAP LS to " ADDRFMT ".", connection.data.addr, - connection.data.port); if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) - { LOG(LOG_WARN, "Couldn't send CAP LS to " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); connection.state = CONN_RECONNECTING; continue; + if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_CAP_LS("302"), sizeof(buf.send.buffer))) > 0) { + buf.send.append_pos = (size_t)temp; + LOG(LOG_VERBOSE, "Sending a CAP LS to " ADDRFMT ".", connection.data.address, + connection.data.service); if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) + { LOG(LOG_WARN, "Couldn't send CAP LS to " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); connection.info.state = CONN_RECONNECTING; continue; } } */ - if (connection.data.pass != NULL - && (temp = Assm_mesg(sendbuf.buffer, Assm_cmd_PASS(connection.data.pass), sizeof(sendbuf.buffer))) > 0) { - sendbuf.append_pos = (size_t)temp; - LOG(LOG_VERBOSE, "Sending PASS authentication to " ADDRFMT, connection.data.addr, connection.data.port); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't send PASS authentication on " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + if (connection.user.password != NULL + && (temp = Assm_mesg(buf.send.buffer, Assm_cmd_PASS(connection.user.password), sizeof(buf.send.buffer))) > 0) { + buf.send.append_pos = (size_t)temp; + LOG(LOG_VERBOSE, "Sending PASS authentication to " ADDRFMT, connection.data.address, connection.data.service); + if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) { + LOG(LOG_WARN, "Couldn't send PASS authentication on " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); + connection.info.state = CONN_RECONNECTING; continue; } } - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_NICK(connection.names.nick), sizeof(sendbuf.buffer))) > 0) { - sendbuf.append_pos = (size_t)temp; - LOG(LOG_VERBOSE, "Sending a NICK registration to " ADDRFMT " containing \"%s\".", connection.data.addr, - connection.data.port, connection.names.nick); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't register nickname on " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_NICK(connection.user.nickname), sizeof(buf.send.buffer))) > 0) { + buf.send.append_pos = (size_t)temp; + LOG(LOG_VERBOSE, "Sending a NICK registration to " ADDRFMT " containing \"%s\".", connection.data.address, + connection.data.service, connection.user.nickname); + if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) { + LOG(LOG_WARN, "Couldn't register nickname on " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); + connection.info.state = CONN_RECONNECTING; continue; } } - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_USER(connection.names.user, connection.names.real, 0), - sizeof(sendbuf.buffer))) + if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_USER(connection.user.username, connection.user.realname, 0), + sizeof(buf.send.buffer))) > 0) { - sendbuf.append_pos = (size_t)temp; - LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", connection.data.addr, - connection.data.port, connection.names.real); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't register user and real name on " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + buf.send.append_pos = (size_t)temp; + LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", connection.data.address, + connection.data.service, connection.user.realname); + if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) { + LOG(LOG_WARN, "Couldn't register user and real name on " ADDRFMT ". " ERRNOFMT, + connection.data.address, connection.data.service, strerror(errno), errno); + connection.info.state = CONN_RECONNECTING; continue; } } - connection.state = CONN_REGISTERED; - } else if (sendbuf.fd == INIT_SOFTFAIL) { - connection.state = CONN_RECONNECTING; + connection.info.state = CONN_REGISTERED; + } else if (buf.send.fd == INIT_SOFTFAIL) { + connection.info.state = CONN_RECONNECTING; continue; - } else if (sendbuf.fd == INIT_HARDFAIL) { - connection.state = CONN_CLOSED; + } else if (buf.send.fd == INIT_HARDFAIL) { + connection.info.state = CONN_CLOSED; continue; } - } else if (connection.state == CONN_ACTIVE) { + } else if (connection.info.state == CONN_ACTIVE) { reconinter = 0; - if (connection.lastmessage < ctime - timeout && connection.lastpong < connection.lastping - timeout) { - LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", connection.data.addr, connection.data.port); - connection.state = CONN_RECONNECTING; + if (connection.info.l_message < ctime - connection.data.timeout + && connection.info.l_pong < connection.info.l_ping - connection.data.timeout) { + LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", connection.data.address, + connection.data.service); + connection.info.state = CONN_RECONNECTING; continue; } - if (ctime - connection.lastmessage >= timeout / 4 && ctime - connection.lastping >= timeout / 4) { + if (ctime - connection.info.l_message >= connection.data.timeout / 4 + && ctime - connection.info.l_ping >= connection.data.timeout / 4) { char mesg[] = "uIRC PING -- XXXXXX"; snprintf(mesg + sizeof(mesg) - 7, 7, "%.6i", rand()); signed long temp; - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf.buffer))) > 0) { - sendbuf.append_pos = (size_t)temp; - LOG(LOG_DEBUG, "Sending ping to " ADDRFMT " with message \"%s\"", connection.data.addr, connection.data.port, - mesg); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't ping " ADDRFMT ". " ERRNOFMT, connection.data.addr, connection.data.port, - strerror(errno), errno); - connection.state = CONN_RECONNECTING; + if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_PING(mesg, NULL), sizeof(buf.send.buffer))) > 0) { + buf.send.append_pos = (size_t)temp; + LOG(LOG_DEBUG, "Sending ping to " ADDRFMT " with message \"%s\"", connection.data.address, + connection.data.service, mesg); + if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1) { + LOG(LOG_WARN, "Couldn't ping " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); + connection.info.state = CONN_RECONNECTING; continue; } - connection.lastping = ctime; + connection.info.l_ping = ctime; } } - if (fifobuf.fd != -1) { + if (buf.fifo.fd != -1) { ssize_t brd, len; /* Buffer writer */ - if ((brd = read(fifobuf.fd, fifobuf.buffer + fifobuf.append_pos, sizeof(fifobuf.buffer) - fifobuf.append_pos - 1)) + if ((brd = + read(buf.fifo.fd, buf.fifo.buffer + buf.fifo.append_pos, sizeof(buf.fifo.buffer) - buf.fifo.append_pos - 1)) > 0) { - *(fifobuf.buffer + (fifobuf.append_pos += (size_t)brd)) = '\0'; - LOG(LOG_DEBUG, "Read %li bytes from FIFO. Now appending at %li", brd, fifobuf.append_pos); + *(buf.fifo.buffer + (buf.fifo.append_pos += (size_t)brd)) = '\0'; + LOG(LOG_DEBUG, "Read %li bytes from FIFO. Now appending at %li", brd, buf.fifo.append_pos); active = true; } else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { LOG(LOG_ERROR, "Failed to read FIFO input. " ERRNOFMT, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + connection.info.state = CONN_RECONNECTING; continue; } memset((void*)&buffer, '\0', sizeof(IRC_Message)); - if ((len = get_buffer_line(fifobuf.buffer, &buffer)) > 0) { + if ((len = get_buffer_line(buf.fifo.buffer, &buffer)) > 0) { LOG(LOG_DEBUG, "%s", "Tokenized FIFO message successfully."); signed long temp; - if ((temp = Assm_mesg(fifobuf.buffer, &buffer, sizeof(fifobuf.buffer))) > 0) { - if (flush_buffer(fifobuf.buffer, (size_t)temp, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, connection.data.addr, - connection.data.port, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + if ((temp = Assm_mesg(buf.fifo.buffer, &buffer, sizeof(buf.fifo.buffer))) > 0) { + if (flush_buffer(buf.fifo.buffer, (size_t)temp, buf.send.fd) == -1) { + LOG(LOG_WARN, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, connection.data.address, + connection.data.service, strerror(errno), errno); + connection.info.state = CONN_RECONNECTING; continue; } } - for (long unsigned int x = 0; x < sizeof(fifobuf.buffer) && *(fifobuf.buffer + len + x); x++) - *(fifobuf.buffer + x) = *(fifobuf.buffer + x + len); - fifobuf.append_pos -= (unsigned long)len; - *(fifobuf.buffer + fifobuf.append_pos) = '\0'; + for (long unsigned int x = 0; x < sizeof(buf.fifo.buffer) && *(buf.fifo.buffer + len + x); x++) + *(buf.fifo.buffer + x) = *(buf.fifo.buffer + x + len); + buf.fifo.append_pos -= (unsigned long)len; + *(buf.fifo.buffer + buf.fifo.append_pos) = '\0'; active = true; } else if (len == -1) - connection.state = CONN_RECONNECTING; + connection.info.state = CONN_RECONNECTING; } } ssize_t brd, len; /* Buffer reader */ - if ((brd = read(recvbuf.fd, recvbuf.buffer + recvbuf.append_pos, sizeof(recvbuf.buffer) - recvbuf.append_pos - 1)) > 0) { - *(recvbuf.buffer + (recvbuf.append_pos += (size_t)brd)) = '\0'; - LOG(LOG_DEBUG, "Read %li bytes from socket buffer. Now appending at %li", brd, recvbuf.append_pos); + if ((brd = read(buf.recv.fd, buf.recv.buffer + buf.recv.append_pos, sizeof(buf.recv.buffer) - buf.recv.append_pos - 1)) > 0) { + *(buf.recv.buffer + (buf.recv.append_pos += (size_t)brd)) = '\0'; + LOG(LOG_DEBUG, "Read %li bytes from socket buffer. Now appending at %li", brd, buf.recv.append_pos); active = true; } else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno); - connection.state = CONN_RECONNECTING; + connection.info.state = CONN_RECONNECTING; continue; } memset((void*)&buffer, '\0', sizeof(IRC_Message)); - if ((len = get_buffer_line(recvbuf.buffer, &buffer)) > 0) { - connection.lastmessage = ctime; + if ((len = get_buffer_line(buf.recv.buffer, &buffer)) > 0) { + connection.info.l_message = ctime; char datebuf[25]; if (buffer.tags.time.value == NULL) { Assm_tag_timestamp(datebuf, sizeof(datebuf), ctime); @@ -301,24 +320,25 @@ int main(int argc, char* argv[]) if (set_path_elem("global", 1, true, &filebuf) > 0 && set_path_elem("out", 2, false, &filebuf) > 0) { LOG(LOG_DEBUG, "Writing message to global path %s.", filebuf.buf); signed long temp; - if ((temp = Assm_mesg(sendbuf.buffer, &buffer, sizeof(sendbuf.buffer))) > 0) write_log(filebuf.buf, sendbuf.buffer); + if ((temp = Assm_mesg(buf.send.buffer, &buffer, sizeof(buf.send.buffer))) > 0) + write_log(filebuf.buf, buf.send.buffer); } - if (prepare_log_path(&buffer, &filebuf, conn) == 1) { + if (prepare_log_path(&buffer, &filebuf, &connection) == 1) { LOG(LOG_DEBUG, "Writing message to path %s.", filebuf.buf); signed long temp; - if ((temp = Assm_mesg(sendbuf.buffer, &buffer, sizeof(sendbuf.buffer))) > 0) write_log(filebuf.buf, sendbuf.buffer); + if ((temp = Assm_mesg(buf.send.buffer, &buffer, sizeof(buf.send.buffer))) > 0) + write_log(filebuf.buf, buf.send.buffer); } - if (!auto_msg_actions(&buffer, conn, &sendbuf)) continue; - for (long unsigned int x = 0; x < sizeof(recvbuf.buffer) && *(recvbuf.buffer + len + x); x++) - *(recvbuf.buffer + x) = *(recvbuf.buffer + x + len); - recvbuf.append_pos -= (unsigned long)len; - *(recvbuf.buffer + recvbuf.append_pos) = '\0'; + if (!auto_msg_actions(&buffer, &connection, &buf.send)) continue; + for (long unsigned int x = 0; x < sizeof(buf.recv.buffer) && *(buf.recv.buffer + len + x); x++) + *(buf.recv.buffer + x) = *(buf.recv.buffer + x + len); + buf.recv.append_pos -= (unsigned long)len; + *(buf.recv.buffer + buf.recv.append_pos) = '\0'; active = true; } else if (len == -1) - connection.state = CONN_RECONNECTING; + connection.info.state = CONN_RECONNECTING; } LOG(LOG_VERBOSE, "%s", "Exiting gracefully."); return EXIT_SUCCESS; } -void print_help(void) {} diff --git a/src/main.h b/src/main.h index 939705c..db1368e 100644 --- a/src/main.h +++ b/src/main.h @@ -21,10 +21,12 @@ #include #include +#include "buffer.h" #include "configuration.h" #include "connection.h" #include "filesystem.h" #include "logging.h" +#include "memory.h" #include "signal.h" #define UIRC_IRCV3 @@ -34,11 +36,8 @@ #ifndef UIRCD_GUARD_MAIN #define UIRCD_GUARD_MAIN -#define VERSION "2020.12.7.0-beta" - -#define recvbuf buffers[0] -#define sendbuf buffers[1] -#define fifobuf buffers[2] +int parse_args(int argc, char** argv, Connection* conn); +void print_help(void); #endif /* UIRCD_GUARD_MAIN */ diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..c5cc7f0 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,41 @@ +/* + * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) + * Copyright (c) 2019, 2020 Alex-David Denes + * + * uIRCd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * uIRCd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with uIRCd. If not, see . + */ + +#include "memory.h" + +/* Description: + * This is a allocation manager that frees or allocates variables to pointers depending on the context. + * If the pointer is already allocated it will free it and replace it with var + * If var is NULL then the pointer is assigned NULL and left "undefined" + * If it isn't NULL, the string var is copied to a allocated block stored in *ptr + * NOTE: This could be expanded to have uses outside of strings but that's not required (yet) + */ +int allocate_copy(char** ptr, const char* const var) +{ + if (var == NULL) LOG(LOG_DEBUG, "%s.", "Freeing pointer because provided variable has the address of NULL"); + if (*ptr != NULL) LOG(LOG_DEBUG, "%s.", "Deallocating already allocated pointer for replacement"); + free(*ptr); + *ptr = NULL; + if (var == NULL) return 1; + if ((*ptr = (char*)malloc(sizeof(char) * (strlen(var) + 1))) != NULL) { + strcpy(*ptr, var); + return 1; + } + return 0; +} + diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000..a5d6b6b --- /dev/null +++ b/src/memory.h @@ -0,0 +1,31 @@ +/* + * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) + * Copyright (c) 2019, 2020 Alex-David Denes + * + * uIRCd is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * uIRCd is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with uIRCd. If not, see . + */ + +#include "logging.h" + +#include +#include +#include + +#ifndef UIRCD_GUARD_MEMORY +#define UIRCD_GUARD_MEMORY + +int allocate_copy(char** ptr, const char* var); + +#endif /* UIRCD_GUARD_MEMORY */ + diff --git a/src/signal.h b/src/signal.h index c6db112..1a5f942 100644 --- a/src/signal.h +++ b/src/signal.h @@ -19,6 +19,10 @@ #include // sig_atomic_t #include // true, false #include // NULL +#include // errno +#include // strerror() + +#include "logging.h" #ifndef UIRCD_GUARD_SIGNAL #define UIRCD_GUARD_SIGNAL @@ -28,5 +32,7 @@ extern sig_atomic_t volatile run; void stop_loop(int sig, siginfo_t* info, void* ucontext); +int setup_signals(void); #endif /* UIRCD_GUARD_SIGNAL */ +