#include #include #include #include #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))); }