changeset 409:6bc379a8f256

wip
author Louis Opter <kalessin@kalessin.fr>
date Thu, 31 Dec 2015 10:14:10 +0100
parents 28915b460db7
children 1830822a9f63
files add_power_transition.patch doc_semver.patch dont_use_ev_assign.patch network_discovery.patch optional_jsonrpc_args.patch series
diffstat 6 files changed, 350 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/add_power_transition.patch	Tue Dec 29 18:40:32 2015 +0100
+++ b/add_power_transition.patch	Thu Dec 31 10:14:10 2015 +0100
@@ -1,21 +1,10 @@
 # HG changeset patch
-# Parent  87ea0f02cb6990de202d043b7ff05c9dbca83296
+# Parent  dfd2e5cf185c1db0f2072f78528a8d4cf0118043
 Add a transition argument to the power functions
 
 diff --git a/CMakeLists.txt b/CMakeLists.txt
 --- a/CMakeLists.txt
 +++ b/CMakeLists.txt
-@@ -4,8 +4,8 @@
- PROJECT(LIGHTSD C)
- 
- SET(CPACK_PACKAGE_VERSION_MAJOR "1")
--SET(CPACK_PACKAGE_VERSION_MINOR "1")
--SET(CPACK_PACKAGE_VERSION_PATCH "2")
-+SET(CPACK_PACKAGE_VERSION_MINOR "2")
-+SET(CPACK_PACKAGE_VERSION_PATCH "0")
- SET(LIGHTSD_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
- 
- MESSAGE(STATUS "lightsd version: ${LIGHTSD_VERSION}")
 @@ -88,6 +88,7 @@
  
  ADD_SUBDIRECTORY(compat)
@@ -536,7 +525,7 @@
 diff --git a/core/lightsd.c b/core/lightsd.c
 --- a/core/lightsd.c
 +++ b/core/lightsd.c
-@@ -52,6 +52,7 @@
+@@ -51,6 +51,7 @@
  #include "timer.h"
  #include "listen.h"
  #include "daemon.h"
@@ -544,7 +533,7 @@
  #include "lightsd.h"
  
  struct lgtd_opts lgtd_opts = {
-@@ -81,6 +82,7 @@
+@@ -181,6 +182,7 @@
      lgtd_listen_close_all();
      lgtd_command_pipe_close_all();
      lgtd_client_close_all();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc_semver.patch	Thu Dec 31 10:14:10 2015 +0100
@@ -0,0 +1,24 @@
+# HG changeset patch
+# Parent  bfa59be534ab65b5caff5b25d70a1d9fa961bfbb
+Document semver a little bit better
+
+diff --git a/docs/changelog.rst b/docs/changelog.rst
+--- a/docs/changelog.rst
++++ b/docs/changelog.rst
+@@ -1,7 +1,15 @@
+ Changelog
+ =========
+ 
+-lightsd uses `semantic versionning <http://semver.org/>`_.
++lightsd uses `semantic versionning <http://semver.org/>`_, here is the summary:
++
++Given a version number MAJOR.MINOR.PATCH:
++
++- MAJOR version gets incremented when you may need to modify your lightsd
++  configuration to keep your setup running;
++- MINOR version gets incremented when functionality or substantial improvements
++  are added in a backwards-compatible manner;
++- PATCH version gets incremented for backwards-compatible bug fixes.
+ 
+ 1.1.2 (2015-11-30)
+ ------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dont_use_ev_assign.patch	Thu Dec 31 10:14:10 2015 +0100
@@ -0,0 +1,136 @@
+# HG changeset patch
+# Parent  eaec17795512845ed7a35e486ee5e9d61aa429a2
+Avoid event_assign for better compatibility across libevent versions
+
+diff --git a/core/lightsd.c b/core/lightsd.c
+--- a/core/lightsd.c
++++ b/core/lightsd.c
+@@ -36,7 +36,6 @@
+ #include <unistd.h>
+ 
+ #include <event2/event.h>
+-#include <event2/event_struct.h>
+ 
+ #include "lifx/wire_proto.h"
+ #include "time_monotonic.h"
+@@ -72,34 +71,16 @@
+ 
+ struct event_base *lgtd_ev_base = NULL;
+ 
++static const int lgtd_signals[] = { SIGINT, SIGTERM, SIGQUIT };
++static struct event *lgtd_signal_evs[LGTD_ARRAY_SIZE(lgtd_signals)] = { NULL };
++
+ static int lgtd_last_signal_received = 0;
+ 
+-void
+-lgtd_cleanup(void)
+-{
+-    lgtd_lifx_discovery_close();
+-    lgtd_listen_close_all();
+-    lgtd_command_pipe_close_all();
+-    lgtd_client_close_all();
+-    lgtd_lifx_broadcast_close();
+-    lgtd_lifx_gateway_close_all();
+-    lgtd_timer_stop_all();
+-    event_base_free(lgtd_ev_base);
+-#if LIBEVENT_VERSION_NUMBER >= 0x02010100
+-    libevent_global_shutdown();
+-#endif
+-    if (lgtd_opts.pidfile) {
+-        unlink(lgtd_opts.pidfile);
+-    }
+-}
+-
+ static void
+ lgtd_signal_event_callback(int signum, short events, void *ctx)
+ {
+     assert(ctx);
+ 
+-    // NOTE: syslog isn't signal safe, don't log anything in this function.
+-
+     lgtd_last_signal_received = signum;
+     event_del((struct event *)ctx);  // restore default behavior
+     event_base_loopbreak(lgtd_ev_base);
+@@ -126,20 +107,18 @@
+ }
+ 
+ static void
+-lgtd_configure_signal_handling(void)
++lgtd_setup_signal_handling(void)
+ {
+-    const int signals[] = {SIGINT, SIGTERM, SIGQUIT};
+-    static struct event sigevs[LGTD_ARRAY_SIZE(signals)];
+-
+-    for (int i = 0; i != LGTD_ARRAY_SIZE(signals); i++) {
+-        evsignal_assign(
+-            &sigevs[i],
+-            lgtd_ev_base,
+-            signals[i],
+-            lgtd_signal_event_callback,
+-            &sigevs[i]
++    for (intptr_t i = 0; i != LGTD_ARRAY_SIZE(lgtd_signals); i++) {
++        lgtd_signal_evs[i] = evsignal_new(
++            // event_self_cbarg() would make things cleaner, but this was
++            // unfortunately added in libevent 2.1 which hasn't been released
++            // as of 2016:
++            lgtd_ev_base, lgtd_signals[i], lgtd_signal_event_callback, (void *)i
+         );
+-        evsignal_add(&sigevs[i], NULL);
++        if (!lgtd_signal_evs[i] || evsignal_add(lgtd_signal_evs[i], NULL)) {
++            lgtd_err(1, "can't configure signal handling");
++        }
+     }
+ 
+     struct sigaction act = { .sa_handler = SIG_IGN };
+@@ -149,6 +128,15 @@
+ }
+ 
+ static void
++lgtd_close_signal_handling(void)
++{
++    for (int i = 0; i != LGTD_ARRAY_SIZE(lgtd_signals); i++) {
++        event_del(lgtd_signal_evs[i]);
++        event_free(lgtd_signal_evs[i]);
++    }
++}
++
++static void
+ lgtd_usage(const char *progname)
+ {
+     printf(
+@@ -186,6 +174,26 @@
+     exit(0);
+ }
+ 
++void
++lgtd_cleanup(void)
++{
++    lgtd_lifx_discovery_close();
++    lgtd_listen_close_all();
++    lgtd_command_pipe_close_all();
++    lgtd_client_close_all();
++    lgtd_lifx_broadcast_close();
++    lgtd_lifx_gateway_close_all();
++    lgtd_timer_stop_all();
++    lgtd_close_signal_handling();
++    event_base_free(lgtd_ev_base);
++#if LIBEVENT_VERSION_NUMBER >= 0x02010100
++    libevent_global_shutdown();
++#endif
++    if (lgtd_opts.pidfile) {
++        unlink(lgtd_opts.pidfile);
++    }
++}
++
+ int
+ main(int argc, char *argv[], char *envp[])
+ {
+@@ -195,7 +203,7 @@
+     lgtd_daemon_setup_proctitle(argc, argv, envp);
+ 
+     lgtd_configure_libevent();
+-    lgtd_configure_signal_handling();
++    lgtd_setup_signal_handling();
+ 
+     static const struct option long_opts[] = {
+         {"listen",          required_argument, NULL, 'l'},
--- a/network_discovery.patch	Tue Dec 29 18:40:32 2015 +0100
+++ b/network_discovery.patch	Thu Dec 31 10:14:10 2015 +0100
@@ -1,6 +1,172 @@
 # HG changeset patch
-# Parent  bfa59be534ab65b5caff5b25d70a1d9fa961bfbb
-Discover NICs connect to LANs and only discover bulbs on those
+# Parent  2f53e91d85172265ef669ad34b90677f25e25d43
+Properly broadcast LIFX discovery packets on all networks (closes GH-2)
+
+It does solve the issue but only is half the solution I'd like to have.
+
+This is really the proper way of achieving the same semantic as
+broadcasting to 255.255.255.255 and is kinda half the solution only.
+What I'd like to add is:
+
+- bind to all local-only networks (right now lightsd binds on 0.0.0.0);
+- watch for network interfaces changes so we can re-bind if necessary,
+  this is really the hard and annoying part as each OS has its own
+  mechanism for this and some (e.g: BSDs) don't even have it AFAIK.
+
+So that people running lightsd on a machine connected to Internet (that
+can happen quickly on a laptop or a phone/tabled) don't have to firewall
+56700.
 
-Closes GH-2.
-
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -4,8 +4,8 @@
+ PROJECT(LIGHTSD C)
+ 
+ SET(CPACK_PACKAGE_VERSION_MAJOR "1")
+-SET(CPACK_PACKAGE_VERSION_MINOR "1")
+-SET(CPACK_PACKAGE_VERSION_PATCH "3")
++SET(CPACK_PACKAGE_VERSION_MINOR "2")
++SET(CPACK_PACKAGE_VERSION_PATCH "0")
+ SET(LIGHTSD_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+ 
+ MESSAGE(STATUS "lightsd version: ${LIGHTSD_VERSION}")
+diff --git a/lifx/broadcast.c b/lifx/broadcast.c
+--- a/lifx/broadcast.c
++++ b/lifx/broadcast.c
+@@ -17,11 +17,14 @@
+ 
+ #include <sys/queue.h>
+ #include <sys/tree.h>
++#include <sys/socket.h>
+ #include <arpa/inet.h>
++#include <net/if.h>
+ #include <assert.h>
+ #include <endian.h>
+ #include <err.h>
+ #include <errno.h>
++#include <ifaddrs.h>
+ #include <stdarg.h>
+ #include <stdbool.h>
+ #include <stdint.h>
+@@ -51,16 +54,35 @@
+ };
+ 
+ static bool
++lgtd_lifx_broadcast_send_packet(void *pkt,
++                                int pkt_sz,
++                                const struct sockaddr *addr,
++                                ev_socklen_t addrlen)
++{
++    char addr_str[INET6_ADDRSTRLEN];
++    LGTD_SOCKADDRTOA(addr, addr_str);
++    lgtd_debug("broadcasting LIFX discovery packet on %s", addr_str);
++
++    int nbytes, socket = lgtd_lifx_broadcast_endpoint.socket;
++    do {
++        nbytes = sendto(socket, pkt, pkt_sz, 0, addr, addrlen);
++    } while (nbytes == -1 && EVUTIL_SOCKET_ERROR() == EINTR);
++
++    if (nbytes != pkt_sz) {
++        lgtd_warn("couldn't broadcast LIFX discovery packet on %s", addr_str);
++        return false;
++    }
++
++    return true;
++}
++
++static bool
+ lgtd_lifx_broadcast_handle_write(void)
+ {
+     assert(lgtd_lifx_broadcast_endpoint.socket != -1);
+ 
+-    struct sockaddr_in lifx_addr = {
+-        .sin_family = AF_INET,
+-        .sin_addr = { INADDR_BROADCAST },
+-        .sin_port = htons(LGTD_LIFX_PROTOCOL_PORT),
+-        .sin_zero = { 0 }
+-    };
++    uint16_t lifx_port = htons(LGTD_LIFX_PROTOCOL_PORT);
++
+     struct lgtd_lifx_packet_header get_pan_gateway;
+     lgtd_lifx_wire_setup_header(
+         &get_pan_gateway,
+@@ -70,31 +92,56 @@
+         LGTD_LIFX_GET_PAN_GATEWAY
+     );
+ 
+-    int nbytes;
+-retry:
+-    nbytes = sendto(
+-        lgtd_lifx_broadcast_endpoint.socket,
+-        (void *)&get_pan_gateway,
+-        sizeof(get_pan_gateway),
+-        0,
+-        (const struct sockaddr *)&lifx_addr,
+-        sizeof(lifx_addr)
+-    );
+-    if (nbytes == sizeof(get_pan_gateway)) {
+-        if (event_del(lgtd_lifx_broadcast_endpoint.write_ev)) {
+-            lgtd_err(1, "can't setup events");
++    bool ok = true;
++    struct ifaddrs *ifaddrs = NULL;
++    if (getifaddrs(&ifaddrs)) {
++        struct sockaddr_in lifx_bcast_addr = {
++            .sin_family = AF_INET,
++            .sin_addr = { INADDR_BROADCAST },
++            .sin_port = lifx_port,
++            .sin_zero = { 0 }
++        };
++        char addr_str[INET6_ADDRSTRLEN];
++        lgtd_warn(
++            "can't fetch the list of network interfaces, falling back on %s",
++            LGTD_SOCKADDRTOA((struct sockaddr *)&lifx_bcast_addr, addr_str)
++        );
++        ok = lgtd_lifx_broadcast_send_packet(
++            &get_pan_gateway,
++            sizeof(get_pan_gateway),
++            (struct sockaddr *)&lifx_bcast_addr,
++            sizeof(lifx_bcast_addr)
++        );
++    } else {
++        for (struct ifaddrs *ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
++            if (ifa->ifa_broadaddr != NULL
++                && (ifa->ifa_flags & IFF_BROADCAST)
++                && ifa->ifa_netmask != NULL) {
++                ev_socklen_t addrlen;
++                struct sockaddr *addr = ifa->ifa_broadaddr;
++                if (addr->sa_family == AF_INET) {
++                    ((struct sockaddr_in *)addr)->sin_port = lifx_port;
++                    addrlen = sizeof(struct sockaddr_in);
++                } else if (addr->sa_family == AF_INET6) {
++                    // TODO: add support for IPv6 on the receive path.
++                    ((struct sockaddr_in6 *)addr)->sin6_port = lifx_port;
++                    addrlen = sizeof(struct sockaddr_in6);
++                } else {
++                    continue;
++                }
++                ok = ok || lgtd_lifx_broadcast_send_packet(
++                    &get_pan_gateway, sizeof(get_pan_gateway), addr, addrlen
++                );
++            }
+         }
+-        return true;
++        freeifaddrs(ifaddrs);
+     }
+-    if (nbytes == -1) {
+-        if (EVUTIL_SOCKET_ERROR() == EINTR) {
+-            goto retry;
+-        }
+-        lgtd_warn("can't broadcast discovery packet");
+-    } else {
+-        lgtd_warnx("can't broadcast discovery packet");
++
++    if (ok && event_del(lgtd_lifx_broadcast_endpoint.write_ev)) {
++        lgtd_err(1, "can't setup events");
+     }
+-    return false;
++
++    return ok;
+ }
+ 
+ static void
--- a/optional_jsonrpc_args.patch	Tue Dec 29 18:40:32 2015 +0100
+++ b/optional_jsonrpc_args.patch	Thu Dec 31 10:14:10 2015 +0100
@@ -2,6 +2,20 @@
 # Parent  bfa59be534ab65b5caff5b25d70a1d9fa961bfbb
 Correctly support optional arguments in the JSON-RPC API
 
+Passing too many arguments as an array also properly fails now.
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -5,7 +5,7 @@
+ 
+ SET(CPACK_PACKAGE_VERSION_MAJOR "1")
+ SET(CPACK_PACKAGE_VERSION_MINOR "1")
+-SET(CPACK_PACKAGE_VERSION_PATCH "2")
++SET(CPACK_PACKAGE_VERSION_PATCH "3")
+ SET(LIGHTSD_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+ 
+ MESSAGE(STATUS "lightsd version: ${LIGHTSD_VERSION}")
 diff --git a/core/jsonrpc.c b/core/jsonrpc.c
 --- a/core/jsonrpc.c
 +++ b/core/jsonrpc.c
--- a/series	Tue Dec 29 18:40:32 2015 +0100
+++ b/series	Thu Dec 31 10:14:10 2015 +0100
@@ -1,6 +1,8 @@
+doc_semver.patch
 optional_jsonrpc_args.patch
+network_discovery.patch
+dont_use_ev_assign.patch
 add_power_transition.patch
-network_discovery.patch
 make_gateway_write_callbacks_low_priority.patch #+future
 use_echo_request_reply_to_measure_latency.patch #+future
 add_ipv4_to_ieee8023mac.patch #+future #+linux