Rewrite a big chunk of the code, split the code into functions and clean it up, fix undefined behaviours and more

This commit is contained in:
Alex D. 2020-10-02 14:38:11 +02:00
parent f0bfff775d
commit a4d1e501eb
Signed by: caskd
GPG Key ID: F92BA85F61F4C173
16 changed files with 666 additions and 375 deletions

View File

@ -7,7 +7,7 @@ IndentWidth: 8
UseTab: ForIndentation
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
BreakBeforeBinaryOperators: NonAssignment

180
.clang-tidy Normal file
View File

@ -0,0 +1,180 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,clang-diagnostic-*,clang-analyzer-*,clang-diagnostic-*,clang-analyzer-*,-*,clang-analyzer-core.*,clang-analyzer-optin.performance.*,clang-analyzer-optin.portability.*,clang-analyzer-nullability.*,clang-analyzer-security.*,clang-analyzer-unix.*,bugprone-*,misc-*,performance-*,readability-*,-*,clang-analyzer-core.*,clang-analyzer-optin.performance.*,clang-analyzer-optin.portability.*,clang-analyzer-nullability.*,clang-analyzer-security.*,clang-analyzer-unix.*,bugprone-*,misc-*,performance-*,readability-*,-readability-isolate-declaration,-readability-else-after-return,-readability-braces-around-statements,-*,clang-analyzer-core.*,clang-analyzer-optin.performance.*,clang-analyzer-optin.portability.*,clang-analyzer-nullability.*,clang-analyzer-security.*,clang-analyzer-unix.*,bugprone-*,misc-*,performance-*,readability-*,-readability-isolate-declaration,-readability-else-after-return,-readability-braces-around-statements,-readability-magic-numbers'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: none
User: caskd
CheckOptions:
- key: bugprone-argument-comment.CommentBoolLiterals
value: '0'
- key: bugprone-argument-comment.CommentCharacterLiterals
value: '0'
- key: bugprone-argument-comment.CommentFloatLiterals
value: '0'
- key: bugprone-argument-comment.CommentIntegerLiterals
value: '0'
- key: bugprone-argument-comment.CommentNullPtrs
value: '0'
- key: bugprone-argument-comment.CommentStringLiterals
value: '0'
- key: bugprone-argument-comment.CommentUserDefinedLiterals
value: '0'
- key: bugprone-argument-comment.IgnoreSingleArgument
value: '0'
- key: bugprone-argument-comment.StrictMode
value: '0'
- key: bugprone-assert-side-effect.AssertMacros
value: assert
- key: bugprone-assert-side-effect.CheckFunctionCalls
value: '0'
- key: bugprone-dangling-handle.HandleClasses
value: 'std::basic_string_view;std::experimental::basic_string_view'
- key: bugprone-dynamic-static-initializers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: bugprone-exception-escape.FunctionsThatShouldNotThrow
value: ''
- key: bugprone-exception-escape.IgnoredExceptions
value: ''
- key: bugprone-misplaced-widening-cast.CheckImplicitCasts
value: '0'
- key: bugprone-not-null-terminated-result.WantToUseSafeFunctions
value: '1'
- key: bugprone-signed-char-misuse.CharTypdefsToIgnore
value: ''
- key: bugprone-sizeof-expression.WarnOnSizeOfCompareToConstant
value: '1'
- key: bugprone-sizeof-expression.WarnOnSizeOfConstant
value: '1'
- key: bugprone-sizeof-expression.WarnOnSizeOfIntegerExpression
value: '0'
- key: bugprone-sizeof-expression.WarnOnSizeOfThis
value: '1'
- key: bugprone-string-constructor.LargeLengthThreshold
value: '8388608'
- key: bugprone-string-constructor.WarnOnLargeLength
value: '1'
- key: bugprone-suspicious-enum-usage.StrictMode
value: '0'
- key: bugprone-suspicious-missing-comma.MaxConcatenatedTokens
value: '5'
- key: bugprone-suspicious-missing-comma.RatioThreshold
value: '0.200000'
- key: bugprone-suspicious-missing-comma.SizeThreshold
value: '5'
- key: bugprone-suspicious-string-compare.StringCompareLikeFunctions
value: ''
- key: bugprone-suspicious-string-compare.WarnOnImplicitComparison
value: '1'
- key: bugprone-suspicious-string-compare.WarnOnLogicalNotComparison
value: '0'
- key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit
value: '16'
- key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField
value: '1'
- key: bugprone-unused-return-value.CheckedFunctions
value: '::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique;::std::unique_ptr::release;::std::basic_string::empty;::std::vector::empty'
- key: cert-dcl16-c.NewSuffixes
value: 'L;LL;LU;LLU'
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
value: '0'
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
value: '1'
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: misc-definitions-in-headers.HeaderFileExtensions
value: ',h,hh,hpp,hxx'
- key: misc-definitions-in-headers.UseHeaderFileExtension
value: '1'
- key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries
value: '1'
- key: misc-unused-parameters.StrictMode
value: '0'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
- key: performance-faster-string-find.StringLikeClasses
value: 'std::basic_string'
- key: performance-for-range-copy.AllowedTypes
value: ''
- key: performance-for-range-copy.WarnOnAllAutoCopies
value: '0'
- key: performance-inefficient-string-concatenation.StrictMode
value: '0'
- key: performance-inefficient-vector-operation.EnableProto
value: '0'
- key: performance-inefficient-vector-operation.VectorLikeClasses
value: '::std::vector'
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: '1'
- key: performance-move-constructor-init.IncludeStyle
value: llvm
- key: performance-no-automatic-move.AllowedTypes
value: ''
- key: performance-type-promotion-in-math-fn.IncludeStyle
value: llvm
- key: performance-unnecessary-copy-initialization.AllowedTypes
value: ''
- key: performance-unnecessary-value-param.AllowedTypes
value: ''
- key: performance-unnecessary-value-param.IncludeStyle
value: llvm
- key: readability-function-size.BranchThreshold
value: '4294967295'
- key: readability-function-size.LineThreshold
value: '4294967295'
- key: readability-function-size.NestingThreshold
value: '4294967295'
- key: readability-function-size.ParameterThreshold
value: '4294967295'
- key: readability-function-size.StatementThreshold
value: '800'
- key: readability-function-size.VariableThreshold
value: '4294967295'
- key: readability-identifier-naming.IgnoreFailedSplit
value: '0'
- key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '0'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '0'
- key: readability-inconsistent-declaration-parameter-name.IgnoreMacros
value: '1'
- key: readability-inconsistent-declaration-parameter-name.Strict
value: '0'
- key: readability-redundant-member-init.IgnoreBaseInCopyConstructors
value: '0'
- key: readability-redundant-smartptr-get.IgnoreMacros
value: '1'
- key: readability-redundant-string-init.StringNames
value: '::std::basic_string'
- key: readability-simplify-boolean-expr.ChainedConditionalAssignment
value: '0'
- key: readability-simplify-boolean-expr.ChainedConditionalReturn
value: '0'
- key: readability-simplify-subscript-expr.Types
value: '::std::basic_string;::std::basic_string_view;::std::vector;::std::array'
- key: readability-static-accessed-through-instance.NameSpecifierNestingThreshold
value: '3'
- key: readability-uppercase-literal-suffix.IgnoreMacros
value: '1'
- key: readability-uppercase-literal-suffix.NewSuffixes
value: ''
...

7
.gitignore vendored
View File

@ -1,6 +1,3 @@
build/
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
.swp
.clangd/
compile_commands.json

View File

@ -1,10 +1,16 @@
cmake_minimum_required(VERSION 3.16)
project(microircd LANGUAGES C)
set(COMPILE_OPTIONS "-Wall -Wextra -pedantic -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 -fanalyzer -fstack-protector")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
add_compile_options(-Wall -Wextra -Wformat-overflow=2 -Wformat-security -Winit-self -Wstrict-overflow=2 -Wstringop-overflow=2 -Walloc-zero -Wduplicated-branches -Wduplicated-cond -Wtrampolines -Wfloat-equal -Wshadow -Wunsafe-loop-optimizations -Wparentheses -pedantic -fanalyzer -fstack-check)
elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Weverything -pedantic -Wno-padded -Wno-disabled-macro-expansion)
endif()
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
if (CMAKE_BUILD_TYPE EQUAL "Debug")
set(COMPILE_OPTIONS "${COMPILE_OPTIONS} -Og")
elseif (CMAKE_BUILD_TYPE EQUAL "Release")

19
src/.clang-format Normal file
View File

@ -0,0 +1,19 @@
---
Language: Cpp
Standard: Cpp11
BasedOnStyle: LLVM
TabWidth: 8
IndentWidth: 8
UseTab: ForIndentation
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Linux
IndentCaseLabels: true
PointerAlignment: Left
ColumnLimit: 0
...

View File

@ -14,49 +14,64 @@
*
* You should have received a copy of the GNU General Public License
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
*/
*/
#include "filesystem.h"
int assemble_path(char** path, char* out, int len)
int mkdir_bottomup(char* path)
{
if (path == NULL || *path == NULL || len <= 0)
if (path == NULL || *path == '\0')
return 0;
char* orig = out;
int cprint;
for (char** i = path; i != NULL && *i != NULL && out - orig < len; i++) {
if (i != path && len - (out - orig) > 0)
*(out++) = '/';
if ((cprint = snprintf(out, len - (out - orig), "%s", *i)) > 0)
out += cprint;
else
return 0;
}
return 1;
}
int mkdir_bottomup(char** dir)
{
if (dir == NULL || *dir == NULL)
return -1;
int cprint;
char buf[PATH_MAX], *bufp = buf;
for (char** i = dir; i != NULL && *i != NULL && bufp - buf < sizeof(buf); i++) {
if (i != dir && sizeof(buf) - (bufp - buf) > 0)
*(bufp++) = '/';
if ((cprint = snprintf(bufp, sizeof(buf) - (bufp - buf), "%s", *i)) > 0) {
if (mkdir(buf, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0 && errno != EEXIST) {
LOG(LOG_ERROR, "Could not create directory \"%s\".", buf);
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 && errno != EEXIST) {
*(x + 1) = save;
LOG(LOG_ERROR, "Could not create directory \"%s\".", path);
return 0;
}
bufp += cprint;
} else {
LOG(LOG_ERROR, "Path limit reached!");
return 0;
*(x + 1) = save;
x++;
}
}
LOG(LOG_DEBUG, "Created directory at: %s", path);
return 1;
}
int cleanup_path_names(char* name)
int makeinput(char* path)
{
if (path == NULL)
return -1;
int tmp;
if ((tmp = mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP)) == 0) {
LOG(LOG_VERBOSE, "Created a FIFO pipe for input at %s.", path);
} else if (errno != EEXIST) {
LOG(LOG_WARN, "Couldn't create FIFO at \"%s\" for input. " ERRNOFMT, path, strerror(errno), errno);
return -1;
}
int fd;
if ((fd = open(path, O_RDONLY | O_NONBLOCK)) != -1) {
LOG(LOG_DEBUG, "Opened \"%s\" for reading.", path);
return fd;
} else
LOG(LOG_WARN, "Couldn't open FIFO pipe \"%s\" for reading. " ERRNOFMT, path, strerror(errno), errno);
return -1;
}
bool write_log(char* path, char* message)
{
FILE* logfile;
if ((logfile = fopen(path, "a")) != NULL) {
fprintf(logfile, "%s", message);
fclose(logfile);
return 1;
} else
LOG(LOG_WARN, "Couldn't open file \"%s\" for appending.", path);
return 0;
}
bool cleanup_path_names(char* name)
{
if (name == NULL)
return 0;
@ -64,9 +79,103 @@ int cleanup_path_names(char* name)
*name = '_';
for (; *name; name++) {
if (isalpha(*name))
*name = tolower(*name);
*name = (char)tolower(*name);
else if (strchr(".+-_#&", *name) == NULL && !isdigit(*name))
*name = '_';
}
return 1;
}
bool add_socket_flags(int fd, int flags)
{
int cflgs;
if ((cflgs = fcntl(fd, F_GETFL)) != -1) {
if (fcntl(fd, F_SETFL, cflgs | flags) == -1) {
LOG(LOG_WARN, "Couldn't add socket flags. " ERRNOFMT, strerror(errno), errno);
return 0;
}
} else {
LOG(LOG_WARN, "Failed to get socket flags. " ERRNOFMT, strerror(errno), errno);
return 0;
}
return 1;
}
ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf* buf)
{
if (buf == NULL || buf->elements[nth_elem].bufpos == NULL)
return -1;
size_t totallen = 0;
for (unsigned long i = 0; i < sizeof(buf->elements) / sizeof(PathBufElem) && buf->elements[i].len > 0; i++)
totallen += buf->elements[i].len;
ssize_t temp;
if ((temp = snprintf(buf->elements[nth_elem].bufpos, sizeof(buf->buf) - totallen, (isdir) ? "%s/" : "%s", content)) == -1)
return -2;
buf->elements[nth_elem].len = (size_t)temp;
if (nth_elem < sizeof(buf->elements) / sizeof(PathBufElem)) {
buf->elements[nth_elem + 1].bufpos = buf->elements[nth_elem].bufpos + temp;
buf->elements[nth_elem + 1].len = 0;
}
return temp;
}
signed int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer)
{
char temp[MAXLINE];
char *type, *bufname;
char* types[] = {"channel", "user"};
switch (message->cmd) {
case JOIN:
case PART:
case MODE:
case TOPIC:
case KICK:
case NAMES:
case RPL_INVITING:
case RPL_BANLIST:
case RPL_ENDOFBANLIST: {
type = types[0];
bufname = message->args[0];
break;
}
case RPL_NOTOPIC:
case RPL_TOPIC: {
bufname = message->args[0];
// NOTE: Some weird servers don't follow the RFC and use args[0] as target nick
if (message->args[2] != NULL)
bufname = message->args[1];
type = types[0];
break;
}
case KILL: {
type = types[1];
bufname = message->args[0];
break;
}
case PRIVMSG:
case NOTICE: {
bufname = message->args[0];
type = types[1];
if (*bufname == '#' || *bufname == '&' || *bufname == '!' || *bufname == '+')
type = types[0];
break;
}
default: return 0;
}
if (set_path_elem(type, 1, true, pathbuffer) <= 0)
return -1;
if (!mkdir_bottomup(pathbuffer->buf))
return -1;
strncpy(temp, bufname, sizeof(temp));
cleanup_path_names(temp);
if (set_path_elem(temp, 2, true, pathbuffer) <= 0)
return -1;
if (!mkdir_bottomup(pathbuffer->buf))
return -1;
if (set_path_elem("out", 3, false, pathbuffer) <= 0)
return -1;
if (!mkdir_bottomup(pathbuffer->buf))
return -1;
return 1;
}

View File

@ -16,23 +16,29 @@
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
*/
#include "uirc/functions.h"
#include "uirc/mappings.h"
#include "global.h"
#include "log.h"
#include "structs.h"
#define UIRC_IRCV3
#include "uirc/functions.h"
#include "uirc/mappings.h"
#include <ctype.h>
#include <errno.h>
#include <linux/limits.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifndef _UIRCD_INCLUDED_FS
#define _UIRCD_INCLUDED_FS
#ifndef UIRCD_INCLUDED_FS
#define UIRCD_INCLUDED_FS
int cleanup_path_names(char* name);
int assemble_path(char** path, char* out, int len);
int mkdir_bottomup(char** dir);
int mkdir_bottomup(char* path);
int makeinput(char* path);
bool cleanup_path_names(char* name);
bool write_log(char* path, char* message);
bool add_socket_flags(int fd, int flags);
ssize_t set_path_elem(char* content, unsigned int nth_elem, bool isdir, PathBuf* buf);
int prepare_log_path(IRC_Message* message, PathBuf* pathbuffer);
#endif

View File

@ -16,18 +16,19 @@
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
*/
#include "structs.h"
#include <signal.h>
#ifndef _UIRCD_INCLUDED_GLOBAL
#define _UIRCD_INCLUDED_GLOBAL
#ifndef UIRCD_INCLUDED_GLOBAL
#define UIRCD_INCLUDED_GLOBAL
#define MAXLINE 512
#define MAXPATH 1024
#define MAXCONN 64
#define MAXNICK 32
#define ERRNOFMT "%s (%i)"
#define ADDRFMT "%s:%s"
extern sig_atomic_t volatile run;
extern int loglevel;
#endif

View File

@ -18,8 +18,8 @@
#include <stdio.h>
#include <string.h>
#ifndef _UIRCD_INCLUDED_LOG
#define _UIRCD_INCLUDED_LOG
#ifndef UIRCD_INCLUDED_LOG
#define UIRCD_INCLUDED_LOG
#define LOG_FATAL 0
#define LOG_ERROR 1
@ -28,23 +28,23 @@
#define LOG_VERBOSE 4
#define LOG_DEBUG 5
#define LOG(LEVEL, ...) \
{ \
if (LEVEL <= loglevel) { \
char* logchar = "?"; \
switch (LEVEL) { \
case (LOG_DEBUG): logchar = "D"; break; \
case (LOG_VERBOSE): logchar = "V"; break; \
case (LOG_INFO): logchar = "I"; break; \
case (LOG_WARN): logchar = "W"; break; \
case (LOG_ERROR): logchar = "E"; break; \
case (LOG_FATAL): logchar = "F"; break; \
} \
fprintf(stderr, "[%s] ", logchar); \
fprintf(stderr, __VA_ARGS__); \
if (loglevel == LOG_DEBUG) \
fprintf(stderr, " --> LINE: %i -- FILE: %s", __LINE__, __FILE__); \
putc('\n', stderr); \
} \
#define LOG(LEVEL, ...) \
if (LEVEL <= loglevel) { \
char* logchar = "?"; \
switch (LEVEL) { \
case (LOG_DEBUG): logchar = "D"; break; \
case (LOG_VERBOSE): logchar = "V"; break; \
case (LOG_INFO): logchar = "I"; break; \
case (LOG_WARN): logchar = "W"; break; \
case (LOG_ERROR): logchar = "E"; break; \
case (LOG_FATAL): logchar = "F"; break; \
} \
fprintf(stderr, "[%s] ", logchar); \
fprintf(stderr, __VA_ARGS__); \
if (loglevel == LOG_DEBUG) \
fprintf(stderr, " --> LINE: %i -- FILE: %s", __LINE__, __FILE__); \
putc('\n', stderr); \
}
#endif

View File

@ -22,8 +22,9 @@ sig_atomic_t volatile run = true;
int loglevel = LOG_FATAL;
int main(int argc, char* argv[])
{
char *quitmsg = "uIRC indev beta", c, *pos = NULL;
unsigned int totcon = 0, actcon = 0, delay = 10, timeout = 30;
int c;
char *quitmsg = "uIRC indev beta", *pos = NULL;
unsigned int totcon = 0, actcon = 0, timeout = 30;
Connection cons[MAXCONN] = {0};
setvbuf(stderr, NULL, _IOLBF, 0); /* Threads may want to print incomplete messages to the log at the same that, avoid that. */
@ -31,7 +32,6 @@ int main(int argc, char* argv[])
* -c Connection in format: nick [ '!' user ] [ '@' host ] [ '/' [ '+' ] port ] [ ',' channel [ ',' channel ... ] ]
* -l Starting directory for message tree
* -m Message sent on closing the bouncer gracefully
* -d Reconnection delay (seconds)
* -t Timeout duration (seconds)
* -V Log level: 0 being FATAL and 5 being DEBUG
* -C Configuration file path
@ -64,8 +64,7 @@ int main(int argc, char* argv[])
break;
}
case 'm': quitmsg = optarg; break;
case 'd': delay = atoi(optarg); break;
case 't': timeout = atoi(optarg); break;
case 't': timeout = (unsigned int)atoi(optarg); break;
case 'C': break; // TODO: Reserved for config file path
case 'V': loglevel = atoi(optarg); break;
case 'v': {
@ -92,7 +91,7 @@ int main(int argc, char* argv[])
break;
}
} else if (cpid == 0) {
return run_main(&cons[actcon], delay, quitmsg, timeout);
return run_main(&cons[actcon], quitmsg, timeout);
} else {
LOG(LOG_VERBOSE, "Successfully forked for connection " ADDRFMT ".", cons[actcon].data.addr, cons[actcon].data.port);
actcon++;
@ -106,283 +105,195 @@ int main(int argc, char* argv[])
return EXIT_SUCCESS;
}
int run_main(Connection* conn, unsigned int recon_inter, char* quitmsg, int timeout)
int run_main(Connection* conn, char* quitmsg, unsigned int timeout)
{
srand((unsigned int)time(NULL));
IRC_Message buffer;
char sendbuf[MAXLINE + 1], recvbuf[MAXLINE + 1], fifobuf[MAXLINE + 1], /* Buffers */
connstr[100], *path[4] = {connstr, NULL, 0}; /* Path buffers */
size_t sendbufpos = 0, recvbufpos = 0, fifobufpos = 0; /* Positions */
signed int connstate = CONN_PENDING, fds[2] = {-1, -1}; /* Connection state and file descriptors */
unsigned int lastping = 0, lastconnect = 0, ctime = 0, lastpong = 0, lastmesg = 0, /* Timestamps */
reconinter = (recon_inter) ? recon_inter : 10; /* Intervals */
get_connstr(connstr, sizeof(connstr), conn);
srand(time(NULL));
Buffer_Info buffers[3]; /* Buffers */
#define recvbuf buffers[0]
#define sendbuf buffers[1]
#define fifobuf buffers[2]
PathBuf filebuf;
signed int reconinter = 0;
time_t ctime;
bool active = true;
struct timespec sleep = {0, 50000000L};
for (;;) {
struct timespec sleep = {0, 10000000L};
nanosleep(&sleep, NULL);
/* Connection manager */
ctime = time(NULL);
if (!run || connstate == CONN_CLOSING) {
if (fds[0] != -1) {
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_QUIT(quitmsg), sizeof(sendbuf))) > 0) {
LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, quitmsg);
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1)
LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
}
close(fds[0]);
if (!active)
nanosleep(&sleep, NULL);
active = false;
if (!run || conn->state == CONN_CLOSING) {
signed long temp;
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_QUIT(quitmsg), sizeof(sendbuf.buffer))) > 0) {
sendbuf.append_pos = (unsigned long)temp;
LOG(LOG_VERBOSE, "Sending a QUIT message to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, quitmsg);
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1)
LOG(LOG_WARN, "Couldn't flush send buffer to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
}
if (fds[1] == -1)
close(fds[1]);
connstate = CONN_CLOSED;
close(sendbuf.fd);
close(fifobuf.fd);
conn->state = CONN_CLOSED;
LOG(LOG_VERBOSE, "Connection to " ADDRFMT " was closed.", conn->data.addr, conn->data.port);
break;
} else if (connstate == CONN_CLOSED)
} else if (conn->state == CONN_CLOSED)
break;
else if (connstate == CONN_PENDING) {
if (ctime - lastconnect < recon_inter)
else if (conn->state == CONN_RECONNECTING) {
close(sendbuf.fd);
close(fifobuf.fd);
conn->state = CONN_PENDING;
continue;
} else if (conn->state == CONN_PENDING) {
if (ctime - conn->lastconnect < reconinter)
continue;
if (fds[0] != -1)
close(fds[0]);
lastconnect = ctime;
int tmp;
if ((tmp = init_conn(conn)) > 0) {
fds[0] = tmp;
memset(recvbuf, '\0', sizeof(recvbuf));
memset(sendbuf, '\0', sizeof(sendbuf));
memset(fifobuf, '\0', sizeof(fifobuf));
lastpong = ctime;
lastping = ctime;
conn->lastconnect = ctime;
filebuf.elements[0].bufpos = filebuf.buf;
int flags;
if ((flags = fcntl(fds[0], F_GETFL)) != -1) {
if (fcntl(fds[0], F_SETFL, flags | O_NONBLOCK) == -1)
LOG(LOG_WARN, "Couldn't set socket to be non-blocking. Messages may be delayed as a result. " ERRNOFMT, strerror(errno), errno);
} else
LOG(LOG_WARN, "Failed to get socket flags. Messages may be delayed as sockets will block. " ERRNOFMT, strerror(errno), errno);
/* Reset all state-dependent values to empty */
memset(&recvbuf, '\0', sizeof(recvbuf));
memset(&sendbuf, '\0', sizeof(sendbuf));
memset(&fifobuf, '\0', sizeof(fifobuf));
conn->lastping = 0;
conn->lastpong = 0;
conn->lastmessage = 0;
/* Create server.port/global for FIFO and open it */
path[1] = category[CAT_GLOB];
path[2] = NULL;
if (mkdir_bottomup(path)) {
path[2] = "in";
path[3] = NULL;
char pbuf[PATH_MAX];
int tmp;
if (assemble_path(path, pbuf, sizeof(pbuf))) {
if ((mkfifo(pbuf, S_IRUSR | S_IWUSR | S_IWGRP)) != 0 && errno != EEXIST) {
LOG(LOG_WARN, "Couldn't create FIFO at \"%s\" for input. " ERRNOFMT, pbuf, strerror(errno), errno);
} else {
LOG(LOG_VERBOSE, "Created a FIFO pipe for input at %s.", pbuf);
ssize_t fd;
if ((fd = open(pbuf, O_RDONLY | O_NONBLOCK)) != -1)
fds[1] = fd;
else
LOG(LOG_WARN, "Couldn't open FIFO pipe \"%s\" for reading. " ERRNOFMT, pbuf, strerror(errno), errno);
}
} else
LOG(LOG_WARN, "Couldn't assemble path for FIFO.");
/* Prepare first part of path */
char tempath[MAXPATH];
if ((get_connstr(tempath, sizeof(tempath), conn)) >= 0) {
cleanup_path_names(tempath);
if (set_path_elem(tempath, 0, true, &filebuf) > 0 && set_path_elem("global", 1, true, &filebuf) > 0) {
if (!mkdir_bottomup(filebuf.buf))
break;
if (set_path_elem("in", 2, false, &filebuf)) {
if ((fifobuf.fd = makeinput(filebuf.buf)) == -1)
break;
}
}
}
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_NICK(conn->names.nick), sizeof(sendbuf))) > 0) {
if ((sendbuf.fd = init_conn(conn)) > 0) {
recvbuf.fd = sendbuf.fd;
add_socket_flags(sendbuf.fd, O_NONBLOCK);
/* Send NICK and USER registration */
// TODO: PASS
signed long temp;
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_NICK(conn->names.nick), sizeof(sendbuf.buffer))) > 0) {
sendbuf.append_pos = (size_t)temp;
LOG(LOG_VERBOSE, "Sending a NICK registration to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, conn->names.nick);
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
LOG(LOG_WARN, "Couldn't register nickname on " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
conn->state = CONN_RECONNECTING;
continue;
}
}
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_USER(conn->names.user, conn->names.real, 0), sizeof(sendbuf))) > 0) {
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_USER(conn->names.user, conn->names.real, 0), sizeof(sendbuf.buffer))) > 0) {
sendbuf.append_pos = (size_t)temp;
LOG(LOG_VERBOSE, "Sending a USER registration to " ADDRFMT " containing \"%s\".", conn->data.addr, conn->data.port, conn->names.real);
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
LOG(LOG_WARN, "Couldn't register user and real name on " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
conn->state = CONN_RECONNECTING;
continue;
}
}
connstate = CONN_REGISTERED;
} else if (tmp == INIT_SOFTFAIL) {
connstate = CONN_PENDING;
conn->state = CONN_REGISTERED;
} else if (sendbuf.fd == INIT_SOFTFAIL) {
conn->state = CONN_RECONNECTING;
continue;
} else if (tmp == INIT_HARDFAIL) {
connstate = CONN_CLOSED;
} else if (sendbuf.fd == INIT_HARDFAIL) {
conn->state = CONN_CLOSED;
continue;
}
} else if (connstate == CONN_ACTIVE) {
if (lastmesg < ctime - timeout && lastpong < lastping - timeout) {
} else if (conn->state == CONN_ACTIVE) {
if (conn->lastmessage < ctime - timeout && conn->lastpong < conn->lastping - timeout) {
LOG(LOG_WARN, "Server " ADDRFMT " didn't respond to a PING in time.", conn->data.addr, conn->data.port);
connstate = CONN_PENDING;
conn->state = CONN_RECONNECTING;
continue;
}
if (ctime - lastmesg >= timeout / 4 && ctime - lastping >= timeout / 4) {
if (ctime - conn->lastmessage >= timeout / 4 && ctime - conn->lastping >= timeout / 4) {
char mesg[] = "uIRC PING -- XXXXXX";
snprintf(mesg + sizeof(mesg) - 7, 7, "%.6i", rand());
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf))) > 0) {
signed long temp;
if ((temp = Assm_mesg(sendbuf.buffer, Assm_cmd_PING(mesg, NULL), sizeof(sendbuf.buffer))) > 0) {
sendbuf.append_pos = (size_t)temp;
LOG(LOG_DEBUG, "Sending ping to " ADDRFMT " with message \"%s\"", conn->data.addr, conn->data.port, mesg);
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
if (flush_buffer(sendbuf.buffer, sendbuf.append_pos, sendbuf.fd) == -1) {
LOG(LOG_WARN, "Couldn't ping " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
conn->state = CONN_RECONNECTING;
continue;
}
lastping = ctime;
conn->lastping = ctime;
}
}
}
/* Buffer reader */
ssize_t brd;
if ((brd = read(fds[0], recvbuf + recvbufpos, sizeof(recvbuf) - recvbufpos - 1)) > 0) {
LOG(LOG_DEBUG, "Read %li bytes.", brd);
*(recvbuf + (recvbufpos += brd)) = '\0';
} else if (brd == 0) {
connstate = CONN_PENDING;
/* Buffer reader */
if ((brd = read(recvbuf.fd, recvbuf.buffer + recvbuf.append_pos, sizeof(recvbuf.buffer) - recvbuf.append_pos - 1)) > 0) {
*(recvbuf.buffer + (recvbuf.append_pos += (size_t)brd)) = '\0';
LOG(LOG_DEBUG, "Read %li bytes from socket buffer. Now appending at %li", brd, recvbuf.append_pos);
active = true;
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
LOG(LOG_ERROR, "Failed to read inbound traffic. " ERRNOFMT, strerror(errno), errno);
connstate = CONN_PENDING;
conn->state = CONN_RECONNECTING;
continue;
}
char* ppoi;
if ((ppoi = strchr(recvbuf, '\n')) != NULL) {
*ppoi = '\0';
if (ppoi > recvbuf && *(ppoi - 1) == '\r')
*(ppoi - 1) = '\0';
LOG(LOG_DEBUG, "Recieved line: %s", recvbuf);
lastmesg = ctime;
memset((void*)&buffer, '\0', sizeof(IRC_Message));
if (Tok_mesg(recvbuf, &buffer) == 1) {
char bufname[MAXPATH + 1], logpath[PATH_MAX], *bprint = "out";
FILE* logfile;
LOG(LOG_DEBUG, "Tokenized message successfully.");
/* Path Assembly and Filtering */
if (buffer.cmd == PRIVMSG || buffer.cmd == NOTICE) {
if (strchr("&!#+", *buffer.args[0])) {
path[1] = category[CAT_CHAN];
bprint = buffer.args[0];
} else if (buffer.name.nick != NULL) {
path[1] = category[CAT_USER];
bprint = buffer.name.nick;
}
} else if (buffer.cmd == RPL_BANLIST || buffer.cmd == RPL_ENDOFBANLIST) {
path[1] = category[CAT_CHAN];
bprint = buffer.args[0];
} else if (buffer.cmd == KILL || buffer.cmd == RPL_AWAY) {
path[1] = category[CAT_USER];
bprint = buffer.name.nick;
} else if (buffer.cmd == JOIN || buffer.cmd == PART) {
path[1] = category[CAT_CHAN];
bprint = buffer.args[0];
} else {
path[1] = category[CAT_GLOB];
}
path[2] = NULL;
if (mkdir_bottomup(path)) {
snprintf(bufname, sizeof(bufname), "%s", bprint);
cleanup_path_names(bufname);
path[2] = bufname;
path[3] = NULL;
if (assemble_path(path, logpath, sizeof(logpath))) {
char linebuf[513];
if (Assm_mesg(sendbuf, &buffer, sizeof(sendbuf)) > 0) {
LOG(LOG_DEBUG, "Assembled line: \"%s\" to write to %s.", sendbuf, bufname);
if ((logfile = fopen(logpath, "a")) != NULL) {
fprintf(logfile, "%s", sendbuf);
fclose(logfile);
} else
LOG(LOG_WARN, "Couldn't open file \"%s\" for appending.", logpath);
}
}
} else
LOG(LOG_WARN, "Log directory couldn't be created. " ERRNOFMT, strerror(errno), errno);
/* Automatic message handling */
switch (buffer.cmd) {
case (PING): {
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", buffer.args[0]);
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_PONG(buffer.args[0], NULL), sizeof(sendbuf))) > 0)
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
LOG(LOG_WARN, "Couldn't pong " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
continue;
}
break;
}
case (PONG): {
if (buffer.trailing && buffer.args[1] != NULL) {
LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", buffer.args[1]);
lastpong = ctime;
}
break;
}
/* Autojoin channels from current connection on first response from the server
* TODO? Split channels and join X channels each
* This most likely is not required unless the user has loooots of channels.
* If you are that type of user, you are free to add that.
*/
case (RPL_WELCOME): {
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.addr, conn->data.port);
connstate = CONN_ACTIVE;
if (conn->data.chans != NULL) {
LOG(LOG_VERBOSE, "Auto-joining channels \"%s\" on " ADDRFMT ".", conn->data.chans, conn->data.addr, conn->data.port);
if ((sendbufpos = Assm_mesg(sendbuf, Assm_cmd_JOIN(conn->data.chans, NULL), sizeof(sendbuf))) > 0) {
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
LOG(LOG_WARN, "Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT, conn->data.chans, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
continue;
}
}
}
break;
}
case (ERROR): {
LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", conn->data.addr, conn->data.port, buffer.args[0]);
break;
}
}
} else
LOG(LOG_WARN, "Received invalid IRC message (see RFC2812).");
for (char* x = (ppoi + 1); *x; x++)
*(recvbuf + (x - (ppoi + 1))) = *x;
recvbufpos -= (ppoi + 1) - recvbuf;
*(recvbuf + recvbufpos) = '\0';
}
ssize_t len;
memset((void*)&buffer, '\0', sizeof(IRC_Message));
if ((len = get_buffer_line(recvbuf.buffer, &buffer)) > 0) {
conn->lastmessage = ctime;
if (set_path_elem("global", 1, true, &filebuf) > 0 && set_path_elem("out", 2, false, &filebuf) > 0) {
LOG(LOG_DEBUG, "Writing message to global path %s.", filebuf.buf);
signed long temp;
if ((temp = Assm_mesg(sendbuf.buffer, &buffer, sizeof(sendbuf.buffer))) > 0)
write_log(filebuf.buf, sendbuf.buffer);
}
if (prepare_log_path(&buffer, &filebuf) == 1) {
LOG(LOG_DEBUG, "Writing message to path %s.", filebuf.buf);
signed long temp;
if ((temp = Assm_mesg(sendbuf.buffer, &buffer, sizeof(sendbuf.buffer))) > 0)
write_log(filebuf.buf, sendbuf.buffer);
}
if (!auto_msg_actions(&buffer, conn, &sendbuf))
continue;
for (long unsigned int x = 0; x < sizeof(recvbuf.buffer) && *(recvbuf.buffer + len + x); x++)
*(recvbuf.buffer + x) = *(recvbuf.buffer + x + len);
recvbuf.append_pos -= (unsigned long)len;
*(recvbuf.buffer + recvbuf.append_pos) = '\0';
active = true;
} else if (len == -1)
conn->state = CONN_RECONNECTING;
/* Buffer writer */
if ((brd = read(fds[1], fifobuf + fifobufpos, sizeof(fifobuf) - fifobufpos - 1)) > 0) {
LOG(LOG_DEBUG, "Read %li bytes from FIFO.", brd);
*(fifobuf + (fifobufpos += brd)) = '\0';
} else if (brd == -1 && errno != EAGAIN && errno != EINTR) {
LOG(LOG_ERROR, "Failed to read FIFO input for connection " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
if ((brd = read(fifobuf.fd, fifobuf.buffer + fifobuf.append_pos, sizeof(fifobuf.buffer) - fifobuf.append_pos - 1)) > 0) {
*(fifobuf.buffer + (fifobuf.append_pos += (size_t)brd)) = '\0';
LOG(LOG_DEBUG, "Read %li bytes from FIFO. Now appending at %li", brd, fifobuf.append_pos);
active = true;
} else if (brd == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
LOG(LOG_ERROR, "Failed to read FIFO input. " ERRNOFMT, strerror(errno), errno);
conn->state = CONN_RECONNECTING;
continue;
}
if ((ppoi = strchr(fifobuf, '\n')) != NULL) {
*ppoi = '\0';
if (ppoi > fifobuf && *(ppoi - 1) == '\r')
*(ppoi - 1) = '\0';
LOG(LOG_DEBUG, "Recieved FIFO line: %s", fifobuf);
memset((void*)&buffer, '\0', sizeof(IRC_Message));
if (Tok_mesg(fifobuf, &buffer) == 1) {
LOG(LOG_DEBUG, "Tokenized FIFO message successfully.");
if ((sendbufpos = Assm_mesg(sendbuf, &buffer, sizeof(sendbuf))) > 0) {
if (flush_buffer(sendbuf, sendbufpos, fds[0]) == -1) {
LOG(LOG_WARN, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
connstate = CONN_PENDING;
continue;
}
memset((void*)&buffer, '\0', sizeof(IRC_Message));
if ((len = get_buffer_line(fifobuf.buffer, &buffer)) > 0) {
LOG(LOG_DEBUG, "Tokenized FIFO message successfully.");
signed long temp;
if ((temp = Assm_mesg(fifobuf.buffer, &buffer, sizeof(fifobuf.buffer))) > 0) {
if (flush_buffer(fifobuf.buffer, (size_t)temp, sendbuf.fd) == -1) {
LOG(LOG_WARN, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
conn->state = CONN_RECONNECTING;
continue;
}
} else
LOG(LOG_WARN, "Received invalid IRC message on FIFO (see RFC2812).");
for (char* x = (ppoi + 1); *x; x++)
*(fifobuf + (x - (ppoi + 1))) = *x;
fifobufpos -= ppoi + 1 - fifobuf;
*(fifobuf + fifobufpos) = '\0';
}
}
for (long unsigned int x = 0; x < sizeof(fifobuf.buffer) && *(fifobuf.buffer + len + x); x++)
*(fifobuf.buffer + x) = *(fifobuf.buffer + x + len);
fifobuf.append_pos -= (unsigned long)len;
*(fifobuf.buffer + fifobuf.append_pos) = '\0';
active = true;
} else if (len == -1)
conn->state = CONN_RECONNECTING;
}
LOG(LOG_VERBOSE, "Exiting thread with connection " ADDRFMT " gracefully.", conn->data.addr, conn->data.port);
return EXIT_SUCCESS;
@ -394,20 +305,22 @@ void print_help(void)
char arg;
char* desc;
char* def;
} arg_list[] = {{'c', "Define connection in format \"nick!user:real name@host/+port,#channel1,#channel2\""},
} arg_list[] = {{'c', "Define connection in format \"nick!user:real name@host/+port,#channel1,#channel2\"", NULL},
{'l', "Directory for logs", "current dir"},
{'m', "Quit message", "uIRC indev beta"},
{'d', "Reconnection delay", "10 seconds"},
{'t', "Timeout duration", "30 seconds"},
{'V', "Log level (0-5)", "0 [LOG_FATAL]"},
/* {'C', "Configuration path", "~/.config/uircd/main.conf"}, */
{'v', "Print version information", NULL},
{'h', "Print this help message", NULL}};
printf("usage: uirc -c [connection] [options...]\n");
for (int i = 0; i < sizeof(arg_list) / sizeof(*arg_list); i++) {
for (size_t i = 0; i < sizeof(arg_list) / sizeof(*arg_list); i++) {
printf("\t-%c\t%s", arg_list[i].arg, arg_list[i].desc);
if (arg_list[i].def != NULL)
printf(" (default: %s)", arg_list[i].def);
putchar('\n');
}
}
void stop_loop() { run = 0; }

View File

@ -29,6 +29,12 @@
#include <sys/wait.h>
#include <unistd.h>
#ifndef UIRCD_INCLUDED_MAIN
#define UIRCD_INCLUDED_MAIN
#define VERSION "indev - testing"
int run_main(Connection* conn, unsigned int recon_inter, char* quitmsg, int timeout);
void stop_loop(void);
int run_main(Connection* conn, char* quitmsg, unsigned int timeout);
void print_help(void);
#endif

View File

@ -18,15 +18,6 @@
#include "misc.h"
char* category[] = {
[CAT_CHAN] = "channel",
[CAT_USER] = "user",
[CAT_GLOB] = "global"};
void stop_loop()
{
run = 0;
}
char* point_after(char* string, char point)
/*
* Used to tokenize right to left based on characters
@ -39,10 +30,79 @@ char* point_after(char* string, char point)
return ret;
}
int get_connstr(char* buf, size_t maxlen, Connection* conn)
ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn)
{
int len = 0;
if ((len = snprintf(buf, maxlen, "%s.%s", conn->data.addr, conn->data.port)) <= 0)
return 0;
return -1;
return len;
}
ssize_t get_buffer_line(char* buf, IRC_Message* parsed)
{
if (buf == NULL || parsed == NULL)
return -1;
char* ppoi;
if ((ppoi = strchr(buf, '\n')) != NULL) {
*ppoi = '\0';
if (ppoi > buf && *(ppoi - 1) == '\r')
*(ppoi - 1) = '\0';
LOG(LOG_DEBUG, "Got message %s", buf);
if (Tok_mesg(buf, parsed) == 1)
return ++ppoi - buf;
LOG(LOG_WARN, "Received invalid IRC message (see RFC2812).");
return -1;
}
return 0;
}
int auto_msg_actions(IRC_Message* message, Connection* conn, Buffer_Info* buf)
{
signed long len;
time_t ctime = time(NULL);
switch (message->cmd) {
case (PING): {
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", message->args[0]);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(message->args[0], NULL), sizeof(buf->buffer))) > 0)
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't pong " ADDRFMT ". " ERRNOFMT, conn->data.addr, conn->data.port, strerror(errno), errno);
conn->state = CONN_RECONNECTING;
return 0;
}
break;
}
case (PONG): {
if (message->trailing && message->args[1] != NULL) {
LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]);
conn->lastpong = ctime;
}
break;
}
/* Autojoin channels from current connection on first response from the server
* TODO: Split channels and join X channels each
* This most likely is not required unless the user has loooots of channels.
* If you are that type of user, you are free to add that case
*/
case (RPL_WELCOME): {
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.addr, conn->data.port);
conn->state = CONN_ACTIVE;
if (conn->data.chans != NULL) {
LOG(LOG_VERBOSE, "Auto-joining channels \"%s\" on " ADDRFMT ".", conn->data.chans, conn->data.addr, conn->data.port);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_JOIN(conn->data.chans, NULL), sizeof(buf->buffer))) > 0) {
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't auto-join channels \"%s\" " ADDRFMT ". " ERRNOFMT, conn->data.chans, conn->data.addr, conn->data.port, strerror(errno), errno);
conn->state = CONN_RECONNECTING;
return 0;
}
}
}
break;
}
case (ERROR): {
LOG(LOG_ERROR, "Received error on connection " ADDRFMT " with the message \"%s\".", conn->data.addr, conn->data.port, message->args[0]);
break;
}
}
return 1;
}

View File

@ -1,44 +1,22 @@
/*
* 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 "uirc/functions.h"
#include "uirc/mappings.h"
#include "global.h"
#include "log.h"
#include "net.h"
#include "structs.h"
#define UIRC_IRCV3
#include "uirc/functions.h"
#include "uirc/helpers.h"
#include "uirc/mappings.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define UIRC_HELPERS
#include "uirc/helpers.h"
#ifndef _UIRCD_INCLUDED_MISC
#define _UIRCD_INCLUDED_MISC
extern char* category[];
enum categories {
CAT_CHAN = 1,
CAT_USER,
CAT_GLOB
};
#ifndef UIRCD_INCLUDED_MISC
#define UIRCD_INCLUDED_MISC
char* point_after(char* string, char point);
void stop_loop();
int get_connstr(char* buf, size_t maxlen, Connection* conn);
int get_category(IRC_Message* mesg);
ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn);
ssize_t get_buffer_line(char* buf, IRC_Message* parsed);
int auto_msg_actions(IRC_Message* message, Connection* conn, Buffer_Info* buf);
#endif

View File

@ -19,7 +19,6 @@
signed int init_conn(Connection* info)
{
const struct timespec retry_timeout = {3, 0.0L};
int sockfd, getaddrres, connectres;
if (info->data.addr == NULL) return INIT_HARDFAIL;
struct addrinfo* conn;
@ -28,7 +27,7 @@ signed int init_conn(Connection* info)
freeaddrinfo(conn);
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) {
return INIT_HARDFAIL;
} else
} else
return INIT_SOFTFAIL;
}
if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) {
@ -42,26 +41,25 @@ signed int init_conn(Connection* info)
freeaddrinfo(conn);
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) {
return INIT_HARDFAIL;
} else
} else
return INIT_SOFTFAIL;
}
freeaddrinfo(conn);
return sockfd;
}
int flush_buffer(char* buf, int buflen, int fd)
ssize_t flush_buffer(char* buf, size_t buflen, int fd)
{
int res;
ssize_t res;
char* pos = buf;
for (;;) {
if ((res = write(fd, pos, buflen - (pos - buf))) != buflen - (pos - buf)) {
if (res == -1) {
if ((size_t)(res = write(fd, pos, buflen - (size_t)(pos - buf))) != buflen - (size_t)(pos - buf)) {
if (res == -1)
return -1;
} else {
else
pos += res;
}
} else
return res;
}
return pos - buf;
}

View File

@ -17,6 +17,7 @@
*/
#define UIRC_HELPERS
#define UIRC_IRCV3
#include "uirc/functions.h"
#include "uirc/helpers.h"
#include "uirc/mappings.h"
@ -36,18 +37,20 @@
#include <time.h>
#include <unistd.h>
#ifndef _UIRCD_INCLUDED_NETWORK
#define _UIRCD_INCLUDED_NETWORK
#ifndef UIRCD_INCLUDED_NETWORK
#define UIRCD_INCLUDED_NETWORK
#define CONN_ACTIVE 2
#define CONN_REGISTERED 1
#define CONN_PENDING 0
#define CONN_CLOSING -1
#define CONN_CLOSED -2
#define CONN_RECONNECTING -1
#define CONN_CLOSING -2
#define CONN_CLOSED -3
#define INIT_HARDFAIL -1
#define INIT_SOFTFAIL -2
signed int init_conn(Connection* info);
int flush_buffer(char* buf, int buflen, int fd);
ssize_t flush_buffer(char* buf, size_t buflen, int fd);
#endif

View File

@ -16,26 +16,41 @@
* along with uIRCd. If not, see <https://www.gnu.org/licenses/>.
*/
#include "global.h"
#define UIRC_IRCV3
#include "uirc/types.h"
#include <time.h>
#include <unistd.h>
#ifndef _UIRCD_INCLUDED_STRUCTS
#define _UIRCD_INCLUDED_STRUCTS
#ifndef UIRCD_INCLUDED_STRUCTS
#define UIRCD_INCLUDED_STRUCTS
typedef struct {
char* addr;
char* port;
char* chans;
char *addr, *port, *chans;
bool ssl;
} Connection_Data;
typedef struct {
char buffer[513];
char* append_pos;
char* nex_line;
int* fd;
size_t append_pos;
int fd;
} Buffer_Info;
typedef struct {
IRC_User names;
Connection_Data data;
time_t lastping, lastpong, lastconnect, lastmessage;
signed short state;
pid_t pid;
} Connection;
typedef struct {
char* bufpos;
size_t len;
} PathBufElem;
typedef struct {
char buf[MAXPATH];
PathBufElem elements[5];
} PathBuf;
#endif