WIP: cleanup code
This commit is contained in:
parent
7329529bca
commit
0da49cab10
|
@ -21,10 +21,12 @@ add_executable(uircd
|
||||||
src/filesystem.c
|
src/filesystem.c
|
||||||
src/misc.c
|
src/misc.c
|
||||||
src/log.c
|
src/log.c
|
||||||
|
src/parsers.c
|
||||||
|
src/conns.c
|
||||||
)
|
)
|
||||||
|
|
||||||
find_library(UIRC_PATH NAMES uirc libuirc REQUIRED)
|
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)
|
set_property(TARGET uircd PROPERTY C_STANDARD 99)
|
||||||
|
|
||||||
install(TARGETS uircd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS uircd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -16,41 +16,23 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include "connection.h"
|
||||||
#define UIRC_IRCV3
|
#include "logging.h"
|
||||||
#include "uirc/types.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_STRUCTS
|
#include <libconfig.h>
|
||||||
#define UIRCD_INCLUDED_STRUCTS
|
|
||||||
typedef struct {
|
|
||||||
char *addr, *port, *chans;
|
|
||||||
bool ssl;
|
|
||||||
} Connection_Data;
|
|
||||||
|
|
||||||
typedef struct {
|
#ifndef UIRCD_GUARD_CONFIGURATION
|
||||||
char buffer[513];
|
#define UIRCD_GUARD_CONFIGURATION
|
||||||
size_t append_pos;
|
|
||||||
int fd;
|
|
||||||
} Buffer_Info;
|
|
||||||
|
|
||||||
typedef struct {
|
#define UIRCD_DEFAULT_ADDR "localhost"
|
||||||
IRC_User names;
|
#define UIRCD_DEFAULT_PORT "6667"
|
||||||
Connection_Data data;
|
#define UIRCD_DEFAULT_NICK "uirc-user"
|
||||||
time_t lastping, lastpong, lastconnect, lastmessage;
|
#define UIRCD_DEFAULT_USER "uIRC-user"
|
||||||
signed short state;
|
#define UIRCD_DEFAULT_REAL "uIRC user"
|
||||||
pid_t pid;
|
|
||||||
} Connection;
|
|
||||||
|
|
||||||
typedef struct {
|
void parse_cmdline_conn(char* arg, Connection* conn);
|
||||||
char* bufpos;
|
int parse_configfile(char* config_path, Connection* conn);
|
||||||
size_t len;
|
void set_conn_defaults(Connection* conn);
|
||||||
} PathBufElem;
|
|
||||||
|
|
||||||
typedef struct {
|
#endif /* UIRCD_GUARD_CONFIGURATION */
|
||||||
char buf[MAXPATH];
|
|
||||||
PathBufElem elements[5];
|
|
||||||
} PathBuf;
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -16,29 +16,25 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define UIRC_HELPERS
|
#include "limits.h"
|
||||||
#define UIRC_IRCV3
|
#include "logging.h"
|
||||||
#include "global.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "structs.h"
|
|
||||||
#include "uirc/functions.h"
|
|
||||||
#include "uirc/helpers.h"
|
|
||||||
#include "uirc/mappings.h"
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <poll.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_NETWORK
|
#define UIRC_IRCV3
|
||||||
#define UIRCD_INCLUDED_NETWORK
|
#define UIRC_HELPERS
|
||||||
|
#include <uirc/uirc.h>
|
||||||
|
|
||||||
|
#ifndef UIRCD_GUARD_CONNECTION
|
||||||
|
#define UIRCD_GUARD_CONNECTION
|
||||||
|
|
||||||
|
#define INIT_HARDFAIL -1
|
||||||
|
#define INIT_SOFTFAIL -2
|
||||||
|
|
||||||
#define CONN_ACTIVE 2
|
#define CONN_ACTIVE 2
|
||||||
#define CONN_REGISTERED 1
|
#define CONN_REGISTERED 1
|
||||||
|
@ -47,10 +43,29 @@
|
||||||
#define CONN_CLOSING -2
|
#define CONN_CLOSING -2
|
||||||
#define CONN_CLOSED -3
|
#define CONN_CLOSED -3
|
||||||
|
|
||||||
#define INIT_HARDFAIL -1
|
typedef struct {
|
||||||
#define INIT_SOFTFAIL -2
|
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);
|
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 */
|
106
src/filesystem.c
106
src/filesystem.c
|
@ -114,59 +114,61 @@ ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf*
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Put this somewhere else and improve it
|
||||||
signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connection* conn)
|
signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer, Connection* conn)
|
||||||
{
|
{
|
||||||
if (message == NULL || pathbuffer == NULL) return -2;
|
if (message == NULL || pathbuffer == NULL) return -2;
|
||||||
char* reused_strings[] = {"channel", "user", "global"};
|
char* reused_strings[] = {"channel", "user", "global"};
|
||||||
struct elems {
|
struct elems {
|
||||||
char* name;
|
char* name;
|
||||||
bool isdir;
|
bool isdir;
|
||||||
} elements[] = {{reused_strings[0], true}, {NULL, true}, {"out", false}};
|
} elements[] = {{reused_strings[0], true}, {NULL, true}, {"out", false}};
|
||||||
char temp[MAXLINE];
|
char temp[UIRCD_LIMITS_LINE];
|
||||||
if (ISCMD(JOIN) || ISCMD(PART) || ISCMD(QUIT) || ISCMD(RPL_USERSSTART) || ISCMD(RPL_USERS) || ISCMD(RPL_NOUSERS) || ISCMD(RPL_ENDOFUSERS)
|
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)) {
|
|| ISCMD(RPL_NAMREPLY) || ISCMD(RPL_ENDOFNAMES)) {
|
||||||
elements[0].name = reused_strings[2];
|
elements[0].name = reused_strings[2];
|
||||||
elements[1].name = "events";
|
elements[1].name = "events";
|
||||||
elements[1].isdir = false;
|
elements[1].isdir = false;
|
||||||
} else if (ISCMD(MOTD) || ISCMD(RPL_MOTD) || ISCMD(RPL_MOTDSTART) || ISCMD(RPL_ENDOFMOTD) || ISCMD(ERR_NOMOTD)) {
|
} else if (ISCMD(MOTD) || ISCMD(RPL_MOTD) || ISCMD(RPL_MOTDSTART) || ISCMD(RPL_ENDOFMOTD) || ISCMD(ERR_NOMOTD)) {
|
||||||
elements[0].name = reused_strings[2];
|
elements[0].name = reused_strings[2];
|
||||||
elements[1].name = "motd";
|
elements[1].name = "motd";
|
||||||
elements[1].isdir = false;
|
elements[1].isdir = false;
|
||||||
} else if (ISCMD(PING) || ISCMD(PONG)) {
|
} else if (ISCMD(PING) || ISCMD(PONG)) {
|
||||||
elements[0].name = reused_strings[2];
|
elements[0].name = reused_strings[2];
|
||||||
elements[1].name = "pings";
|
elements[1].name = "pings";
|
||||||
elements[1].isdir = false;
|
elements[1].isdir = false;
|
||||||
} else if (ISCMD(RPL_LIST) || ISCMD(RPL_LISTEND)) {
|
} else if (ISCMD(RPL_LIST) || ISCMD(RPL_LISTEND)) {
|
||||||
elements[0].name = reused_strings[2];
|
elements[0].name = reused_strings[2];
|
||||||
elements[1].name = "channels";
|
elements[1].name = "channels";
|
||||||
elements[1].isdir = false;
|
elements[1].isdir = false;
|
||||||
} else if (ISCMD(PRIVMSG) || ISCMD(NOTICE)) {
|
} else if (ISCMD(PRIVMSG) || ISCMD(NOTICE)) {
|
||||||
if (message->args[0] == NULL) return -2;
|
if (message->args[0] == NULL) return -2;
|
||||||
if (strcmp(conn->names.nick, message->args[0]) == 0 && message->name.nick != NULL) {
|
if (strcmp(conn->names.nick, message->args[0]) == 0 && message->name.nick != NULL) {
|
||||||
elements[0].name = reused_strings[1];
|
elements[0].name = reused_strings[1];
|
||||||
strncpy(temp, message->name.nick, sizeof(temp));
|
strncpy(temp, message->name.nick, sizeof(temp));
|
||||||
} else if (*message->args[0] == '#' || *message->args[0] == '&' || *message->args[0] == '+' || *message->args[0] == '!') {
|
} else if (*message->args[0] == '#' || *message->args[0] == '&' || *message->args[0] == '+' || *message->args[0] == '!') {
|
||||||
strncpy(temp, message->args[0], sizeof(temp));
|
strncpy(temp, message->args[0], sizeof(temp));
|
||||||
} else
|
} else
|
||||||
return 0; // TODO: Parse patterns as well
|
return 0; // TODO: Parse patterns as well
|
||||||
cleanup_path_names(temp);
|
cleanup_path_names(temp);
|
||||||
elements[1].name = temp;
|
elements[1].name = temp;
|
||||||
} else if (ISCMD(RPL_TOPIC) || ISCMD(RPL_NOTOPIC)) {
|
} else if (ISCMD(RPL_TOPIC) || ISCMD(RPL_NOTOPIC)) {
|
||||||
if (message->args[0] == NULL || message->args[1] == NULL) return -2;
|
if (message->args[0] == NULL || message->args[1] == NULL) return -2;
|
||||||
if (message->args[2] != NULL)
|
if (message->args[2] != NULL)
|
||||||
strncpy(temp, message->args[1], sizeof(temp));
|
strncpy(temp, message->args[1], sizeof(temp));
|
||||||
else
|
else
|
||||||
strncpy(temp, message->args[0], sizeof(temp));
|
strncpy(temp, message->args[0], sizeof(temp));
|
||||||
cleanup_path_names(temp);
|
cleanup_path_names(temp);
|
||||||
elements[1].name = temp;
|
elements[1].name = temp;
|
||||||
elements[2].name = "topic";
|
elements[2].name = "topic";
|
||||||
} else
|
} else
|
||||||
return 0;
|
return 0;
|
||||||
for (unsigned long i = 0; i < sizeof(elements) / sizeof(*elements); i++) {
|
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 (set_path_elem(elements[i].name, (unsigned int)i + 1, elements[i].isdir, pathbuffer) <= 0) return -1;
|
||||||
if (!elements[i].isdir) return 1;
|
if (!elements[i].isdir) return 1;
|
||||||
if (!mkdir_bottomup(pathbuffer->buf)) return -1;
|
if (!mkdir_bottomup(pathbuffer->buf)) return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -16,31 +16,32 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "structs.h"
|
|
||||||
#define UIRC_IRCV3
|
|
||||||
#include "uirc/functions.h"
|
|
||||||
#include "uirc/mappings.h"
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_FS
|
#define UIRC_IRCV3
|
||||||
#define UIRCD_INCLUDED_FS
|
#include <uirc/types.h>
|
||||||
|
|
||||||
int mkdir_bottomup(char* path);
|
#include "connection.h"
|
||||||
int makeinput(char* path);
|
#include "limits.h"
|
||||||
bool cleanup_path_names(char* name);
|
#include "logging.h"
|
||||||
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))
|
|
||||||
|
|
||||||
#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 */
|
||||||
|
|
|
@ -16,19 +16,12 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <signal.h>
|
#ifndef UIRCD_GUARD_LIMITS
|
||||||
|
#define UIRCD_GUARD_LIMITS
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_GLOBAL
|
#define UIRCD_LIMITS_LINE 512
|
||||||
#define UIRCD_INCLUDED_GLOBAL
|
#define UIRCD_LIMITS_NICK 32
|
||||||
|
#define UIRCD_LIMITS_USER 32
|
||||||
#define MAXLINE 512
|
#define UIRCD_LIMITS_REAL 32
|
||||||
#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
|
|
||||||
|
|
||||||
|
#endif /* UIRCD_GUARD_LIMITS */
|
|
@ -16,7 +16,8 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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'};
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd)
|
* 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
|
* Copyright (c) 2019, 2020 Alex-David Denes
|
||||||
* General Public License as published by * the Free Software Foundation, either version 3 of the License, or any later version.
|
*
|
||||||
|
* 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,
|
* uIRCd is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
@ -12,14 +16,10 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include <stdio.h> // fprintf()
|
||||||
#include "structs.h"
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_LOG
|
#ifndef UIRCD_GUARD_LOGGING
|
||||||
#define UIRCD_INCLUDED_LOG
|
#define UIRCD_GUARD_LOGGING
|
||||||
|
|
||||||
#define LOG_FATAL 0
|
#define LOG_FATAL 0
|
||||||
#define LOG_ERROR 1
|
#define LOG_ERROR 1
|
||||||
|
@ -27,10 +27,14 @@
|
||||||
#define LOG_INFO 3
|
#define LOG_INFO 3
|
||||||
#define LOG_VERBOSE 4
|
#define LOG_VERBOSE 4
|
||||||
#define LOG_DEBUG 5
|
#define LOG_DEBUG 5
|
||||||
extern char logchars[];
|
|
||||||
|
#define ERRNOFMT "%s (%i)"
|
||||||
|
#define ADDRFMT "%s:%s"
|
||||||
|
|
||||||
#define LOG(LEVEL, FORMAT, ...) \
|
#define LOG(LEVEL, FORMAT, ...) \
|
||||||
if (LEVEL <= loglevel) fprintf(stderr, "[%c:L%i] " FORMAT "\n", logchars[LEVEL], __LINE__, __VA_ARGS__)
|
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 */
|
341
src/main.c
341
src/main.c
|
@ -18,16 +18,9 @@
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
sig_atomic_t volatile run = true;
|
|
||||||
int loglevel = LOG_FATAL;
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int c;
|
Connection connection;
|
||||||
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. */
|
|
||||||
|
|
||||||
/* Arguments:
|
/* Arguments:
|
||||||
* -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ]
|
* -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ]
|
||||||
* -l Starting directory for message tree
|
* -l Starting directory for message tree
|
||||||
|
@ -38,21 +31,13 @@ int main(int argc, char* argv[])
|
||||||
* -v Version and license information
|
* -v Version and license information
|
||||||
* -h Help/Usage
|
* -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) {
|
switch (c) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
cons[totcon].data.chans = point_after(optarg, ',');
|
/* NOTE: PASS and capabilities cannot be provided via the command line (per-connection).
|
||||||
if ((cons[totcon].data.port = point_after(optarg, '/')) != NULL) {
|
* Consider using the configuration file. */
|
||||||
if (*cons[totcon].data.port == '+') {
|
parse_cmdline_conn(optarg, &connection);
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'l': {
|
case 'l': {
|
||||||
|
@ -63,66 +48,46 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'm': quitmsg = optarg; break;
|
case 'm': connection.quitmsg = optarg; break;
|
||||||
case 't': timeout = (unsigned int)atoi(optarg); break;
|
case 't': connection.timeout = (unsigned int)atoi(optarg); break;
|
||||||
case 'C': break; // TODO: Reserved for config file path
|
case 'C': {
|
||||||
|
parse_configfile(optarg, &connection);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'V': loglevel = atoi(optarg); break;
|
case 'V': loglevel = atoi(optarg); break;
|
||||||
case 'v': {
|
case 'v': {
|
||||||
printf("uIRCd version " VERSION "\n");
|
printf("uIRCd version " VERSION "\n");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
case 'h': print_help(); return EXIT_SUCCESS;
|
case 'h': {
|
||||||
}
|
// TODO: Fix this
|
||||||
}
|
struct help {
|
||||||
if (totcon < 1) {
|
char arg;
|
||||||
LOG(LOG_FATAL, "%s", "No connection was provided.");
|
char* desc;
|
||||||
return EXIT_FAILURE;
|
char* def;
|
||||||
}
|
} arg_list[] = {{'c', "Define connection in format \"nick!user:real name@host/+port,#channel1,#channel2\"", NULL},
|
||||||
|
{'l', "Directory for logs", "current dir"},
|
||||||
pid_t cpid;
|
{'m', "Quit message", "uIRC indev beta"},
|
||||||
struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = stop_loop};
|
{'t', "Timeout duration", "30 seconds"},
|
||||||
sigemptyset(&sa.sa_mask);
|
{'V', "Log level (0-5)", "0 [LOG_FATAL]"},
|
||||||
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
{'C', "Configuration path", "${XDG_CONFIG_HOME:-~/.config}/uircd/main.conf"},
|
||||||
LOG(LOG_WARN, "sigaction() failed. Children won't respond to signals. " ERRNOFMT, strerror(errno), errno);
|
{'v', "Print version information", NULL},
|
||||||
}
|
{'h', "Print this help message", NULL}};
|
||||||
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
printf("usage: uirc -c [connection] [options...]\n");
|
||||||
LOG(LOG_WARN, "sigaction() failed. Children won't respond to signals. " ERRNOFMT, strerror(errno), errno);
|
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);
|
||||||
for (unsigned int actcon = 0; actcon < totcon && run; actcon++) {
|
putchar('\n');
|
||||||
cpid = fork();
|
}
|
||||||
if (cpid == -1) {
|
return EXIT_SUCCESS;
|
||||||
if (errno != EAGAIN) {
|
|
||||||
LOG(LOG_FATAL, "Failed to fork child. " ERRNOFMT, strerror(errno), errno);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} 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;) {
|
set_conn_defaults(&connection);
|
||||||
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)
|
|
||||||
{
|
|
||||||
srand((unsigned int)time(NULL));
|
srand((unsigned int)time(NULL));
|
||||||
IRC_Message buffer;
|
IRC_Message buffer;
|
||||||
Buffer_Info buffers[3]; /* Buffers */
|
Buffer_Info buffers[3]; /* Buffers */
|
||||||
#define recvbuf buffers[0]
|
|
||||||
#define sendbuf buffers[1]
|
|
||||||
#define fifobuf buffers[2]
|
|
||||||
PathBuf filebuf;
|
PathBuf filebuf;
|
||||||
signed int reconinter = 0;
|
signed int reconinter = 0;
|
||||||
time_t ctime;
|
time_t ctime;
|
||||||
|
@ -132,135 +97,188 @@ int run_main(Connection* conn, char* quitmsg, unsigned int timeout)
|
||||||
ctime = time(NULL);
|
ctime = time(NULL);
|
||||||
if (!active) nanosleep(&sleep, NULL);
|
if (!active) nanosleep(&sleep, NULL);
|
||||||
active = false;
|
active = false;
|
||||||
if (!run || conn->state == CONN_CLOSING) {
|
if (!run || connection.state == CONN_CLOSING) {
|
||||||
signed long temp;
|
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;
|
sendbuf.append_pos = (unsigned long)temp;
|
||||||
LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port,
|
LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", connection.data.addr,
|
||||||
quitmsg);
|
connection.data.port, connection.quitmsg);
|
||||||
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1)
|
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,
|
LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, connection.data.addr,
|
||||||
strerror(errno), errno);
|
connection.data.port, strerror(errno), errno);
|
||||||
}
|
}
|
||||||
close(sendbuf.fd);
|
close(sendbuf.fd);
|
||||||
close(fifobuf.fd);
|
close(fifobuf.fd);
|
||||||
conn->state = CONN_CLOSED;
|
connection.state = CONN_CLOSED;
|
||||||
LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", conn->data.addr, conn->data.port);
|
LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", connection.data.addr, connection.data.port);
|
||||||
break;
|
break;
|
||||||
} else if (conn->state == CONN_CLOSED)
|
} else if (connection.state == CONN_CLOSED)
|
||||||
break;
|
break;
|
||||||
else if (conn->state == CONN_RECONNECTING) {
|
else if (connection.state == CONN_RECONNECTING) {
|
||||||
close(sendbuf.fd);
|
close(sendbuf.fd);
|
||||||
close(fifobuf.fd);
|
close(fifobuf.fd);
|
||||||
conn->state = CONN_PENDING;
|
connection.state = CONN_PENDING;
|
||||||
if (reconinter == 0)
|
if (reconinter == 0) {
|
||||||
reconinter = 10;
|
reconinter = 2;
|
||||||
else if (reconinter > 300)
|
} else if (reconinter > 300) {
|
||||||
reconinter = 300;
|
reconinter = 300;
|
||||||
else
|
} else {
|
||||||
reconinter *= 2;
|
reconinter *= 2;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (conn->state == CONN_PENDING) {
|
} else if (connection.state == CONN_PENDING) {
|
||||||
if (ctime - conn->lastconnect < reconinter) continue;
|
if (ctime - connection.lastconnect < reconinter) continue;
|
||||||
conn->lastconnect = ctime;
|
connection.lastconnect = ctime;
|
||||||
filebuf.elements[0].bufpos = filebuf.buf;
|
filebuf.elements[0].bufpos = filebuf.buf;
|
||||||
|
|
||||||
/* Reset all state-dependent values to empty */
|
/* Reset all state-dependent values to empty */
|
||||||
memset(&recvbuf, '\0', sizeof(recvbuf));
|
memset(&recvbuf, '\0', sizeof(recvbuf));
|
||||||
|
recvbuf.fd = -1;
|
||||||
memset(&sendbuf, '\0', sizeof(sendbuf));
|
memset(&sendbuf, '\0', sizeof(sendbuf));
|
||||||
|
sendbuf.fd = -1;
|
||||||
memset(&fifobuf, '\0', sizeof(fifobuf));
|
memset(&fifobuf, '\0', sizeof(fifobuf));
|
||||||
conn->lastping = 0;
|
fifobuf.fd = -1;
|
||||||
conn->lastpong = 0;
|
connection.lastping = 0;
|
||||||
conn->lastmessage = 0;
|
connection.lastpong = 0;
|
||||||
|
connection.lastmessage = 0;
|
||||||
|
|
||||||
/* Prepare first part of path */
|
/* Prepare first part of path */
|
||||||
char tempath[MAXPATH];
|
char tempath[MAXPATH];
|
||||||
if ((get_connstr(tempath, sizeof(tempath), conn)) >= 0) {
|
if ((get_connstr(tempath, sizeof(tempath), conn)) >= 0) {
|
||||||
cleanup_path_names(tempath);
|
cleanup_path_names(tempath);
|
||||||
if (set_path_elem(tempath, 0, true, &filebuf) > 0 && set_path_elem("global", 1, true, &filebuf) > 0) {
|
if (set_path_elem(tempath, 0, true, &filebuf) > 0 && set_path_elem("global", 1, true, &filebuf) > 0) {
|
||||||
if (!mkdir_bottomup(filebuf.buf)) break;
|
if (mkdir_bottomup(filebuf.buf)) {
|
||||||
if (set_path_elem("in", 2, false, &filebuf)) {
|
if (set_path_elem("in", 2, false, &filebuf))
|
||||||
if ((fifobuf.fd = makeinput(filebuf.buf)) == -1) break;
|
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) {
|
if ((sendbuf.fd = init_conn(conn)) > 0) {
|
||||||
recvbuf.fd = sendbuf.fd;
|
recvbuf.fd = sendbuf.fd;
|
||||||
add_socket_flags(sendbuf.fd, O_NONBLOCK);
|
add_socket_flags(sendbuf.fd, O_NONBLOCK);
|
||||||
/* Send NICK and USER registration */
|
|
||||||
// TODO: PASS
|
/* Registration process and CAP negotiation (TODO) */
|
||||||
signed long temp;
|
signed long temp;
|
||||||
/*
|
/*
|
||||||
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_CAP_LS("302"), sizeof(sendbuf.buffer))) > 0) {
|
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_CAP_LS("302"), sizeof(sendbuf.buffer))) > 0) {
|
||||||
sendbuf.append_pos = (size_t)temp;
|
sendbuf.append_pos = (size_t)temp;
|
||||||
LOG(LOG_VERBOSE, "Sending a CAP LS to " ADDRFMT ".", conn->data.addr, conn->data.port);
|
LOG(LOG_VERBOSE, "Sending a CAP LS to " ADDRFMT ".", connection.data.addr,
|
||||||
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
|
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, conn->data.addr, conn->data.port,
|
{ LOG(LOG_WARN, "Couldn't send CAP LS to " ADDRFMT ". " ERRNOFMT, connection.data.addr,
|
||||||
strerror(errno), errno);
|
connection.data.port, strerror(errno), errno); connection.state = CONN_RECONNECTING; continue;
|
||||||
conn->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;
|
sendbuf.append_pos = (size_t)temp;
|
||||||
LOG(LOG_VERBOSE, "Sending a NICK registration to " ADDRFMT " containing \"%s\".", conn->data.addr,
|
LOG(LOG_VERBOSE, "Sending PASS authentication to " ADDRFMT, connection.data.addr, connection.data.port);
|
||||||
conn->data.port, conn->names.nick);
|
|
||||||
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
|
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
|
||||||
LOG(LOG_WARN, "Couldn't register nickname on " ADDRFMT ". " ERRNOFMT, conn->data.addr,
|
LOG(LOG_WARN, "Couldn't send PASS authentication on " ADDRFMT ". " ERRNOFMT, connection.data.addr,
|
||||||
conn->data.port, strerror(errno), errno);
|
connection.data.port, strerror(errno), errno);
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
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) {
|
> 0) {
|
||||||
sendbuf.append_pos = (size_t)temp;
|
sendbuf.append_pos = (size_t)temp;
|
||||||
LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", conn->data.addr,
|
LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", connection.data.addr,
|
||||||
conn->data.port, conn->names.real);
|
connection.data.port, connection.names.real);
|
||||||
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
|
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,
|
LOG(LOG_WARN, "Couldn't register user and real name on " ADDRFMT ". " ERRNOFMT, connection.data.addr,
|
||||||
conn->data.port, strerror(errno), errno);
|
connection.data.port, strerror(errno), errno);
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn->state = CONN_REGISTERED;
|
connection.state = CONN_REGISTERED;
|
||||||
} else if (sendbuf.fd == INIT_SOFTFAIL) {
|
} else if (sendbuf.fd == INIT_SOFTFAIL) {
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
} else if (sendbuf.fd == INIT_HARDFAIL) {
|
} else if (sendbuf.fd == INIT_HARDFAIL) {
|
||||||
conn->state = CONN_CLOSED;
|
connection.state = CONN_CLOSED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if (conn->state == CONN_ACTIVE) {
|
} else if (connection.state == CONN_ACTIVE) {
|
||||||
reconinter = 0;
|
reconinter = 0;
|
||||||
if (conn->lastmessage < ctime - timeout && conn->lastpong < conn->lastping - timeout) {
|
if (connection.lastmessage < ctime - timeout && connection.lastpong < connection.lastping - timeout) {
|
||||||
LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", conn->data.addr, conn->data.port);
|
LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", connection.data.addr, connection.data.port);
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
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";
|
char mesg[] = "uIRC PING -- XXXXXX";
|
||||||
snprintf(mesg + sizeof(mesg) - 7, 7, "%.6i", rand());
|
snprintf(mesg + sizeof(mesg) - 7, 7, "%.6i", rand());
|
||||||
signed long temp;
|
signed long temp;
|
||||||
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf.buffer))) > 0) {
|
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf.buffer))) > 0) {
|
||||||
sendbuf.append_pos = (size_t)temp;
|
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) {
|
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);
|
strerror(errno), errno);
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
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 */
|
/* Buffer reader */
|
||||||
if ((brd = read(recvbuf.fd, recvbuf.buffer + recvbuf.append_pos, sizeof(recvbuf.buffer) - recvbuf.append_pos - 1)) > 0) {
|
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';
|
*(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;
|
active = true;
|
||||||
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
||||||
LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno);
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t len;
|
|
||||||
memset((void*)&buffer, '\0', sizeof(IRC_Message));
|
memset((void*)&buffer, '\0', sizeof(IRC_Message));
|
||||||
if ((len = get_buffer_line(recvbuf.buffer, &buffer)) > 0) {
|
if ((len = get_buffer_line(recvbuf.buffer, &buffer)) > 0) {
|
||||||
conn->lastmessage = ctime;
|
connection.lastmessage = ctime;
|
||||||
char datebuf[25];
|
char datebuf[25];
|
||||||
if (buffer.tags.time.value == NULL) {
|
if (buffer.tags.time.value == NULL) {
|
||||||
Assm_tag_timestamp(datebuf, sizeof(datebuf), ctime);
|
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';
|
*(recvbuf.buffer + recvbuf.append_pos) = '\0';
|
||||||
active = true;
|
active = true;
|
||||||
} else if (len == -1)
|
} else if (len == -1)
|
||||||
conn->state = CONN_RECONNECTING;
|
connection.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;
|
|
||||||
}
|
}
|
||||||
LOG(LOG_VERBOSE, "Exiting thread with connection " ADDRFMT " gracefully.", conn->data.addr, conn->data.port);
|
LOG(LOG_VERBOSE, "%s", "Exiting gracefully.");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_help(void)
|
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; }
|
|
||||||
|
|
||||||
|
|
34
src/main.h
34
src/main.h
|
@ -16,25 +16,29 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "filesystem.h"
|
|
||||||
#include "log.h"
|
|
||||||
#include "misc.h"
|
|
||||||
#include "net.h"
|
|
||||||
#include "structs.h"
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#ifndef UIRCD_INCLUDED_MAIN
|
#include "configuration.h"
|
||||||
#define UIRCD_INCLUDED_MAIN
|
#include "connection.h"
|
||||||
#define VERSION "2020.10.30.1-beta"
|
#include "filesystem.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "signal.h"
|
||||||
|
|
||||||
void stop_loop(void);
|
#define UIRC_IRCV3
|
||||||
int run_main(Connection* conn, char* quitmsg, unsigned int timeout);
|
#define UIRC_HELPERS
|
||||||
void print_help(void);
|
#include <uirc/uirc.h>
|
||||||
#endif
|
|
||||||
|
#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 */
|
||||||
|
|
||||||
|
|
133
src/misc.c
133
src/misc.c
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
22
src/misc.h
22
src/misc.h
|
@ -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 <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
66
src/net.c
66
src/net.c
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -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 <signal.h> // sig_atomic_t
|
||||||
|
#include <stdbool.h> // true, false
|
||||||
|
#include <stdio.h> // 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 */
|
Reference in New Issue