Mercurial > louis > mq > lightsd
changeset 26:f7a28109a8a7
Wip
author | Louis Opter <kalessin@kalessin.fr> |
---|---|
date | Sun, 04 May 2014 18:49:22 -0700 |
parents | 4ca36619afd5 |
children | 7d3f1e395a1d |
files | start_a_plugin_api.patch |
diffstat | 1 files changed, 383 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/start_a_plugin_api.patch Sun May 04 15:19:51 2014 -0700 +++ b/start_a_plugin_api.patch Sun May 04 18:49:22 2014 -0700 @@ -10,6 +10,17 @@ ADD_SUBDIRECTORY(core) +ADD_SUBDIRECTORY(plugins) +diff --git a/TODO.rst b/TODO.rst +new file mode 100644 +--- /dev/null ++++ b/TODO.rst +@@ -0,0 +1,6 @@ ++TODO ++==== ++ ++- cleanup/simplify the discovery code; ++- use timers to do smarter discovery; ++- only export what's necessary in gateway.h/gateway.c. diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -39,11 +50,325 @@ - LIST_ENTRY(lifxd_client) link; -}; -LIST_HEAD(lifxd_client_list, lifxd_client); +diff --git a/core/lifxd.c b/core/lifxd.c +--- a/core/lifxd.c ++++ b/core/lifxd.c +@@ -49,6 +49,7 @@ + #include "bulb.h" + #include "gateway.h" + #include "discovery.h" ++#include "plugin.h" + #include "version.h" + #include "lifxd.h" + +@@ -56,6 +57,7 @@ + .foreground = false, + .master_host = NULL, + .master_port = 56700, ++ .plugin_directory = NULL, + .verbosity = LIFXD_DEBUG + }; + +@@ -116,7 +118,7 @@ + { + printf( + "Usage: %s [-m master_bulb_host] [-p master_bulb_port] " +- "[-v debug|info|warning|error] [-f] [-h] [-V]\n", ++ "[-d plugin_directory] [-v debug|info|warning|error] [-f] [-h] [-V]\n", + progname + ); + exit(0); +@@ -126,13 +128,14 @@ + main(int argc, char *argv[]) + { + static const struct option opts[] = { +- {"foreground", no_argument, NULL, 'f'}, +- {"help", no_argument, NULL, 'h'}, +- {"master-host", required_argument, NULL, 'm'}, +- {"master-port", required_argument, NULL, 'p'}, +- {"verbosity", required_argument, NULL, 'v'}, +- {"version", no_argument, NULL, 'V'}, +- {NULL, 0, NULL, 0} ++ {"foreground", no_argument, NULL, 'f'}, ++ {"help", no_argument, NULL, 'h'}, ++ {"master-host", required_argument, NULL, 'm'}, ++ {"master-port", required_argument, NULL, 'p'}, ++ {"plugin-directory", required_argument, NULL, 'd'}, ++ {"verbosity", required_argument, NULL, 'v'}, ++ {"version", no_argument, NULL, 'V'}, ++ {NULL, 0, NULL, 0} + }; + + for (int rv = getopt_long(argc, argv, "fhm:p:v:V", opts, NULL); +@@ -141,22 +144,25 @@ + switch (rv) { + case 'f': + lifxd_opts.foreground = true; +- break ; ++ break; + case 'h': + lifxd_usage(argv[0]); + case 'm': + lifxd_opts.master_host = optarg; +- break ; ++ break; + case 'p': + errno = 0; + long port = strtol(optarg, NULL, 10); + if (!errno && port <= UINT16_MAX && port > 0) { + lifxd_opts.master_port = port; +- break ; ++ break; + } + lifxd_errx( + 1, "The master port must be between 1 and %d", UINT16_MAX + ); ++ case 'd': ++ lifxd_opts.plugin_directory = optarg; ++ break; + case 'v': + for (int i = 0;;) { + const char *verbose_levels[] = { +@@ -164,13 +170,13 @@ + }; + if (!strcasecmp(optarg, verbose_levels[i])) { + lifxd_opts.verbosity = i; +- break ; ++ break; + } + if (++i == LIFXD_ARRAY_SIZE(verbose_levels)) { + lifxd_errx(1, "Unknown verbosity level: %s", optarg); + } + } +- break ; ++ break; + case 'V': + printf("%s v%s\n", argv[0], LIFXD_VERSION); + return 0; +@@ -185,6 +191,7 @@ + lifxd_gateway_load_packet_infos_map(); + lifxd_configure_libevent(); + lifxd_configure_signal_handling(); ++ lifxd_plugin_start_all(); + + if (lifxd_opts.master_host) { + struct lifxd_gateway *gw = lifxd_gateway_open( +diff --git a/core/lifxd.h b/core/lifxd.h +--- a/core/lifxd.h ++++ b/core/lifxd.h +@@ -44,6 +44,7 @@ + bool foreground; + const char *master_host; + uint16_t master_port; ++ const char *plugin_directory; + enum lifxd_verbosity verbosity; + }; + +diff --git a/core/plugin.c b/core/plugin.c +new file mode 100644 +--- /dev/null ++++ b/core/plugin.c +@@ -0,0 +1,195 @@ ++// Copyright (c) 2014, Louis Opter <kalessin@kalessin.fr> ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are met: ++// ++// 1. Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// ++// 2. Redistributions in binary form must reproduce the above copyright notice, ++// this list of conditions and the following disclaimer in the documentation ++// and/or other materials provided with the distribution. ++// ++// 3. Neither the name of the copyright holder nor the names of its contributors ++// may be used to endorse or promote products derived from this software ++// without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++// POSSIBILITY OF SUCH DAMAGE. ++ ++#include <sys/queue.h> ++#include <sys/un.h> ++#include <assert.h> ++#include <err.h> ++#include <limits.h> ++#include <stdarg.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++#include <event2/event.h> ++#include <event2/util.h> ++ ++#include "bulb.h" ++#include "plugin.h" ++#include "lifxd.h" ++ ++enum { LIFXD_PLUGIN_SOCKET_PATH_SIZE = 32 }; ++enum { LIFXD_PLUGIN_SOCKET_BACKLOG = 16 }; ++ ++static struct { ++ evutil_socket_t socket; ++ struct event *ev; ++ char socket_path[LIFXD_PLUGIN_SOCKET_PATH_SIZE]; ++ char directory[]; ++} lifxd_plugin_endpoint = { ++ .socket = -1, ++ .ev = NULL, ++#define LIFXD_PLUGIN_SOCKET_DIR "/tmp/lifxdXXXXXX" ++ .directory = LIFXD_PLUGIN_SOCKET_DIR ++}; ++ ++static struct lifxd_plugin_list lifxd_plugins = \ ++ SLIST_HEAD_INITIALIZER(&lifxd_plugins); ++ ++static void ++lifxd_plugin_event_callback(evutil_socket_t socket, short events, void *ctx) ++{ ++ (void)ctx; ++ ++ if (events & EV_READ) { ++ struct sockaddr_un peer; ++ ev_socklen_t addrlen; ++ evutil_socket_t plugin = accept( ++ socket, (struct sockaddr *)&peer, &addrlen ++ ); ++ if (plugin == -1) { ++ lifxd_err(1, "can't accept new connection on the plugin socket"); ++ } ++ if (evutil_make_socket_nonblocking(plugin) == -1) { ++ evutil_closesocket(plugin); ++ lifxd_err(1, "can't accept new connection on the plugin socket"); ++ } ++ // XXX How do I know which plugin this socket corresponds to? ++ } else { ++ lifxd_warn("unexpected event on the plugin socket, events=%#x", events); ++ } ++} ++ ++static bool ++lifxd_plugin_setup(void) ++{ ++ assert(lifxd_plugin_endpoint.socket == -1); ++ ++ lifxd_plugin_endpoint.socket = socket(AF_UNIX, SOCK_STREAM, 0); ++ ++ if (evutil_make_socket_nonblocking(lifxd_plugin_endpoint.socket) == -1) { ++ goto err_ononblock; ++ } ++ ++ if (!mkdtemp(lifxd_plugin_endpoint.directory)) { ++ goto err_mkdtemp; ++ } ++ strlcpy( ++ lifxd_plugin_endpoint.socket_path, ++ lifxd_plugin_endpoint.directory, ++ sizeof(lifxd_plugin_endpoint.socket_path) ++ ); ++ strlcat( ++ lifxd_plugin_endpoint.socket_path, ++ "/core", ++ sizeof(lifxd_plugin_endpoint.socket_path) ++ ); ++ ++ struct sockaddr_un addr = { .sun_family = AF_UNIX }; ++ strlcpy( ++ addr.sun_path, lifxd_plugin_endpoint.socket_path, sizeof(addr.sun_path) ++ ); ++ int err = bind( ++ lifxd_plugin_endpoint.socket, (struct sockaddr *)&addr, sizeof(addr) ++ ); ++ if (err == -1) { ++ goto err_bind; ++ } ++ ++ err = listen(lifxd_plugin_endpoint.socket, LIFXD_PLUGIN_SOCKET_BACKLOG); ++ if (err == -1) { ++ goto err_listen; ++ } ++ ++ lifxd_plugin_endpoint.ev = event_new( ++ lifxd_ev_base, ++ lifxd_plugin_endpoint.socket, ++ EV_READ|EV_PERSIST, ++ lifxd_plugin_event_callback, ++ NULL ++ ); ++ if (!lifxd_plugin_endpoint.ev) { ++ goto err_event_new; ++ } ++ ++err_event_new: ++err_listen: ++err_bind: ++ rmdir(lifxd_plugin_endpoint.directory); ++ memset( ++ lifxd_plugin_endpoint.socket_path, ++ 0, ++ sizeof(lifxd_plugin_endpoint.socket_path) ++ ); ++ strlcpy( ++ lifxd_plugin_endpoint.directory, ++ LIFXD_PLUGIN_SOCKET_DIR, ++ sizeof(LIFXD_PLUGIN_SOCKET_DIR) ++ ); ++err_mkdtemp: ++err_ononblock: ++ evutil_closesocket(lifxd_plugin_endpoint.socket); ++ lifxd_plugin_endpoint.socket = -1; ++ return false; ++} ++ ++void ++lifxd_plugin_start_one(const char *path) ++{ ++ ++} ++ ++bool ++lifxd_plugin_start_all(void) ++{ ++ assert(lifxd_ev_base); ++ ++ if (lifxd_plugin_endpoint.socket == -1 && !lifxd_plugin_setup()) { ++ return false; ++ } ++ ++ char path[PATH_MAX]; ++ ++ strlcpy(path, lifxd_opts.plugin_directory, sizeof(path)); ++ strlcat(path, "/pulse", sizeof(path)); ++ lifxd_plugin_start_one(path); ++ ++ return true; ++} ++ ++void ++lifxd_plugin_stop_all(void) ++{ ++ evutil_closesocket(lifxd_plugin_endpoint.socket); ++ lifxd_plugin_endpoint.socket = -1; ++ unlink(lifxd_plugin_endpoint.socket_path); ++ rmdir(lifxd_plugin_endpoint.directory); ++} diff --git a/core/plugin.h b/core/plugin.h new file mode 100644 --- /dev/null +++ b/core/plugin.h -@@ -0,0 +1,33 @@ +@@ -0,0 +1,44 @@ +// Copyright (c) 2014, Louis Opter <kalessin@kalessin.fr> +// All rights reserved. +// @@ -75,13 +400,59 @@ + +#pragma once + -+bool lifxd_plugin_start(void); -+void lifxd_plugin_stop(void); ++enum { LIFXD_PLUGIN_NAME_SIZE = 32 }; ++ ++struct lifxd_plugin { ++ SLIST_ENTRY(lifxd_plugin) link; ++ char name[LIFXD_PLUGIN_NAME_SIZE]; ++ pid_t pid; ++ struct bufferevent *io; ++}; ++SLIST_HEAD(lifxd_plugin_list, lifxd_plugin); ++ ++bool lifxd_plugin_start_all(void); ++void lifxd_plugin_stop_all(void); ++void lifxd_plugin_update_all(void); +diff --git a/plugins/plugin.c b/plugins/plugin.c +new file mode 100644 +--- /dev/null ++++ b/plugins/plugin.c +@@ -0,0 +1,30 @@ ++// Copyright (c) 2014, Louis Opter <kalessin@kalessin.fr> ++// All rights reserved. ++// ++// Redistribution and use in source and binary forms, with or without ++// modification, are permitted provided that the following conditions are met: ++// ++// 1. Redistributions of source code must retain the above copyright notice, ++// this list of conditions and the following disclaimer. ++// ++// 2. Redistributions in binary form must reproduce the above copyright notice, ++// this list of conditions and the following disclaimer in the documentation ++// and/or other materials provided with the distribution. ++// ++// 3. Neither the name of the copyright holder nor the names of its contributors ++// may be used to endorse or promote products derived from this software ++// without specific prior written permission. ++// ++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ++// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++// POSSIBILITY OF SUCH DAMAGE. ++ ++ diff --git a/plugins/plugin.h b/plugins/plugin.h new file mode 100644 --- /dev/null +++ b/plugins/plugin.h -@@ -0,0 +1,54 @@ +@@ -0,0 +1,62 @@ +// Copyright (c) 2014, Louis Opter <kalessin@kalessin.fr> +// All rights reserved. +// @@ -130,6 +501,14 @@ +}; +SLIST_HEAD(lifxd_light_list, lifxd_light); + ++//! Entry point of your plugin. ++void lifxd_plugin_main(void); ++ ++void lifxd_plugin_error(const char *, ...); ++void lifxd_plugin_warn(const char *, ...); ++void lifxd_plugin_info(const char *, ...); ++void lifxd_plugin_debug(const char *, ...); ++ +struct lifxd_light_list lifxd_plugin_get_lights(void); +struct lifxd_light_list lifxd_plugin_wait_for_light_changes(void); +void lifxd_plugin_set_lights(struct lifxd_light *);