Version 2021.01.24: Feature redesign
- Removed RELAXED_RFC, will be supported as addtion in form of patches later - Remove Buffer_Info and use separate buffer types where it makes sense - Make FIFO a raw passthrough pipe - Redefine read/write _buffer - Rename buffer_offset_move to dequeue_bytes - Remove filtering, will be supported by separate binaries - Simplify registration and channel commits - Merge automatic replies in main.c - Remove path filtering, now only using fixed paths - Setup signals earlier - Add option for write_buffer to do a full flush or only partial if not possible - Use global buffers for registration
This commit is contained in:
parent
b5e46c5635
commit
9a357c63e7
|
@ -1,16 +1,16 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
project(
|
||||
uIRCd
|
||||
VERSION 2021.01.19
|
||||
VERSION 2021.01.24
|
||||
DESCRIPTION "High performance IRC daemon based on uIRC"
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
set(UIRCD_VERSION "${PROJECT_VERSION}")
|
||||
add_compile_definitions(UIRCD_VERSION="${UIRCD_VERSION}")
|
||||
add_compile_definitions(UIRC_HELPERS UIRC_IRCV3)
|
||||
|
||||
OPTION(BUILD_LIBCONFIG "Build support for configurations" ON )
|
||||
OPTION(UIRCD_RELAXED_RFC "Build without following RFC2812 entirely" OFF) # This allows features like a dynamic buffer and more to exist
|
||||
OPTION(CODE_ANALYZER "Analyze the code statically" OFF)
|
||||
OPTION(CODE_COVERAGE "Build with coverage tools" OFF)
|
||||
|
||||
|
@ -19,7 +19,6 @@ add_executable(uircd
|
|||
src/configuration.c
|
||||
src/connection.c
|
||||
src/filesystem.c
|
||||
src/logging.c
|
||||
src/main.c
|
||||
src/memory.c
|
||||
src/misc.c
|
||||
|
@ -43,40 +42,14 @@ endif()
|
|||
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Werror")
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat-overflow=2
|
||||
-Wformat-security
|
||||
-Winit-self
|
||||
-Wstrict-overflow=2
|
||||
-Wstringop-overflow=2
|
||||
-Walloc-zero
|
||||
-Wduplicated-branches
|
||||
-Wduplicated-cond
|
||||
-Wtrampolines
|
||||
-Wfloat-equal
|
||||
-Wshadow
|
||||
-Wunsafe-loop-optimizations
|
||||
-Wparentheses
|
||||
-fstack-check
|
||||
-pedantic
|
||||
)
|
||||
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")
|
||||
if (CODE_ANALYZER)
|
||||
add_compile_options(-fanalyzer)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fanalyzer")
|
||||
endif()
|
||||
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(
|
||||
-Weverything
|
||||
-Wno-padded
|
||||
-Wno-disabled-macro-expansion
|
||||
-pedantic
|
||||
)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Weverything -Wno-padded -Wno-disabled-macro-expansion -pedantic")
|
||||
if (CODE_COVERAGE)
|
||||
add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
|
||||
endif()
|
||||
if (CODE_ANALYZER)
|
||||
add_compile_options(--analyze)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ cmake -B build/ -DCMAKE_BUILD_TYPE=Release .
|
|||
| Option | Description | Type | Default | Supported since |
|
||||
|:------------------:|:----------------------------------------------------------------------:|:--------:|:-------:|:---------------:|
|
||||
| BUILD_LIBCONFIG | Build and link against libconfig | boolean | true | 2021.01.04 |
|
||||
| UIRCD_RELAXED_RFC |Don't enforce strict RFC2812. Allows dynamic buffers and more features. | boolean | false | 2021.01.12 |
|
||||
| CODE_ANALYZER | Use static analysis tools | boolean | false | 2020.10.30 |
|
||||
| CODE_COVERAGE | Generate code coverage output | boolean | false | 2020.10.30 |
|
||||
|
||||
|
|
79
src/buffer.c
79
src/buffer.c
|
@ -29,38 +29,39 @@
|
|||
#include <unistd.h> // write()
|
||||
|
||||
ssize_t
|
||||
read_buffer(Buffer_Info* binfo)
|
||||
read_buffer(char* dest, int fd, size_t len)
|
||||
{
|
||||
assert(binfo != NULL);
|
||||
assert(dest != NULL);
|
||||
if (len == 0) return 0;
|
||||
ssize_t brd;
|
||||
if ((brd = read(binfo->fd, binfo->buffer + binfo->data_size, binfo->buf_size - binfo->data_size - 1)) > 0) {
|
||||
*(binfo->buffer + (binfo->data_size += (size_t) brd)) = '\0';
|
||||
LOG(LOG_DEBUG, "Read %li bytes from socket buffer and currently at position %li", brd, binfo->data_size);
|
||||
if ((brd = read(fd, dest, len)) > 0) {
|
||||
*(dest + brd) = '\0';
|
||||
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 inbound traffic on fd %i: " ERRNOFMT, binfo->fd, strerror(errno), errno);
|
||||
LOG(LOG_WARNING, "Failed to read buffer on fd %i: " ERRNOFMT, fd, strerror(errno), errno);
|
||||
}
|
||||
return brd;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
write_buffer(Buffer_Info* binfo)
|
||||
write_buffer(const char* src, int fd, size_t len, bool fullflush)
|
||||
{
|
||||
assert(binfo != NULL);
|
||||
assert(src != NULL);
|
||||
if (len == 0) return 0;
|
||||
ssize_t res;
|
||||
size_t pos = 0;
|
||||
for (;;) {
|
||||
size_t left = binfo->data_size - pos;
|
||||
if ((size_t)(res = write(binfo->fd, binfo->buffer + pos, left)) != left) {
|
||||
if (res == -1 && errno != EINTR) {
|
||||
LOG(LOG_WARNING, "Couldn't flush buffer to fd %i: " ERRNOFMT, binfo->fd, strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
pos += res;
|
||||
LOG(LOG_DEBUG, "Wrote %lu bytes to fd %i", res, binfo->fd);
|
||||
} else
|
||||
size_t b_wr = 0;
|
||||
do {
|
||||
if ((res = write(fd, src + b_wr, len - b_wr)) > 0) {
|
||||
LOG(LOG_DEBUG, "Wrote %lu bytes to fd %i", res, len);
|
||||
b_wr += (size_t) res;
|
||||
} else if (res == -1) {
|
||||
if (!fullflush && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) return 0;
|
||||
LOG(LOG_WARNING, "Couldn't flush buffer to fd %i: " ERRNOFMT, fd, strerror(errno), errno);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
} while (fullflush && b_wr < len);
|
||||
return (ssize_t) b_wr;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -71,36 +72,18 @@ write_buffer(Buffer_Info* binfo)
|
|||
* 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
|
||||
buffer_offset_move(Buffer_Info* binfo, size_t offset)
|
||||
dequeue_bytes(char* str, size_t cnt, size_t len)
|
||||
{
|
||||
assert(binfo != NULL);
|
||||
assert(str != NULL);
|
||||
assert(cnt <= len);
|
||||
size_t pos = 0;
|
||||
do {
|
||||
char* dest = binfo->buffer + pos;
|
||||
size_t b_left = binfo->data_size - pos - offset;
|
||||
strncpy(dest, dest + offset, (b_left < offset) ? b_left : offset);
|
||||
LOG(LOG_DEBUG, "Moved %lu bytes from %lu to %lu", (b_left < offset) ? b_left : offset, offset + pos, pos);
|
||||
pos += offset;
|
||||
} while (offset + pos < binfo->data_size);
|
||||
binfo->data_size -= offset;
|
||||
return binfo->data_size;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
reset_buffer(Buffer_Info* binfo, short clr_fd)
|
||||
{
|
||||
if (clr_fd) {
|
||||
if (clr_fd == 2) close(binfo->fd);
|
||||
binfo->fd = -1;
|
||||
}
|
||||
#ifdef UIRCD_RELAXED_RFC
|
||||
if (binfo->buffer != NULL) free(binfo->buffer);
|
||||
binfo->buffer = NULL;
|
||||
binfo->buf_size = 0;
|
||||
#else /* UIRCD_RELAXED_RFC */
|
||||
*binfo->buffer = '\0';
|
||||
binfo->buf_size = UIRCD_LIMITS_LINE + 1;
|
||||
#endif /* UIRCD_RELAXED_RFC */
|
||||
binfo->data_size = 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
20
src/buffer.h
20
src/buffer.h
|
@ -24,21 +24,9 @@
|
|||
#ifndef UIRCD_GUARD_BUFFER
|
||||
#define UIRCD_GUARD_BUFFER
|
||||
|
||||
typedef struct {
|
||||
char
|
||||
#ifdef UIRCD_RELAXED_RFC
|
||||
* buffer
|
||||
#else /* UIRCD_RELAXED_RFC */
|
||||
buffer[UIRCD_LIMITS_LINE + 1]
|
||||
#endif /* UIRCD_RELAXED_RFC */
|
||||
;
|
||||
size_t data_size, buf_size;
|
||||
int fd;
|
||||
} Buffer_Info;
|
||||
|
||||
ssize_t read_buffer(Buffer_Info* binfo);
|
||||
ssize_t write_buffer(Buffer_Info* binfo);
|
||||
size_t buffer_offset_move(Buffer_Info* binfo, size_t offset);
|
||||
int reset_buffer(Buffer_Info* binfo, short clr_fd);
|
||||
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 */
|
||||
|
||||
|
|
250
src/connection.c
250
src/connection.c
|
@ -34,10 +34,8 @@
|
|||
#include <sys/types.h> // size_t ssize_t socklen_t
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> // ??
|
||||
|
||||
#define UIRC_HELPERS
|
||||
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
||||
#include <unistd.h> // ??
|
||||
|
||||
signed int
|
||||
init_connection(Connection* conn)
|
||||
|
@ -68,227 +66,45 @@ init_connection(Connection* conn)
|
|||
return sockfd;
|
||||
}
|
||||
|
||||
signed int
|
||||
get_msgchannel(IRC_Message* mesg)
|
||||
bool
|
||||
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.
|
||||
// Maybe offering a static context would allow reentrant calls
|
||||
switch (mesg->cmd) {
|
||||
case JOIN:
|
||||
case PART:
|
||||
case MODE:
|
||||
case TOPIC:
|
||||
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;
|
||||
}
|
||||
ssize_t tmp;
|
||||
IRC_Message build_buf;
|
||||
if (user->password != NULL && (tmp = Assm_mesg(buf, Assm_cmd_PASS(&build_buf, user->password), len)) > 0) {
|
||||
if (write_buffer(buf, fd, (size_t) tmp, true) != -1) {
|
||||
LOG(LOG_INFO, "Sent PASS authentication");
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
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*
|
||||
get_categ(IRC_Message* mesg)
|
||||
bool
|
||||
commit_channelist(char* buf, size_t len, int fd, Channel* chans)
|
||||
{
|
||||
switch (mesg->cmd) {
|
||||
case JOIN:
|
||||
case PART:
|
||||
case QUIT:
|
||||
case KICK: return "events";
|
||||
case TOPIC:
|
||||
case RPL_TOPIC:
|
||||
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 ((buf->data_size = Assm_mesg(buf->buffer, Assm_cmd_PONG(mesg->args[0], NULL), buf->buf_size)) > 0)
|
||||
if (write_buffer(buf) == -1) {
|
||||
LOG(LOG_WARNING, "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 with mesg \"%s\"", mesg->args[1]); }
|
||||
break;
|
||||
}
|
||||
/* Autojoin channels from current conn on first response from the server */
|
||||
case (RPL_WELCOME): {
|
||||
LOG(LOG_NOTICE, "Connection established to " ADDRFMT, conn->data.address, conn->data.service);
|
||||
conn->info.state = CONN_ACTIVE;
|
||||
conn->info.reconinter = 0;
|
||||
if (!commit_channelist(buf, conn)) return 0;
|
||||
break;
|
||||
}
|
||||
/* TODO: IRCv3 capabilities
|
||||
case (CAP): {
|
||||
if (mesg->args[1] != NULL) {
|
||||
if (strcmp(mesg->args[1], "LS") == 0) {
|
||||
LOG(LOG_INFO,
|
||||
"Requesting capabilities \"%s\" on " ADDRFMT ".",
|
||||
mesg->args[2],
|
||||
conn->data.address,
|
||||
conn->data.service);
|
||||
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(mesg->args[2]), buf->csize)) > 0) {
|
||||
if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) {
|
||||
LOG(LOG_WARNING,
|
||||
"Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT,
|
||||
mesg->args[2],
|
||||
conn->data.address,
|
||||
conn->data.service,
|
||||
strerror(errno),
|
||||
errno);
|
||||
conn->info.state = CONN_RECONNECTING;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(mesg->args[1], "ACK") == 0) {
|
||||
LOG(LOG_INFO, "Ending capability negotiation on " ADDRFMT ".", conn->data.address, conn->data.service);
|
||||
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_END(), buf->csize)) > 0) {
|
||||
if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) {
|
||||
LOG(LOG_WARNING,
|
||||
"Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT,
|
||||
conn->data.address,
|
||||
conn->data.service,
|
||||
strerror(errno),
|
||||
errno);
|
||||
conn->info.state = CONN_RECONNECTING;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case (ERROR): {
|
||||
LOG(LOG_ERR, "Received error: %s", mesg->args[0]);
|
||||
break;
|
||||
}
|
||||
case (JOIN):
|
||||
case (PART): {
|
||||
resize_chanarray(&conn->info.channels);
|
||||
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_WARNING, "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 ((buf->data_size = Assm_mesg(buf->buffer, &msg, buf->buf_size)) > 0) {
|
||||
if (write_buffer(buf) == -1) {
|
||||
LOG(LOG_WARNING,
|
||||
"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;
|
||||
ssize_t tmp;
|
||||
for (unsigned int i = 0; chans != NULL && chans[i].name != NULL; i++) {
|
||||
IRC_Message msg = { .args = { chans[i].name, chans[i].key, NULL }, .trailing = true, .cmd = (chans[i].joined) ? JOIN : PART };
|
||||
if ((tmp = Assm_mesg(buf, &msg, len)) > 0) {
|
||||
if (write_buffer(buf, fd, (size_t) tmp, true) == -1) {
|
||||
LOG(LOG_WARNING, "Couldn't auto-join channel \"%s\": " ERRNOFMT, chans[i].name, strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
register_user(Connection* conn, Buffer_Info* buf)
|
||||
{
|
||||
/* Registration process and CAP negotiation (TODO)
|
||||
if ((temp = Assm_mesg(buf.send[0].buffer, Assm_cmd_CAP_LS("302"), sizeof(buf.send[0].buffer))) > 0) {
|
||||
buf.send[0].data_size = (size_t) temp;
|
||||
LOG(LOG_INFO, "Sending a CAP LS to " ADDRFMT ".", connection.data.address, connection.data.service);
|
||||
if (flush_buffer(buf.send[0].buffer, buf.send[0].data_size, buf.send[0].fd) == -1) {
|
||||
LOG(LOG_WARNING,
|
||||
"Couldn't send CAP LS to " ADDRFMT ". " ERRNOFMT,
|
||||
connection.data.address,
|
||||
connection.data.service,
|
||||
strerror(errno),
|
||||
errno);
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (conn->user.password != NULL && (buf->data_size = Assm_mesg(buf->buffer, Assm_cmd_PASS(conn->user.password), buf->buf_size)) > 0) {
|
||||
if (write_buffer(buf) != -1) {
|
||||
LOG(LOG_INFO, "Sent PASS authentication to " ADDRFMT, conn->data.address, conn->data.service);
|
||||
} else {
|
||||
conn->info.state = CONN_RECONNECTING;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ((buf->data_size = Assm_mesg(buf->buffer, Assm_cmd_NICK(conn->user.nickname), buf->buf_size)) > 0) {
|
||||
if (write_buffer(buf) != -1) {
|
||||
LOG(LOG_INFO, "Sent NICK registration to " ADDRFMT " with nickname \"%s\".", conn->data.address, conn->data.service, conn->user.nickname);
|
||||
} else {
|
||||
conn->info.state = CONN_RECONNECTING;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if ((buf->data_size = Assm_mesg(buf->buffer, Assm_cmd_USER(conn->user.username, conn->user.realname, 0), buf->buf_size)) > 0) {
|
||||
if (write_buffer(buf) != -1) {
|
||||
LOG(LOG_INFO,
|
||||
"Sent USER registration to " ADDRFMT " with username \"%s\" and realname \"%s\".",
|
||||
conn->data.address,
|
||||
conn->data.service,
|
||||
conn->user.username,
|
||||
conn->user.realname);
|
||||
} else {
|
||||
conn->info.state = CONN_RECONNECTING;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@
|
|||
|
||||
#include <stdbool.h> // bool
|
||||
#include <sys/types.h> // size_t ssize_t socklen_t
|
||||
|
||||
#define UIRC_IRCV3
|
||||
#define UIRC_HELPERS
|
||||
#include <uirc/uirc.h> // Assm_mesg Assm_cmd...
|
||||
|
||||
#ifndef UIRCD_GUARD_CONNECTION
|
||||
|
@ -63,12 +60,9 @@ typedef struct {
|
|||
Connection_Info info;
|
||||
} Connection;
|
||||
|
||||
signed int init_connection(Connection* conn);
|
||||
signed int get_msgchannel(IRC_Message* mesg);
|
||||
int auto_msg_actions(IRC_Message* mesg, Connection* conn, Buffer_Info* buf);
|
||||
int commit_channelist(Buffer_Info* buf, Connection* conn);
|
||||
const char* get_categ(IRC_Message* mesg);
|
||||
int register_user(Connection* conn, Buffer_Info* buf);
|
||||
signed int init_connection(Connection* conn);
|
||||
bool register_user(char* buf, size_t len, int fd, Connection_User* user);
|
||||
bool commit_channelist(char* buf, size_t len, int fd, Channel* chans);
|
||||
|
||||
#endif /* UIRCD_GUARD_CONNECTION */
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <ctype.h> // isalpha() isdigit()
|
||||
#include <errno.h> // errno
|
||||
#include <fcntl.h> // fnctl()
|
||||
#include <limits.h> // ??
|
||||
#include <stdbool.h> // bool
|
||||
#include <stdio.h> // fopen() FILE fprintf()
|
||||
#include <string.h> // strerror()
|
||||
|
@ -33,29 +32,6 @@
|
|||
#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_ERR, "Could not create directory \"%s\": " ERRNOFMT, path, strerror(errno), errno);
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
LOG(LOG_DEBUG, "Created directory at \"%s\"", path);
|
||||
*(x + 1) = save;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
makeinput(const char* path)
|
||||
{
|
||||
|
@ -80,7 +56,7 @@ write_log(const char* path, const char* message)
|
|||
FILE* logfile;
|
||||
if ((logfile = fopen(path, "a")) != NULL) {
|
||||
fprintf(logfile, "%s", message);
|
||||
LOG(LOG_DEBUG, "Wrote to log %s", path);
|
||||
LOG(LOG_DEBUG, "Wrote to log \"%s\"", path);
|
||||
fclose(logfile);
|
||||
return 1;
|
||||
} else
|
||||
|
@ -88,19 +64,6 @@ write_log(const char* path, const char* message)
|
|||
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
|
||||
add_socket_flags(int fd, int flags)
|
||||
{
|
||||
|
@ -114,53 +77,3 @@ add_socket_flags(int fd, int flags)
|
|||
LOG(LOG_WARNING, "Failed to get socket flags: " ERRNOFMT, strerror(errno), errno);
|
||||
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 <sys/types.h>
|
||||
|
||||
#define UIRC_IRCV3
|
||||
#include <uirc/uirc.h> // IRC_Message
|
||||
|
||||
#ifndef UIRCD_GUARD_FILESYSTEM
|
||||
#define UIRCD_GUARD_FILESYSTEM
|
||||
|
||||
int mkdir_bottomup(char* path);
|
||||
int makeinput(const char* path);
|
||||
bool write_log(const char* path, const char* message);
|
||||
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);
|
||||
int makeinput(const char* path);
|
||||
bool write_log(const char* path, const char* message);
|
||||
bool add_socket_flags(int fd, int flags);
|
||||
|
||||
#endif /* UIRCD_GUARD_FILESYSTEM */
|
||||
|
||||
|
|
|
@ -1,19 +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 "logging.h"
|
|
@ -16,6 +16,8 @@
|
|||
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#ifndef UIRCD_GUARD_LOGGING
|
||||
#define UIRCD_GUARD_LOGGING
|
||||
|
||||
|
|
219
src/main.c
219
src/main.c
|
@ -35,11 +35,8 @@
|
|||
#include <sys/types.h> // time_t size_t
|
||||
#include <syslog.h> // openlog() syslog()
|
||||
#include <time.h> // time()
|
||||
#include <unistd.h> // getopt() chdir() close()
|
||||
|
||||
#define UIRC_IRCV3
|
||||
#define UIRC_HELPERS
|
||||
#include <uirc/uirc.h> // IRC_Message
|
||||
#include <unistd.h> // getopt() chdir() close()
|
||||
|
||||
int
|
||||
parse_args(int argc, char** argv, Connection* conn)
|
||||
|
@ -133,18 +130,15 @@ int
|
|||
main(int argc, char* argv[])
|
||||
{
|
||||
IRC_Message buffer;
|
||||
Connection connection = { 0 };
|
||||
time_t ctime; // Current time
|
||||
struct timespec sleep = { 1, 0 }; // Interval between loops when idle (network buffer is empty)
|
||||
Connection connection = { .info.state = CONN_PENDING }; // Start off with a pending connection
|
||||
time_t ctime; // Current time
|
||||
struct timespec sleep = { 1, 0 }; // Interval between loops when idle (network buffer is empty)
|
||||
struct {
|
||||
Buffer_Info recv[2], // Network recv buffer / FIFO read buffer
|
||||
send[2], // Network send buffer / FIFO send buffer
|
||||
log; // Log writing buffer
|
||||
} buf = {
|
||||
.recv = { { .fd = -1 }, { .fd = -1 } },
|
||||
.send = { { .fd = -1 }, { .fd = -1 } },
|
||||
.log = { .fd = -1 },
|
||||
};
|
||||
char buf[UIRCD_LIMITS_LINE + 1];
|
||||
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
|
||||
|
@ -152,14 +146,17 @@ main(int argc, char* argv[])
|
|||
openlog("uIRCd", LOG_CONS | LOG_PID | LOG_PERROR, LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
init_chanarray(&connection.info.channels);
|
||||
setup_signals();
|
||||
if (!set_config_defaults(&connection)) {
|
||||
LOG(LOG_ERR, "Couldn't allocate memory for configuration variables: " ERRNOFMT, strerror(errno), errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
switch (parse_args(argc, argv, &connection)) {
|
||||
case 0: return EXIT_SUCCESS;
|
||||
case -1: return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (connection.data.path != NULL) {
|
||||
int tmpres;
|
||||
// TODO: Add chroot()/jail support by default where supported
|
||||
|
@ -167,9 +164,8 @@ main(int argc, char* argv[])
|
|||
LOG(LOG_ERR, "Couldn't change log directory to %s: " ERRNOFMT, connection.data.path, strerror(errno), errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
LOG(LOG_INFO, "Changed root directory to %s", connection.data.path);
|
||||
LOG(LOG_INFO, "Changed log root directory to %s", connection.data.path);
|
||||
}
|
||||
setup_signals();
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
|
@ -177,109 +173,108 @@ main(int argc, char* argv[])
|
|||
for (;;) {
|
||||
ctime = time(NULL);
|
||||
if (connection.info.state == CONN_CLOSED) {
|
||||
|
||||
LOG(LOG_INFO, "Exiting gracefully");
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
} else if (!run || connection.info.state == CONN_CLOSING) {
|
||||
if ((buf.send[0].data_size = Assm_mesg(buf.send[0].buffer, Assm_cmd_QUIT(connection.data.quitmsg), buf.send[0].buf_size)) > 0) {
|
||||
if (write_buffer(&buf.send[0]) != -1)
|
||||
|
||||
ssize_t len;
|
||||
IRC_Message build_buf;
|
||||
if ((len = Assm_mesg(Buf_INTERNAL, Assm_cmd_QUIT(&build_buf, connection.data.quitmsg), sizeof(Buf_INTERNAL))) > 0) {
|
||||
ssize_t tmp;
|
||||
if ((tmp = write_buffer(Buf_INTERNAL, net_fd, (size_t) len, true)) > 0)
|
||||
LOG(LOG_INFO, "Sent a QUIT message to " ADDRFMT " containing \"%s\"", connection.data.address, connection.data.service, connection.data.quitmsg);
|
||||
else if (tmp == -1)
|
||||
LOG(LOG_WARNING, "Failed to send a QUIT message to " ADDRFMT " containing \"%s\"", connection.data.address, connection.data.service, connection.data.quitmsg);
|
||||
}
|
||||
reset_buffer(&buf.recv[0], 2); // net rw/FIFO read fd
|
||||
reset_buffer(&buf.recv[1], 2); // FIFO read fd
|
||||
close(net_fd);
|
||||
close(fifo_fd);
|
||||
connection.info.state = CONN_CLOSED;
|
||||
LOG(LOG_INFO, "Connection to " ADDRFMT " was closed", connection.data.address, connection.data.service);
|
||||
continue;
|
||||
|
||||
} else if (connection.info.state == CONN_RECONNECTING) {
|
||||
|
||||
close(net_fd);
|
||||
close(fifo_fd);
|
||||
net_fd = -1;
|
||||
fifo_fd = -1;
|
||||
connection.info.state = CONN_PENDING;
|
||||
if (connection.info.reconinter <= 300) connection.info.reconinter += 5;
|
||||
continue;
|
||||
|
||||
} else if (connection.info.state == CONN_PENDING) {
|
||||
|
||||
// Reconnection throttling
|
||||
if (ctime - connection.info.l_connect < connection.info.reconinter) continue;
|
||||
|
||||
connection.info.l_connect = ctime;
|
||||
|
||||
/* Reset all state-dependent values to empty */
|
||||
reset_buffer(&buf.recv[0], 2);
|
||||
reset_buffer(&buf.recv[1], 2);
|
||||
reset_buffer(&buf.send[0], 1);
|
||||
reset_buffer(&buf.send[1], 1);
|
||||
reset_buffer(&buf.log, 1);
|
||||
connection.info.l_message = 0;
|
||||
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;
|
||||
|
||||
// Connection initialisation and registration
|
||||
if ((buf.send[0].fd = init_connection(&connection)) > 0) {
|
||||
buf.recv[0].fd = buf.send[1].fd = buf.send[0].fd;
|
||||
add_socket_flags(buf.send[0].fd, O_NONBLOCK);
|
||||
if (!register_user(&connection, &buf.send[0])) {
|
||||
fifo_fd = makeinput("in");
|
||||
|
||||
signed int tmp;
|
||||
if ((tmp = init_connection(&connection)) > 0) {
|
||||
add_socket_flags(tmp, O_NONBLOCK);
|
||||
net_fd = tmp;
|
||||
if (register_user(Buf_INTERNAL, sizeof(Buf_INTERNAL), net_fd, &connection.user)) {
|
||||
LOG(LOG_INFO, "Registered to server " ADDRFMT, connection.data.address, connection.data.service);
|
||||
connection.info.state = CONN_REGISTERED;
|
||||
} else {
|
||||
LOG(LOG_WARNING, "Failed to register to server " 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[0].fd == INIT_SOFTFAIL) {
|
||||
} else if (tmp == INIT_SOFTFAIL) {
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
} else if (buf.send[0].fd == INIT_HARDFAIL) {
|
||||
} else if (tmp == INIT_HARDFAIL) {
|
||||
connection.info.state = CONN_CLOSED;
|
||||
continue;
|
||||
}
|
||||
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) {
|
||||
LOG(LOG_WARNING, "Timed out because no message was received since %lu", connection.info.l_message);
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
}
|
||||
if (buf.recv[1].fd != -1) {
|
||||
ssize_t r_bytes, len;
|
||||
if ((r_bytes = read_buffer(&buf.recv[1])) == -1) {
|
||||
|
||||
if (fifo_fd >= 0) {
|
||||
/* FIFO input is passthrough, no validation is made, allows raw input */
|
||||
ssize_t r_bytes, w_bytes;
|
||||
|
||||
if ((r_bytes = read_buffer(Buf_FIFO.buf + Buf_FIFO.pos, fifo_fd, sizeof(Buf_FIFO.buf) - Buf_FIFO.pos - 1)) == -1) {
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
}
|
||||
|
||||
memset((void*) &buffer, '\0', sizeof(IRC_Message));
|
||||
if ((len = tok_irc_line(buf.recv[1].buffer)) > 0) {
|
||||
LOG(LOG_DEBUG, "Got IRC message: %s", buf.recv[1].buffer);
|
||||
if (Tok_mesg(buf.recv[1].buffer, &buffer) == 1) {
|
||||
if ((buf.send[1].data_size = Assm_mesg(buf.send[1].buffer, &buffer, buf.send[1].buf_size)) > 0) {
|
||||
if (write_buffer(&buf.send[1]) == -1) {
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else
|
||||
LOG(LOG_WARNING, "Received invalid IRC message on FIFO (see RFC2812)");
|
||||
|
||||
buffer_offset_move(&buf.recv[1], len);
|
||||
} else if (buf.recv[1].data_size == buf.recv[1].buf_size - 1) {
|
||||
#ifdef UIRCD_RELAXED_RFC
|
||||
// TODO: Add resize here
|
||||
#else /* UIRCD_RELAXED_RFC */
|
||||
LOG(LOG_WARNING, "FIFO buffer is full and no message could be parsed");
|
||||
reset_buffer(&buf.recv[1], false);
|
||||
#endif /* UIRCD_RELAXED_RFC */
|
||||
}
|
||||
} else {
|
||||
char pathbuf[UIRCD_LIMITS_PATH];
|
||||
if (get_path(pathbuf, sizeof(pathbuf), &connection, NULL, true, true, false) >= 0) {
|
||||
if (mkdir_bottomup(pathbuf)) buf.recv[1].fd = makeinput(pathbuf);
|
||||
}
|
||||
} else if (r_bytes > 0)
|
||||
Buf_FIFO.pos += (size_t) r_bytes;
|
||||
if ((w_bytes = write_buffer(Buf_FIFO.buf, net_fd, Buf_FIFO.pos, false)) == -1) {
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
} else if (w_bytes > 0)
|
||||
Buf_FIFO.pos -= dequeue_bytes(Buf_FIFO.buf, (size_t) w_bytes, Buf_FIFO.pos);
|
||||
}
|
||||
|
||||
} else if (connection.info.state == CONN_ACTIVE) {
|
||||
connection.info.state = CONN_IDLE;
|
||||
if (Buf_RECV.pos == 0) connection.info.state = CONN_IDLE;
|
||||
}
|
||||
|
||||
/* Receive buffer reader */
|
||||
ssize_t r_bytes, len;
|
||||
if ((r_bytes = read_buffer(&buf.recv[0])) == -1) {
|
||||
if ((r_bytes = read_buffer(Buf_RECV.buf + Buf_RECV.pos, net_fd, sizeof(Buf_RECV.buf) - Buf_RECV.pos - 1)) == -1) {
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
Buf_RECV.pos += (size_t) r_bytes;
|
||||
|
||||
memset((void*) &buffer, '\0', sizeof(IRC_Message));
|
||||
if ((len = tok_irc_line(buf.recv[0].buffer)) > 0) {
|
||||
LOG(LOG_DEBUG, "Got IRC message on recvbuffer: %s", buf.recv[0].buffer);
|
||||
if (Tok_mesg(buf.recv[0].buffer, &buffer) == 1) {
|
||||
if ((len = tok_irc_line(Buf_RECV.buf)) > 0) {
|
||||
LOG(LOG_DEBUG, "Got IRC message on recvbuffer: %s", Buf_RECV.buf);
|
||||
if (Tok_mesg(Buf_RECV.buf, &buffer) == 1) {
|
||||
connection.info.l_message = ctime;
|
||||
|
||||
char datebuf[25];
|
||||
|
@ -288,32 +283,60 @@ main(int argc, char* argv[])
|
|||
buffer.tags.time.value = datebuf;
|
||||
}
|
||||
|
||||
char logpath[UIRCD_LIMITS_PATH];
|
||||
if ((buf.log.data_size = Assm_mesg(buf.log.buffer, &buffer, buf.log.buf_size)) > 0) {
|
||||
printf("%s", buf.log.buffer);
|
||||
bool match[][3] = { { false, false, false }, { true, false, false }, { true, false, true } };
|
||||
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) {
|
||||
if (mkdir_bottomup(logpath)) write_log(logpath, buf.log.buffer);
|
||||
}
|
||||
if ((Assm_mesg(Buf_INTERNAL, &buffer, sizeof(Buf_INTERNAL))) > 0) {
|
||||
printf("%s", Buf_INTERNAL);
|
||||
write_log("out", Buf_INTERNAL);
|
||||
}
|
||||
|
||||
switch (buffer.cmd) {
|
||||
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[0])) continue;
|
||||
|
||||
buffer_offset_move(&buf.recv[0], len);
|
||||
connection.info.state = CONN_ACTIVE;
|
||||
} else
|
||||
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;
|
||||
} else if (buf.recv[0].data_size == buf.recv[0].buf_size - 1) {
|
||||
#ifdef UIRCD_RELAXED_RFC
|
||||
// TODO: Add resize here
|
||||
#else /* UIRCD_RELAXED_RFC */
|
||||
LOG(LOG_WARNING, "Receive buffer is full and no message could be parsed");
|
||||
connection.info.state = CONN_RECONNECTING;
|
||||
#endif /* UIRCD_RELAXED_RFC */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UIRC_IRCV3
|
||||
#define UIRC_HELPERS
|
||||
#include <uirc/uirc.h>
|
||||
|
||||
ssize_t
|
||||
|
|
|
@ -24,3 +24,4 @@
|
|||
ssize_t tok_irc_line(char* buf);
|
||||
|
||||
#endif /* UIRCD_GUARD_MISC */
|
||||
|
||||
|
|
Reference in New Issue