WIP: logging part 1

This commit is contained in:
Alex D. 2020-12-20 23:53:56 +00:00
parent d2e9932e01
commit 8b035c5871
Signed by: caskd
GPG Key ID: F92BA85F61F4C173
7 changed files with 196 additions and 109 deletions

View File

@ -19,17 +19,14 @@
#include "buffer.h" #include "buffer.h"
ssize_t ssize_t
get_buffer_line(char* buf, IRC_Message* parsed) get_buffer_line(char* buf)
{ {
if (buf == NULL || parsed == NULL) return -1; if (buf == NULL) return -1;
char* ppoi; char* ppoi;
if ((ppoi = strchr(buf, '\n')) != NULL) { if ((ppoi = strchr(buf, '\n')) != NULL) {
*ppoi = '\0'; *ppoi = '\0';
if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0'; if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0';
LOG(LOG_DEBUG, "Got IRC message: %s", buf); return ++ppoi - buf;
if (Tok_mesg(buf, parsed) == 1) return ++ppoi - buf;
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
return -1;
} }
return 0; return 0;
} }

View File

@ -27,6 +27,6 @@
#define UIRC_HELPERS #define UIRC_HELPERS
#include <uirc/uirc.h> // Tok_mesg() #include <uirc/uirc.h> // Tok_mesg()
ssize_t get_buffer_line(char* buf, IRC_Message* parsed); ssize_t get_buffer_line(char* buf);
ssize_t flush_buffer(char* buf, size_t buflen, int fd); ssize_t flush_buffer(char* buf, size_t buflen, int fd);

View File

@ -19,114 +19,148 @@
#include "connection.h" #include "connection.h"
signed int signed int
init_connection(Connection* info) init_connection(Connection* conn)
{ {
int sockfd, getaddrres, connectres; int sockfd, getaddrres, connectres;
struct addrinfo* conn; struct addrinfo* addr_info;
if ((getaddrres = getaddrinfo(info->data.address, info->data.service, NULL, &conn)) != 0) { if ((getaddrres = getaddrinfo(conn->data.address, conn->data.service, NULL, &addr_info)) != 0) {
freeaddrinfo(conn); freeaddrinfo(addr_info);
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) { if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) {
LOG(LOG_ERROR, LOG(LOG_ERROR,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT, "Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address, conn->data.address,
info->data.service, conn->data.service,
gai_strerror(getaddrres), gai_strerror(getaddrres),
getaddrres); getaddrres);
return INIT_HARDFAIL; return INIT_HARDFAIL;
} else { } else {
LOG(LOG_WARN, LOG(LOG_WARN,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT, "Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address, conn->data.address,
info->data.service, conn->data.service,
gai_strerror(getaddrres), gai_strerror(getaddrres),
getaddrres); getaddrres);
return INIT_SOFTFAIL; return INIT_SOFTFAIL;
} }
} }
if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) { if ((sockfd = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol)) < 0) {
LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno); LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, conn->data.address, conn->data.service, strerror(errno), errno);
freeaddrinfo(conn); freeaddrinfo(addr_info);
return INIT_HARDFAIL; return INIT_HARDFAIL;
} }
if ((connectres = connect(sockfd, conn->ai_addr, conn->ai_addrlen)) == -1) { if ((connectres = connect(sockfd, addr_info->ai_addr, addr_info->ai_addrlen)) == -1) {
close(sockfd); close(sockfd);
freeaddrinfo(conn); freeaddrinfo(addr_info);
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) { if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) {
LOG(LOG_ERROR, LOG(LOG_ERROR,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT, "Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address, conn->data.address,
info->data.service, conn->data.service,
strerror(errno), strerror(errno),
errno); errno);
return INIT_HARDFAIL; return INIT_HARDFAIL;
} else { } else {
LOG(LOG_WARN, LOG(LOG_WARN,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT, "Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address, conn->data.address,
info->data.service, conn->data.service,
strerror(errno), strerror(errno),
errno); errno);
return INIT_SOFTFAIL; return INIT_SOFTFAIL;
} }
} }
freeaddrinfo(conn); freeaddrinfo(addr_info);
return sockfd; return sockfd;
} }
signed int
get_msgchannel(IRC_Message* mesg)
{
// TODO: These message arguments might be parsed differently depending on what command they offer.
// Maybe offering a static context would allow reentrant calls
switch (mesg->cmd) {
case JOIN:
case PART:
case MODE:
case TOPIC:
case LIST:
case NAMES:
case INVITE:
case KICK:
case PRIVMSG:
case NOTICE: return 0;
}
return -1;
}
const char*
get_categ(IRC_Message* mesg)
{
switch (mesg->cmd) {
case JOIN:
case PART:
case KICK: return "events";
case TOPIC: return "topic";
case PRIVMSG:
case NOTICE: return "msgs";
default: return NULL;
}
}
int int
auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf) auto_msg_actions(IRC_Message* mesg, Connection* conn, Buffer_Info* buf)
{ {
signed long len; signed long len;
time_t ctime = time(NULL); time_t ctime = time(NULL);
switch (message->cmd) { switch (mesg->cmd) {
case (PING): { case (PING): {
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", message->args[0]); LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", mesg->args[0]);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(message->args[0], NULL), sizeof(buf->buffer))) > 0) if ((len = Assm_mesg(buf->buffer, Assm_cmd_PONG(mesg->args[0], NULL), sizeof(buf->buffer))) > 0)
if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) { if (flush_buffer(buf->buffer, (size_t) len, buf->fd) == -1) {
LOG(LOG_WARN, LOG(LOG_WARN,
"Couldn't pong " ADDRFMT ". " ERRNOFMT, "Couldn't pong " ADDRFMT ". " ERRNOFMT,
connection->data.address, conn->data.address,
connection->data.service, conn->data.service,
strerror(errno), strerror(errno),
errno); errno);
connection->info.state = CONN_RECONNECTING; conn->info.state = CONN_RECONNECTING;
return 0; return 0;
} }
break; break;
} }
case (PONG): { case (PONG): {
if (message->trailing && message->args[1] != NULL) { if (mesg->trailing && mesg->args[1] != NULL) {
LOG(LOG_DEBUG, "Got PONG back with message \"%s\".", message->args[1]); LOG(LOG_DEBUG, "Got PONG back with mesg \"%s\".", mesg->args[1]);
connection->info.l_pong = ctime; conn->info.l_pong = ctime;
} }
break; break;
} }
/* Autojoin channels from current connection on first response from the server */ /* Autojoin channels from current conn on first response from the server */
case (RPL_WELCOME): { case (RPL_WELCOME): {
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", connection->data.address, connection->data.service); LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.address, conn->data.service);
connection->info.state = CONN_ACTIVE; conn->info.state = CONN_ACTIVE;
if (!commit_channelist(buf, connection)) return 0; if (!commit_channelist(buf, conn)) return 0;
break; break;
} }
/* /*
case (CAP): { case (CAP): {
if (message->args[1] != NULL && strcmp(message->args[1], "LS") == 0) { if (mesg->args[1] != NULL && strcmp(mesg->args[1], "LS") == 0) {
LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], connection->data.address, LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", mesg->args[2], conn->data.address,
connection->data.port); conn->data.port);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(message->args[2]), sizeof(buf->buffer))) > 0) { if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(mesg->args[2]), sizeof(buf->buffer))) > 0) {
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, message->args[2], LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, mesg->args[2],
connection->data.address, connection->data.port, strerror(errno), errno); conn->data.address, conn->data.port, strerror(errno), errno);
connection->state = CONN_RECONNECTING; conn->state = CONN_RECONNECTING;
return 0; return 0;
} }
} }
} else if (message->args[1] != NULL && strcmp(message->args[1], "ACK") == 0) { } else if (mesg->args[1] != NULL && strcmp(mesg->args[1], "ACK") == 0) {
LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", connection->data.address, connection->data.port); LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", conn->data.address, conn->data.port);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_END(), sizeof(buf->buffer))) > 0) { if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_END(), sizeof(buf->buffer))) > 0) {
if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) { if (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
LOG(LOG_WARN, "Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT, LOG(LOG_WARN, "Couldn't end capability negotiation on " ADDRFMT ". " ERRNOFMT,
connection->data.address, connection->data.port, strerror(errno), errno); connection->state = CONN_RECONNECTING; return 0; conn->data.address, conn->data.port, strerror(errno), errno); conn->state = CONN_RECONNECTING; return 0;
} }
} }
} }
@ -134,36 +168,27 @@ auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf)
} }
*/ */
case (ERROR): { case (ERROR): {
LOG(LOG_ERROR, "Received error %s.", message->args[0]); LOG(LOG_ERROR, "Received error %s.", mesg->args[0]);
break; break;
} }
case (JOIN): case (JOIN):
case (PART): { case (PART): {
set_channel(&connection->info.channels[get_channelindex(message->args[0], connection->info.channels)], set_channel(&conn->info.channels[get_channelindex(mesg->args[0], conn->info.channels)],
message->args[0], mesg->args[0],
message->args[1], mesg->args[1],
message->cmd == JOIN); mesg->cmd == JOIN);
break; break;
} }
case (ERR_NICKNAMEINUSE): case (ERR_NICKNAMEINUSE):
case (ERR_NICKCOLLISION): { case (ERR_NICKCOLLISION): {
LOG(LOG_ERROR, "Nickname %s is already taken.", connection->user.nickname); LOG(LOG_ERROR, "Nickname %s is already taken.", conn->user.nickname);
connection->info.state = CONN_RECONNECTING; conn->info.state = CONN_RECONNECTING;
break; break;
} }
} }
return 1; return 1;
} }
ssize_t
get_connstr(char* buf, size_t maxlen, Connection* conn)
{
int len = 0;
LOG(LOG_DEBUG, "Preparing path: " ADDRFMT, conn->data.address, conn->data.service);
if ((len = snprintf(buf, maxlen, "%s.%s", conn->data.address, conn->data.service)) <= 0) return -1;
return len;
}
int int
commit_channelist(Buffer_Info* buf, Connection* conn) commit_channelist(Buffer_Info* buf, Connection* conn)
{ {

View File

@ -49,6 +49,8 @@
#define CONN_CLOSING -2 #define CONN_CLOSING -2
#define CONN_CLOSED -3 #define CONN_CLOSED -3
#define CHANNELMASK(STR) (strchr("#&+!", *STR) != NULL)
typedef struct { typedef struct {
char * address, *service, *quitmsg, *path; char * address, *service, *quitmsg, *path;
time_t timeout; time_t timeout;
@ -78,10 +80,11 @@ typedef struct {
Connection_Info info; Connection_Info info;
} Connection; } Connection;
signed int init_connection(Connection* info); signed int init_connection(Connection* conn);
int auto_msg_actions(IRC_Message* message, Connection* connection, Buffer_Info* buf); signed int get_msgchannel(IRC_Message* mesg);
ssize_t get_connstr(char* buf, size_t maxlen, Connection* conn); int auto_msg_actions(IRC_Message* mesg, Connection* conn, Buffer_Info* buf);
int commit_channelist(Buffer_Info* buf, Connection* conn); int commit_channelist(Buffer_Info* buf, Connection* conn);
const char* get_categ(IRC_Message* mesg);
#endif /* UIRCD_GUARD_CONNECTION */ #endif /* UIRCD_GUARD_CONNECTION */

View File

@ -42,7 +42,7 @@ mkdir_bottomup(char* path)
} }
int int
makeinput(char* path) makeinput(const char* path)
{ {
if (path == NULL) return -1; if (path == NULL) return -1;
if (mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP) == 0) { if (mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP) == 0) {
@ -60,11 +60,11 @@ makeinput(char* path)
} }
bool bool
write_log(char* path, char* message) write_log(const char* path, const char* message)
{ {
FILE* logfile; FILE* logfile;
if ((logfile = fopen(path, "a")) != NULL) { if ((logfile = fopen(path, "a")) != NULL) {
fprintf(logfile, "%s", message); fprintf(logfile, "%s\r\n", message);
fclose(logfile); fclose(logfile);
return 1; return 1;
} else } else
@ -101,3 +101,48 @@ add_socket_flags(int fd, int flags)
return 1; return 1;
} }
ssize_t
get_log_path(char* buf, size_t lim, Connection* conn, IRC_Message* msg, bool global, bool input)
{
if (buf == NULL || conn == NULL || msg == NULL) return -1;
ssize_t res;
const char* save = buf;
if (conn->data.address == NULL || conn->data.service == NULL
|| (res = snprintf(buf, lim, "%s.%s", conn->data.address, conn->data.service)) == -1)
return -1;
clean_and_push(&lim, (size_t) res, &buf);
int ci = -1;
if (global) {
if ((res = snprintf(buf, lim, "global")) == -1) return -1;
} else if ((ci = get_msgchannel(msg)) != -1 && msg->args[ci] != NULL) {
if ((res = snprintf(buf, lim, "channel")) == -1) return -1;
clean_and_push(&lim, (size_t) res, &buf);
if ((res = snprintf(buf, lim, "%s", msg->args[ci])) == -1) return -1;
} else if (msg->name.nick != NULL) {
if ((res = snprintf(buf, lim, "user")) == -1) return -1;
clean_and_push(&lim, (size_t) res, &buf);
if ((res = snprintf(buf, lim, "%s", msg->name.nick)) == -1) return -1;
} else {
return -1;
}
clean_and_push(&lim, (size_t) res, &buf);
const char* category = NULL;
if (input) {
if ((res = snprintf(buf, lim, "in")) == -1) return -1;
} else if ((category = get_categ(msg)) != NULL) {
if ((res = snprintf(buf, lim, "%s", category)) == -1) return -1;
} else {
if ((res = snprintf(buf, lim, "out")) == -1) return -1;
}
return (buf - save);
}
void
clean_and_push(size_t* lim, size_t res, char** buf)
{
cleanup_path_names(*buf);
*(*(buf) + res) = '/';
*lim -= (size_t) res + 1;
*buf += (size_t) res + 1;
}

View File

@ -33,11 +33,13 @@
#ifndef UIRCD_GUARD_FILESYSTEM #ifndef UIRCD_GUARD_FILESYSTEM
#define UIRCD_GUARD_FILESYSTEM #define UIRCD_GUARD_FILESYSTEM
int mkdir_bottomup(char* path); int mkdir_bottomup(char* path);
int makeinput(char* path); int makeinput(const char* path);
bool write_log(char* path, char* message); bool write_log(const char* path, const char* message);
bool cleanup_path_names(char* name); bool cleanup_path_names(char* name);
bool add_socket_flags(int fd, int flags); bool add_socket_flags(int fd, int flags);
ssize_t get_log_path(char* buf, size_t lim, Connection* conn, IRC_Message* msg, bool global, bool input);
void clean_and_push(size_t* lim, size_t res, char** buf);
#endif /* UIRCD_GUARD_FILESYSTEM */ #endif /* UIRCD_GUARD_FILESYSTEM */

View File

@ -299,26 +299,30 @@ main(int argc, char* argv[])
} }
memset((void*) &buffer, '\0', sizeof(IRC_Message)); memset((void*) &buffer, '\0', sizeof(IRC_Message));
if ((len = get_buffer_line(buf.fifo.buffer, &buffer)) > 0) { if ((len = get_buffer_line(buf.fifo.buffer)) > 0) {
LOG(LOG_DEBUG, "%s", "Tokenized FIFO message successfully."); LOG(LOG_DEBUG, "Got FIFO message: %s", buf.fifo.buffer);
signed long temp; if (Tok_mesg(buf.fifo.buffer, &buffer) == 1) {
if ((temp = Assm_mesg(buf.fifo.buffer, &buffer, sizeof(buf.fifo.buffer))) > 0) { LOG(LOG_DEBUG, "%s", "Tokenized FIFO message successfully.");
if (flush_buffer(buf.fifo.buffer, (size_t) temp, buf.send.fd) == -1) { signed long temp;
LOG(LOG_WARN, if ((temp = Assm_mesg(buf.fifo.buffer, &buffer, sizeof(buf.fifo.buffer))) > 0) {
"Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT, if (flush_buffer(buf.fifo.buffer, (size_t) temp, buf.send.fd) == -1) {
connection.data.address, LOG(LOG_WARN,
connection.data.service, "Couldn't send FIFO input to " ADDRFMT ". " ERRNOFMT,
strerror(errno), connection.data.address,
errno); connection.data.service,
connection.info.state = CONN_RECONNECTING; strerror(errno),
continue; errno);
connection.info.state = CONN_RECONNECTING;
continue;
}
} }
} for (long unsigned int x = 0; x < sizeof(buf.fifo.buffer) && *(buf.fifo.buffer + len + x); x++)
for (long unsigned int x = 0; x < sizeof(buf.fifo.buffer) && *(buf.fifo.buffer + len + x); x++) *(buf.fifo.buffer + x) = *(buf.fifo.buffer + x + len);
*(buf.fifo.buffer + x) = *(buf.fifo.buffer + x + len); buf.fifo.append_pos -= (unsigned long) len;
buf.fifo.append_pos -= (unsigned long) len; *(buf.fifo.buffer + buf.fifo.append_pos) = '\0';
*(buf.fifo.buffer + buf.fifo.append_pos) = '\0'; connection.info.active = true;
connection.info.active = true; } else
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
} else if (len == -1) } else if (len == -1)
connection.info.state = CONN_RECONNECTING; connection.info.state = CONN_RECONNECTING;
} }
@ -337,19 +341,30 @@ main(int argc, char* argv[])
} }
memset((void*) &buffer, '\0', sizeof(IRC_Message)); memset((void*) &buffer, '\0', sizeof(IRC_Message));
if ((len = get_buffer_line(buf.recv.buffer, &buffer)) > 0) { if ((len = get_buffer_line(buf.recv.buffer)) > 0) {
connection.info.l_message = ctime; LOG(LOG_DEBUG, "Got IRC message: %s", buf.recv.buffer);
char datebuf[25]; char save[sizeof(buf.recv.buffer)];
if (buffer.tags.time.value == NULL) { strcpy(save, buf.recv.buffer);
Assm_tag_timestamp(datebuf, sizeof(datebuf), ctime); printf("%s\r\n", save);
buffer.tags.time.value = datebuf; if (Tok_mesg(buf.recv.buffer, &buffer) == 1) {
} char logpath[UIRCD_LIMITS_PATH];
if (!auto_msg_actions(&buffer, &connection, &buf.send)) continue; if (get_log_path(logpath, sizeof(logpath), &connection, &buffer, true, false) >= 0) {
for (long unsigned int x = 0; x < sizeof(buf.recv.buffer) && *(buf.recv.buffer + len + x); x++) if (mkdir_bottomup(logpath)) write_log(logpath, save);
*(buf.recv.buffer + x) = *(buf.recv.buffer + x + len); }
buf.recv.append_pos -= (unsigned long) len; connection.info.l_message = ctime;
*(buf.recv.buffer + buf.recv.append_pos) = '\0'; char datebuf[25];
connection.info.active = true; if (buffer.tags.time.value == NULL) {
Assm_tag_timestamp(datebuf, sizeof(datebuf), ctime);
buffer.tags.time.value = datebuf;
}
if (!auto_msg_actions(&buffer, &connection, &buf.send)) continue;
for (long unsigned int x = 0; x < sizeof(buf.recv.buffer) && *(buf.recv.buffer + len + x); x++)
*(buf.recv.buffer + x) = *(buf.recv.buffer + x + len);
buf.recv.append_pos -= (unsigned long) len;
*(buf.recv.buffer + buf.recv.append_pos) = '\0';
connection.info.active = true;
} else
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
} else if (len == -1) } else if (len == -1)
connection.info.state = CONN_RECONNECTING; connection.info.state = CONN_RECONNECTING;
} }