From 77635c120bdb8f6228a825f9d8fbb18882731925 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 1 Aug 2020 19:45:14 +0200 Subject: [PATCH] Rewrite lots of things, reorganize stuff, add reconnect delays and fix most reconnect hangs or bugs --- CMakeLists.txt | 1 - lib/uIRC | 2 +- src/filesystem.c | 50 ++++++----------- src/filesystem.h | 6 +-- src/global.h | 6 +-- src/log.h | 6 ++- src/main.c | 114 +++++++++++++++++++++++++++------------ src/main.h | 12 ++--- src/memory.c | 65 ---------------------- src/memory.h | 40 -------------- src/misc.c | 25 +-------- src/misc.h | 2 - src/net.c | 136 ++++++++++++++++++++++++++++++----------------- src/net.h | 34 +++++++++--- src/structs.h | 1 + 15 files changed, 228 insertions(+), 272 deletions(-) delete mode 100644 src/memory.c delete mode 100644 src/memory.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ada90a..1ef055f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(lib/uIRC) add_executable(uircd src/main.c src/filesystem.c - src/memory.c src/misc.c src/net.c src/log.c diff --git a/lib/uIRC b/lib/uIRC index 0f73ea6..56df6c0 160000 --- a/lib/uIRC +++ b/lib/uIRC @@ -1 +1 @@ -Subproject commit 0f73ea68d8defe4af5fc861e69d9c314c56c80ee +Subproject commit 56df6c09d649ef2ab791da21ca706b7ba350e29f diff --git a/src/filesystem.c b/src/filesystem.c index 67aa4ad..e382905 100644 --- a/src/filesystem.c +++ b/src/filesystem.c @@ -17,42 +17,22 @@ */ #include "filesystem.h" -int write_log(char* line, char* root, IRC_Message* mesg, Connection* conn) + +int create_dirtree(Connection* conn, char* root) { - char path[MAXPATH], bufs[2][MAXPATH], *arrpath[6] = {0}, **ppos = arrpath; + char buf[MAXPATH], *arrpath[3] = {0}, **ppos = arrpath; if (root != NULL) *(ppos++) = root; - if (snprintf(bufs[0], MAXPATH, "%s.%s", conn->data.addr, conn->data.port) <= 0) + if (snprintf(buf, MAXPATH, "%s.%s", conn->data.addr, conn->data.port) <= 0) return 0; - cleanup_path_names(bufs[0]); - *(ppos++) = bufs[0]; - if ((mesg->cmd == NOTICE || mesg->cmd == PRIVMSG) && mesg->name.nick != NULL && *mesg->name.nick != '\0') { - if (strchr("#!&+", *mesg->args[0]) != NULL) - *(ppos++) = "channel"; - else - *(ppos++) = "user"; - if (snprintf(bufs[1], MAXPATH, "%s", strcmp(conn->names.nick, mesg->args[0]) ? mesg->args[0] : mesg->name.nick) <= 0) + cleanup_path_names(buf); + *(ppos++) = buf; + char* dirs[] = {"channel", "user", "global"}; + for (unsigned int i = 0; i < sizeof(dirs) / sizeof(char*); i++) { + *ppos = dirs[i]; + if (!mkdir_bottomup(arrpath, NULL)) return 0; - cleanup_path_names(bufs[1]); - *(ppos++) = bufs[1]; - } else - *(ppos++) = "global"; - if (!mkdir_bottomup(arrpath)) - return 0; - *(ppos++) = "out.log"; - if (!assemble_path(arrpath, path, MAXPATH)) - return 0; - FILE* logfile; - if ((logfile = fopen(path, "a")) == NULL) { - LOG_ERRNO(LOG_ERROR, "Error on opening log file.", path, conn); - return 0; - } else { - if (line == NULL && mesg != NULL) - Assm_mesg(bufs[0], mesg, MAXPATH); - if (fprintf(logfile, "%s\n", (line != NULL) ? line : bufs[0]) <= 0) - LOG_ERRNO(LOG_ERROR, "Error on writing to the log file", path, conn); } - fclose(logfile); return 1; } int assemble_path(char** path, char* out, int len) @@ -71,7 +51,7 @@ int assemble_path(char** path, char* out, int len) } return 1; } -int mkdir_bottomup(char** dir) +int mkdir_bottomup(char** dir, char* start) { if (dir == NULL || *dir == NULL) return -1; @@ -81,8 +61,12 @@ int mkdir_bottomup(char** dir) if (i != dir && len - (bufp - buf) > 0) *(bufp++) = '/'; if ((cprint = snprintf(bufp, len - (bufp - buf), "%s", *i)) > 0) { - if (mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST) - return 0; + if (start == NULL || *i >= start) { + if (mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST) { + LOG_ERRNO(LOG_ERROR, "Could not create directory.", buf); + return 0; + } + } bufp += cprint; } else return 0; diff --git a/src/filesystem.h b/src/filesystem.h index 6f3bcb0..1478adf 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -19,19 +19,19 @@ #include "../lib/uIRC/include/functions.h" #include "../lib/uIRC/include/mappings.h" #include "global.h" -#include "structs.h" #include "log.h" +#include "structs.h" #include #include #include #include #include +#include #ifndef _UIRCD_INCLUDED_FS #define _UIRCD_INCLUDED_FS int cleanup_path_names(char* name); int assemble_path(char** path, char* out, int len); -int write_log(char* line, char* root, IRC_Message* mesg, Connection* conn); -int mkdir_bottomup(char** dir); +int mkdir_bottomup(char** dir, char* start); #endif diff --git a/src/global.h b/src/global.h index 1a346be..ec4aa4b 100644 --- a/src/global.h +++ b/src/global.h @@ -26,10 +26,6 @@ #define MAXPATH 1024 #define MAXCONN 64 -extern sig_atomic_t volatile actcon; -extern int totcon; +extern sig_atomic_t volatile run; extern int loglevel; -extern Connection cons[MAXCONN]; -extern char sendbuf[MAXLINE + 1]; -extern int sendbuflen; #endif diff --git a/src/log.h b/src/log.h index b14c125..4d1e418 100644 --- a/src/log.h +++ b/src/log.h @@ -31,8 +31,10 @@ #define LOG_INFO 3 #define LOG_DEBUG 4 -#define LOG(level, mesg, subj, conn) plog(level, mesg, subj, conn, __LINE__, __FILE__, false) -#define LOG_ERRNO(level, mesg, subj, conn) plog(level, mesg, subj, conn, __LINE__, __FILE__, true) +#define LOG(level, mesg, subj) plog(level, mesg, subj, NULL, __LINE__, __FILE__, false) +#define LOG_ERRNO(level, mesg, subj) plog(level, mesg, subj, NULL, __LINE__, __FILE__, true) +#define LOG_CONN(level, mesg, subj, conn) plog(level, mesg, subj, conn, __LINE__, __FILE__, false) +#define LOG_CONN_ERRNO(level, mesg, subj, conn) plog(level, mesg, subj, conn, __LINE__, __FILE__, true) int plog(int level, char* mesg, char* subject, Connection* conn, int line, char* file, bool use_errno); #endif diff --git a/src/main.c b/src/main.c index 7b340e5..8b8c992 100644 --- a/src/main.c +++ b/src/main.c @@ -18,16 +18,13 @@ #include "main.h" -sig_atomic_t volatile actcon = 0; -int totcon = 0; -Connection cons[MAXCONN] = {0}; -char sendbuf[MAXLINE + 1]; -int sendbuflen; +sig_atomic_t volatile run = true; int loglevel = LOG_FATAL; - int main(int argc, char* argv[]) { - char c, *pos, *root = NULL; + char sendbuf[MAXLINE + 1], *quitmsg = "uIRC indev beta", *root = NULL, c, *pos; + int totcon = 0, actcon = 0, sendbuflen, delay = 10; + Connection cons[MAXCONN] = {0}; while ((c = getopt(argc, argv, "C:m:c:l:j:V:vh")) != -1) { switch (c) { case 'c': { @@ -43,11 +40,13 @@ int main(int argc, char* argv[]) cons[totcon].names.real = ((pos = point_after(optarg, ':')) == NULL) ? "uIRC user" : pos; cons[totcon].names.user = ((pos = point_after(optarg, '!')) == NULL) ? "uIRC-user" : pos; cons[totcon].names.nick = optarg; + cons[totcon].fds[0] = -1; cons[totcon++].connstate = CONN_PENDING; break; } case 'l': root = optarg; break; - case 'm': break; // TODO: Reserved for quit message + case 'm': quitmsg = optarg; break; + case 'd': delay = atoi(optarg); break; case 'C': break; // TODO: Reserved for config file path case 'V': loglevel = atoi(optarg); @@ -59,76 +58,123 @@ int main(int argc, char* argv[]) } } if (totcon < 1) { - LOG(LOG_FATAL, "No connection was provided.", NULL, NULL); + LOG(LOG_FATAL, "No connection was provided.", NULL); return EXIT_FAILURE; } signal(SIGINT, stop_loop); signal(SIGTERM, stop_loop); IRC_Message buffer = {0}; int res; - time_t tmp; + int tmp; + time_t ctime; do { + actcon = 0; for (int t = 0; t < totcon; t++) { - if (cons[t].connstate == CONN_ACTIVE && (tmp = time(NULL)) - cons[t].lastping >= 10) { - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_PING("UIRC PONG", NULL), sizeof(sendbuf))) > 0) { - LOG(LOG_DEBUG, "Sending ping...", NULL, &cons[t]); - flush_buffer(&cons[t]); - cons[t].lastping = tmp; + ctime = time(NULL); + if (cons[t].connstate == CONN_CLOSING || !run) { + if (cons[t].fds[0] != -1) { + if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_QUIT(quitmsg), sizeof(sendbuf))) > 0) + flush_buffer(sendbuf, sendbuflen, &cons[t]); } - } - if (!connection_manager(&cons[t])) + LOG_CONN(LOG_INFO, "Closing connection.", NULL, &cons[t]); + cons[t].connstate = CONN_CLOSED; + close_sockets(cons[t].fds, 2); + continue; + } else if (cons[t].connstate == CONN_ACTIVE) { + actcon++; + if (ctime - cons[t].lastping >= 10) { + if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_PING("UIRC PONG", NULL), sizeof(sendbuf))) > 0) { + LOG_CONN(LOG_DEBUG, "Sending ping...", sendbuf, &cons[t]); + flush_buffer(sendbuf, sendbuflen, &cons[t]); + cons[t].lastping = ctime; + } + } + } else if (cons[t].connstate == CONN_PENDING) { + actcon++; + if (ctime - cons[t].lastconnect < delay) + continue; + cons[t].connstate = CONN_CLOSED; + close_sockets(cons[t].fds, 2); + memset(cons[t].buf.buffer, '\0', 513); + cons[t].buf.nex_line = NULL; + cons[t].buf.append_pos = NULL; + if ((tmp = init_conn(&cons[t])) > 0) { + cons[t].fds[0] = tmp; + cons[t].buf.fd = &cons[t].fds[0]; + cons[t].connstate = CONN_ACTIVE; + cons[t].lastconnect = ctime; + if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_NICK(cons[t].names.nick), sizeof(sendbuf))) > 0) + flush_buffer(sendbuf, sendbuflen, &cons[t]); + if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_USER(cons[t].names.user, cons[t].names.real, 0), sizeof(sendbuf))) > 0) + flush_buffer(sendbuf, sendbuflen, &cons[t]); + LOG_CONN(LOG_INFO, "Connection established!", NULL, &cons[t]); + } + } else if (cons[t].connstate == CONN_CLOSED) continue; switch ((res = readline_mem(&cons[t].buf))) { case READLINE_LINE_READY: { - LOG(LOG_DEBUG, "Line ready.", cons[t].buf.buffer, &cons[t]); + LOG_CONN(LOG_DEBUG, "Line ready.", cons[t].buf.buffer, &cons[t]); char origmsg[513]; strncpy(origmsg, cons[t].buf.buffer, 512); if (Tok_mesg(cons[t].buf.buffer, &buffer) == 1) { - LOG(LOG_DEBUG, "Tokenized message successfully.", NULL, &cons[t]); - handle_irc_message(&buffer, &cons[t]); - write_log(origmsg, root, &buffer, &cons[t]); + LOG(LOG_DEBUG, "Tokenized message successfully.", NULL); + switch (buffer.cmd) { + case (PING): { + LOG_CONN(LOG_DEBUG, "Auto-replying to ping.", buffer.args[0], &cons[t]); + if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_PONG(buffer.args[0], NULL), sizeof(sendbuf))) > 0) + flush_buffer(sendbuf, sendbuflen, &cons[t]); + break; + } + /* Autojoin channels from current connection on first response from the server */ + case (RPL_WELCOME): { + LOG_CONN(LOG_INFO, "Auto-joining channels.", cons[t].data.chans, &cons[t]); + IRC_Message* mesg = Assm_cmd_JOIN(cons[t].data.chans, NULL); + if ((sendbuflen = Assm_mesg(sendbuf, mesg, sizeof(sendbuf))) > 0) + flush_buffer(sendbuf, sendbuflen, &cons[t]); + break; + } + case (RPL_BOUNCE): { + break; // TODO: Make bounces work + } + } } else - LOG(LOG_WARN, "Received invalid IRC message (see RFC2812)", origmsg, &cons[t]); + LOG_CONN(LOG_WARN, "Received invalid IRC message (see RFC2812)", origmsg, &cons[t]); break; } case READLINE_TRYAGAIN: break; case READLINE_INTERRUPTED: { - LOG(LOG_DEBUG, "Caught interrupt. Shutting down.", NULL, &cons[t]); - actcon = 0; + LOG(LOG_DEBUG, "Caught interrupt. Shutting down.", NULL); + run = false; break; } default: { switch (res) { case READLINE_EOF: cons[t].connstate = CONN_PENDING; - LOG(LOG_INFO, "Encountered EOF. Reconnecting...", NULL, &cons[t]); + LOG_CONN(LOG_INFO, "Encountered EOF. Reconnecting...", NULL, &cons[t]); break; case READLINE_FULL: cons[t].connstate = CONN_PENDING; - LOG_ERRNO(LOG_ERROR, "Buffer is full and no line can be found. Reinitializing...", NULL, &cons[t]); + LOG_CONN_ERRNO(LOG_ERROR, "Buffer is full and no line can be found. Reinitializing...", NULL, &cons[t]); break; case READLINE_SOCKET_FAIL: cons[t].connstate = CONN_PENDING; - LOG_ERRNO(LOG_WARN, "Socket was invalid or closed. Reconnecting...", NULL, &cons[t]); + LOG_CONN_ERRNO(LOG_WARN, "Socket was invalid or closed. Reconnecting...", NULL, &cons[t]); break; case READLINE_POLL_FAIL: cons[t].connstate = CONN_PENDING; - LOG_ERRNO(LOG_WARN, "Failed to poll the socket. Reconnecting...", NULL, &cons[t]); + LOG_CONN_ERRNO(LOG_WARN, "Failed to poll the socket. Reconnecting...", NULL, &cons[t]); break; + case READLINE_UNKNOWN_ERR: default: cons[t].connstate = CONN_CLOSING; - LOG_ERRNO(LOG_ERROR, "An unknown error happened. Disabling connection.", NULL, &cons[t]); + LOG_CONN_ERRNO(LOG_ERROR, "An unknown error happened. Disabling connection.", NULL, &cons[t]); break; } break; } } - if (actcon <= 0) { - LOG(LOG_INFO, "No more active connections. Closing.", NULL, &cons[t]); - break; - } } } while (actcon > 0); - close_gracefully(); return EXIT_SUCCESS; } diff --git a/src/main.h b/src/main.h index bd3269d..1a45799 100644 --- a/src/main.h +++ b/src/main.h @@ -11,19 +11,17 @@ * 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 . -*/ + */ -#define UIRC_HELPERS -#include "../lib/uIRC/include/uirc.h" -#include "filesystem.h" #include "global.h" #include "log.h" -#include "memory.h" #include "misc.h" #include "net.h" +#include "memory.h" +#include "structs.h" #include #include #include @@ -31,5 +29,7 @@ #include #include #include +#define UIRC_HELPERS +#include "../lib/uIRC/include/uirc.h" #define VERSION "alpha" diff --git a/src/memory.c b/src/memory.c deleted file mode 100644 index 4b0380a..0000000 --- a/src/memory.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) - * Copyright (c) 2019, 2020 Alex-David Denes - * - * uIRCd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * uIRCd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with uIRCd. If not, see . - */ - -#include "memory.h" - -int readline_mem(Buffer_Info* bs) -{ - if (bs->fd == NULL || *(bs->fd) < 0) - return READLINE_SOCKET_FAIL; - // Read to the last position in the buffer or at the beginning if buffer was just initiated - int b_read = 0; - char* nl = NULL; - if (bs->append_pos == NULL) - bs->append_pos = bs->buffer; - for (;;) { - char tmpcpy[513]; - if (bs->nex_line != NULL) { - strcpy(tmpcpy, bs->nex_line); - strcpy(bs->buffer, tmpcpy); - bs->append_pos -= (bs->nex_line - bs->buffer); - bs->nex_line = NULL; - } - if ((nl = strchr(bs->buffer, '\n')) != NULL) { - if (nl > bs->buffer && *(nl - 1) == '\r') - *(nl - 1) = '\0'; - *nl = '\0'; - bs->nex_line = nl + 1; - break; - } else if (bs->append_pos == bs->buffer + 512) - return READLINE_FULL; - struct pollfd pollinf[] = {{.fd = *bs->fd, .events = POLLRDNORM}}; - switch (poll(pollinf, 1, 10)) { - case -1: { - if (errno != EINTR) // We don't throw a error on a damn ^C - return READLINE_POLL_FAIL; - return READLINE_INTERRUPTED; - } - default: { - if (pollinf[0].revents ^ POLLRDNORM) - return READLINE_TRYAGAIN; - break; - } - } - if ((b_read = read(*bs->fd, bs->append_pos, 512 - (bs->append_pos - bs->buffer))) == -1) - return READLINE_EOF; - bs->append_pos += b_read; - *bs->append_pos = '\0'; - } - return READLINE_LINE_READY; -} diff --git a/src/memory.h b/src/memory.h deleted file mode 100644 index 3247475..0000000 --- a/src/memory.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of uIRCd. (https://git.redxen.eu/caskd/uIRCd) - * Copyright (c) 2019, 2020 Alex-David Denes - * - * uIRCd is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * uIRCd is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with uIRCd. If not, see . - */ - -#include "structs.h" -#include -#include -#include -#include -#include -#include -#include - -#ifndef _UIRCD_INCLUDED_MEM -#define _UIRCD_INCLUDED_MEM - -#define READLINE_LINE_READY 1 -#define READLINE_TRYAGAIN 0 -#define READLINE_EOF -1 -#define READLINE_FULL -2 -#define READLINE_POLL_FAIL -4 -#define READLINE_SOCKET_FAIL -5 -#define READLINE_INTERRUPTED -6 - -int readline_mem(Buffer_Info* bs); -#endif diff --git a/src/misc.c b/src/misc.c index 5e02471..ba52bf6 100644 --- a/src/misc.c +++ b/src/misc.c @@ -20,7 +20,7 @@ void stop_loop() { - actcon = 0; + run = 0; } char* point_after(char* string, char point) /* @@ -33,26 +33,3 @@ char* point_after(char* string, char point) *(ret++) = '\0'; return ret; } -int handle_irc_message(IRC_Message* mesg, Connection* conn) -{ - switch (mesg->cmd) { - case (PING): { - LOG(LOG_DEBUG, "Responding to ping.", mesg->trailing, conn); - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_PONG(mesg->trailing, NULL), sizeof(sendbuf))) > 0) - flush_buffer(conn); - break; - } - /* Autojoin channels from current connection on first response from the server */ - case (RPL_WELCOME): { - LOG(LOG_DEBUG, "Auto-joining channels.", conn->data.chans, conn); - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_JOIN(conn->data.chans, NULL), sizeof(sendbuf))) > 0) - flush_buffer(conn); - break; - } - case (RPL_BOUNCE): { - break; // TODO: Make bounces work - } - default: return 0; - } - return 1; -} diff --git a/src/misc.h b/src/misc.h index 5cfbe10..b453722 100644 --- a/src/misc.h +++ b/src/misc.h @@ -19,7 +19,6 @@ #include "../lib/uIRC/include/functions.h" #include "../lib/uIRC/include/mappings.h" #include "global.h" -#include "net.h" #include "structs.h" #include #include @@ -33,5 +32,4 @@ char* point_after(char* string, char point); void stop_loop(); -int handle_irc_message(IRC_Message* mesg, Connection* conn); #endif diff --git a/src/net.c b/src/net.c index 4ba2b80..d2576b8 100644 --- a/src/net.c +++ b/src/net.c @@ -27,7 +27,7 @@ signed int init_conn(Connection* info) if ((getaddrres = getaddrinfo(info->data.addr, info->data.port, NULL, &conn)) == 0) { break; } else { - LOG_ERRNO(LOG_ERROR, "Failed to get address info.", NULL, info); + LOG_CONN_ERRNO(LOG_ERROR, "Failed to get address info.", NULL, info); if (i == 2 || (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME)) { freeaddrinfo(conn); return -1; @@ -41,7 +41,7 @@ signed int init_conn(Connection* info) return -1; } if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) { - LOG_ERRNO(LOG_ERROR, "Failed to open a socket.", NULL, info); + LOG_CONN_ERRNO(LOG_ERROR, "Failed to open a socket.", NULL, info); return -1; } for (unsigned int i = 0; i < 3; i++) { @@ -49,7 +49,7 @@ signed int init_conn(Connection* info) if (connectres == 0 || (connectres == -1 && errno == EINTR)) { break; } else { - LOG_ERRNO(LOG_ERROR, "Failed to connect to host.", NULL, info); + LOG_CONN_ERRNO(LOG_ERROR, "Failed to connect to host.", NULL, info); if (i == 2 || (connectres != EADDRNOTAVAIL && connectres != ETIMEDOUT && connectres != ECONNRESET && connectres != ECONNREFUSED)) { close(sockfd); return -1; @@ -64,64 +64,104 @@ signed int init_conn(Connection* info) } return sockfd; } -int connection_manager(Connection* conn) + +int readline_mem(Buffer_Info* bs) { - switch (conn->connstate) { - case CONN_PENDING: { - int tmp; - conn->connstate = CONN_CLOSED; - conn->fds[0] = -1; - memset(conn->buf.buffer, '\0', 513); - conn->buf.nex_line = NULL; - conn->buf.append_pos = NULL; - if ((tmp = init_conn(conn)) > 0) { - conn->fds[0] = tmp; - conn->buf.fd = &conn->fds[0]; - conn->connstate = CONN_ACTIVE; - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_NICK(conn->names.nick), sizeof(sendbuf))) > 0) - flush_buffer(conn); - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_USER(conn->names.user, conn->names.real, 0), sizeof(sendbuf))) > 0) - flush_buffer(conn); - actcon++; - LOG(LOG_INFO, "Connection established!", NULL, conn); - return 1; - } - return 0; + if (bs->fd == NULL || *(bs->fd) < 0) + return READLINE_SOCKET_FAIL; + // Read to the last position in the buffer or at the beginning if buffer was just initiated + int b_read = 0; + char* nl = NULL; + if (bs->append_pos == NULL) + bs->append_pos = bs->buffer; + for (;;) { + char tmpcpy[513]; + if (!run) + return READLINE_INTERRUPTED; + if (bs->nex_line != NULL) { + strcpy(tmpcpy, bs->nex_line); + strcpy(bs->buffer, tmpcpy); + bs->append_pos -= (bs->nex_line - bs->buffer); + bs->nex_line = NULL; } - case CONN_CLOSING: { - if ((sendbuflen = Assm_mesg(sendbuf, Assm_cmd_QUIT(">> uIRC beta"), sizeof(sendbuf))) > 0) - flush_buffer(conn); - LOG(LOG_INFO, "Closing connection.", NULL, conn); - conn->connstate = CONN_CLOSED; - close(conn->fds[0]); - conn->fds[0] = -1; - return 0; + if ((nl = strchr(bs->buffer, '\n')) != NULL) { + if (nl > bs->buffer && *(nl - 1) == '\r') + *(nl - 1) = '\0'; + *nl = '\0'; + bs->nex_line = nl + 1; + break; + } else if (bs->append_pos == bs->buffer + 512) + return READLINE_FULL; + switch (poll_conn(*bs->fd)) { + case PCON_ERR: return READLINE_POLL_FAIL; + case PCON_INTER: return READLINE_INTERRUPTED; + case PCON_NREADY: return READLINE_TRYAGAIN; + case PCON_READY: break; + default: return READLINE_POLL_FAIL; } - case CONN_CLOSED: return 0; - default: return 1; + if ((b_read = read(*bs->fd, bs->append_pos, 512 - (bs->append_pos - bs->buffer))) == -1) { + if (errno == EINTR) + return READLINE_INTERRUPTED; + else if (errno == ENOTCONN || errno == ETIMEDOUT || errno == ECONNRESET) + return READLINE_EOF; + else + return READLINE_UNKNOWN_ERR; + } + bs->append_pos += b_read; + *bs->append_pos = '\0'; + if (b_read == 0) + return READLINE_EOF; } + return READLINE_LINE_READY; } -void close_gracefully() -{ - for (int x = 0; x < totcon; x++) { - if (cons[x].connstate >= 0) - cons[x].connstate = CONN_CLOSING; - connection_manager(&cons[x]); - } -} -void flush_buffer(Connection* conn) + +void flush_buffer(char* send_buf, int send_buflen, Connection* conn) { int res; - char* pos = sendbuf; + char* pos = send_buf; for (;;) { - if ((res = write(conn->fds[0], pos, sendbuflen - (pos - sendbuf))) != sendbuflen - (pos - sendbuf)) { + if ((res = write(conn->fds[0], pos, send_buflen - (pos - send_buf))) != send_buflen - (pos - send_buf)) { if (res == -1) { conn->connstate = CONN_PENDING; - LOG(LOG_ERROR, "Couldn't flush send buffer over network. Will attempt to reconnect.", NULL, conn); + LOG_ERRNO(LOG_ERROR, "Couldn't flush send buffer over network. Will attempt to reconnect.", NULL); break; - } else + } else { + LOG_CONN(LOG_DEBUG, "Sent a chunked message.", NULL, conn); pos += res; + } } else break; } + LOG_CONN(LOG_DEBUG, "Message sent.", send_buf, conn); +} + +int poll_conn(int fd) +{ + struct pollfd pollinf[] = {{.fd = fd, .events = POLLIN}}; + switch (poll(pollinf, 1, 10)) { + case -1: { + if (errno != EINTR) // We don't throw a error on a damn ^C + return PCON_ERR; + return PCON_INTER; + } + default: { + if (pollinf[0].revents & POLLIN) + return PCON_READY; + else if (pollinf[0].revents == 0) + return PCON_NREADY; + return PCON_ERR; + } + } + return PCON_ERR; +} + +int close_sockets(int* fds, int cnt) +{ + int res; + for (int i = 0; i < cnt; i++) { + if ((res = close(fds[i])) == -1) + return 0; + fds[i] = -1; + } + return 1; } diff --git a/src/net.h b/src/net.h index 073ebc2..216490f 100644 --- a/src/net.h +++ b/src/net.h @@ -16,33 +16,51 @@ * along with uIRCd. If not, see . */ +#define UIRC_HELPERS #include "../lib/uIRC/include/functions.h" +#include "../lib/uIRC/include/helpers.h" +#include "../lib/uIRC/include/mappings.h" #include "global.h" #include "log.h" #include "structs.h" #include #include +#include #include #include #include #include +#include #include #include #include #include -#define UIRC_HELPERS -#include "../lib/uIRC/include/helpers.h" #ifndef _UIRCD_INCLUDED_NETWORK #define _UIRCD_INCLUDED_NETWORK #define CONN_ACTIVE 1 -#define CONN_PENDING -1 -#define CONN_CLOSING -2 -#define CONN_CLOSED -3 +#define CONN_PENDING 0 +#define CONN_CLOSING -1 +#define CONN_CLOSED -2 + +#define PCON_READY 1 +#define PCON_NREADY 0 +#define PCON_INTER -1 +#define PCON_ERR -2 + +#define READLINE_LINE_READY 1 +#define READLINE_TRYAGAIN 0 +#define READLINE_EOF -1 +#define READLINE_FULL -2 +#define READLINE_POLL_FAIL -4 +#define READLINE_SOCKET_FAIL -5 +#define READLINE_INTERRUPTED -6 +#define READLINE_UNKNOWN_ERR -7 signed int init_conn(Connection* info); -int connection_manager(Connection* conn); -void flush_buffer(Connection* conn); -void close_gracefully(); +int readline_mem(Buffer_Info* bs); +void flush_buffer(char* send_buf, int send_buflen, Connection* conn); +int poll_conn(int fd); +int close_sockets(int* fds, int cnt); #endif diff --git a/src/structs.h b/src/structs.h index dab6106..f8c4bf1 100644 --- a/src/structs.h +++ b/src/structs.h @@ -40,5 +40,6 @@ typedef struct { signed int fds[2]; signed int connstate; time_t lastping; + time_t lastconnect; } Connection; #endif