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"
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;
if ((ppoi = strchr(buf, '\n')) != NULL) {
*ppoi = '\0';
if (ppoi > buf && *(ppoi - 1) == '\r') *(ppoi - 1) = '\0';
LOG(LOG_DEBUG, "Got IRC message: %s", buf);
if (Tok_mesg(buf, parsed) == 1) return ++ppoi - buf;
LOG(LOG_WARN, "%s", "Received invalid IRC message (see RFC2812).");
return -1;
return ++ppoi - buf;
}
return 0;
}

View File

@ -27,6 +27,6 @@
#define UIRC_HELPERS
#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);

View File

@ -19,114 +19,148 @@
#include "connection.h"
signed int
init_connection(Connection* info)
init_connection(Connection* conn)
{
int sockfd, getaddrres, connectres;
struct addrinfo* conn;
if ((getaddrres = getaddrinfo(info->data.address, info->data.service, NULL, &conn)) != 0) {
freeaddrinfo(conn);
struct addrinfo* addr_info;
if ((getaddrres = getaddrinfo(conn->data.address, conn->data.service, NULL, &addr_info)) != 0) {
freeaddrinfo(addr_info);
if (getaddrres != EAI_AGAIN && getaddrres != EAI_NONAME) {
LOG(LOG_ERROR,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
conn->data.address,
conn->data.service,
gai_strerror(getaddrres),
getaddrres);
return INIT_HARDFAIL;
} else {
LOG(LOG_WARN,
"Failed to get address info for " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
conn->data.address,
conn->data.service,
gai_strerror(getaddrres),
getaddrres);
return INIT_SOFTFAIL;
}
}
if ((sockfd = socket(conn->ai_family, conn->ai_socktype, conn->ai_protocol)) < 0) {
LOG(LOG_ERROR, "Failed to open a socket for " ADDRFMT ". " ERRNOFMT, info->data.address, info->data.service, strerror(errno), errno);
freeaddrinfo(conn);
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, conn->data.address, conn->data.service, strerror(errno), errno);
freeaddrinfo(addr_info);
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);
freeaddrinfo(conn);
freeaddrinfo(addr_info);
if (errno != EADDRNOTAVAIL && errno != ETIMEDOUT && errno != ECONNRESET && errno != ECONNREFUSED) {
LOG(LOG_ERROR,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
conn->data.address,
conn->data.service,
strerror(errno),
errno);
return INIT_HARDFAIL;
} else {
LOG(LOG_WARN,
"Failed to connect to host " ADDRFMT ". " ERRNOFMT,
info->data.address,
info->data.service,
conn->data.address,
conn->data.service,
strerror(errno),
errno);
return INIT_SOFTFAIL;
}
}
freeaddrinfo(conn);
freeaddrinfo(addr_info);
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
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;
time_t ctime = time(NULL);
switch (message->cmd) {
switch (mesg->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)
LOG(LOG_DEBUG, "Auto-replying to ping \"%s\".", mesg->args[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) {
LOG(LOG_WARN,
"Couldn't pong " ADDRFMT ". " ERRNOFMT,
connection->data.address,
connection->data.service,
conn->data.address,
conn->data.service,
strerror(errno),
errno);
connection->info.state = CONN_RECONNECTING;
conn->info.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]);
connection->info.l_pong = ctime;
if (mesg->trailing && mesg->args[1] != NULL) {
LOG(LOG_DEBUG, "Got PONG back with mesg \"%s\".", mesg->args[1]);
conn->info.l_pong = ctime;
}
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): {
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", connection->data.address, connection->data.service);
connection->info.state = CONN_ACTIVE;
if (!commit_channelist(buf, connection)) return 0;
LOG(LOG_INFO, "Connection established to " ADDRFMT ".", conn->data.address, conn->data.service);
conn->info.state = CONN_ACTIVE;
if (!commit_channelist(buf, conn)) return 0;
break;
}
/*
case (CAP): {
if (message->args[1] != NULL && strcmp(message->args[1], "LS") == 0) {
LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", message->args[2], connection->data.address,
connection->data.port);
if ((len = Assm_mesg(buf->buffer, Assm_cmd_CAP_REQ(message->args[2]), sizeof(buf->buffer))) > 0) {
if (mesg->args[1] != NULL && strcmp(mesg->args[1], "LS") == 0) {
LOG(LOG_VERBOSE, "Requesting capabilities \"%s\" on " ADDRFMT ".", mesg->args[2], conn->data.address,
conn->data.port);
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) {
LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, message->args[2],
connection->data.address, connection->data.port, strerror(errno), errno);
connection->state = CONN_RECONNECTING;
LOG(LOG_WARN, "Couldn't request capabilities \"%s\" on " ADDRFMT ". " ERRNOFMT, mesg->args[2],
conn->data.address, conn->data.port, strerror(errno), errno);
conn->state = CONN_RECONNECTING;
return 0;
}
}
} else if (message->args[1] != NULL && strcmp(message->args[1], "ACK") == 0) {
LOG(LOG_VERBOSE, "Ending capability negotiation on " ADDRFMT ".", connection->data.address, connection->data.port);
} else if (mesg->args[1] != NULL && strcmp(mesg->args[1], "ACK") == 0) {
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 (flush_buffer(buf->buffer, (size_t)len, buf->fd) == -1) {
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): {
LOG(LOG_ERROR, "Received error %s.", message->args[0]);
LOG(LOG_ERROR, "Received error %s.", mesg->args[0]);
break;
}
case (JOIN):
case (PART): {
set_channel(&connection->info.channels[get_channelindex(message->args[0], connection->info.channels)],
message->args[0],
message->args[1],
message->cmd == JOIN);
set_channel(&conn->info.channels[get_channelindex(mesg->args[0], conn->info.channels)],
mesg->args[0],
mesg->args[1],
mesg->cmd == JOIN);
break;
}
case (ERR_NICKNAMEINUSE):
case (ERR_NICKCOLLISION): {
LOG(LOG_ERROR, "Nickname %s is already taken.", connection->user.nickname);
connection->info.state = CONN_RECONNECTING;
LOG(LOG_ERROR, "Nickname %s is already taken.", conn->user.nickname);
conn->info.state = CONN_RECONNECTING;
break;
}
}
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
commit_channelist(Buffer_Info* buf, Connection* conn)
{

View File

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

View File

@ -42,7 +42,7 @@ mkdir_bottomup(char* path)
}
int
makeinput(char* path)
makeinput(const char* path)
{
if (path == NULL) return -1;
if (mkfifo(path, S_IRUSR | S_IWUSR | S_IWGRP) == 0) {
@ -60,11 +60,11 @@ makeinput(char* path)
}
bool
write_log(char* path, char* message)
write_log(const char* path, const char* message)
{
FILE* logfile;
if ((logfile = fopen(path, "a")) != NULL) {
fprintf(logfile, "%s", message);
fprintf(logfile, "%s\r\n", message);
fclose(logfile);
return 1;
} else
@ -101,3 +101,48 @@ add_socket_flags(int fd, int flags)
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
#define UIRCD_GUARD_FILESYSTEM
int mkdir_bottomup(char* path);
int makeinput(char* path);
bool write_log(char* path, char* message);
bool cleanup_path_names(char* name);
bool add_socket_flags(int fd, int flags);
int mkdir_bottomup(char* path);
int makeinput(const char* path);
bool write_log(const char* path, const char* message);
bool cleanup_path_names(char* name);
bool add_socket_flags(int fd, int flags);
ssize_t get_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 */

View File

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