WIP: part 2
This commit is contained in:
parent
0da49cab10
commit
fc99d4e88f
|
@ -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})
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
address = "41.157.98.109";
|
||||
service = "9006";
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UIRC_IRCV3
|
||||
#define UIRC_HELPERS
|
||||
#include <uirc/uirc.h>
|
||||
|
||||
ssize_t get_buffer_line(char* buf, IRC_Message* parsed);
|
||||
ssize_t flush_buffer(char* buf, size_t buflen, int fd);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "connection.h"
|
||||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
#include "limits.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -38,3 +38,4 @@ extern const char logchars[];
|
|||
extern int loglevel;
|
||||
|
||||
#endif /* UIRCD_GUARD_LOGGING */
|
||||
|
||||
|
|
388
src/main.c
388
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 <host> [ <options> ... ]\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) {}
|
||||
|
|
|
@ -21,10 +21,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef UIRCD_GUARD_MEMORY
|
||||
#define UIRCD_GUARD_MEMORY
|
||||
|
||||
int allocate_copy(char** ptr, const char* var);
|
||||
|
||||
#endif /* UIRCD_GUARD_MEMORY */
|
||||
|
|
@ -19,6 +19,10 @@
|
|||
#include <signal.h> // sig_atomic_t
|
||||
#include <stdbool.h> // true, false
|
||||
#include <stdio.h> // NULL
|
||||
#include <errno.h> // errno
|
||||
#include <string.h> // 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 */
|
||||
|
||||
|
|
Reference in New Issue