summaryrefslogtreecommitdiffstats
path: root/client/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/daemon.c')
-rw-r--r--client/daemon.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/client/daemon.c b/client/daemon.c
new file mode 100644
index 0000000..fd69ef5
--- /dev/null
+++ b/client/daemon.c
@@ -0,0 +1,198 @@
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+#include "daemon.h"
+#include "../daemon/common.h"
+#include "connection.h"
+
+int sock = -1;
+GIOChannel *channel = NULL;
+GSList *send_message_queue = NULL;
+
+static void dispatch(message_t *m) {
+ switch (m->code) {
+ case MSG_PACKET :
+ conn_new((ipq_packet_msg_t*) (m+1));
+ break;
+ default:
+ break;
+ }
+ g_free(m);
+}
+
+static gboolean recv_work() {
+ static guint8 temp[sizeof(message_t)];
+ static message_t *m = NULL;
+ static guint index = 0;
+
+ guint8 *p;
+ size_t l;
+ ssize_t r;
+
+ if (index < sizeof(message_t)) {
+ p = temp + index;
+ l = sizeof(message_t);
+ } else {
+ p = ((guint8*) m) + index;
+ l = m->length+sizeof(message_t);
+ }
+
+ if ((r = read(sock, p, l-index)) < 0) {
+ g_message("read() failed, exiting.");
+ gtk_main_quit();
+ return FALSE;
+ }
+
+ index += r;
+
+ if (index == sizeof(message_t)) {
+ m = g_malloc(((message_t*) temp)->length + sizeof(message_t));
+ memcpy(m, temp, sizeof(message_t));
+ }
+
+ if (index >= sizeof(message_t))
+ if (index == sizeof(message_t) + m->length) {
+ dispatch(m);
+ m = NULL;
+ index = 0;
+ }
+
+ return TRUE;
+}
+
+static gboolean send_work() {
+ static message_t *m = NULL;
+ static int index = 0;
+ guint l, r;
+ guint8* p;
+
+ if (!m) {
+ if (!send_message_queue)
+ return FALSE;
+
+ m = (message_t*) send_message_queue->data;
+ send_message_queue = g_slist_remove(send_message_queue, m);
+
+ index = 0;
+ }
+
+ p = ((guint8*) m) + index;
+ l = m->length + sizeof(message_t);
+
+ if ((r = write(sock, p, l - index)) < 0) {
+ g_message("write() failed, exiting");
+ gtk_main_quit();
+ return FALSE;
+ }
+
+ index += r;
+
+
+ if (index >= l) {
+ g_free(m);
+ m = NULL;
+ index = 0;
+ }
+
+
+ return m || send_message_queue;
+}
+
+
+static gboolean callback(GIOChannel *source, GIOCondition condition, gpointer data) {
+
+ if (condition & G_IO_HUP) {
+ gtk_main_quit();
+ return FALSE;
+ }
+
+ if (condition & G_IO_IN)
+ return recv_work();
+
+ if (condition & G_IO_OUT)
+ return send_work();
+
+ g_error("Huch?");
+ return FALSE;
+}
+
+static int enqueue_message(message_t *m) {
+
+ send_message_queue = g_slist_append(send_message_queue, m);
+
+ if (!send_message_queue->next)
+ g_io_add_watch(channel, G_IO_OUT, callback, NULL);
+
+ return 0;
+}
+
+static message_t* new_message(message_code_t code, guint8* p, guint s) {
+ message_t* m;
+
+ if (!p)
+ s = 0;
+
+ m = g_malloc(sizeof(message_t) + s);
+
+ m->code = code;
+ m->pid = getpid();
+ m->length = s;
+
+ if (p)
+ memcpy(m+1, p, s);
+
+ return m;
+}
+
+static int unix_socket(gchar *p) {
+ struct sockaddr_un addr;
+ int sock;
+
+ if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ perror("socket(PF_LOCAL, SOCK_STREAM, 0)");
+ return -1;
+ }
+
+ addr.sun_family = AF_LOCAL;
+ strncpy(addr.sun_path, p, sizeof(addr.sun_path));
+ addr.sun_path[sizeof(addr.sun_path)-1] = 0;
+
+ if (connect(sock, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) {
+ perror("connect()");
+ return -1;
+ }
+
+ return sock;
+}
+
+int daemon_init() {
+
+ if ((sock = unix_socket(SOCKET_PATH)) < 0)
+ return -1;
+
+ channel = g_io_channel_unix_new(sock);
+ g_io_add_watch(channel, G_IO_IN|G_IO_HUP, callback, NULL);
+
+ return 0;
+}
+
+
+void daemon_done() {
+ if (sock >= 0)
+ close(sock);
+
+ if (channel)
+ g_io_channel_unref(channel);
+}
+
+
+void daemon_verdict(unsigned long id, guint r) {
+ static guint8 buf[sizeof(unsigned long) + sizeof(guint32)];
+
+ *((unsigned long*) &buf[0]) = id;
+ *((guint32*) &buf[sizeof(unsigned long)]) = r;
+
+ enqueue_message(new_message(MSG_VERDICT, buf, sizeof(buf)));
+}