summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct17
-rw-r--r--commands.c31
-rw-r--r--commands.h8
-rw-r--r--httpd.c92
-rw-r--r--httpd.h9
-rw-r--r--main.c22
-rw-r--r--music.c90
-rw-r--r--music.h29
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
diff --git a/httpd.c b/httpd.c
new file mode 100644
index 0000000..49b6b1e
--- /dev/null
+++ b/httpd.c
@@ -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;
+}
diff --git a/httpd.h b/httpd.h
new file mode 100644
index 0000000..73b2c2f
--- /dev/null
+++ b/httpd.h
@@ -0,0 +1,9 @@
+#ifndef _HTTPD_H_
+#define _HTTPD_H_
+
+#include <glib.h>
+
+gboolean httpd_start();
+void httpd_stop();
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..bcf52d8
--- /dev/null
+++ b/main.c
@@ -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;
+}
diff --git a/music.c b/music.c
new file mode 100644
index 0000000..2e618bd
--- /dev/null
+++ b/music.c
@@ -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;
+}
diff --git a/music.h b/music.h
new file mode 100644
index 0000000..a51204e
--- /dev/null
+++ b/music.h
@@ -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