diff --git a/.gitignore b/.gitignore index 544caf0..6638998 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ src/server/stanza.lo src/server/xmppclient.lo src/client/.dirstamp src/client/stabber.lo - +src/server/log.lo diff --git a/Makefile.am b/Makefile.am index 687a924..7652cef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,6 +5,7 @@ sources = \ src/server/xmppclient.c src/server/xmppclient.h \ src/server/parser.c src/server/parser.h \ src/server/stanza.c src/server/stanza.h \ + src/server/log.c src/server/log.h \ src/client/stabber.c src/client/stabber.h libstabber_la_LDFLAGS = -export-symbols-regex '^stabber_' diff --git a/configure-debug b/configure-debug index 85bfd81..10a63b9 100755 --- a/configure-debug +++ b/configure-debug @@ -1,3 +1,3 @@ #!/bin/sh -./configure CFLAGS='-g3 -O0' CXXFLAGS='-g3 -O0' +./configure CFLAGS='-g3 -O0' CXXFLAGS='-g3 -O0' --prefix=/usr diff --git a/runstabber.c b/runstabber.c index 60ba8e0..9003691 100644 --- a/runstabber.c +++ b/runstabber.c @@ -1,6 +1,41 @@ +#include +#include #include -int main(void) + +int +main(int argc , char *argv[]) { - return stabber_start(5230); + int port = 0; + + GOptionEntry entries[] = + { + { "port", 'p', 0, G_OPTION_ARG_INT, &port, "Listen port", NULL }, + { NULL } + }; + + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, entries, NULL); + if (!g_option_context_parse(context, &argc, &argv, &error)) { + g_print("%s\n", error->message); + g_option_context_free(context); + g_error_free(error); + return 1; + } + + g_option_context_free(context); + + if (port == 0) { + port = 5230; + } + + + if (argc == 2) { + port = atoi(argv[1]); + } + + return stabber_start(port); } diff --git a/src/server/log.c b/src/server/log.c new file mode 100644 index 0000000..6b8cdac --- /dev/null +++ b/src/server/log.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include + +#include +#include + +static FILE *logp; +static GTimeZone *tz; +static GDateTime *dt; + +gchar * +_xdg_get_data_home(void) +{ + gchar *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home) + g_strstrip(xdg_data_home); + + if (xdg_data_home && (strcmp(xdg_data_home, "") != 0)) { + return strdup(xdg_data_home); + } else { + GString *default_path = g_string_new(getenv("HOME")); + g_string_append(default_path, "/.local/share"); + gchar *result = strdup(default_path->str); + g_string_free(default_path, TRUE); + + return result; + } +} + +static gchar * +_get_main_log_file(void) +{ + gchar *xdg_data = _xdg_get_data_home(); + GString *logfile = g_string_new(xdg_data); + g_string_append(logfile, "/stabber/logs/stabber"); + g_string_append(logfile, ".log"); + gchar *result = strdup(logfile->str); + free(xdg_data); + g_string_free(logfile, TRUE); + + return result; +} + +gboolean +_create_dir(char *name) +{ + struct stat sb; + if (stat(name, &sb) != 0) { + if (errno != ENOENT || mkdir(name, S_IRWXU) != 0) { + return FALSE; + } + } else { + if ((sb.st_mode & S_IFDIR) != S_IFDIR) { + return FALSE; + } + } + + return TRUE; +} + +gboolean +_mkdir_recursive(const char *dir) +{ + int i; + gboolean result = TRUE; + + for (i = 1; i <= strlen(dir); i++) { + if (dir[i] == '/' || dir[i] == '\0') { + gchar *next_dir = g_strndup(dir, i); + result = _create_dir(next_dir); + g_free(next_dir); + if (!result) { + break; + } + } + } + + return result; +} + +void +log_init(void) +{ + gchar *xdg_data = _xdg_get_data_home(); + GString *log_dir = g_string_new(xdg_data); + g_string_append(log_dir, "/stabber/logs"); + _mkdir_recursive(log_dir->str); + g_string_free(log_dir, TRUE); + g_free(xdg_data); + + tz = g_time_zone_new_local(); + gchar *log_file = _get_main_log_file(); + logp = fopen(log_file, "a"); + g_chmod(log_file, S_IRUSR | S_IWUSR); + free(log_file); +} + +void +log_println(const char * const msg, ...) +{ + va_list arg; + va_start(arg, msg); + GString *fmt_msg = g_string_new(NULL); + g_string_vprintf(fmt_msg, msg, arg); + dt = g_date_time_new_now(tz); + gchar *date_fmt = g_date_time_format(dt, "%d/%m/%Y %H:%M:%S"); + fprintf(logp, "%s: %s\n", date_fmt, fmt_msg->str); + g_date_time_unref(dt); + fflush(logp); + g_free(date_fmt); + g_string_free(fmt_msg, TRUE); + va_end(arg); +} + +void +log_print(const char * const msg, ...) +{ + va_list arg; + va_start(arg, msg); + GString *fmt_msg = g_string_new(NULL); + g_string_vprintf(fmt_msg, msg, arg); + dt = g_date_time_new_now(tz); + gchar *date_fmt = g_date_time_format(dt, "%d/%m/%Y %H:%M:%S"); + fprintf(logp, "%s: %s", date_fmt, fmt_msg->str); + g_date_time_unref(dt); + fflush(logp); + g_free(date_fmt); + g_string_free(fmt_msg, TRUE); + va_end(arg); +} + +void +log_print_chars(const char * const msg, ...) +{ + va_list arg; + va_start(arg, msg); + GString *fmt_msg = g_string_new(NULL); + g_string_vprintf(fmt_msg, msg, arg); + fprintf(logp, "%s", fmt_msg->str); + fflush(logp); + g_string_free(fmt_msg, TRUE); + va_end(arg); +} + +void +log_close(void) +{ + g_time_zone_unref(tz); + if (logp) { + fclose(logp); + } +} diff --git a/src/server/log.h b/src/server/log.h new file mode 100644 index 0000000..5013677 --- /dev/null +++ b/src/server/log.h @@ -0,0 +1,10 @@ +#ifndef __H_LOG +#define __H_LOG + +void log_init(void); +void log_close(void); +void log_println(const char * const msg, ...); +void log_print(const char * const msg, ...); +void log_print_chars(const char * const msg, ...); + +#endif diff --git a/src/server/server.c b/src/server/server.c index eca7528..ae5f082 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -9,6 +9,7 @@ #include "server/parser.h" #include "server/stanza.h" #include "server/server.h" +#include "server/log.h" #define XML_START "" @@ -29,8 +30,7 @@ listen_for_xmlstart(XMPPClient *client) GString *stream = g_string_new(""); errno = 0; while ((read_size = recv(client->sock, buf, 1, 0)) > 0) { - printf("%c", buf[0]); - fflush(stdout); + log_print_chars("%c", buf[0]); g_string_append_len(stream, buf, read_size); memset(buf, 0, sizeof(buf)); if (g_strcmp0(stream->str, XML_START) == 0) { @@ -40,21 +40,23 @@ listen_for_xmlstart(XMPPClient *client) // error if (read_size == -1) { - perror("Error receiving on connection"); + char *errmsg = strerror(errno); + log_println(""); + log_println("Error receiving on connection: %s", errmsg); + free(errmsg); xmppclient_end_session(client); g_string_free(stream, TRUE); return -1; // client closed } else if (read_size == 0) { - printf("\n%s:%d - Client disconnected.\n", client->ip, client->port); + log_println(""); + log_println("%s:%d - Client disconnected.", client->ip, client->port); xmppclient_end_session(client); g_string_free(stream, TRUE); return -1; } - printf("\n"); - fflush(stdout); return 0; } @@ -68,14 +70,14 @@ send_to(XMPPClient *client, const char * const stanza) to_send -= sent; marker += sent; } - printf("SENT: %s\n", stanza); - fflush(stdout); + log_println("SENT: %s", stanza); } void stream_end(XMPPClient *client) { - printf("\n--> Stream end callback fired\n"); + log_print_chars("\n"); + log_println("--> Stream end callback fired"); send_to(client, STREAM_END); } @@ -89,9 +91,8 @@ listen_to(XMPPClient *client) GString *stream = g_string_new(""); errno = 0; while ((read_size = recv(client->sock, buf, 1, 0)) > 0) { - printf("%c", buf[0]); + log_print_chars("%c", buf[0]); parser_feed(buf, 1); - fflush(stdout); parser_reset(); g_string_append_len(stream, buf, read_size); if (g_str_has_suffix(stream->str, STREAM_END)) { @@ -103,14 +104,18 @@ listen_to(XMPPClient *client) // error if (read_size == -1) { - perror("Error receiving on connection"); + char *errmsg = strerror(errno); + log_println(""); + log_println("Error receiving on connection: %s", errmsg); + free(errmsg); xmppclient_end_session(client); g_string_free(stream, TRUE); return -1; // client closed } else if (read_size == 0) { - printf("\n%s:%d - Client disconnected.\n", client->ip, client->port); + log_println(""); + log_println("%s:%d - Client disconnected.", client->ip, client->port); xmppclient_end_session(client); g_string_free(stream, TRUE); return -1; @@ -122,17 +127,19 @@ listen_to(XMPPClient *client) void stream_start_callback(XMPPClient *client) { - printf("\n--> Stream start callback fired\n"); + log_print_chars("\n"); + log_println("--> Stream start callback fired"); send_to(client, XML_START); send_to(client, STREAM_RESP); send_to(client, FEATURES); - printf("RECV: "); + log_print("RECV: "); } void auth_callback(XMPPStanza *stanza, XMPPClient *client) { - printf("\n--> Auth callback fired\n"); + log_print_chars("\n"); + log_println("--> Auth callback fired"); XMPPStanza *query = stanza_get_child_by_ns(stanza, "jabber:iq:auth"); XMPPStanza *username = stanza_get_child_by_name(query, "username"); XMPPStanza *password = stanza_get_child_by_name(query, "password"); @@ -143,13 +150,14 @@ auth_callback(XMPPStanza *stanza, XMPPClient *client) client->resource = strdup(resource->content->str); send_to(client, AUTH_RESP); - printf("RECV: "); + log_print("RECV: "); } int server_run(int port) { - printf("Starting on port: %d...\n", port); + log_init(); + log_println("Starting on port: %d...", port); struct sockaddr_in server_addr, client_addr; @@ -157,7 +165,9 @@ server_run(int port) errno = 0; int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); // ipv4, tcp, ip if (listen_socket == -1) { - perror("Could not create socket"); + char *errmsg = strerror(errno); + log_println("Could not create socket: %s", errmsg); + free(errmsg); return 0; } @@ -169,7 +179,9 @@ server_run(int port) errno = 0; int ret = bind(listen_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)); if (ret == -1) { - perror("Bind failed"); + char *errmsg = strerror(errno); + log_println("Bind failed: %s", errmsg); + free(errmsg); return 0; } @@ -177,30 +189,34 @@ server_run(int port) errno = 0; ret = listen(listen_socket, 5); if (ret == -1) { - perror("Listen failed"); + char *errmsg = strerror(errno); + log_println("Listen failed: %s", errmsg); + free(errmsg); return 0; } - puts("Waiting for incoming connections..."); + log_println("Waiting for incoming connections..."); // connection accept int c = sizeof(struct sockaddr_in); errno = 0; int client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, (socklen_t*)&c); if (client_socket == -1) { - perror("Accept failed"); + char *errmsg = strerror(errno); + log_println("Accept failed: %s", errmsg); + free(errmsg); return 0; } XMPPClient *client = xmppclient_new(client_addr, client_socket); parser_init(client, stream_start_callback, auth_callback); - printf("RECV: "); + log_print("RECV: "); int res = listen_for_xmlstart(client); if (res == -1) { return 0; } - printf("RECV: "); + log_print("RECV: "); listen_to(client); stanza_show_all(); @@ -213,42 +229,7 @@ server_run(int port) shutdown(listen_socket, 2); close(listen_socket); + log_close(); + return 1; } - -int -main(int argc , char *argv[]) -{ - int port = 0; - - GOptionEntry entries[] = - { - { "port", 'p', 0, G_OPTION_ARG_INT, &port, "Listen port", NULL }, - { NULL } - }; - - GError *error = NULL; - GOptionContext *context; - - context = g_option_context_new(NULL); - g_option_context_add_main_entries(context, entries, NULL); - if (!g_option_context_parse(context, &argc, &argv, &error)) { - g_print("%s\n", error->message); - g_option_context_free(context); - g_error_free(error); - return 1; - } - - g_option_context_free(context); - - if (port == 0) { - port = 5230; - } - - - if (argc == 2) { - port = atoi(argv[1]); - } - - return server_run(port); -} diff --git a/src/server/stanza.c b/src/server/stanza.c index e651738..f318546 100644 --- a/src/server/stanza.c +++ b/src/server/stanza.c @@ -4,6 +4,7 @@ #include #include "server/stanza.h" +#include "server/log.h" static GList *stanzas; @@ -31,24 +32,24 @@ stanza_new(const char *name, const char **attributes) void stanza_show(XMPPStanza *stanza) { - printf("NAME : %s\n", stanza->name); + log_println("NAME : %s", stanza->name); if (stanza->content && stanza->content->len > 0) { - printf("CONTENT: %s\n", stanza->content->str); + log_println("CONTENT: %s", stanza->content->str); } if (stanza->attrs) { GList *curr_attr = stanza->attrs; while (curr_attr) { XMPPAttr *attr = curr_attr->data; - printf("ATTR : %s='%s'\n", attr->name, attr->value); + log_println("ATTR : %s='%s'", attr->name, attr->value); curr_attr = g_list_next(curr_attr); } } if (stanza->children) { - printf("CHILDREN:\n"); + log_println("CHILDREN:"); GList *curr_child = stanza->children; while (curr_child) { XMPPStanza *child = curr_child->data; @@ -65,7 +66,7 @@ stanza_show_all(void) while (curr) { XMPPStanza *stanza = curr->data; stanza_show(stanza); - printf("\n"); + log_println(""); curr = g_list_next(curr); } }