]> git.meshlink.io Git - catta/commitdiff
* add initial implmenentation of a "simple protocol" for usage with nss-mdns
authorLennart Poettering <lennart@poettering.net>
Thu, 16 Jun 2005 12:51:20 +0000 (12:51 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 16 Jun 2005 12:51:20 +0000 (12:51 +0000)
git-svn-id: file:///home/lennart/svn/public/avahi/trunk@113 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe

avahi-core/server.c
avahi-daemon/Makefile.am
avahi-daemon/main.c
avahi-daemon/simple-protocol.c [new file with mode: 0644]
avahi-daemon/simple-protocol.h [new file with mode: 0644]

index 5b00e444453a541b43eb720bf4b634866bae49a1..1630b29098b85ca4a1cfd91c86cef69afc294dcb 100644 (file)
@@ -1274,7 +1274,7 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah
 
     s->fd_legacy_unicast_ipv4 = s->fd_ipv4 >= 0 && s->config.enable_reflector ? avahi_open_legacy_unicast_socket_ipv4() : -1;
     s->fd_legacy_unicast_ipv6 = s->fd_ipv6 >= 0 && s->config.enable_reflector ? avahi_open_legacy_unicast_socket_ipv6() : -1;
-    
+
     if (c)
         g_main_context_ref(s->context = c);
     else
index 3a033934d93d5f2945a88e0b1a200ccb34281a3b..029a6d7e0c245020540664dbb4b1c8175c2111bf 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.am 52 2005-05-06 16:23:30Z lennart $
+# $Id$
 #
 # This file is part of avahi.
 # 
@@ -35,7 +35,8 @@ bin_PROGRAMS = \
        avahi
 
 avahi_SOURCES = \
-       main.c
+       main.c \
+       simple-protocol.c
 
 avahi_CFLAGS = $(AM_CFLAGS)
 avahi_LDADD = $(AM_LDADD) ../avahi-core/libavahi-core.la ../avahi-common/libavahi-common.la
index 9a02391da8283270994446e9b632fa43137ff649..3875865c380441aa798e8cb8c221fef024a36b3b 100644 (file)
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#include "simple-protocol.h"
+
 #define DBUS_SERVICE_AVAHI "org.freedesktop.Avahi"
 
 static DBusHandlerResult
 do_register (DBusConnection *conn, DBusMessage *message)
 {
-       DBusError error;
-       char *s;
+    DBusError error;
+    char *s;
 
-       dbus_error_init (&error);
+    dbus_error_init (&error);
 
-       dbus_message_get_args (message, &error,
-                       DBUS_TYPE_STRING, &s,
-                       DBUS_TYPE_INVALID);
+    dbus_message_get_args (message, &error,
+                           DBUS_TYPE_STRING, &s,
+                           DBUS_TYPE_INVALID);
 
-       if (dbus_error_is_set (&error))
-       {
-               g_warning ("Error parsing register attempt");
-               dbus_error_free (&error);
+    if (dbus_error_is_set (&error))
+    {
+        g_warning ("Error parsing register attempt");
+        dbus_error_free (&error);
 
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
+        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
 
-       g_message ("Register received from: %s", s);
+    g_message ("Register received from: %s", s);
 
-       return DBUS_HANDLER_RESULT_HANDLED;
+    return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 static DBusHandlerResult
 signal_filter (DBusConnection *conn, DBusMessage *message, void *user_data)
 {
-       GMainLoop *loop = user_data;
-       DBusError error;
-
-       dbus_error_init (&error);
-
-       g_message ("dbus: interface=%s, path=%s, member=%s",
-                       dbus_message_get_interface (message),
-                       dbus_message_get_path (message),
-                       dbus_message_get_member (message));
-
-       if (dbus_message_is_signal (message,
-                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
-                               "Disconnected"))
-       {
-               /* No, we shouldn't quit, but until we get somewhere
-                * usefull such that we can restore our state, we will */
-               g_warning ("Disconnnected from d-bus");
-
-               g_main_loop_quit (loop);
-               return DBUS_HANDLER_RESULT_HANDLED;
-       } else if (dbus_message_is_method_call (message, DBUS_SERVICE_AVAHI,
-                               "Register"))
-       {
-               return do_register (conn, message);
-       } else if (dbus_message_is_signal (message,
-                               DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
-                               "ServiceAcquired"))
-       {
-               char *name;
-
-               dbus_message_get_args (message, &error,
-                               DBUS_TYPE_STRING, &name,
-                               DBUS_TYPE_INVALID);
-
-               if (dbus_error_is_set (&error))
-               {
-                       g_warning ("Error parsing NameAcquired message");
-                       dbus_error_free (&error);
-
-                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-               }
-
-               g_message ("dbus: ServiceAcquired (%s)", name);
-
-               return DBUS_HANDLER_RESULT_HANDLED;
-       }
-
-       g_message ("dbus: missed event");
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    GMainLoop *loop = user_data;
+    DBusError error;
+
+    dbus_error_init (&error);
+
+    g_message ("dbus: interface=%s, path=%s, member=%s",
+               dbus_message_get_interface (message),
+               dbus_message_get_path (message),
+               dbus_message_get_member (message));
+
+    if (dbus_message_is_signal (message,
+                                DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+                                "Disconnected"))
+    {
+        /* No, we shouldn't quit, but until we get somewhere
+         * usefull such that we can restore our state, we will */
+        g_warning ("Disconnnected from d-bus");
+
+        g_main_loop_quit (loop);
+        return DBUS_HANDLER_RESULT_HANDLED;
+    } else if (dbus_message_is_method_call (message, DBUS_SERVICE_AVAHI,
+                                            "Register"))
+    {
+        return do_register (conn, message);
+    } else if (dbus_message_is_signal (message,
+                                       DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                       "ServiceAcquired"))
+    {
+        char *name;
+
+        dbus_message_get_args (message, &error,
+                               DBUS_TYPE_STRING, &name,
+                               DBUS_TYPE_INVALID);
+
+        if (dbus_error_is_set (&error))
+        {
+            g_warning ("Error parsing NameAcquired message");
+            dbus_error_free (&error);
+
+            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+        }
+
+        g_message ("dbus: ServiceAcquired (%s)", name);
+
+        return DBUS_HANDLER_RESULT_HANDLED;
+    }
+
+    g_message ("dbus: missed event");
+
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
-               
+                
 int main(int argc, char *argv[]) {
     GMainLoop *loop = NULL;
-    DBusConnection *bus;
+    DBusConnection *bus = NULL;
     DBusError error;
+    gint r = -1;
 
     loop = g_main_loop_new(NULL, FALSE);
 
     dbus_error_init (&error);
 
-
     bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
 
     if (bus == NULL)
     {
-           g_warning ("dbus_bus_get(): %s", error.message);
-           dbus_error_free (&error);
+        g_warning ("dbus_bus_get(): %s", error.message);
+        dbus_error_free (&error);
 
-           return -1;
+        goto finish;
     }
 
     dbus_connection_setup_with_g_main (bus, NULL);
@@ -138,27 +140,43 @@ int main(int argc, char *argv[]) {
 
     if (dbus_error_is_set (&error))
     {
-           g_warning ("dbus_error_is_set (): %s", error.message);
-           dbus_error_free (&error);
+        g_warning ("dbus_error_is_set (): %s", error.message);
+        dbus_error_free (&error);
 
-           return -1;
+        goto finish;
     }
 
     dbus_connection_add_filter (bus, signal_filter, loop, NULL);
     dbus_bus_add_match (bus,
-                   "type='method_call',interface='org.freedesktop.Avahi'",
-                   &error);
+                        "type='method_call',interface='org.freedesktop.Avahi'",
+                        &error);
 
     if (dbus_error_is_set (&error))
     {
-           g_warning ("dbus_bus_add_match (): %s", error.message);
-           dbus_error_free (&error);
+        g_warning ("dbus_bus_add_match (): %s", error.message);
+        dbus_error_free (&error);
 
-           return -1;
+        goto finish;
     }
 
+    if (simple_protocol_setup(NULL) < 0)
+        goto finish;
+
     g_main_loop_run(loop);
-    g_main_loop_unref(loop);
+
+    r = 0;
     
-    return 0;
+finish:
+
+    simple_protocol_shutdown();
+
+    if (bus) {
+        dbus_connection_disconnect(bus);
+        dbus_connection_unref(bus);
+    }
+
+    if (loop)
+        g_main_loop_unref(loop);
+
+    return r;
 }
diff --git a/avahi-daemon/simple-protocol.c b/avahi-daemon/simple-protocol.c
new file mode 100644 (file)
index 0000000..71dd639
--- /dev/null
@@ -0,0 +1,329 @@
+/* $Id$ */
+
+/***
+  This file is part of avahi.
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <avahi-core/llist.h>
+
+#include "simple-protocol.h"
+
+#define BUFFER_SIZE (10*1024)
+
+#define UNIX_SOCKET_PATH "/tmp/avahi"
+#define UNIX_SOCKET UNIX_SOCKET_PATH"/socket"
+
+#define CLIENTS_MAX 50
+
+typedef struct Client Client;
+typedef struct Server Server;
+
+struct Client {
+    Server *server;
+    
+    gint fd;
+    GPollFD poll_fd;
+
+    gchar inbuf[BUFFER_SIZE], outbuf[BUFFER_SIZE];
+    guint inbuf_length, outbuf_length;
+    
+    AVAHI_LLIST_FIELDS(Client, clients);
+};
+
+struct Server {
+    GSource source;
+    GMainContext *context;
+    GPollFD poll_fd;
+    gint fd;
+    AVAHI_LLIST_HEAD(Client, clients);
+
+    guint n_clients;
+};
+
+static Server *server = NULL;
+
+static void client_free(Client *c) {
+    g_assert(c);
+
+    g_assert(c->server->n_clients >= 1);
+    c->server->n_clients--;
+    
+    g_source_remove_poll(&c->server->source, &c->poll_fd);
+    close(c->fd);
+    AVAHI_LLIST_REMOVE(Client, clients, c->server->clients, c);
+    g_free(c);
+}
+
+static void client_new(Server *s, int fd) {
+    Client *c;
+
+    g_assert(fd >= 0);
+
+    c = g_new(Client, 1);
+    c->server = s;
+    c->fd = fd;
+
+    c->inbuf_length = c->outbuf_length = 0;
+
+    memset(&c->poll_fd, 0, sizeof(GPollFD));
+    c->poll_fd.fd = fd;
+    c->poll_fd.events = G_IO_IN|G_IO_ERR|G_IO_HUP;
+    g_source_add_poll(&s->source, &c->poll_fd);
+
+    AVAHI_LLIST_PREPEND(Client, clients, s->clients, c);
+    s->n_clients++;
+}
+
+static void client_output(Client *c, const guint8*data, guint size) {
+    guint k, m;
+    
+    g_assert(c);
+    g_assert(data);
+
+    if (!size)
+        return;
+
+    k = sizeof(c->outbuf) - c->outbuf_length;
+    m = size > k ? k : size;
+
+    memcpy(c->outbuf + c->outbuf_length, data, m);
+    c->outbuf_length += m;
+}
+
+static void handle_line(Client *c, const gchar *s) {
+    gchar t[256];
+
+    g_assert(c);
+    g_assert(s);
+
+    snprintf(t, sizeof(t), "you said <%s>\n", s);
+    client_output(c, (guint8*) t, strlen(t));
+}
+
+static void handle_input(Client *c) {
+    g_assert(c);
+
+    for (;;) {
+        gchar *e;
+        guint k;
+
+        if (!(e = memchr(c->inbuf, '\n', c->inbuf_length)))
+            break;
+
+        k = e - (gchar*) c->inbuf;
+        *e = 0;
+        
+        handle_line(c, c->inbuf);
+        c->inbuf_length -= k + 1;
+        memmove(c->inbuf, e+1, c->inbuf_length);
+    }
+}
+
+static void client_work(Client *c) {
+    g_assert(c);
+
+    if ((c->poll_fd.revents & G_IO_IN) && c->inbuf_length < sizeof(c->inbuf)) {
+        ssize_t r;
+        
+        if ((r = read(c->fd, c->inbuf + c->inbuf_length, sizeof(c->inbuf) - c->inbuf_length)) <= 0) {
+            if (r < 0)
+                g_warning("read(): %s", strerror(errno));
+            client_free(c);
+            return;
+        }
+
+        c->inbuf_length += r;
+        g_assert(c->inbuf_length <= sizeof(c->inbuf));
+
+        handle_input(c);
+    }
+
+    if ((c->poll_fd.revents & G_IO_OUT) && c->outbuf_length > 0) {
+        ssize_t r;
+
+        if ((r = write(c->fd, c->outbuf, c->outbuf_length)) < 0) {
+            g_warning("write(): %s", strerror(errno));
+            client_free(c);
+            return;
+        }
+
+        g_assert((guint) r <= c->outbuf_length);
+        c->outbuf_length -= r;
+        
+        if (c->outbuf_length)
+            memmove(c->outbuf, c->outbuf + r, c->outbuf_length - r);
+    }
+
+    c->poll_fd.events =
+        G_IO_ERR |
+        G_IO_HUP |
+        (c->outbuf_length > 0 ? G_IO_OUT : 0) |
+        (c->inbuf_length < sizeof(c->inbuf) ? G_IO_IN : 0);
+}
+
+static gboolean prepare_func(GSource *source, gint *timeout) {
+    g_assert(source);
+    g_assert(timeout);
+    
+    *timeout = -1;
+    return FALSE;
+}
+
+static gboolean check_func(GSource *source) {
+    Server *s = (Server*) source;
+    Client *c;
+    
+    g_assert(s);
+
+    if (s->poll_fd.revents)
+        return TRUE;
+    
+    for (c = s->clients; c; c = c->clients_next)
+        if (c->poll_fd.revents)
+            return TRUE;
+
+    return FALSE;
+}
+
+static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) {
+    Server *s = (Server*) source;
+    Client *c, *n;
+    
+    g_assert(s);
+
+    if (s->poll_fd.revents & G_IO_IN) {
+        gint fd;
+
+        if ((fd = accept(s->fd, NULL, NULL)) < 0)
+            g_warning("accept(): %s", strerror(errno));
+        else
+            client_new(s, fd);
+    } else if (s->poll_fd.revents)
+        g_error("Invalid revents");
+
+    for (c = s->clients; c; c = n) {
+        n = c->clients_next;
+        if (c->poll_fd.revents)
+            client_work(c);
+    }
+    
+    return TRUE;
+}
+
+int simple_protocol_setup(GMainContext *c) {
+    struct sockaddr_un sa;
+    mode_t u;
+
+    static GSourceFuncs source_funcs = {
+        prepare_func,
+        check_func,
+        dispatch_func,
+        NULL,
+        NULL,
+        NULL
+    };
+    
+    g_assert(!server);
+
+    server = (Server*) g_source_new(&source_funcs, sizeof(Server));
+    server->fd = -1;
+    AVAHI_LLIST_HEAD_INIT(Client, server->clients);
+    if (c)
+        g_main_context_ref(server->context = c);
+    else
+        server->context = g_main_context_default();
+    server->clients = NULL;
+
+    u = umask(0000);
+
+    if (mkdir(UNIX_SOCKET_PATH, 0755) < 0 && errno != EEXIST) {
+        g_warning("mkdir(): %s", strerror(errno));
+        goto fail;
+    }
+    
+    if ((server->fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+        g_warning("socket(PF_LOCAL, SOCK_STREAM, 0): %s", strerror(errno));
+        goto fail;
+    }
+
+    memset(&sa, 0, sizeof(sa));
+    sa.sun_family = AF_LOCAL;
+    strncpy(sa.sun_path, UNIX_SOCKET, sizeof(sa.sun_path)-1);
+
+    if (bind(server->fd, &sa, sizeof(sa)) < 0) {
+        g_warning("bind(): %s", strerror(errno));
+        goto fail;
+    }
+    
+    if (listen(server->fd, 2) < 0) {
+        g_warning("listen(): %s", strerror(errno));
+        goto fail;
+    }
+
+    umask(u);
+
+    memset(&server->poll_fd, 0, sizeof(GPollFD));
+    server->poll_fd.fd = server->fd;
+    server->poll_fd.events = G_IO_IN|G_IO_ERR;
+    g_source_add_poll(&server->source, &server->poll_fd);
+
+    g_source_attach(&server->source, server->context);
+    
+    return 0;
+
+fail:
+    
+    umask(u);
+    simple_protocol_shutdown();
+
+    return -1;
+}
+
+void simple_protocol_shutdown(void) {
+
+    if (server) {
+
+        while (server->clients)
+            client_free(server->clients);
+        
+        if (server->fd >= 0) {
+            unlink(UNIX_SOCKET_PATH);
+            close(server->fd);
+        }
+
+        g_main_context_unref(server->context);
+        g_source_destroy(&server->source);
+        g_source_unref(&server->source);
+
+        server = NULL;
+    }
+}
diff --git a/avahi-daemon/simple-protocol.h b/avahi-daemon/simple-protocol.h
new file mode 100644 (file)
index 0000000..2b82ef9
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef foosimpleprotocolhfoo
+#define foosimpleprotocolhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of avahi.
+  avahi is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as
+  published by the Free Software Foundation; either version 2.1 of the
+  License, or (at your option) any later version.
+  avahi is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
+  Public License for more details.
+  You should have received a copy of the GNU Lesser General Public
+  License along with avahi; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+int simple_protocol_setup(GMainContext *c);
+void simple_protocol_shutdown(void);
+
+#endif