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:
parent
f0bfff775d
commit
a4d1e501eb
@ -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
180
.clang-tidy
Normal 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
7
.gitignore
vendored
@ -1,6 +1,3 @@
|
||||
build/
|
||||
CMakeFiles/
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
Makefile
|
||||
.swp
|
||||
.clangd/
|
||||
compile_commands.json
|
||||
|
@ -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
19
src/.clang-format
Normal 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
|
||||
...
|
||||
|
175
src/filesystem.c
175
src/filesystem.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
40
src/log.h
40
src/log.h
@ -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
|
||||
|
||||
|
383
src/main.c
383
src/main.c
@ -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; }
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
82
src/misc.c
82
src/misc.c
@ -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;
|
||||
}
|
||||
|
||||
|
46
src/misc.h
46
src/misc.h
@ -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
|
||||
|
||||
|
18
src/net.c
18
src/net.c
@ -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;
|
||||
}
|
||||
|
||||
|
13
src/net.h
13
src/net.h
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user