diff options
-rw-r--r-- | SConstruct | 17 | ||||
-rw-r--r-- | commands.c | 31 | ||||
-rw-r--r-- | commands.h | 8 | ||||
-rw-r--r-- | httpd.c | 92 | ||||
-rw-r--r-- | httpd.h | 9 | ||||
-rw-r--r-- | main.c | 22 | ||||
-rw-r--r-- | music.c | 90 | ||||
-rw-r--r-- | music.h | 29 |
8 files changed, 298 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..bf87dfe --- /dev/null +++ b/SConstruct @@ -0,0 +1,17 @@ +AddOption('--release', action = 'store_true') + +env = Environment(CPPPATH = ['.']) + +env.Append(CCFLAGS = ['-std=c99']) + +if GetOption('release'): + env.Append(CCFLAGS = ['-O2']) +else: + env.Append(CCFLAGS = ['-Wall', '-g']) + +env.ParseConfig('pkg-config --cflags --libs glib-2.0') +env.ParseConfig('pkg-config --cflags --libs gio-2.0') + +env.Program('foo', Glob('*.c')) + +# vim: syn=python diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..b11b09c --- /dev/null +++ b/commands.c @@ -0,0 +1,31 @@ +#include "commands.h" +#include "music.h" + +#include <glib.h> +#include <string.h> + +static void commands_list(GSocketConnection *connection, const gchar *cmd) { + gchar **data = g_strsplit(cmd, " ", 2); + for(gint i = 0; data[i]; i++) { + g_debug("\tdata[%d] = %s", i, data[i]); + } + g_assert(data[0] != NULL && data[1] != NULL); + + gchar *dirname = g_strdup(data[1]); + + struct directory *directory = music_find_dir(dirname); + g_assert(directory != NULL); + + GSocket *socket = g_socket_connection_get_socket(connection); + for(struct file *f = directory->files; f; f = f->next) { + g_socket_send(socket, f->name, strlen(f->name), NULL, NULL); + g_socket_send(socket, "\n", 1, NULL, NULL); + } +} + +void commands_handle(GSocketConnection *connection, const gchar *cmd) { + g_debug("handling command string %s", cmd); + if(g_ascii_strncasecmp(cmd, "/list", 5) == 0) { + commands_list(connection, cmd); + } +} diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..7b90f95 --- /dev/null +++ b/commands.h @@ -0,0 +1,8 @@ +#ifndef _COMMANDS_H_ +#define _COMMANDS_H_ + +#include <gio/gio.h> + +void commands_handle(GSocketConnection *connection, const gchar *cmd); + +#endif @@ -0,0 +1,92 @@ +#include "httpd.h" +#include "commands.h" + +#include <gio/gio.h> +#include <string.h> + +GSocketService *ss = NULL; + +static gboolean service_incoming(GSocketService *service, + GSocketConnection *connection, GObject *source_object, + gpointer user_data) { + GSocket *socket; + GError *error = NULL; + + g_debug("incoming connection to service"); + + socket = g_socket_connection_get_socket(connection); + if(socket == NULL) { + g_error("g_socket_connection_get_socket() returned NULL"); + return FALSE; + } + + GString *string = g_string_new(NULL); + gboolean done = FALSE; + gssize tot = 0; + + while(done == FALSE) { + gchar buffer[0x400]; + gssize len = g_socket_receive(socket, buffer, 0x400, NULL, &error); + if(len == -1) { + g_error(error->message); + g_error_free(error); + return FALSE; + } + tot += len; + g_string_append_len(string, buffer, len); + + /* TODO: find a more sane way to stop reading */ + if(string->len >= 4 && g_strcmp0(string->str + string->len - 4, "\r\n\r\n") == 0) { + done = TRUE; + } + } + g_debug("read %lu bytes", tot); + g_debug("HTTP header:\n%s", string->str); + + /* split headers */ + gchar **data = g_strsplit(string->str, "\r\n", 0); + + g_string_free(string, TRUE); + + gchar **firstline = g_strsplit(data[0], " ", 0); + /* this sets the first character of the last string in + * firstline to \0 (HTTP version) */ + firstline[g_strv_length(firstline)-1] = '\0'; + /* now join from the second string to get the request path */ + gchar *path = g_strjoinv(" ", firstline + 1); + + g_strfreev(firstline); + + for(gint i = 1; strlen(data[i]); i++) { + g_debug("data[%d] = %s", i, data[i]); + } + + g_strfreev(data); + + commands_handle(connection, path); + + if(g_socket_close(socket, &error) == FALSE) { + g_error(error->message); + g_error_free(error); + return FALSE; + } + + return FALSE; +} + +gboolean httpd_start() { + ss = g_threaded_socket_service_new(10); + + g_socket_listener_add_inet_port((GSocketListener*)ss, 8000, NULL, NULL); + + g_signal_connect(ss, "incoming", (GCallback)service_incoming, NULL); + g_socket_service_start(ss); + + return TRUE; +} + +void httpd_stop() { + g_socket_service_stop(ss); + g_free(ss); + ss = NULL; +} @@ -0,0 +1,9 @@ +#ifndef _HTTPD_H_ +#define _HTTPD_H_ + +#include <glib.h> + +gboolean httpd_start(); +void httpd_stop(); + +#endif @@ -0,0 +1,22 @@ +#include "music.h" +#include "httpd.h" + +#include <glib.h> +#include <glib-object.h> + +int main(int argc, char **argv) { + g_type_init(); + + music_init(argv[1]); + music_scan_root(); + + httpd_start(); + + GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(main_loop); + + httpd_stop(); + music_free(); + + return 0; +} @@ -0,0 +1,90 @@ +#include "music.h" + +#include <glib/gstdio.h> + +struct directory *music_root = NULL; + +gboolean music_init(const gchar *path) { + music_root = g_new0(struct directory, 1); + music_root->path = g_strdup(path); + + return 1; +} + +gboolean music_scan(struct directory *directory) { + GError *error = NULL; + GDir *dir = g_dir_open(directory->path, 0, &error); + + if(dir == NULL) { + g_error("%s", error->message); + g_error_free(error); + return 0; + } + + const gchar *entry; + while((entry = g_dir_read_name(dir)) != NULL) { + struct file *f = g_new0(struct file, 1); + f->name = g_strdup(entry); + + if(directory->files == NULL) { + directory->files = f; + } else { + struct file *last = directory->files; + while(last->next) last = last->next; + last->next = f; + } + } + + g_dir_close(dir); + + return 1; +} + +gboolean music_scan_root() { + g_assert(music_root != NULL); + + return music_scan(music_root); +} + +static struct directory *music_find_dir_rec(struct directory *root, const gchar *path) { + if(g_strcmp0(root->path, path) == 0) + return root; + + /* TODO: implement this */ + g_error("not implemented"); + + return NULL; +} + +struct directory *music_find_dir(const gchar *path) { + return music_find_dir_rec(music_root, path); +} + +static void music_do_free(struct directory *root) { + struct directory *node; + + g_assert(root != NULL); + + for(node = root->sub; node; node = node->next) { + music_do_free(node); + } + + for(node = root->next; node; node = node->next) { + music_do_free(node); + } + + for(struct file *f = root->files; f; f = f->next) { + g_free(f->name); + g_free(f); + } + + g_free(root->path); + g_free(root); +} + +void music_free() { + g_assert(music_root != NULL); + + music_do_free(music_root); + music_root = NULL; +} @@ -0,0 +1,29 @@ +#ifndef _MUSIC_H_ +#define _MUSIC_H_ + +/* for size_t */ +#include <stddef.h> + +#include <glib.h> + +struct file { + gchar *name; + gssize size; + struct file *next; +}; + +struct directory { + char *path; + struct directory *sub, *next; + struct file *files; +}; + +extern struct directory *music_root; + +gboolean music_init(const gchar *path); +gboolean music_scan(struct directory *directory); +gboolean music_scan_root(); +struct directory *music_find_dir(const gchar *path); +void music_free(); + +#endif |