Compare commits
21 Commits
2021.01.03
...
master
Author | SHA1 | Date |
---|---|---|
|
9a357c63e7 | |
|
b5e46c5635 | |
|
14664963e7 | |
|
b0350595ba | |
|
6fb4c44039 | |
|
7b9b39e1a9 | |
|
f4b2cb90f3 | |
|
af191b4364 | |
|
75d79a5c87 | |
|
fd976a9066 | |
|
fd2821f444 | |
|
845066176d | |
|
f9931033b4 | |
|
d6491bb593 | |
|
9b07bcb10b | |
|
58acf3e337 | |
|
75480d3606 | |
|
17fb6344bd | |
|
77e4d79599 | |
|
84caf7ad8e | |
|
bde12cdec2 |
|
@ -17,7 +17,7 @@ BinPackParameters: 'false'
|
||||||
BreakBeforeBinaryOperators: NonAssignment
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
BreakBeforeBraces: Linux
|
BreakBeforeBraces: Linux
|
||||||
BreakStringLiterals: 'false'
|
BreakStringLiterals: 'false'
|
||||||
ColumnLimit: '150'
|
ColumnLimit: '200'
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||||
Cpp11BracedListStyle: 'false'
|
Cpp11BracedListStyle: 'false'
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
project(microircd LANGUAGES C)
|
project(
|
||||||
|
uIRCd
|
||||||
|
VERSION 2021.01.24
|
||||||
|
DESCRIPTION "High performance IRC daemon based on uIRC"
|
||||||
|
LANGUAGES C
|
||||||
|
)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
set(UIRCD_VERSION "${PROJECT_VERSION}")
|
||||||
|
add_compile_definitions(UIRCD_VERSION="${UIRCD_VERSION}")
|
||||||
|
add_compile_definitions(UIRC_HELPERS UIRC_IRCV3)
|
||||||
|
|
||||||
set(UIRCD_VERSION "2021.01.03")
|
OPTION(BUILD_LIBCONFIG "Build support for configurations" ON )
|
||||||
add_compile_definitions(UIRCD_VERSION="${UIRC_VERSION}")
|
OPTION(CODE_ANALYZER "Analyze the code statically" OFF)
|
||||||
|
OPTION(CODE_COVERAGE "Build with coverage tools" OFF)
|
||||||
OPTION(CODE_ANALYZER "Analyze the code statically" OFF)
|
|
||||||
OPTION(CODE_COVERAGE "Build with coverage tools" OFF)
|
|
||||||
|
|
||||||
add_executable(uircd
|
add_executable(uircd
|
||||||
src/buffer.c
|
src/buffer.c
|
||||||
src/configuration.c
|
src/configuration.c
|
||||||
src/connection.c
|
src/connection.c
|
||||||
src/filesystem.c
|
src/filesystem.c
|
||||||
src/logging.c
|
|
||||||
src/main.c
|
src/main.c
|
||||||
src/memory.c
|
src/memory.c
|
||||||
|
src/misc.c
|
||||||
src/signal.c
|
src/signal.c
|
||||||
src/channels.c
|
src/channels.c
|
||||||
)
|
)
|
||||||
|
@ -24,53 +29,33 @@ add_executable(uircd
|
||||||
find_library(UIRC_PATH NAMES uirc REQUIRED)
|
find_library(UIRC_PATH NAMES uirc REQUIRED)
|
||||||
target_link_libraries(uircd ${UIRC_PATH})
|
target_link_libraries(uircd ${UIRC_PATH})
|
||||||
|
|
||||||
find_library(LIBCONFIG_PATH NAMES config)
|
if(BUILD_LIBCONFIG)
|
||||||
if(NOT LIBCONFIG_PATH)
|
find_library(LIBCONFIG_PATH NAMES config)
|
||||||
message(WARNING "libconfig not found. uIRCd will not support configuration files")
|
if(NOT LIBCONFIG_PATH)
|
||||||
else()
|
message(WARNING "libconfig not found. uIRCd will not support configuration files")
|
||||||
message(STATUS "Building with libconfig support")
|
else()
|
||||||
add_compile_definitions(UIRCD_FEATURE_LIBCONFIG)
|
message(STATUS "Building with libconfig support")
|
||||||
target_link_libraries(uircd ${LIBCONFIG_PATH})
|
add_compile_definitions(UIRCD_FEATURE_LIBCONFIG)
|
||||||
|
target_link_libraries(uircd ${LIBCONFIG_PATH})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Werror")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Werror")
|
||||||
add_compile_options(-pedantic)
|
|
||||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||||
add_compile_options(
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -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 -fstack-check -pedantic")
|
||||||
-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
|
|
||||||
-fstack-check
|
|
||||||
)
|
|
||||||
if (CODE_ANALYZER)
|
if (CODE_ANALYZER)
|
||||||
add_compile_options(-fanalyzer)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fanalyzer")
|
||||||
endif()
|
endif()
|
||||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||||
add_compile_options(
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Weverything -Wno-padded -Wno-disabled-macro-expansion -pedantic")
|
||||||
-Weverything
|
|
||||||
-Wno-padded
|
|
||||||
-Wno-disabled-macro-expansion
|
|
||||||
)
|
|
||||||
if (CODE_COVERAGE)
|
if (CODE_COVERAGE)
|
||||||
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_target_properties(uircd PROPERTIES
|
set_target_properties(uircd PROPERTIES
|
||||||
C_STANDARD 99
|
C_STANDARD 99
|
||||||
VERSION "${UIRCD_VERSION}"
|
VERSION ${UIRCD_VERSION}
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
|
|
@ -15,7 +15,8 @@ cmake -B build/ -DCMAKE_BUILD_TYPE=Release .
|
||||||
```
|
```
|
||||||
| Option | Description | Type | Default | Supported since |
|
| Option | Description | Type | Default | Supported since |
|
||||||
|:------------------:|:----------------------------------------------------------------------:|:--------:|:-------:|:---------------:|
|
|:------------------:|:----------------------------------------------------------------------:|:--------:|:-------:|:---------------:|
|
||||||
| CODE_ANALYZER | Use static analysis tools | boolean | true | 2020.10.30 |
|
| BUILD_LIBCONFIG | Build and link against libconfig | boolean | true | 2021.01.04 |
|
||||||
|
| CODE_ANALYZER | Use static analysis tools | boolean | false | 2020.10.30 |
|
||||||
| CODE_COVERAGE | Generate code coverage output | boolean | false | 2020.10.30 |
|
| CODE_COVERAGE | Generate code coverage output | boolean | false | 2020.10.30 |
|
||||||
|
|
||||||
Following that, just use your build system and compile it
|
Following that, just use your build system and compile it
|
||||||
|
|
72
src/buffer.c
72
src/buffer.c
|
@ -20,42 +20,70 @@
|
||||||
|
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
#include <assert.h> // assert()
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
#include <stdio.h> // fprintf()
|
#include <stdio.h> // fprintf()
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
#include <sys/types.h> // size_t ssize_t
|
#include <sys/types.h> // size_t ssize_t
|
||||||
|
#include <syslog.h> // syslog()
|
||||||
#include <unistd.h> // write()
|
#include <unistd.h> // write()
|
||||||
|
|
||||||
#define UIRC_IRCV3
|
|
||||||
#define UIRC_HELPERS
|
|
||||||
#include <uirc/uirc.h> // Tok_mesg()
|
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
get_buffer_line(char* buf)
|
read_buffer(char* dest, int fd, size_t len)
|
||||||
{
|
{
|
||||||
if (buf == NULL) return -1;
|
assert(dest != NULL);
|
||||||
char* ppoi;
|
if (len == 0) return 0;
|
||||||
if ((ppoi = strchr(buf, '\n')) != NULL) {
|
ssize_t brd;
|
||||||
*ppoi = '\0';
|
if ((brd = read(fd, dest, len)) > 0) {
|
||||||
if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0';
|
*(dest + brd) = '\0';
|
||||||
return ++ppoi - buf;
|
LOG(LOG_DEBUG, "Read %li bytes from fd buffer %i", brd, fd);
|
||||||
|
} else if (brd == -1) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) return 0;
|
||||||
|
LOG(LOG_WARNING, "Failed to read buffer on fd %i: " ERRNOFMT, fd, strerror(errno), errno);
|
||||||
}
|
}
|
||||||
return 0;
|
return brd;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
flush_buffer(char* buf, size_t buflen, int fd)
|
write_buffer(const char* src, int fd, size_t len, bool fullflush)
|
||||||
{
|
{
|
||||||
|
assert(src != NULL);
|
||||||
|
if (len == 0) return 0;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
char* pos = buf;
|
size_t b_wr = 0;
|
||||||
LOG(LOG_DEBUG, "Will write %s to socket %i", buf, fd);
|
do {
|
||||||
for (;;) {
|
if ((res = write(fd, src + b_wr, len - b_wr)) > 0) {
|
||||||
if ((size_t)(res = write(fd, pos, buflen - (size_t)(pos - buf))) != buflen - (size_t)(pos - buf)) {
|
LOG(LOG_DEBUG, "Wrote %lu bytes to fd %i", res, len);
|
||||||
if (res == -1 && errno != EINTR) return -1;
|
b_wr += (size_t) res;
|
||||||
else
|
} else if (res == -1) {
|
||||||
pos += res;
|
if (!fullflush && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) return 0;
|
||||||
} else
|
LOG(LOG_WARNING, "Couldn't flush buffer to fd %i: " ERRNOFMT, fd, strerror(errno), errno);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
} while (fullflush && b_wr < len);
|
||||||
|
return (ssize_t) b_wr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Move a string to the begging of a buffer from offset
|
||||||
|
*
|
||||||
|
* This function moves string in a buffer to the begging in chunks.
|
||||||
|
* Chunks are either offset sized or b_left sized depending if the offset is bigger than how much is left.
|
||||||
|
* This is done because strcpy may be optimized and copy order is not defined, so destination might overwrite source on a rtl copy
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
dequeue_bytes(char* str, size_t cnt, size_t len)
|
||||||
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
assert(cnt <= len);
|
||||||
|
size_t pos = 0;
|
||||||
|
do {
|
||||||
|
char* dest = str + pos;
|
||||||
|
size_t b_left = len - cnt - pos;
|
||||||
|
strncpy(dest, dest + cnt, (b_left < cnt) ? b_left : cnt);
|
||||||
|
LOG(LOG_DEBUG, "Moved %lu bytes from %lu to %lu", (b_left < cnt) ? b_left : cnt, cnt + pos, pos);
|
||||||
|
pos += cnt;
|
||||||
|
} while (cnt + pos < len);
|
||||||
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
src/buffer.h
13
src/buffer.h
|
@ -16,8 +16,17 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "limits.h"
|
||||||
|
|
||||||
|
#include <stdbool.h> // bool
|
||||||
#include <sys/types.h> // size_t ssize_t
|
#include <sys/types.h> // size_t ssize_t
|
||||||
|
|
||||||
ssize_t get_buffer_line(char* buf);
|
#ifndef UIRCD_GUARD_BUFFER
|
||||||
ssize_t flush_buffer(char* buf, size_t buflen, int fd);
|
#define UIRCD_GUARD_BUFFER
|
||||||
|
|
||||||
|
ssize_t read_buffer(char* dest, int fd, size_t len);
|
||||||
|
ssize_t write_buffer(const char* src, int fd, size_t len, bool fullflush);
|
||||||
|
size_t dequeue_bytes(char* str, size_t cnt, size_t len);
|
||||||
|
|
||||||
|
#endif /* UIRCD_GUARD_BUFFER */
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,11 @@
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
#include <stdbool.h> // bool
|
#include <stdbool.h> // bool
|
||||||
#include <stdio.h> // snprintf()
|
#include <stdio.h> // snprintf()
|
||||||
|
#include <stdlib.h> // malloc() realloc()
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
#include <sys/socket.h> // sockaddr connect()
|
#include <sys/socket.h> // sockaddr connect()
|
||||||
#include <sys/types.h> // size_t ssize_t socklen_t
|
#include <sys/types.h> // size_t ssize_t socklen_t
|
||||||
#include <stdlib.h> // malloc() realloc()
|
#include <syslog.h> // syslog()
|
||||||
|
|
||||||
int
|
int
|
||||||
init_chanarray(Channel** chans)
|
init_chanarray(Channel** chans)
|
||||||
|
@ -37,7 +38,7 @@ init_chanarray(Channel** chans)
|
||||||
if ((*chans = malloc(sizeof(Channel))) != NULL) {
|
if ((*chans = malloc(sizeof(Channel))) != NULL) {
|
||||||
memset(*chans, '\0', sizeof(Channel));
|
memset(*chans, '\0', sizeof(Channel));
|
||||||
} else {
|
} else {
|
||||||
LOG(LOG_WARN, "Could not initialise channel array. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_ERR, "Could not initialise channel array: " ERRNOFMT, strerror(errno), errno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,13 +50,13 @@ resize_chanarray(Channel** chans)
|
||||||
{
|
{
|
||||||
unsigned int i = get_channelindex(NULL, *chans);
|
unsigned int i = get_channelindex(NULL, *chans);
|
||||||
Channel* tmp = NULL;
|
Channel* tmp = NULL;
|
||||||
LOG(LOG_DEBUG, "Found %i existing channels.", i);
|
LOG(LOG_DEBUG, "Found %i existing channels", i);
|
||||||
if ((tmp = realloc(*chans, (i + 2) * sizeof(Channel))) != NULL) {
|
if ((tmp = realloc(*chans, (i + 2) * sizeof(Channel))) != NULL) {
|
||||||
*chans = tmp;
|
*chans = tmp;
|
||||||
tmp[i + 1].name = NULL;
|
tmp[i + 1].name = NULL;
|
||||||
tmp[i + 1].key = NULL;
|
tmp[i + 1].key = NULL;
|
||||||
} else {
|
} else {
|
||||||
LOG(LOG_WARN, "Could not allocate channel struct. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_ERR, "Could not allocate channel struct: " ERRNOFMT, strerror(errno), errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (signed int) i;
|
return (signed int) i;
|
||||||
|
@ -67,17 +68,13 @@ set_channel(Channel* chan, const char* name, const char* key, bool joined)
|
||||||
LOG(LOG_DEBUG, "Setting channel %s", (name == NULL) ? chan->name : name);
|
LOG(LOG_DEBUG, "Setting channel %s", (name == NULL) ? chan->name : name);
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
if (!allocate_copy(&chan->name, name)) {
|
if (!allocate_copy(&chan->name, name)) {
|
||||||
LOG(LOG_WARN, "Couldn't allocate memory for the channel name %s. " ERRNOFMT, name, strerror(errno), errno);
|
LOG(LOG_ERR, "Couldn't allocate memory for the channel name %s: " ERRNOFMT, name, strerror(errno), errno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (key != NULL) {
|
if (key != NULL) {
|
||||||
if (!allocate_copy(&chan->key, key)) {
|
if (!allocate_copy(&chan->key, key)) {
|
||||||
LOG(LOG_WARN,
|
LOG(LOG_ERR, "Couldn't allocate memory for the channel %s key: " ERRNOFMT, (name == NULL) ? chan->name : name, strerror(errno), errno);
|
||||||
"Couldn't allocate memory for the channel %s key. " ERRNOFMT,
|
|
||||||
(name == NULL) ? chan->name : name,
|
|
||||||
strerror(errno),
|
|
||||||
errno);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#ifndef UIRCD_GUARD_CHANNELS
|
#ifndef UIRCD_GUARD_CHANNELS
|
||||||
#define UIRCD_GUARD_CHANNELS
|
#define UIRCD_GUARD_CHANNELS
|
||||||
|
|
||||||
|
#define CHANNELMASK(STR) (strchr("#&+!", *STR) != NULL)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *name, *key;
|
char *name, *key;
|
||||||
bool joined;
|
bool joined;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
|
#include <syslog.h> // syslog()
|
||||||
|
|
||||||
#ifdef UIRCD_FEATURE_LIBCONFIG
|
#ifdef UIRCD_FEATURE_LIBCONFIG
|
||||||
#include <libconfig.h> // config_t config_setting_t config_init() ...
|
#include <libconfig.h> // config_t config_setting_t config_init() ...
|
||||||
|
|
||||||
|
@ -52,17 +54,14 @@ parse_configfile(char* config_path, Connection* conn)
|
||||||
config_setting_t* chans;
|
config_setting_t* chans;
|
||||||
if ((chans = config_lookup(&conf, ".channels")) != NULL) {
|
if ((chans = config_lookup(&conf, ".channels")) != NULL) {
|
||||||
// TODO: Check if config_setting_length can return negative values
|
// TODO: Check if config_setting_length can return negative values
|
||||||
resize_chanarray(&conn->info.channels);
|
|
||||||
for (unsigned int i = 0; i < (unsigned int) config_setting_length(chans); i++) {
|
for (unsigned int i = 0; i < (unsigned int) config_setting_length(chans); i++) {
|
||||||
config_setting_t* chanelem = config_setting_get_elem(chans, i);
|
config_setting_t* chanelem = config_setting_get_elem(chans, i);
|
||||||
const char * name = NULL, *key = NULL;
|
const char * name = NULL, *key = NULL;
|
||||||
config_setting_lookup_string(chanelem, "name", &name);
|
config_setting_lookup_string(chanelem, "name", &name);
|
||||||
config_setting_lookup_string(chanelem, "key", &key);
|
config_setting_lookup_string(chanelem, "key", &key);
|
||||||
LOG(LOG_DEBUG, "Got channel #%i: %s", i, name);
|
LOG(LOG_DEBUG, "Got channel #%i: %s", i, name);
|
||||||
if (name != NULL) {
|
|
||||||
set_channel(&conn->info.channels[get_channelindex(name, conn->info.channels)], name, key, true);
|
|
||||||
}
|
|
||||||
resize_chanarray(&conn->info.channels);
|
resize_chanarray(&conn->info.channels);
|
||||||
|
if (name != NULL) set_channel(&conn->info.channels[get_channelindex(name, conn->info.channels)], name, key, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,14 +75,11 @@ parse_configfile(char* config_path, Connection* conn)
|
||||||
};
|
};
|
||||||
mapconf(user, usermaps, sizeof(usermaps) / sizeof(*usermaps));
|
mapconf(user, usermaps, sizeof(usermaps) / sizeof(*usermaps));
|
||||||
}
|
}
|
||||||
|
LOG(LOG_DEBUG, "Parsed configuration file successfully");
|
||||||
res = 1;
|
res = 1;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
LOG(LOG_WARN,
|
LOG(LOG_WARNING, "Encountered a error while reading the config file: %s :\"%s\" line %d", config_error_text(&conf), config_error_file(&conf), config_error_line(&conf));
|
||||||
"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);
|
config_destroy(&conf);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -96,9 +92,9 @@ mapconf(config_setting_t* setting, Mapping* mapping, unsigned long len)
|
||||||
config_setting_lookup_string(setting, mapping[i].str, &var);
|
config_setting_lookup_string(setting, mapping[i].str, &var);
|
||||||
if (var != NULL) {
|
if (var != NULL) {
|
||||||
if (allocate_copy(mapping[i].save, var)) {
|
if (allocate_copy(mapping[i].save, var)) {
|
||||||
LOG(LOG_DEBUG, "Saved %s to %p", var, (const void*) mapping[i].save);
|
LOG(LOG_DEBUG, "Allocated %s to %p", var, (const void*) mapping[i].save);
|
||||||
} else {
|
} else {
|
||||||
LOG(LOG_WARN, "Failed to allocate memory to save config variable %s = %s", mapping[i].str, var);
|
LOG(LOG_ERR, "Failed to allocate memory to save config variable %s as %s", mapping[i].str, var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,9 +106,8 @@ int
|
||||||
set_config_defaults(Connection* conn)
|
set_config_defaults(Connection* conn)
|
||||||
{
|
{
|
||||||
Mapping defsalloc[] = {
|
Mapping defsalloc[] = {
|
||||||
{ UIRCD_DEFAULT_ADDR, &conn->data.address }, { UIRCD_DEFAULT_PORT, &conn->data.service },
|
{ UIRCD_DEFAULT_ADDR, &conn->data.address }, { UIRCD_DEFAULT_PORT, &conn->data.service }, { UIRCD_DEFAULT_QUITMSG, &conn->data.quitmsg },
|
||||||
{ UIRCD_DEFAULT_QUITMSG, &conn->data.quitmsg }, { UIRCD_DEFAULT_NICK, &conn->user.nickname },
|
{ UIRCD_DEFAULT_NICK, &conn->user.nickname }, { UIRCD_DEFAULT_USER, &conn->user.username }, { UIRCD_DEFAULT_REAL, &conn->user.realname },
|
||||||
{ UIRCD_DEFAULT_USER, &conn->user.username }, { UIRCD_DEFAULT_REAL, &conn->user.realname },
|
|
||||||
};
|
};
|
||||||
for (unsigned int i = 0; i < sizeof(defsalloc) / sizeof(*defsalloc); i++) {
|
for (unsigned int i = 0; i < sizeof(defsalloc) / sizeof(*defsalloc); i++) {
|
||||||
if (!allocate_copy(defsalloc[i].save, defsalloc[i].str)) return 0;
|
if (!allocate_copy(defsalloc[i].save, defsalloc[i].str)) return 0;
|
||||||
|
|
|
@ -27,9 +27,9 @@
|
||||||
|
|
||||||
#define UIRCD_DEFAULT_ADDR "localhost"
|
#define UIRCD_DEFAULT_ADDR "localhost"
|
||||||
#define UIRCD_DEFAULT_PORT "6667"
|
#define UIRCD_DEFAULT_PORT "6667"
|
||||||
#define UIRCD_DEFAULT_NICK "uirc-user"
|
#define UIRCD_DEFAULT_NICK "uircd-user"
|
||||||
#define UIRCD_DEFAULT_USER "uIRC-user"
|
#define UIRCD_DEFAULT_USER "uIRCd-user"
|
||||||
#define UIRCD_DEFAULT_REAL "uIRC user"
|
#define UIRCD_DEFAULT_REAL "uIRCd user"
|
||||||
#define UIRCD_DEFAULT_QUITMSG "uIRCd " UIRCD_VERSION
|
#define UIRCD_DEFAULT_QUITMSG "uIRCd " UIRCD_VERSION
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
208
src/connection.c
208
src/connection.c
|
@ -32,10 +32,10 @@
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
#include <sys/socket.h> // sockaddr connect()
|
#include <sys/socket.h> // sockaddr connect()
|
||||||
#include <sys/types.h> // size_t ssize_t socklen_t
|
#include <sys/types.h> // size_t ssize_t socklen_t
|
||||||
#include <unistd.h> // ??
|
#include <syslog.h>
|
||||||
|
#include <time.h>
|
||||||
#define UIRC_HELPERS
|
|
||||||
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
||||||
|
#include <unistd.h> // ??
|
||||||
|
|
||||||
signed int
|
signed int
|
||||||
init_connection(Connection* conn)
|
init_connection(Connection* conn)
|
||||||
|
@ -44,25 +44,20 @@ init_connection(Connection* conn)
|
||||||
struct addrinfo* addr_info;
|
struct addrinfo* addr_info;
|
||||||
if ((getaddrres = getaddrinfo(conn->data.address, conn->data.service, NULL, &addr_info)) != 0) {
|
if ((getaddrres = getaddrinfo(conn->data.address, conn->data.service, NULL, &addr_info)) != 0) {
|
||||||
freeaddrinfo(addr_info);
|
freeaddrinfo(addr_info);
|
||||||
LOG(LOG_WARN,
|
LOG(LOG_WARNING, "Failed to get address info for " ADDRFMT ": " ERRNOFMT, conn->data.address, conn->data.service, gai_strerror(getaddrres), getaddrres);
|
||||||
"Failed to get address info for " ADDRFMT ". " ERRNOFMT,
|
|
||||||
conn->data.address,
|
|
||||||
conn->data.service,
|
|
||||||
gai_strerror(getaddrres),
|
|
||||||
getaddrres);
|
|
||||||
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) return INIT_HARDFAIL;
|
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) return INIT_HARDFAIL;
|
||||||
else
|
else
|
||||||
return INIT_SOFTFAIL;
|
return INIT_SOFTFAIL;
|
||||||
}
|
}
|
||||||
if ((sockfd = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol)) < 0) {
|
if ((sockfd = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol)) < 0) {
|
||||||
LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, conn->data.address, conn->data.service, strerror(errno), errno);
|
LOG(LOG_WARNING, "Failed to open a socket for " ADDRFMT ": " ERRNOFMT, conn->data.address, conn->data.service, strerror(errno), errno);
|
||||||
freeaddrinfo(addr_info);
|
freeaddrinfo(addr_info);
|
||||||
return INIT_HARDFAIL;
|
return INIT_HARDFAIL;
|
||||||
}
|
}
|
||||||
if ((connectres = connect(sockfd, addr_info->ai_addr, addr_info->ai_addrlen)) == -1) {
|
if ((connectres = connect(sockfd, addr_info->ai_addr, addr_info->ai_addrlen)) == -1) {
|
||||||
close(sockfd);
|
close(sockfd);
|
||||||
freeaddrinfo(addr_info);
|
freeaddrinfo(addr_info);
|
||||||
LOG(LOG_ERROR, "Failed to connect to host " ADDRFMT ". " ERRNOFMT, conn->data.address, conn->data.service, strerror(errno), errno);
|
LOG(LOG_WARNING, "Failed to connect to host " ADDRFMT ": " ERRNOFMT, conn->data.address, conn->data.service, strerror(errno), errno);
|
||||||
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) return INIT_HARDFAIL;
|
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) return INIT_HARDFAIL;
|
||||||
else
|
else
|
||||||
return INIT_SOFTFAIL;
|
return INIT_SOFTFAIL;
|
||||||
|
@ -71,172 +66,45 @@ init_connection(Connection* conn)
|
||||||
return sockfd;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
signed int
|
bool
|
||||||
get_msgchannel(IRC_Message* mesg)
|
register_user(char* buf, size_t len, int fd, Connection_User* user)
|
||||||
{
|
{
|
||||||
// TODO: These message arguments might be parsed differently depending on what command they offer.
|
ssize_t tmp;
|
||||||
// Maybe offering a static context would allow reentrant calls
|
IRC_Message build_buf;
|
||||||
switch (mesg->cmd) {
|
if (user->password != NULL && (tmp = Assm_mesg(buf, Assm_cmd_PASS(&build_buf, user->password), len)) > 0) {
|
||||||
case JOIN:
|
if (write_buffer(buf, fd, (size_t) tmp, true) != -1) {
|
||||||
case PART:
|
LOG(LOG_INFO, "Sent PASS authentication");
|
||||||
case MODE:
|
} else
|
||||||
case TOPIC:
|
return false;
|
||||||
case LIST:
|
|
||||||
case NAMES:
|
|
||||||
case INVITE:
|
|
||||||
case KICK:
|
|
||||||
case PRIVMSG:
|
|
||||||
case NOTICE: {
|
|
||||||
if (CHANNELMASK(mesg->args[0])) return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RPL_TOPIC:
|
|
||||||
case RPL_NOTOPIC:
|
|
||||||
case RPL_ENDOFNAMES: {
|
|
||||||
if (CHANNELMASK(mesg->args[1])) return 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RPL_NAMREPLY: {
|
|
||||||
if (CHANNELMASK(mesg->args[2])) return 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return -1;
|
if ((tmp = Assm_mesg(buf, Assm_cmd_NICK(&build_buf, user->nickname), len)) > 0) {
|
||||||
|
if (write_buffer(buf, fd, (size_t) tmp, true) != -1) {
|
||||||
|
LOG(LOG_INFO, "Sent NICK registration with nickname \"%s\".", user->nickname);
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((tmp = Assm_mesg(buf, Assm_cmd_USER(&build_buf, user->username, user->realname, 0), len)) > 0) {
|
||||||
|
if (write_buffer(buf, fd, (size_t) tmp, true) != -1) {
|
||||||
|
LOG(LOG_INFO, "Sent USER registration with username \"%s\" and realname \"%s\".", user->username, user->realname);
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
bool
|
||||||
get_categ(IRC_Message* mesg)
|
commit_channelist(char* buf, size_t len, int fd, Channel* chans)
|
||||||
{
|
{
|
||||||
switch (mesg->cmd) {
|
ssize_t tmp;
|
||||||
case JOIN:
|
for (unsigned int i = 0; chans != NULL && chans[i].name != NULL; i++) {
|
||||||
case PART:
|
IRC_Message msg = { .args = { chans[i].name, chans[i].key, NULL }, .trailing = true, .cmd = (chans[i].joined) ? JOIN : PART };
|
||||||
case QUIT:
|
if ((tmp = Assm_mesg(buf, &msg, len)) > 0) {
|
||||||
case KICK: return "events";
|
if (write_buffer(buf, fd, (size_t) tmp, true) == -1) {
|
||||||
case TOPIC:
|
LOG(LOG_WARNING, "Couldn't auto-join channel \"%s\": " ERRNOFMT, chans[i].name, strerror(errno), errno);
|
||||||
case RPL_TOPIC:
|
return false;
|
||||||
case RPL_NOTOPIC: return "topic";
|
|
||||||
case PRIVMSG:
|
|
||||||
case NOTICE: return "msgs";
|
|
||||||
case RPL_MOTD:
|
|
||||||
case RPL_MOTDSTART:
|
|
||||||
case RPL_ENDOFMOTD:
|
|
||||||
case ERR_NOMOTD: return "motd";
|
|
||||||
case PING:
|
|
||||||
case PONG: return "pings";
|
|
||||||
case RPL_NAMREPLY:
|
|
||||||
case RPL_ENDOFNAMES: return "names";
|
|
||||||
case RPL_LISTSTART:
|
|
||||||
case RPL_LIST:
|
|
||||||
case RPL_LISTEND:
|
|
||||||
case LIST: return "list";
|
|
||||||
default: return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
auto_msg_actions(IRC_Message* mesg, Connection* conn, Buffer_Info* buf)
|
|
||||||
{
|
|
||||||
signed long len;
|
|
||||||
time_t ctime = time(NULL);
|
|
||||||
switch (mesg->cmd) {
|
|
||||||
case (PING): {
|
|
||||||
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", mesg->args[0]);
|
|
||||||
if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(mesg->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.address,
|
|
||||||
conn->data.service,
|
|
||||||
strerror(errno),
|
|
||||||
errno);
|
|
||||||
conn->info.state = CONN_RECONNECTING;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (PONG): {
|
|
||||||
if (mesg->trailing && mesg->args[1] != NULL) {
|
|
||||||
LOG(LOG_DEBUG, "Got PONG back with mesg \"%s\".", mesg->args[1]);
|
|
||||||
conn->info.l_pong = ctime;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Autojoin channels from current conn on first response from the server */
|
|
||||||
case (RPL_WELCOME): {
|
|
||||||
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.address, conn->data.service);
|
|
||||||
conn->info.state = CONN_ACTIVE;
|
|
||||||
if (!commit_channelist(buf, conn)) return 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
case (CAP): {
|
|
||||||
if (mesg->args[1] != NULL && strcmp(mesg->args[1], "LS") == 0) {
|
|
||||||
LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", mesg->args[2], conn->data.address,
|
|
||||||
conn->data.port);
|
|
||||||
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(mesg->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, mesg->args[2],
|
|
||||||
conn->data.address, conn->data.port, strerror(errno), errno);
|
|
||||||
conn->state = CONN_RECONNECTING;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (mesg->args[1] != NULL && strcmp(mesg->args[1], "ACK") == 0) {
|
|
||||||
LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", conn->data.address, 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.address, conn->data.port, strerror(errno), errno); conn->state = CONN_RECONNECTING; return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
case (ERROR): {
|
|
||||||
LOG(LOG_ERROR, "Received error %s.", mesg->args[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (JOIN):
|
|
||||||
case (PART): {
|
|
||||||
set_channel(&conn->info.channels[get_channelindex(mesg->args[0], conn->info.channels)],
|
|
||||||
mesg->args[0],
|
|
||||||
mesg->args[1],
|
|
||||||
mesg->cmd == JOIN);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (ERR_NICKNAMEINUSE):
|
|
||||||
case (ERR_NICKCOLLISION): {
|
|
||||||
LOG(LOG_ERROR, "Nickname %s is already taken.", conn->user.nickname);
|
|
||||||
conn->info.state = CONN_RECONNECTING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
commit_channelist(Buffer_Info* buf, Connection* conn)
|
|
||||||
{
|
|
||||||
signed long len;
|
|
||||||
for (unsigned int i = 0; conn->info.channels != NULL && conn->info.channels[i].name != NULL; i++) {
|
|
||||||
IRC_Message msg = { .args = { conn->info.channels[i].name, conn->info.channels[i].key, NULL },
|
|
||||||
.trailing = true,
|
|
||||||
.cmd = (conn->info.channels[i].joined) ? JOIN : PART };
|
|
||||||
if ((len = Assm_mesg(buf->buffer, &msg, 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->info.channels[i].name,
|
|
||||||
conn->data.address,
|
|
||||||
conn->data.service,
|
|
||||||
strerror(errno),
|
|
||||||
errno);
|
|
||||||
conn->info.state = CONN_RECONNECTING;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,14 +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 "buffer.h"
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
|
|
||||||
#include <stdbool.h> // bool
|
#include <stdbool.h> // bool
|
||||||
#include <sys/types.h> // size_t ssize_t socklen_t
|
#include <sys/types.h> // size_t ssize_t socklen_t
|
||||||
|
|
||||||
#define UIRC_IRCV3
|
|
||||||
#define UIRC_HELPERS
|
|
||||||
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
||||||
|
|
||||||
#ifndef UIRCD_GUARD_CONNECTION
|
#ifndef UIRCD_GUARD_CONNECTION
|
||||||
|
@ -32,15 +30,14 @@
|
||||||
#define INIT_HARDFAIL -1
|
#define INIT_HARDFAIL -1
|
||||||
#define INIT_SOFTFAIL -2
|
#define INIT_SOFTFAIL -2
|
||||||
|
|
||||||
#define CONN_ACTIVE 2
|
#define CONN_ACTIVE 3
|
||||||
|
#define CONN_IDLE 2
|
||||||
#define CONN_REGISTERED 1
|
#define CONN_REGISTERED 1
|
||||||
#define CONN_PENDING 0
|
#define CONN_PENDING 0
|
||||||
#define CONN_RECONNECTING -1
|
#define CONN_RECONNECTING -1
|
||||||
#define CONN_CLOSING -2
|
#define CONN_CLOSING -2
|
||||||
#define CONN_CLOSED -3
|
#define CONN_CLOSED -3
|
||||||
|
|
||||||
#define CHANNELMASK(STR) (strchr("#&+!", *STR) != NULL)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char * address, *service, *quitmsg, *path;
|
char * address, *service, *quitmsg, *path;
|
||||||
time_t timeout;
|
time_t timeout;
|
||||||
|
@ -51,30 +48,21 @@ typedef struct {
|
||||||
} Connection_User; // User information [persistent]
|
} Connection_User; // User information [persistent]
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
time_t l_ping, l_pong, l_connect, l_message;
|
time_t l_connect, l_message;
|
||||||
Channel* channels;
|
Channel* channels;
|
||||||
signed short state;
|
signed short state;
|
||||||
signed int reconinter;
|
signed int reconinter;
|
||||||
bool active;
|
|
||||||
} Connection_Info; // Connection information [temporary]
|
} Connection_Info; // Connection information [temporary]
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char buffer[UIRCD_LIMITS_LINE + 1];
|
|
||||||
size_t append_pos;
|
|
||||||
int fd;
|
|
||||||
} Buffer_Info;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Connection_User user;
|
Connection_User user;
|
||||||
Connection_Data data;
|
Connection_Data data;
|
||||||
Connection_Info info;
|
Connection_Info info;
|
||||||
} Connection;
|
} Connection;
|
||||||
|
|
||||||
signed int init_connection(Connection* conn);
|
signed int init_connection(Connection* conn);
|
||||||
signed int get_msgchannel(IRC_Message* mesg);
|
bool register_user(char* buf, size_t len, int fd, Connection_User* user);
|
||||||
int auto_msg_actions(IRC_Message* mesg, Connection* conn, Buffer_Info* buf);
|
bool commit_channelist(char* buf, size_t len, int fd, Channel* chans);
|
||||||
int commit_channelist(Buffer_Info* buf, Connection* conn);
|
|
||||||
const char* get_categ(IRC_Message* mesg);
|
|
||||||
|
|
||||||
#endif /* UIRCD_GUARD_CONNECTION */
|
#endif /* UIRCD_GUARD_CONNECTION */
|
||||||
|
|
||||||
|
|
104
src/filesystem.c
104
src/filesystem.c
|
@ -25,51 +25,28 @@
|
||||||
#include <ctype.h> // isalpha() isdigit()
|
#include <ctype.h> // isalpha() isdigit()
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
#include <fcntl.h> // fnctl()
|
#include <fcntl.h> // fnctl()
|
||||||
#include <limits.h> // ??
|
|
||||||
#include <stdbool.h> // bool
|
#include <stdbool.h> // bool
|
||||||
#include <stdio.h> // fopen() FILE fprintf()
|
#include <stdio.h> // fopen() FILE fprintf()
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
#include <sys/stat.h> // mkfifo() mkdir()
|
#include <sys/stat.h> // mkfifo() mkdir()
|
||||||
#include <sys/types.h> // size_t ssize_t mode_t
|
#include <sys/types.h> // size_t ssize_t mode_t
|
||||||
|
#include <syslog.h> // syslog()
|
||||||
int
|
|
||||||
mkdir_bottomup(char* path)
|
|
||||||
{
|
|
||||||
if (path == NULL || *path == '\0') return 0;
|
|
||||||
for (char* x = path; x != NULL && *x;) {
|
|
||||||
if ((x = strchr(x, '/')) != NULL) {
|
|
||||||
char save = *(x + 1);
|
|
||||||
*(x + 1) = '\0';
|
|
||||||
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
|
|
||||||
if (errno != EEXIST) {
|
|
||||||
*(x + 1) = save;
|
|
||||||
LOG(LOG_ERROR, "Could not create directory \"%s\".", path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
LOG(LOG_DEBUG, "Created directory at: %s", path);
|
|
||||||
*(x + 1) = save;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
makeinput(const char* path)
|
makeinput(const char* path)
|
||||||
{
|
{
|
||||||
if (path == NULL) return -1;
|
if (path == NULL) return -1;
|
||||||
if (mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP) == 0) {
|
if (mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP) == 0) {
|
||||||
LOG(LOG_VERBOSE, "Created a FIFO pipe for input at %s.", path);
|
LOG(LOG_DEBUG, "Created a FIFO pipe for input at \"%s\"", path);
|
||||||
} else if (errno != EEXIST) {
|
} else if (errno != EEXIST) {
|
||||||
LOG(LOG_WARN, "Couldn't create FIFO at \"%s\" for input. " ERRNOFMT, path, strerror(errno), errno);
|
LOG(LOG_WARNING, "Couldn't create FIFO at \"%s\" for input: " ERRNOFMT, path, strerror(errno), errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int fd;
|
int fd;
|
||||||
if ((fd = open(path, O_RDONLY | O_NONBLOCK)) == -1) {
|
if ((fd = open(path, O_RDONLY | O_NONBLOCK)) == -1) {
|
||||||
LOG(LOG_WARN, "Couldn't open FIFO pipe \"%s\" for reading. " ERRNOFMT, path, strerror(errno), errno);
|
LOG(LOG_WARNING, "Couldn't open FIFO pipe \"%s\" for reading: " ERRNOFMT, path, strerror(errno), errno);
|
||||||
} else
|
} else
|
||||||
LOG(LOG_DEBUG, "Opened \"%s\" for reading.", path);
|
LOG(LOG_DEBUG, "Opened FIFO pipe \"%s\" for reading", path);
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,87 +56,24 @@ write_log(const char* path, const char* message)
|
||||||
FILE* logfile;
|
FILE* logfile;
|
||||||
if ((logfile = fopen(path, "a")) != NULL) {
|
if ((logfile = fopen(path, "a")) != NULL) {
|
||||||
fprintf(logfile, "%s", message);
|
fprintf(logfile, "%s", message);
|
||||||
LOG(LOG_DEBUG, "Wrote to log %s.", path);
|
LOG(LOG_DEBUG, "Wrote to log \"%s\"", path);
|
||||||
fclose(logfile);
|
fclose(logfile);
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
} else
|
||||||
LOG(LOG_WARN, "Couldn't open file \"%s\" for appending.", path);
|
LOG(LOG_WARNING, "Couldn't open file \"%s\" for appending: " ERRNOFMT, path, strerror(errno), errno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
cleanup_path_names(char* name)
|
|
||||||
{
|
|
||||||
if (name == NULL) return 0;
|
|
||||||
if (!strcmp("..", name) || !strcmp(".", name)) *name = '_';
|
|
||||||
for (; *name; name++) {
|
|
||||||
if (isalpha(*name)) *name = (char) tolower(*name);
|
|
||||||
else if (strchr(".+-_#&", *name) == NULL && !isdigit(*name))
|
|
||||||
*name = '_';
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
add_socket_flags(int fd, int flags)
|
add_socket_flags(int fd, int flags)
|
||||||
{
|
{
|
||||||
int cflgs;
|
int cflgs;
|
||||||
if ((cflgs = fcntl(fd, F_GETFL)) != -1) {
|
if ((cflgs = fcntl(fd, F_GETFL)) != -1) {
|
||||||
if (fcntl(fd, F_SETFL, cflgs | flags) == -1) {
|
if (fcntl(fd, F_SETFL, cflgs | flags) == -1) {
|
||||||
LOG(LOG_WARN, "Couldn't add socket flags. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_WARNING, "Couldn't add socket flags: " ERRNOFMT, strerror(errno), errno);
|
||||||
} else
|
} else
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
} else
|
||||||
LOG(LOG_WARN, "Failed to get socket flags. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_WARNING, "Failed to get socket flags: " ERRNOFMT, strerror(errno), errno);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
|
||||||
get_path(char* buf, size_t lim, Connection* conn, IRC_Message* msg, bool global, bool input, bool output)
|
|
||||||
{
|
|
||||||
if (buf == NULL || conn == NULL) return -1;
|
|
||||||
ssize_t res;
|
|
||||||
const char* save = buf;
|
|
||||||
|
|
||||||
int ci = -1;
|
|
||||||
const char *dir = NULL, *subdir = NULL;
|
|
||||||
if (global) {
|
|
||||||
dir = "global";
|
|
||||||
} else if (msg != NULL && (ci = get_msgchannel(msg)) != -1 && msg->args[ci] != NULL) {
|
|
||||||
dir = "channel";
|
|
||||||
subdir = msg->args[ci];
|
|
||||||
} else if (msg != NULL && msg->name.nick != NULL) {
|
|
||||||
dir = "user";
|
|
||||||
subdir = msg->name.nick;
|
|
||||||
} else
|
|
||||||
return -1;
|
|
||||||
if ((res = snprintf(buf, lim, "%s", dir)) == -1) return -1;
|
|
||||||
clean_and_push(&lim, (size_t) res, &buf, true);
|
|
||||||
if (subdir != NULL) {
|
|
||||||
if ((res = snprintf(buf, lim, "%s", subdir)) == -1) return -1;
|
|
||||||
clean_and_push(&lim, (size_t) res, &buf, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* category = NULL;
|
|
||||||
if (input) {
|
|
||||||
category = "in";
|
|
||||||
} else if (output) {
|
|
||||||
category = "out";
|
|
||||||
} else {
|
|
||||||
if ((category = get_categ(msg)) == NULL) return -1;
|
|
||||||
}
|
|
||||||
if ((res = snprintf(buf, lim, "%s", category)) == -1) return -1;
|
|
||||||
clean_and_push(&lim, (size_t) res, &buf, false);
|
|
||||||
|
|
||||||
return (buf - save);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
clean_and_push(size_t* lim, size_t res, char** buf, bool dir)
|
|
||||||
{
|
|
||||||
cleanup_path_names(*buf);
|
|
||||||
if (dir) *(*(buf) + res) = '/';
|
|
||||||
*lim -= (size_t) res + dir;
|
|
||||||
*buf += (size_t) res + dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -20,20 +20,14 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define UIRC_IRCV3
|
|
||||||
#include <uirc/uirc.h> // IRC_Message
|
#include <uirc/uirc.h> // IRC_Message
|
||||||
|
|
||||||
#ifndef UIRCD_GUARD_FILESYSTEM
|
#ifndef UIRCD_GUARD_FILESYSTEM
|
||||||
#define UIRCD_GUARD_FILESYSTEM
|
#define UIRCD_GUARD_FILESYSTEM
|
||||||
|
|
||||||
int mkdir_bottomup(char* path);
|
int makeinput(const char* path);
|
||||||
int makeinput(const char* path);
|
bool write_log(const char* path, const char* message);
|
||||||
bool write_log(const char* path, const char* message);
|
bool add_socket_flags(int fd, int flags);
|
||||||
bool cleanup_path_names(char* name);
|
|
||||||
bool add_socket_flags(int fd, int flags);
|
|
||||||
ssize_t get_path(char* buf, size_t lim, Connection* conn, IRC_Message* msg, bool global, bool input, bool output);
|
|
||||||
void clean_and_push(size_t* lim, size_t res, char** buf, bool dir);
|
|
||||||
|
|
||||||
#endif /* UIRCD_GUARD_FILESYSTEM */
|
#endif /* UIRCD_GUARD_FILESYSTEM */
|
||||||
|
|
||||||
|
|
|
@ -16,24 +16,15 @@
|
||||||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
#ifndef UIRCD_GUARD_LOGGING
|
#ifndef UIRCD_GUARD_LOGGING
|
||||||
#define UIRCD_GUARD_LOGGING
|
#define UIRCD_GUARD_LOGGING
|
||||||
|
|
||||||
#define LOG_FATAL 0
|
|
||||||
#define LOG_ERROR 1
|
|
||||||
#define LOG_WARN 2
|
|
||||||
#define LOG_INFO 3
|
|
||||||
#define LOG_VERBOSE 4
|
|
||||||
#define LOG_DEBUG 5
|
|
||||||
|
|
||||||
#define ERRNOFMT "%s (%i)"
|
#define ERRNOFMT "%s (%i)"
|
||||||
#define ADDRFMT "%s:%s"
|
#define ADDRFMT "%s:%s"
|
||||||
|
|
||||||
#define LOG(LEVEL, FORMAT, ...) \
|
#define LOG(LEVEL, ...) syslog(LEVEL, __VA_ARGS__)
|
||||||
if (LEVEL <= loglevel) fprintf(stderr, "[%c:L%i] " FORMAT "\n", logchars[LEVEL], __LINE__, __VA_ARGS__)
|
|
||||||
|
|
||||||
extern const char logchars[];
|
|
||||||
extern int loglevel;
|
|
||||||
|
|
||||||
#endif /* UIRCD_GUARD_LOGGING */
|
#endif /* UIRCD_GUARD_LOGGING */
|
||||||
|
|
||||||
|
|
385
src/main.c
385
src/main.c
|
@ -24,19 +24,19 @@
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "misc.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
#include <fcntl.h> // O_NONBLOCK
|
#include <fcntl.h> // O_NONBLOCK
|
||||||
#include <stdio.h> // printf()
|
#include <stdio.h> // printf()
|
||||||
#include <stdlib.h> // srand()
|
#include <stdlib.h> // EXIT_SUCCESS EXIT_FAILURE
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
#include <sys/types.h> // time_t size_t
|
#include <sys/types.h> // time_t size_t
|
||||||
#include <unistd.h> // getopt() chdir() close()
|
#include <syslog.h> // openlog() syslog()
|
||||||
|
#include <time.h> // time()
|
||||||
#define UIRC_IRCV3
|
|
||||||
#define UIRC_HELPERS
|
|
||||||
#include <uirc/uirc.h> // IRC_Message
|
#include <uirc/uirc.h> // IRC_Message
|
||||||
|
#include <unistd.h> // getopt() chdir() close()
|
||||||
|
|
||||||
int
|
int
|
||||||
parse_args(int argc, char** argv, Connection* conn)
|
parse_args(int argc, char** argv, Connection* conn)
|
||||||
|
@ -45,17 +45,27 @@ parse_args(int argc, char** argv, Connection* conn)
|
||||||
unsigned long chanindex = 0;
|
unsigned long chanindex = 0;
|
||||||
while ((c = getopt(argc,
|
while ((c = getopt(argc,
|
||||||
argv,
|
argv,
|
||||||
"V:a:p:t:N:U:R:P:q:c:k:"
|
"V:a:p:d:t:N:U:R:P:q:c:k:"
|
||||||
#ifdef UIRCD_FEATURE_LIBCONFIG
|
#ifdef UIRCD_FEATURE_LIBCONFIG
|
||||||
"C:"
|
"C:"
|
||||||
#endif /* UIRCD_FEATURE_LIBCONFIG */
|
#endif /* UIRCD_FEATURE_LIBCONFIG */
|
||||||
"vh"))
|
"vh"))
|
||||||
!= -1) {
|
!= -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'V': loglevel = atoi(optarg); break;
|
case 'V': {
|
||||||
|
int levelmask = atoi(optarg);
|
||||||
|
setlogmask(LOG_UPTO(levelmask));
|
||||||
|
LOG(LOG_DEBUG, "Log level was set to %i", levelmask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'a': allocate_copy(&conn->data.address, optarg); break;
|
case 'a': allocate_copy(&conn->data.address, optarg); break;
|
||||||
case 'p': allocate_copy(&conn->data.service, optarg); break;
|
case 'p': allocate_copy(&conn->data.service, optarg); break;
|
||||||
case 't': conn->data.timeout = (unsigned int) atoi(optarg); break;
|
case 'd': allocate_copy(&conn->data.path, optarg); break;
|
||||||
|
case 't': {
|
||||||
|
conn->data.timeout = (unsigned int) atoi(optarg);
|
||||||
|
LOG(LOG_DEBUG, "Timeout was set to %li", conn->data.timeout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'N': allocate_copy(&conn->user.nickname, optarg); break;
|
case 'N': allocate_copy(&conn->user.nickname, optarg); break;
|
||||||
case 'U': allocate_copy(&conn->user.username, optarg); break;
|
case 'U': allocate_copy(&conn->user.username, optarg); break;
|
||||||
case 'R': allocate_copy(&conn->user.realname, optarg); break;
|
case 'R': allocate_copy(&conn->user.realname, optarg); break;
|
||||||
|
@ -64,13 +74,11 @@ parse_args(int argc, char** argv, Connection* conn)
|
||||||
case 'c': {
|
case 'c': {
|
||||||
resize_chanarray(&conn->info.channels);
|
resize_chanarray(&conn->info.channels);
|
||||||
chanindex = get_channelindex(optarg, conn->info.channels);
|
chanindex = get_channelindex(optarg, conn->info.channels);
|
||||||
if (!set_channel(&conn->info.channels[chanindex], optarg, NULL, true))
|
if (!set_channel(&conn->info.channels[chanindex], optarg, NULL, true)) LOG(LOG_WARNING, "Couldn't set channel %s as chan #%lu", optarg, chanindex);
|
||||||
LOG(LOG_WARN, "Couldn't set channel %s as chan #%lu.", optarg, chanindex);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'k': {
|
case 'k': {
|
||||||
if (!set_channel(&conn->info.channels[chanindex], NULL, optarg, true))
|
if (!set_channel(&conn->info.channels[chanindex], NULL, optarg, true)) LOG(LOG_WARNING, "Couldn't set key for channel #%lu", chanindex);
|
||||||
LOG(LOG_WARN, "Couldn't set key for channel #%lu.", chanindex);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'v': printf("uIRCd version " UIRCD_VERSION); return 0;
|
case 'v': printf("uIRCd version " UIRCD_VERSION); return 0;
|
||||||
|
@ -99,8 +107,8 @@ print_help(void)
|
||||||
{ 'P', "str", "Password for registration", NULL },
|
{ 'P', "str", "Password for registration", NULL },
|
||||||
{ 'd', "str", "Directory for logs", "current dir" },
|
{ 'd', "str", "Directory for logs", "current dir" },
|
||||||
{ 'q', "str", "Quit message", UIRCD_DEFAULT_QUITMSG },
|
{ 'q', "str", "Quit message", UIRCD_DEFAULT_QUITMSG },
|
||||||
{ 't', "uint", "Timeout duration", "20 seconds" },
|
{ 't', "uint", "Timeout duration", NULL },
|
||||||
{ 'V', "int", "Log level", "0 [LOG_FATAL]" },
|
{ 'V', "int", "Log level", "7 [LOG_INFO]" },
|
||||||
{ 'c', "str", "Channel", NULL },
|
{ 'c', "str", "Channel", NULL },
|
||||||
{ 'k', "str", "Channel key", NULL },
|
{ 'k', "str", "Channel key", NULL },
|
||||||
#ifdef UIRCD_FEATURE_LIBCONFIG
|
#ifdef UIRCD_FEATURE_LIBCONFIG
|
||||||
|
@ -122,259 +130,214 @@ int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
IRC_Message buffer;
|
IRC_Message buffer;
|
||||||
Connection connection = { 0 };
|
Connection connection = { .info.state = CONN_PENDING }; // Start off with a pending connection
|
||||||
time_t ctime;
|
time_t ctime; // Current time
|
||||||
struct timespec sleep = { 0, 50000000L };
|
struct timespec sleep = { 1, 0 }; // Interval between loops when idle (network buffer is empty)
|
||||||
struct {
|
struct {
|
||||||
Buffer_Info recv, send, fifo, log;
|
char buf[UIRCD_LIMITS_LINE + 1];
|
||||||
} buf;
|
size_t pos;
|
||||||
|
} Buf_FIFO = { .pos = 0 }, Buf_RECV = { .pos = 0 }; // async buffers, these are managed without blocking
|
||||||
|
int net_fd = -1, fifo_fd = -1; // Network I/O and FIFO I/O (logs are opened and closed on write)
|
||||||
|
char Buf_INTERNAL[UIRCD_LIMITS_LINE + 1]; // sync internal buffer, must be fully flushed each use
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialisation
|
||||||
|
*/
|
||||||
|
openlog("uIRCd", LOG_CONS | LOG_PID | LOG_PERROR, LOG_DAEMON);
|
||||||
|
setlogmask(LOG_UPTO(LOG_INFO));
|
||||||
init_chanarray(&connection.info.channels);
|
init_chanarray(&connection.info.channels);
|
||||||
srand((unsigned int) time(NULL));
|
setup_signals();
|
||||||
if (!set_config_defaults(&connection)) {
|
if (!set_config_defaults(&connection)) {
|
||||||
LOG(LOG_FATAL, "Couldn't allocate memory for configuration variables. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_ERR, "Couldn't allocate memory for configuration variables: " ERRNOFMT, strerror(errno), errno);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parse_args(argc, argv, &connection)) {
|
switch (parse_args(argc, argv, &connection)) {
|
||||||
case 0: return EXIT_SUCCESS;
|
case 0: return EXIT_SUCCESS;
|
||||||
case -1: return EXIT_FAILURE;
|
case -1: return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection.data.path != NULL) {
|
if (connection.data.path != NULL) {
|
||||||
int tmpres;
|
int tmpres;
|
||||||
// TODO: Add chroot()/jail support by default where supported
|
// TODO: Add chroot()/jail support by default where supported
|
||||||
if ((tmpres = chdir(connection.data.path)) != 0) {
|
if ((tmpres = chdir(connection.data.path)) != 0) {
|
||||||
LOG(LOG_ERROR, "Couldn't change log directory to %s. " ERRNOFMT, connection.data.path, strerror(errno), errno);
|
LOG(LOG_ERR, "Couldn't change log directory to %s: " ERRNOFMT, connection.data.path, strerror(errno), errno);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
LOG(LOG_VERBOSE, "Changed directory to %s.", connection.data.path);
|
LOG(LOG_INFO, "Changed log root directory to %s", connection.data.path);
|
||||||
}
|
}
|
||||||
setup_signals();
|
|
||||||
|
/*
|
||||||
|
* Main loop
|
||||||
|
*/
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ctime = time(NULL);
|
ctime = time(NULL);
|
||||||
if (!connection.info.active) nanosleep(&sleep, NULL);
|
if (connection.info.state == CONN_CLOSED) {
|
||||||
connection.info.active = false;
|
|
||||||
if (!run || connection.info.state == CONN_CLOSING) {
|
LOG(LOG_INFO, "Exiting gracefully");
|
||||||
signed long temp;
|
return EXIT_SUCCESS;
|
||||||
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;
|
} else if (!run || connection.info.state == CONN_CLOSING) {
|
||||||
LOG(LOG_VERBOSE,
|
|
||||||
"Sending a QUIT message to " ADDRFMT " containing \"%s\".",
|
ssize_t len;
|
||||||
connection.data.address,
|
IRC_Message build_buf;
|
||||||
connection.data.service,
|
if ((len = Assm_mesg(Buf_INTERNAL, Assm_cmd_QUIT(&build_buf, connection.data.quitmsg), sizeof(Buf_INTERNAL))) > 0) {
|
||||||
connection.data.quitmsg);
|
ssize_t tmp;
|
||||||
if (flush_buffer(buf.send.buffer, buf.send.append_pos, buf.send.fd) == -1)
|
if ((tmp = write_buffer(Buf_INTERNAL, net_fd, (size_t) len, true)) > 0)
|
||||||
LOG(LOG_WARN,
|
LOG(LOG_INFO, "Sent a QUIT message to " ADDRFMT " containing \"%s\"", connection.data.address, connection.data.service, connection.data.quitmsg);
|
||||||
"Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT,
|
else if (tmp == -1)
|
||||||
connection.data.address,
|
LOG(LOG_WARNING, "Failed to send a QUIT message to " ADDRFMT " containing \"%s\"", connection.data.address, connection.data.service, connection.data.quitmsg);
|
||||||
connection.data.service,
|
|
||||||
strerror(errno),
|
|
||||||
errno);
|
|
||||||
}
|
}
|
||||||
close(buf.send.fd);
|
close(net_fd);
|
||||||
close(buf.fifo.fd);
|
close(fifo_fd);
|
||||||
connection.info.state = CONN_CLOSED;
|
connection.info.state = CONN_CLOSED;
|
||||||
LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", connection.data.address, connection.data.service);
|
LOG(LOG_INFO, "Connection to " ADDRFMT " was closed", connection.data.address, connection.data.service);
|
||||||
break;
|
continue;
|
||||||
} else if (connection.info.state == CONN_CLOSED)
|
|
||||||
break;
|
} else if (connection.info.state == CONN_RECONNECTING) {
|
||||||
else if (connection.info.state == CONN_RECONNECTING) {
|
|
||||||
close(buf.send.fd);
|
close(net_fd);
|
||||||
close(buf.fifo.fd);
|
close(fifo_fd);
|
||||||
|
net_fd = -1;
|
||||||
|
fifo_fd = -1;
|
||||||
connection.info.state = CONN_PENDING;
|
connection.info.state = CONN_PENDING;
|
||||||
if (connection.info.reconinter <= 300) connection.info.reconinter += 5;
|
if (connection.info.reconinter <= 300) connection.info.reconinter += 5;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if (connection.info.state == CONN_PENDING) {
|
} else if (connection.info.state == CONN_PENDING) {
|
||||||
|
|
||||||
|
// Reconnection throttling
|
||||||
if (ctime - connection.info.l_connect < connection.info.reconinter) continue;
|
if (ctime - connection.info.l_connect < connection.info.reconinter) continue;
|
||||||
connection.info.l_connect = ctime;
|
Buf_RECV.buf[(Buf_RECV.pos = 0)] = '\0';
|
||||||
|
Buf_FIFO.buf[(Buf_FIFO.pos = 0)] = '\0';
|
||||||
|
connection.info.l_connect = ctime;
|
||||||
|
connection.info.l_message = 0;
|
||||||
|
|
||||||
/* Reset all state-dependent values to empty */
|
// Connection initialisation and registration
|
||||||
memset(&buf, '\0', sizeof(buf));
|
fifo_fd = makeinput("in");
|
||||||
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;
|
|
||||||
|
|
||||||
if ((buf.send.fd = init_connection(&connection)) > 0) {
|
signed int tmp;
|
||||||
buf.recv.fd = buf.send.fd;
|
if ((tmp = init_connection(&connection)) > 0) {
|
||||||
add_socket_flags(buf.send.fd, O_NONBLOCK);
|
add_socket_flags(tmp, O_NONBLOCK);
|
||||||
|
net_fd = tmp;
|
||||||
/* Registration process and CAP negotiation (TODO) */
|
if (register_user(Buf_INTERNAL, sizeof(Buf_INTERNAL), net_fd, &connection.user)) {
|
||||||
signed long temp;
|
LOG(LOG_INFO, "Registered to server " ADDRFMT, connection.data.address, connection.data.service);
|
||||||
/*
|
connection.info.state = CONN_REGISTERED;
|
||||||
if ((temp = Assm_mesg(buf.send.buffer, Assm_cmd_CAP_LS("302"), sizeof(buf.send.buffer))) > 0) {
|
} else {
|
||||||
buf.send.append_pos = (size_t)temp;
|
LOG(LOG_WARNING, "Failed to register to server " ADDRFMT ": " ERRNOFMT, connection.data.address, connection.data.service, strerror(errno), errno);
|
||||||
LOG(LOG_VERBOSE, "Sending a CAP LS to " ADDRFMT ".", connection.data.address,
|
connection.info.state = CONN_RECONNECTING;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*/
|
} else if (tmp == INIT_SOFTFAIL) {
|
||||||
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(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(buf.send.buffer,
|
|
||||||
Assm_cmd_USER(connection.user.username, connection.user.realname, 0),
|
|
||||||
sizeof(buf.send.buffer)))
|
|
||||||
> 0) {
|
|
||||||
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.info.state = CONN_REGISTERED;
|
|
||||||
} else if (buf.send.fd == INIT_SOFTFAIL) {
|
|
||||||
connection.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
continue;
|
} else if (tmp == INIT_HARDFAIL) {
|
||||||
} else if (buf.send.fd == INIT_HARDFAIL) {
|
|
||||||
connection.info.state = CONN_CLOSED;
|
connection.info.state = CONN_CLOSED;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else if (connection.info.state == CONN_ACTIVE) {
|
continue;
|
||||||
|
|
||||||
|
} else if (connection.info.state == CONN_IDLE) {
|
||||||
|
|
||||||
|
if (connection.info.state == CONN_IDLE) nanosleep(&sleep, NULL);
|
||||||
if (connection.data.timeout > 0 && connection.info.l_message < ctime - connection.data.timeout) {
|
if (connection.data.timeout > 0 && connection.info.l_message < ctime - connection.data.timeout) {
|
||||||
LOG(LOG_WARN, "Timed out because no message was received since %lu.", connection.data.timeout);
|
LOG(LOG_WARNING, "Timed out because no message was received since %lu", connection.info.l_message);
|
||||||
connection.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (buf.fifo.fd != -1) {
|
|
||||||
ssize_t brd, len;
|
if (fifo_fd >= 0) {
|
||||||
/* Buffer writer */
|
/* FIFO input is passthrough, no validation is made, allows raw input */
|
||||||
if ((brd =
|
ssize_t r_bytes, w_bytes;
|
||||||
read(buf.fifo.fd, buf.fifo.buffer + buf.fifo.append_pos, sizeof(buf.fifo.buffer) - buf.fifo.append_pos - 1))
|
|
||||||
> 0) {
|
if ((r_bytes = read_buffer(Buf_FIFO.buf + Buf_FIFO.pos, fifo_fd, sizeof(Buf_FIFO.buf) - Buf_FIFO.pos - 1)) == -1) {
|
||||||
*(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);
|
|
||||||
connection.info.active = true;
|
|
||||||
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
|
|
||||||
LOG(LOG_ERROR, "Failed to read FIFO fifo. " ERRNOFMT, strerror(errno), errno);
|
|
||||||
connection.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else if (r_bytes > 0)
|
||||||
|
Buf_FIFO.pos += (size_t) r_bytes;
|
||||||
memset((void*) &buffer, '\0', sizeof(IRC_Message));
|
if ((w_bytes = write_buffer(Buf_FIFO.buf, net_fd, Buf_FIFO.pos, false)) == -1) {
|
||||||
if ((len = get_buffer_line(buf.fifo.buffer)) > 0) {
|
|
||||||
LOG(LOG_DEBUG, "Got FIFO message: %s", buf.fifo.buffer);
|
|
||||||
if (Tok_mesg(buf.fifo.buffer, &buffer) == 1) {
|
|
||||||
LOG(LOG_DEBUG, "%s", "Tokenized FIFO message successfully.");
|
|
||||||
signed long temp;
|
|
||||||
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 fifo 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(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';
|
|
||||||
connection.info.active = true;
|
|
||||||
} else
|
|
||||||
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
|
|
||||||
} else if (len == -1)
|
|
||||||
connection.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
} else {
|
continue;
|
||||||
char pathbuf[UIRCD_LIMITS_PATH];
|
} else if (w_bytes > 0)
|
||||||
if (get_path(pathbuf, sizeof(pathbuf), &connection, NULL, true, true, false) >= 0) {
|
Buf_FIFO.pos -= dequeue_bytes(Buf_FIFO.buf, (size_t) w_bytes, Buf_FIFO.pos);
|
||||||
if (mkdir_bottomup(pathbuf)) buf.fifo.fd = makeinput(pathbuf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (connection.info.state == CONN_ACTIVE) {
|
||||||
|
if (Buf_RECV.pos == 0) connection.info.state = CONN_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t brd, len;
|
/* Receive buffer reader */
|
||||||
/* Buffer reader */
|
ssize_t r_bytes, len;
|
||||||
if ((brd = read(buf.recv.fd, buf.recv.buffer + buf.recv.append_pos, sizeof(buf.recv.buffer) - buf.recv.append_pos - 1)) > 0) {
|
if ((r_bytes = read_buffer(Buf_RECV.buf + Buf_RECV.pos, net_fd, sizeof(Buf_RECV.buf) - Buf_RECV.pos - 1)) == -1) {
|
||||||
*(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);
|
|
||||||
connection.info.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.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
continue;
|
continue;
|
||||||
}
|
} else
|
||||||
|
Buf_RECV.pos += (size_t) r_bytes;
|
||||||
|
|
||||||
memset((void*) &buffer, '\0', sizeof(IRC_Message));
|
memset((void*) &buffer, '\0', sizeof(IRC_Message));
|
||||||
if ((len = get_buffer_line(buf.recv.buffer)) > 0) {
|
if ((len = tok_irc_line(Buf_RECV.buf)) > 0) {
|
||||||
LOG(LOG_DEBUG, "Got IRC message: %s", buf.recv.buffer);
|
LOG(LOG_DEBUG, "Got IRC message on recvbuffer: %s", Buf_RECV.buf);
|
||||||
if (Tok_mesg(buf.recv.buffer, &buffer) == 1) {
|
if (Tok_mesg(Buf_RECV.buf, &buffer) == 1) {
|
||||||
connection.info.l_message = ctime;
|
connection.info.l_message = 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);
|
||||||
buffer.tags.time.value = datebuf;
|
buffer.tags.time.value = datebuf;
|
||||||
}
|
}
|
||||||
char logpath[UIRCD_LIMITS_PATH];
|
|
||||||
if (Assm_mesg(buf.log.buffer, &buffer, sizeof(buf.log.buffer)) > 0) {
|
if ((Assm_mesg(Buf_INTERNAL, &buffer, sizeof(Buf_INTERNAL))) > 0) {
|
||||||
printf("%s\r\n", buf.log.buffer);
|
printf("%s", Buf_INTERNAL);
|
||||||
bool match[][3] = { { false, false, false }, { true, false, false }, { true, false, true } };
|
write_log("out", Buf_INTERNAL);
|
||||||
for (unsigned long i = 0; i < sizeof(match) / sizeof(*match); i++) {
|
}
|
||||||
if (get_path(logpath, sizeof(logpath), &connection, &buffer, match[i][0], match[i][1], match[i][2])
|
|
||||||
>= 0) {
|
switch (buffer.cmd) {
|
||||||
if (mkdir_bottomup(logpath)) write_log(logpath, buf.log.buffer);
|
case (PING): {
|
||||||
}
|
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\"", buffer.args[0]);
|
||||||
|
ssize_t tmp;
|
||||||
|
IRC_Message build_buf;
|
||||||
|
if ((tmp = Assm_mesg(Buf_INTERNAL, Assm_cmd_PONG(&build_buf, buffer.args[0], NULL), sizeof(Buf_INTERNAL))) > 0)
|
||||||
|
if (write_buffer(Buf_INTERNAL, net_fd, (size_t) tmp, true) == -1) {
|
||||||
|
LOG(LOG_WARNING, "Couldn't pong " ADDRFMT ". " ERRNOFMT, connection.data.address, connection.data.service, strerror(errno), errno);
|
||||||
|
connection.info.state = CONN_RECONNECTING;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Autojoin channels from current conn on first response from the server */
|
||||||
|
case (RPL_WELCOME): {
|
||||||
|
LOG(LOG_NOTICE, "Connection established to " ADDRFMT, connection.data.address, connection.data.service);
|
||||||
|
connection.info.state = CONN_ACTIVE;
|
||||||
|
connection.info.reconinter = 0;
|
||||||
|
if (!commit_channelist(Buf_INTERNAL, sizeof(Buf_INTERNAL), net_fd, connection.info.channels)) connection.info.state = CONN_RECONNECTING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ERROR): {
|
||||||
|
LOG(LOG_ERR, "Received error: %s", buffer.args[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (JOIN):
|
||||||
|
case (PART): {
|
||||||
|
resize_chanarray(&connection.info.channels);
|
||||||
|
set_channel(&connection.info.channels[get_channelindex(buffer.args[0], connection.info.channels)], buffer.args[0], buffer.args[1], buffer.cmd == JOIN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (ERR_NICKNAMEINUSE):
|
||||||
|
case (ERR_NICKCOLLISION): {
|
||||||
|
LOG(LOG_WARNING, "Nickname \"%s\" is already taken", connection.user.nickname);
|
||||||
|
connection.info.state = CONN_RECONNECTING;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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++)
|
connection.info.state = CONN_ACTIVE;
|
||||||
*(buf.recv.buffer + x) = *(buf.recv.buffer + x + len);
|
|
||||||
buf.recv.append_pos -= (unsigned long) len;
|
|
||||||
*(buf.recv.buffer + buf.recv.append_pos) = '\0';
|
|
||||||
connection.info.active = true;
|
|
||||||
} else
|
} else
|
||||||
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
|
LOG(LOG_WARNING, "Received invalid IRC message (see RFC2812).");
|
||||||
} else if (len == -1)
|
Buf_RECV.pos -= dequeue_bytes(Buf_RECV.buf, (size_t) len, Buf_RECV.pos);
|
||||||
|
} else {
|
||||||
|
if (len == 0) {
|
||||||
|
if (Buf_RECV.pos != sizeof(Buf_RECV.buf) - 1) continue;
|
||||||
|
LOG(LOG_WARNING, "Receive buffer is full and no message could be parsed");
|
||||||
|
}
|
||||||
connection.info.state = CONN_RECONNECTING;
|
connection.info.state = CONN_RECONNECTING;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LOG(LOG_VERBOSE, "%s", "Exiting gracefully.");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <stdio.h> // fprintf()
|
#include <stdio.h> // fprintf()
|
||||||
#include <stdlib.h> // malloc() free()
|
#include <stdlib.h> // malloc() free()
|
||||||
#include <string.h> // strcpy()
|
#include <string.h> // strcpy()
|
||||||
|
#include <syslog.h> // syslog()
|
||||||
|
|
||||||
/* Description:
|
/* Description:
|
||||||
* This is a allocation manager that frees or allocates variables to pointers depending on the context.
|
* This is a allocation manager that frees or allocates variables to pointers depending on the context.
|
||||||
|
@ -35,8 +36,8 @@
|
||||||
int
|
int
|
||||||
allocate_copy(char** ptr, const char* const var)
|
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 (var == NULL) LOG(LOG_DEBUG, "Freeing pointer because provided variable has the address of NULL");
|
||||||
if (*ptr != NULL) LOG(LOG_DEBUG, "%s.", "Deallocating already allocated pointer for replacement");
|
if (*ptr != NULL) LOG(LOG_DEBUG, "Deallocating already allocated pointer for replacement");
|
||||||
free(*ptr);
|
free(*ptr);
|
||||||
*ptr = NULL;
|
*ptr = NULL;
|
||||||
if (var == NULL) return 1;
|
if (var == NULL) return 1;
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uirc/uirc.h>
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
tok_irc_line(char* buf)
|
||||||
|
{
|
||||||
|
assert(buf != NULL);
|
||||||
|
char* ppoi;
|
||||||
|
if ((ppoi = strchr(buf, '\n')) != NULL) {
|
||||||
|
*ppoi = '\0';
|
||||||
|
if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0';
|
||||||
|
return ++ppoi - buf;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -16,8 +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 "logging.h"
|
#include <sys/types.h> // ssize_t
|
||||||
|
|
||||||
int loglevel = LOG_FATAL;
|
#ifndef UIRCD_GUARD_MISC
|
||||||
const char logchars[] = { [LOG_DEBUG] = 'D', [LOG_VERBOSE] = 'V', [LOG_INFO] = 'I', [LOG_WARN] = 'W', [LOG_ERROR] = 'E', [LOG_FATAL] = 'F' };
|
#define UIRCD_GUARD_MISC
|
||||||
|
|
||||||
|
ssize_t tok_irc_line(char* buf);
|
||||||
|
|
||||||
|
#endif /* UIRCD_GUARD_MISC */
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <stdbool.h> // true, false
|
#include <stdbool.h> // true, false
|
||||||
#include <stdio.h> // NULL, fprintf()
|
#include <stdio.h> // NULL, fprintf()
|
||||||
#include <string.h> // strerror()
|
#include <string.h> // strerror()
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
sig_atomic_t volatile run = true;
|
sig_atomic_t volatile run = true;
|
||||||
|
|
||||||
|
@ -40,11 +41,11 @@ setup_signals(void)
|
||||||
struct sigaction sa = { .sa_flags = SA_SIGINFO, .sa_sigaction = stop_loop };
|
struct sigaction sa = { .sa_flags = SA_SIGINFO, .sa_sigaction = stop_loop };
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
||||||
LOG(LOG_WARN, "sigaction() failed. Children won't respond to signal SIGINT. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_WARNING, "sigaction() failed: Children won't respond to signal SIGINT: " ERRNOFMT, strerror(errno), errno);
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
||||||
LOG(LOG_WARN, "sigaction() failed. Children won't respond to signal SIGTERM. " ERRNOFMT, strerror(errno), errno);
|
LOG(LOG_WARNING, "sigaction() failed: Children won't respond to signal SIGTERM: " ERRNOFMT, strerror(errno), errno);
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
Reference in New Issue