From 0da49cab10cfabddef68d6b8449cb7da9a5a45d6 Mon Sep 17 00:00:00 2001 From: Alex Denes Date: Tue, 8 Dec 2020 02:16:12 +0000 Subject: [PATCH] WIP: cleanup code --- CMakeLists.txt | 6 +- src/configuration.c | 64 ++++++ src/{structs.h => configuration.h} | 46 ++-- src/connection.c | 181 +++++++++++++++ src/{net.h => connection.h} | 55 +++-- src/filesystem.c | 106 ++++----- src/filesystem.h | 37 ++-- src/{global.h => limits.h} | 21 +- src/{log.c => logging.c} | 5 +- src/{log.h => logging.h} | 26 ++- src/main.c | 341 +++++++++++++---------------- src/main.h | 34 +-- src/misc.c | 133 ----------- src/misc.h | 22 -- src/net.c | 66 ------ src/signal.c | 38 ++++ src/signal.h | 32 +++ 17 files changed, 637 insertions(+), 576 deletions(-) create mode 100644 src/configuration.c rename src/{structs.h => configuration.h} (54%) create mode 100644 src/connection.c rename src/{net.h => connection.h} (59%) rename src/{global.h => limits.h} (73%) rename src/{log.c => logging.c} (79%) rename src/{log.h => logging.h} (62%) delete mode 100644 src/misc.c delete mode 100644 src/misc.h delete mode 100644 src/net.c create mode 100644 src/signal.c create mode 100644 src/signal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 836d8eb..590638f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,12 @@ add_executable(uircd src/filesystem.c src/misc.c src/log.c + src/parsers.c + src/conns.c ) - find_library(UIRC_PATH NAMES uirc libuirc REQUIRED) -target_link_libraries(uircd ${UIRC_PATH}) +find_library(LIBCONFIG_PATH NAMES config libconfig REQUIRED) +target_link_libraries(uircd ${UIRC_PATH} ${LIBCONFIG_PATH}) set_property(TARGET uircd PROPERTY C_STANDARD 99) install(TARGETS uircd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/configuration.c b/src/configuration.c new file mode 100644 index 0000000..fd6b6c2 --- /dev/null +++ b/src/configuration.c @@ -0,0 +1,64 @@ +/* + * 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 "configuration.h" + +int parse_configfile(char* config_path, Connection* conn) +{ + config_t conf; + int res = -1; + 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) { + struct maps { + const char* str; + const 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}, + }; + 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); + } + res = 1; + } + } else + LOG(LOG_WARN, "Encountered a error while reading the config file. %s in %s line %d", config_error_text(&conf), + config_error_file(&conf), config_error_line(&conf)); + config_destroy(&conf); + return res; +} + +void set_conn_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}, + }; + for (unsigned int i = 0; i < sizeof(defs) / sizeof(*defs); i++) + if (defs[i].var == NULL) *defs[i].var = defs[i].def; +} diff --git a/src/structs.h b/src/configuration.h similarity index 54% rename from src/structs.h rename to src/configuration.h index 2de0c50..af25595 100644 --- a/src/structs.h +++ b/src/configuration.h @@ -16,41 +16,23 @@ * along with uIRCd. If not, see . */ -#include "global.h" -#define UIRC_IRCV3 -#include "uirc/types.h" -#include -#include +#include "connection.h" +#include "logging.h" -#ifndef UIRCD_INCLUDED_STRUCTS -#define UIRCD_INCLUDED_STRUCTS -typedef struct { - char *addr, *port, *chans; - bool ssl; -} Connection_Data; +#include -typedef struct { - char buffer[513]; - size_t append_pos; - int fd; -} Buffer_Info; +#ifndef UIRCD_GUARD_CONFIGURATION +#define UIRCD_GUARD_CONFIGURATION -typedef struct { - IRC_User names; - Connection_Data data; - time_t lastping, lastpong, lastconnect, lastmessage; - signed short state; - pid_t pid; -} Connection; +#define UIRCD_DEFAULT_ADDR "localhost" +#define UIRCD_DEFAULT_PORT "6667" +#define UIRCD_DEFAULT_NICK "uirc-user" +#define UIRCD_DEFAULT_USER "uIRC-user" +#define UIRCD_DEFAULT_REAL "uIRC user" -typedef struct { - char* bufpos; - size_t len; -} PathBufElem; +void parse_cmdline_conn(char* arg, Connection* conn); +int parse_configfile(char* config_path, Connection* conn); +void set_conn_defaults(Connection* conn); -typedef struct { - char buf[MAXPATH]; - PathBufElem elements[5]; -} PathBuf; -#endif +#endif /* UIRCD_GUARD_CONFIGURATION */ diff --git a/src/connection.c b/src/connection.c new file mode 100644 index 0000000..454e878 --- /dev/null +++ b/src/connection.c @@ -0,0 +1,181 @@ +/* + * 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 "connection.h" + +signed int init_conn(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) { + 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, + 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, + 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); + freeaddrinfo(conn); + return INIT_HARDFAIL; + } + if ((connectres = connect(sockfd, conn->ai_addr, conn->ai_addrlen)) == -1) { + 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); + return INIT_HARDFAIL; + } else { + LOG(LOG_WARN, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, strerror(errno), errno); + return INIT_SOFTFAIL; + } + } + freeaddrinfo(conn); + return sockfd; +} + +int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf) +{ + signed long len; + time_t ctime = time(NULL); + switch (message->cmd) { + case (PING): { + 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, + strerror(errno), errno); + connection->state = CONN_RECONNECTING; + return 0; + } + break; + } + case (PONG): { + if (message->trailing && message->args[1] != NULL) { + LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]); + connection->lastpong = 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 + */ + 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) { + 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; + return 0; + } + } + } + break; + } + /* + 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, + 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->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); + 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, + connection->data.port, strerror(errno), errno); + connection->state = CONN_RECONNECTING; + return 0; + } + } + } + break; + } + */ + case (ERROR): { + LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", connection->data.addr, + connection->data.port, 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; + 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; + return len; +} + diff --git a/src/net.h b/src/connection.h similarity index 59% rename from src/net.h rename to src/connection.h index 1292cc5..63fd81f 100644 --- a/src/net.h +++ b/src/connection.h @@ -16,29 +16,25 @@ * along with uIRCd. If not, see . */ -#define UIRC_HELPERS -#define UIRC_IRCV3 -#include "global.h" -#include "log.h" -#include "structs.h" -#include "uirc/functions.h" -#include "uirc/helpers.h" -#include "uirc/mappings.h" +#include "limits.h" +#include "logging.h" + #include #include -#include -#include -#include #include #include -#include -#include #include -#include #include -#ifndef UIRCD_INCLUDED_NETWORK -#define UIRCD_INCLUDED_NETWORK +#define UIRC_IRCV3 +#define UIRC_HELPERS +#include + +#ifndef UIRCD_GUARD_CONNECTION +#define UIRCD_GUARD_CONNECTION + +#define INIT_HARDFAIL -1 +#define INIT_SOFTFAIL -2 #define CONN_ACTIVE 2 #define CONN_REGISTERED 1 @@ -47,10 +43,29 @@ #define CONN_CLOSING -2 #define CONN_CLOSED -3 -#define INIT_HARDFAIL -1 -#define INIT_SOFTFAIL -2 +typedef struct { + const char *addr, *port, *chans, *pass; +} Connection_Data; +typedef struct { + const char *nick, *user, *real; +} Connection_User; +typedef struct { + char buffer[UIRCD_LIMITS_LINE + 1]; + size_t append_pos; + int fd; +} Buffer_Info; +typedef struct { + Connection_User names; + Connection_Data data; + const char *quitmsg, *path; + unsigned long timeout; + signed short state; + time_t lastping, lastpong, lastconnect, lastmessage; +} Connection; -signed int init_conn(Connection* info); +signed int init_connection(Connection* info); ssize_t flush_buffer(char* buf, size_t buflen, int fd); -#endif +ssize_t get_buffer_line(char* buf, IRC_Message* parsed); +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 2883629..6635883 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -114,59 +114,61 @@ ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf* 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; - char* reused_strings[] = {"channel", "user", "global"}; - struct elems { - char* name; - bool isdir; - } elements[] = {{reused_strings[0], true}, {NULL, true}, {"out", false}}; - char temp[MAXLINE]; - if (ISCMD(JOIN) || ISCMD(PART) || ISCMD(QUIT) || ISCMD(RPL_USERSSTART) || ISCMD(RPL_USERS) || ISCMD(RPL_NOUSERS) || ISCMD(RPL_ENDOFUSERS) - || ISCMD(RPL_NAMREPLY) || ISCMD(RPL_ENDOFNAMES)) { - elements[0].name = reused_strings[2]; - elements[1].name = "events"; - elements[1].isdir = false; - } else if (ISCMD(MOTD) || ISCMD(RPL_MOTD) || ISCMD(RPL_MOTDSTART) || ISCMD(RPL_ENDOFMOTD) || ISCMD(ERR_NOMOTD)) { - elements[0].name = reused_strings[2]; - elements[1].name = "motd"; - elements[1].isdir = false; - } else if (ISCMD(PING) || ISCMD(PONG)) { - elements[0].name = reused_strings[2]; - elements[1].name = "pings"; - elements[1].isdir = false; - } else if (ISCMD(RPL_LIST) || ISCMD(RPL_LISTEND)) { - elements[0].name = reused_strings[2]; - elements[1].name = "channels"; - 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) { - 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] == '!') { - strncpy(temp, message->args[0], sizeof(temp)); - } else - return 0; // TODO: Parse patterns as well - cleanup_path_names(temp); - elements[1].name = temp; - } else if (ISCMD(RPL_TOPIC) || ISCMD(RPL_NOTOPIC)) { - if (message->args[0] == NULL || message->args[1] == NULL) return -2; - if (message->args[2] != NULL) - strncpy(temp, message->args[1], sizeof(temp)); - else - strncpy(temp, message->args[0], sizeof(temp)); - cleanup_path_names(temp); - elements[1].name = temp; - elements[2].name = "topic"; - } else - return 0; - for (unsigned long i = 0; i < sizeof(elements) / sizeof(*elements); i++) { - if (set_path_elem(elements[i].name, (unsigned int)i + 1, elements[i].isdir, pathbuffer) <= 0) return -1; - if (!elements[i].isdir) return 1; - if (!mkdir_bottomup(pathbuffer->buf)) return -1; - } - return -1; + if (message == NULL || pathbuffer == NULL) return -2; + char* reused_strings[] = {"channel", "user", "global"}; + struct elems { + char* name; + bool isdir; + } elements[] = {{reused_strings[0], true}, {NULL, true}, {"out", false}}; + char temp[UIRCD_LIMITS_LINE]; + if (ISCMD(JOIN) || ISCMD(PART) || ISCMD(QUIT) || ISCMD(RPL_USERSSTART) || ISCMD(RPL_USERS) || ISCMD(RPL_NOUSERS) || ISCMD(RPL_ENDOFUSERS) + || ISCMD(RPL_NAMREPLY) || ISCMD(RPL_ENDOFNAMES)) { + elements[0].name = reused_strings[2]; + elements[1].name = "events"; + elements[1].isdir = false; + } else if (ISCMD(MOTD) || ISCMD(RPL_MOTD) || ISCMD(RPL_MOTDSTART) || ISCMD(RPL_ENDOFMOTD) || ISCMD(ERR_NOMOTD)) { + elements[0].name = reused_strings[2]; + elements[1].name = "motd"; + elements[1].isdir = false; + } else if (ISCMD(PING) || ISCMD(PONG)) { + elements[0].name = reused_strings[2]; + elements[1].name = "pings"; + elements[1].isdir = false; + } else if (ISCMD(RPL_LIST) || ISCMD(RPL_LISTEND)) { + elements[0].name = reused_strings[2]; + elements[1].name = "channels"; + 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) { + 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] == '!') { + strncpy(temp, message->args[0], sizeof(temp)); + } else + return 0; // TODO: Parse patterns as well + cleanup_path_names(temp); + elements[1].name = temp; + } else if (ISCMD(RPL_TOPIC) || ISCMD(RPL_NOTOPIC)) { + if (message->args[0] == NULL || message->args[1] == NULL) return -2; + if (message->args[2] != NULL) + strncpy(temp, message->args[1], sizeof(temp)); + else + strncpy(temp, message->args[0], sizeof(temp)); + cleanup_path_names(temp); + elements[1].name = temp; + elements[2].name = "topic"; + } else + return 0; + for (unsigned long i = 0; i < sizeof(elements) / sizeof(*elements); i++) { + if (set_path_elem(elements[i].name, (unsigned int)i + 1, elements[i].isdir, pathbuffer) <= 0) return -1; + if (!elements[i].isdir) return 1; + if (!mkdir_bottomup(pathbuffer->buf)) return -1; + } + return -1; } +*/ diff --git a/src/filesystem.h b/src/filesystem.h index 7504092..57e1578 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -16,31 +16,32 @@ * along with uIRCd. If not, see . */ -#include "global.h" -#include "log.h" -#include "structs.h" -#define UIRC_IRCV3 -#include "uirc/functions.h" -#include "uirc/mappings.h" #include #include #include +#include #include #include #include -#include +#include -#ifndef UIRCD_INCLUDED_FS -#define UIRCD_INCLUDED_FS +#define UIRC_IRCV3 +#include -int mkdir_bottomup(char* path); -int makeinput(char* path); -bool cleanup_path_names(char* name); -bool write_log(char* path, char* message); -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); -#define ISCMD(CMD) (message->cmd == (CMD)) +#include "connection.h" +#include "limits.h" +#include "logging.h" -#endif +#ifndef UIRCD_GUARD_FILESYSTEM +#define UIRCD_GUARD_FILESYSTEM +typedef struct { + char* bufpos; + size_t len; +} PathBufElem; +typedef struct { + char buf[PATH_MAX]; + PathBufElem elements[5]; +} PathBuf; + +#endif /* UIRCD_GUARD_FILESYSTEM */ diff --git a/src/global.h b/src/limits.h similarity index 73% rename from src/global.h rename to src/limits.h index 31eb8af..459997b 100644 --- a/src/global.h +++ b/src/limits.h @@ -16,19 +16,12 @@ * along with uIRCd. If not, see . */ -#include +#ifndef UIRCD_GUARD_LIMITS +#define UIRCD_GUARD_LIMITS -#ifndef UIRCD_INCLUDED_GLOBAL -#define UIRCD_INCLUDED_GLOBAL - -#define MAXLINE 512 -#define MAXPATH 1024 -#define MAXCONN 64 -#define MAXNICK 32 -#define ERRNOFMT "%s (%i)" -#define ADDRFMT "%s:%s" - -extern sig_atomic_t volatile run; -extern int loglevel; -#endif +#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/log.c b/src/logging.c similarity index 79% rename from src/log.c rename to src/logging.c index 623d273..b907f92 100644 --- a/src/log.c +++ b/src/logging.c @@ -16,7 +16,8 @@ * along with uIRCd. If not, see . */ -#include "log.h" +#include "logging.h" -char logchars[] = {[LOG_DEBUG] = 'D', [LOG_VERBOSE] = 'V', [LOG_INFO] = 'I', [LOG_WARN] = 'W', [LOG_ERROR] = 'E', [LOG_FATAL] = 'F'}; +int loglevel = LOG_FATAL; +const char logchars[] = {[LOG_DEBUG] = 'D', [LOG_VERBOSE] = 'V', [LOG_INFO] = 'I', [LOG_WARN] = 'W', [LOG_ERROR] = 'E', [LOG_FATAL] = 'F'}; diff --git a/src/log.h b/src/logging.h similarity index 62% rename from src/log.h rename to src/logging.h index a6ea310..e63d56f 100644 --- a/src/log.h +++ b/src/logging.h @@ -1,7 +1,11 @@ /* * 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. + * 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 @@ -12,14 +16,10 @@ * along with uIRCd. If not, see . */ -#include "global.h" -#include "structs.h" -#include -#include -#include +#include // fprintf() -#ifndef UIRCD_INCLUDED_LOG -#define UIRCD_INCLUDED_LOG +#ifndef UIRCD_GUARD_LOGGING +#define UIRCD_GUARD_LOGGING #define LOG_FATAL 0 #define LOG_ERROR 1 @@ -27,10 +27,14 @@ #define LOG_INFO 3 #define LOG_VERBOSE 4 #define LOG_DEBUG 5 -extern char logchars[]; + +#define ERRNOFMT "%s (%i)" +#define ADDRFMT "%s:%s" #define LOG(LEVEL, FORMAT, ...) \ if (LEVEL <= loglevel) fprintf(stderr, "[%c:L%i] " FORMAT "\n", logchars[LEVEL], __LINE__, __VA_ARGS__) -#endif +extern const char logchars[]; +extern int loglevel; +#endif /* UIRCD_GUARD_LOGGING */ diff --git a/src/main.c b/src/main.c index 21cdf8f..764fdd6 100644 --- a/src/main.c +++ b/src/main.c @@ -18,16 +18,9 @@ #include "main.h" -sig_atomic_t volatile run = true; -int loglevel = LOG_FATAL; int main(int argc, char* argv[]) { - int c; - char *quitmsg = "uIRCd " VERSION, *pos = NULL; - unsigned int totcon = 0, timeout = 30; - Connection cons[MAXCONN] = {0}; - setvbuf(stderr, NULL, _IOLBF, 0); /* Threads may want to print incomplete messages to the log at the same that, avoid that. */ - + Connection connection; /* Arguments: * -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ] * -l Starting directory for message tree @@ -38,21 +31,13 @@ int main(int argc, char* argv[]) * -v Version and license information * -h Help/Usage */ - while ((c = getopt(argc, argv, /* "C:" */ "m:c:l:t:j:V:vh")) != -1) { + int c; + while ((c = getopt(argc, argv, "C:m:c:l:t:j:V:vh")) != -1) { switch (c) { case 'c': { - cons[totcon].data.chans = point_after(optarg, ','); - if ((cons[totcon].data.port = point_after(optarg, '/')) != NULL) { - if (*cons[totcon].data.port == '+') { - cons[totcon].data.ssl = true; - cons[totcon].data.port++; - } - } else - cons[totcon].data.port = "6667"; - cons[totcon].data.addr = ((pos = point_after(optarg, '@')) == NULL) ? "localhost" : pos; - cons[totcon].names.real = ((pos = point_after(optarg, ':')) == NULL) ? "uIRCd user" : pos; - cons[totcon].names.user = ((pos = point_after(optarg, '!')) == NULL) ? "uIRCd-user" : pos; - cons[totcon++].names.nick = optarg; + /* 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': { @@ -63,66 +48,46 @@ int main(int argc, char* argv[]) } break; } - case 'm': quitmsg = optarg; break; - case 't': timeout = (unsigned int)atoi(optarg); break; - case 'C': break; // TODO: Reserved for config file path + 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': print_help(); return EXIT_SUCCESS; - } - } - if (totcon < 1) { - LOG(LOG_FATAL, "%s", "No connection was provided."); - return EXIT_FAILURE; - } - - pid_t cpid; - struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = stop_loop}; - sigemptyset(&sa.sa_mask); - if (sigaction(SIGINT, &sa, NULL) == -1) { - LOG(LOG_WARN, "sigaction() failed. Children won't respond to signals. " ERRNOFMT, strerror(errno), errno); - } - if (sigaction(SIGTERM, &sa, NULL) == -1) { - LOG(LOG_WARN, "sigaction() failed. Children won't respond to signals. " ERRNOFMT, strerror(errno), errno); - } - - for (unsigned int actcon = 0; actcon < totcon && run; actcon++) { - cpid = fork(); - if (cpid == -1) { - if (errno != EAGAIN) { - LOG(LOG_FATAL, "Failed to fork child. " ERRNOFMT, strerror(errno), errno); - break; + 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; } - } else if (cpid == 0) { - return run_main(&cons[actcon], quitmsg, timeout); - } else { - LOG(LOG_VERBOSE, "Successfully forked for connection " ADDRFMT ".", cons[actcon].data.addr, cons[actcon].data.port); } } - for (pid_t wpid = 1; wpid > 0;) { - if ((wpid = waitpid(-1, NULL, 0)) > 0) { - LOG(LOG_VERBOSE, "Child %i closed.", wpid); - } else if (errno == EINTR) { - kill(0, SIGTERM); - wpid = 1; - } - } - LOG(LOG_VERBOSE, "%s", "Exiting gracefully."); - return EXIT_SUCCESS; -} - -int run_main(Connection* conn, char* quitmsg, unsigned int timeout) -{ + set_conn_defaults(&connection); srand((unsigned int)time(NULL)); IRC_Message buffer; Buffer_Info buffers[3]; /* Buffers */ -#define recvbuf buffers[0] -#define sendbuf buffers[1] -#define fifobuf buffers[2] PathBuf filebuf; signed int reconinter = 0; time_t ctime; @@ -132,135 +97,188 @@ int run_main(Connection* conn, char* quitmsg, unsigned int timeout) ctime = time(NULL); if (!active) nanosleep(&sleep, NULL); active = false; - if (!run || conn->state == CONN_CLOSING) { + if (!run || connection.state == CONN_CLOSING) { signed long temp; - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_QUIT(quitmsg), sizeof(sendbuf.buffer))) > 0) { + 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\".", conn->data.addr, conn->data.port, - quitmsg); + 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, conn->data.addr, conn->data.port, - strerror(errno), errno); + LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, connection.data.addr, + connection.data.port, strerror(errno), errno); } close(sendbuf.fd); close(fifobuf.fd); - conn->state = CONN_CLOSED; - LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", conn->data.addr, conn->data.port); + connection.state = CONN_CLOSED; + LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", connection.data.addr, connection.data.port); break; - } else if (conn->state == CONN_CLOSED) + } else if (connection.state == CONN_CLOSED) break; - else if (conn->state == CONN_RECONNECTING) { + else if (connection.state == CONN_RECONNECTING) { close(sendbuf.fd); close(fifobuf.fd); - conn->state = CONN_PENDING; - if (reconinter == 0) - reconinter = 10; - else if (reconinter > 300) + connection.state = CONN_PENDING; + if (reconinter == 0) { + reconinter = 2; + } else if (reconinter > 300) { reconinter = 300; - else + } else { reconinter *= 2; + } continue; - } else if (conn->state == CONN_PENDING) { - if (ctime - conn->lastconnect < reconinter) continue; - conn->lastconnect = ctime; + } else if (connection.state == CONN_PENDING) { + if (ctime - connection.lastconnect < reconinter) continue; + connection.lastconnect = 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)); - conn->lastping = 0; - conn->lastpong = 0; - conn->lastmessage = 0; + fifobuf.fd = -1; + connection.lastping = 0; + connection.lastpong = 0; + connection.lastmessage = 0; /* Prepare first part of path */ char tempath[MAXPATH]; if ((get_connstr(tempath, sizeof(tempath), conn)) >= 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)) break; - if (set_path_elem("in", 2, false, &filebuf)) { - if ((fifobuf.fd = makeinput(filebuf.buf)) == -1) break; + if (mkdir_bottomup(filebuf.buf)) { + if (set_path_elem("in", 2, false, &filebuf)) + fifobuf.fd = makeinput(filebuf.buf); + else + LOG(LOG_WARN, "%s", "Couldn't append \"in\" to pathname."); } - } - } + } else + LOG(LOG_WARN, "%s", "Couldn't prepare FIFO pathname."); + } 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); - /* Send NICK and USER registration */ - // TODO: PASS + + /* 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 ".", conn->data.addr, conn->data.port); - if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) { - LOG(LOG_WARN, "Couldn't send CAP LS to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, - strerror(errno), errno); - conn->state = CONN_RECONNECTING; - continue; + 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(sendbuf.buffer, Assm_cmd_NICK(conn->names.nick), sizeof(sendbuf.buffer))) > 0) { + 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 a NICK registration to " ADDRFMT " containing \"%s\".", conn->data.addr, - conn->data.port, conn->names.nick); + 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 register nickname on " ADDRFMT ". " ERRNOFMT, conn->data.addr, - conn->data.port, strerror(errno), errno); - conn->state = CONN_RECONNECTING; + LOG(LOG_WARN, "Couldn't send PASS authentication on " ADDRFMT ". " ERRNOFMT, connection.data.addr, + connection.data.port, strerror(errno), errno); + connection.state = CONN_RECONNECTING; continue; } } - if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_USER(conn->names.user, conn->names.real, 0), sizeof(sendbuf.buffer))) + 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; + continue; + } + } + if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_USER(connection.names.user, connection.names.real, 0), + sizeof(sendbuf.buffer))) > 0) { sendbuf.append_pos = (size_t)temp; - LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", conn->data.addr, - conn->data.port, conn->names.real); + 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, conn->data.addr, - conn->data.port, strerror(errno), errno); - conn->state = CONN_RECONNECTING; + 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; continue; } } - conn->state = CONN_REGISTERED; + connection.state = CONN_REGISTERED; } else if (sendbuf.fd == INIT_SOFTFAIL) { - conn->state = CONN_RECONNECTING; + connection.state = CONN_RECONNECTING; continue; } else if (sendbuf.fd == INIT_HARDFAIL) { - conn->state = CONN_CLOSED; + connection.state = CONN_CLOSED; continue; } - } else if (conn->state == CONN_ACTIVE) { + } else if (connection.state == CONN_ACTIVE) { reconinter = 0; - if (conn->lastmessage < ctime - timeout && conn->lastpong < conn->lastping - timeout) { - LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", conn->data.addr, conn->data.port); - conn->state = CONN_RECONNECTING; + 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; continue; } - if (ctime - conn->lastmessage >= timeout / 4 && ctime - conn->lastping >= timeout / 4) { + if (ctime - connection.lastmessage >= timeout / 4 && ctime - connection.lastping >= 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\"", conn->data.addr, conn->data.port, mesg); + 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, conn->data.addr, conn->data.port, + LOG(LOG_WARN, "Couldn't ping " ADDRFMT ". " ERRNOFMT, connection.data.addr, connection.data.port, strerror(errno), errno); - conn->state = CONN_RECONNECTING; + connection.state = CONN_RECONNECTING; continue; } - conn->lastping = ctime; + connection.lastping = ctime; } } + + if (fifobuf.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)) + > 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); + 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; + continue; + } + + memset((void*)&buffer, '\0', sizeof(IRC_Message)); + if ((len = get_buffer_line(fifobuf.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; + 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'; + active = true; + } else if (len == -1) + connection.state = CONN_RECONNECTING; + } } - ssize_t brd; - + 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'; @@ -268,14 +286,13 @@ int run_main(Connection* conn, char* quitmsg, unsigned int timeout) active = true; } else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno); - conn->state = CONN_RECONNECTING; + connection.state = CONN_RECONNECTING; continue; } - ssize_t len; memset((void*)&buffer, '\0', sizeof(IRC_Message)); if ((len = get_buffer_line(recvbuf.buffer, &buffer)) > 0) { - conn->lastmessage = ctime; + connection.lastmessage = ctime; char datebuf[25]; if (buffer.tags.time.value == NULL) { Assm_tag_timestamp(datebuf, sizeof(datebuf), ctime); @@ -298,64 +315,10 @@ int run_main(Connection* conn, char* quitmsg, unsigned int timeout) *(recvbuf.buffer + recvbuf.append_pos) = '\0'; active = true; } else if (len == -1) - conn->state = CONN_RECONNECTING; - - /* Buffer writer */ - if ((brd = read(fifobuf.fd, fifobuf.buffer + fifobuf.append_pos, sizeof(fifobuf.buffer) - fifobuf.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); - active = true; - } else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { - LOG(LOG_ERROR, "Failed to read FIFO input. " ERRNOFMT, strerror(errno), errno); - conn->state = CONN_RECONNECTING; - continue; - } - - memset((void*)&buffer, '\0', sizeof(IRC_Message)); - if ((len = get_buffer_line(fifobuf.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, conn->data.addr, conn->data.port, - strerror(errno), errno); - conn->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'; - active = true; - } else if (len == -1) - conn->state = CONN_RECONNECTING; + connection.state = CONN_RECONNECTING; } - LOG(LOG_VERBOSE, "Exiting thread with connection " ADDRFMT " gracefully.", conn->data.addr, conn->data.port); + LOG(LOG_VERBOSE, "%s", "Exiting gracefully."); return EXIT_SUCCESS; } -void print_help(void) -{ - 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", "~/.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("\t-%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'); - } -} - -void stop_loop() { run = 0; } - +void print_help(void) {} diff --git a/src/main.h b/src/main.h index 9cbf108..939705c 100644 --- a/src/main.h +++ b/src/main.h @@ -16,25 +16,29 @@ * along with uIRCd. If not, see . */ -#include "filesystem.h" -#include "log.h" -#include "misc.h" -#include "net.h" -#include "structs.h" -#include #include -#include #include #include -#include #include -#ifndef UIRCD_INCLUDED_MAIN -#define UIRCD_INCLUDED_MAIN -#define VERSION "2020.10.30.1-beta" +#include "configuration.h" +#include "connection.h" +#include "filesystem.h" +#include "logging.h" +#include "signal.h" -void stop_loop(void); -int run_main(Connection* conn, char* quitmsg, unsigned int timeout); -void print_help(void); -#endif +#define UIRC_IRCV3 +#define UIRC_HELPERS +#include + +#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] + +#endif /* UIRCD_GUARD_MAIN */ diff --git a/src/misc.c b/src/misc.c deleted file mode 100644 index e9adff6..0000000 --- a/src/misc.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 "misc.h" - -char* point_after(char* string, char point) -/* - * Used to tokenize right to left based on characters - * Replaces point with '\0' if found and points after it - */ -{ - char* ret = strchr(string, point); - if (ret != NULL) *(ret++) = '\0'; - return ret; -} - -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; - return len; -} - -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 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; -} - -int auto_msg_actions(IRC_Message* message, Connection* conn, Buffer_Info* buf) -{ - signed long len; - time_t ctime = time(NULL); - switch (message->cmd) { - case (PING): { - 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, conn->data.addr, conn->data.port, strerror(errno), - errno); - conn->state = CONN_RECONNECTING; - return 0; - } - break; - } - case (PONG): { - if (message->trailing && message->args[1] != NULL) { - LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]); - conn->lastpong = 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 - */ - case (RPL_WELCOME): { - LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.addr, conn->data.port); - conn->state = CONN_ACTIVE; - if (conn->data.chans != NULL) { - LOG(LOG_VERBOSE, "Auto-joining channels \"%s\" on " ADDRFMT ".", conn->data.chans, conn->data.addr, conn->data.port); - if ((len = Assm_mesg(buf->buffer, Assm_cmd_JOIN(conn->data.chans, 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, conn->data.chans, - conn->data.addr, conn->data.port, strerror(errno), errno); - conn->state = CONN_RECONNECTING; - return 0; - } - } - } - break; - } - /* - case (CAP): { - if (message->args[1] != NULL && strcmp(message->args[1], "LS") == 0) { - LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], conn->data.addr, - conn->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], - conn->data.addr, conn->data.port, strerror(errno), errno); - conn->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 ".", conn->data.addr, conn->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, conn->data.addr, - conn->data.port, strerror(errno), errno); - conn->state = CONN_RECONNECTING; - return 0; - } - } - } - break; - } - */ - case (ERROR): { - LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", conn->data.addr, conn->data.port, - message->args[0]); - break; - } - } - return 1; -} - diff --git a/src/misc.h b/src/misc.h deleted file mode 100644 index 5deb5f0..0000000 --- a/src/misc.h +++ /dev/null @@ -1,22 +0,0 @@ - -#include "global.h" -#include "log.h" -#include "net.h" -#include "structs.h" -#define UIRC_IRCV3 -#include "uirc/functions.h" -#include "uirc/helpers.h" -#include "uirc/mappings.h" -#include -#include -#include - -#ifndef UIRCD_INCLUDED_MISC -#define UIRCD_INCLUDED_MISC - -char* point_after(char* string, char point); -ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn); -ssize_t get_buffer_line(char* buf, IRC_Message* parsed); -int auto_msg_actions(IRC_Message* message, Connection* conn, Buffer_Info* buf); -#endif - diff --git a/src/net.c b/src/net.c deleted file mode 100644 index 4a52bf4..0000000 --- a/src/net.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 "net.h" - -signed int init_conn(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) { - LOG(LOG_ERROR, "Failed to get address info for %s:%s. %s (%i)", info->data.addr, info->data.port, gai_strerror(getaddrres), - getaddrres); - freeaddrinfo(conn); - if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) { - return INIT_HARDFAIL; - } else - 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); - freeaddrinfo(conn); - return INIT_HARDFAIL; - } - if ((connectres = connect(sockfd, conn->ai_addr, conn->ai_addrlen)) == -1) { - LOG(LOG_ERROR, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, info->data.addr, info->data.port, strerror(errno), errno); - close(sockfd); - freeaddrinfo(conn); - if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) { - return INIT_HARDFAIL; - } else - return INIT_SOFTFAIL; - } - freeaddrinfo(conn); - return sockfd; -} - -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) - return -1; - else - pos += res; - } else - return res; - } -} - diff --git a/src/signal.c b/src/signal.c new file mode 100644 index 0000000..206aef0 --- /dev/null +++ b/src/signal.c @@ -0,0 +1,38 @@ +/* + * 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 "signal.h" + +sig_atomic_t volatile run = true; +void stop_loop(int sig, siginfo_t* info, void* ucontext) { run = 0; } +int setup_signals(void) +{ + int res = 1; + struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = stop_loop}; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGINT, &sa, NULL) == -1) { + LOG(LOG_WARN, "sigaction() failed. Children won't respond to signal SIGINT. " ERRNOFMT, strerror(errno), errno); + res = 0; + } + if (sigaction(SIGTERM, &sa, NULL) == -1) { + LOG(LOG_WARN, "sigaction() failed. Children won't respond to signal SIGTERM. " ERRNOFMT, strerror(errno), errno); + res = 0; + } + return res; +} + diff --git a/src/signal.h b/src/signal.h new file mode 100644 index 0000000..c6db112 --- /dev/null +++ b/src/signal.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 // sig_atomic_t +#include // true, false +#include // NULL + +#ifndef UIRCD_GUARD_SIGNAL +#define UIRCD_GUARD_SIGNAL + +/* Description: + * This allows signals to be caught and for them to change something in the stack without causing problems or undefined behaviour */ +extern sig_atomic_t volatile run; + +void stop_loop(int sig, siginfo_t* info, void* ucontext); + +#endif /* UIRCD_GUARD_SIGNAL */