Disconnect when same SSID selected (#1)
[dhcpcd-ui] / src / dhcpcd-online / dhcpcd-online.c
index 334960ca4ba98b1464cf49972ebdddeb254a9ac9..6596220de16ad41e6074e8d95891166762f3da35 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * dhcpcd-online
- * Copyright 2014 Roy Marples <roy@marples.name>
+ * Copyright 2014-2015 Roy Marples <roy@marples.name>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 # endif
 #endif
 
+#ifndef timespeccmp
+#define        timespeccmp(tsp, usp, cmp)                                      \
+       (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
+           ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
+           ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif
+#ifndef timespecsub
+#define        timespecsub(tsp, usp, vsp)                                      \
+       do {                                                            \
+               (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;          \
+               (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;       \
+               if ((vsp)->tv_nsec < 0) {                               \
+                       (vsp)->tv_sec--;                                \
+                       (vsp)->tv_nsec += 1000000000L;                  \
+               }                                                       \
+       } while (/* CONSTCOND */ 0)
+#endif
+
+/* Incase we need to pass anything else in context to status cb */
+struct ctx {
+       struct pollfd pollfd;
+};
+
 static void __dead
 do_exit(DHCPCD_CONNECTION *con, int code)
 {
 
+       /* Unregister the status callback so that close doesn't spam. */
+       dhcpcd_set_status_callback(con, NULL, NULL);
+
        dhcpcd_close(con);
        dhcpcd_free(con);
        exit(code);
 }
 
 static void
-do_status_cb(DHCPCD_CONNECTION *con, const char *status, void __unused *arg)
+status_cb(DHCPCD_CONNECTION *con,
+    unsigned int status, const char *status_msg, void *arg)
 {
+       struct ctx *ctx;
 
-       syslog(LOG_INFO, "%s", status);
-       if (strcmp(status, "connected") == 0)
+       syslog(LOG_INFO, "%s", status_msg);
+       switch (status) {
+       case DHC_CONNECTED:
                do_exit(con, EXIT_SUCCESS);
+               /* NOT REACHED */
+       case DHC_DOWN:
+               ctx = arg;
+               ctx->pollfd.fd = -1;
+               break;
+       }
 }
 
 int
@@ -77,7 +112,7 @@ main(int argc, char **argv)
        DHCPCD_CONNECTION *con;
        bool xflag;
        struct timespec now, end, t;
-       struct pollfd pfd;
+       struct ctx ctx;
        int timeout, n, lerrno;
        long lnum;
        char *lend;
@@ -86,6 +121,9 @@ main(int argc, char **argv)
        timeout = 30;
 
        xflag = false;
+       ctx.pollfd.fd = -1;
+       ctx.pollfd.events = POLLIN;
+       ctx.pollfd.revents = 0;
 
        openlog("dhcpcd-online", LOG_PERROR, 0);
        setlogmask(LOG_UPTO(LOG_INFO));
@@ -121,18 +159,15 @@ main(int argc, char **argv)
                syslog(LOG_ERR, "dhcpcd_new: %m");
                return EXIT_FAILURE;
        }
+       dhcpcd_set_status_callback(con, status_cb, &ctx);
 
-       dhcpcd_set_status_callback(con, do_status_cb, NULL);
-
-       if ((pfd.fd = dhcpcd_open(con)) == -1) {
+       if ((ctx.pollfd.fd = dhcpcd_open(con, false)) == -1) {
                lerrno = errno;
                syslog(LOG_WARNING, "dhcpcd_open: %m");
                if (xflag)
                        do_exit(con, EXIT_FAILURE);
        } else
                lerrno = 0;
-       pfd.events = POLLIN;
-       pfd.revents = 0;
 
        /* Work out our timeout time */
        if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
@@ -150,7 +185,7 @@ main(int argc, char **argv)
                        syslog(LOG_ERR, "timed out");
                        do_exit(con, EXIT_FAILURE);
                }
-               if (pfd.fd == -1) {
+               if (ctx.pollfd.fd == -1) {
                        n = poll(NULL, 0, DHCPCD_RETRYOPEN);
                } else {
                        /* poll(2) should really take a timespec */
@@ -160,23 +195,23 @@ main(int argc, char **argv)
                            (t.tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
                                timeout = INT_MAX;
                        else
-                               timeout = (int)t.tv_sec * 1000 +
-                                   (t.tv_nsec + 999999) / 1000000;
-                       n = poll(&pfd, 1, timeout);
+                               timeout = (int)(t.tv_sec * 1000 +
+                                   (t.tv_nsec + 999999) / 1000000);
+                       n = poll(&ctx.pollfd, 1, timeout);
                }
                if (n == -1) {
                        syslog(LOG_ERR, "poll: %m");
                        do_exit(con, EXIT_FAILURE);
                }
-               if (pfd.fd == -1) {
-                       if ((pfd.fd = dhcpcd_open(con)) == -1) {
+               if (ctx.pollfd.fd == -1) {
+                       if ((ctx.pollfd.fd = dhcpcd_open(con, false)) == -1) {
                                if (lerrno != errno) {
                                        lerrno = errno;
                                        syslog(LOG_WARNING, "dhcpcd_open: %m");
                                }
                        }
                } else {
-                       if (n > 0 && pfd.revents)
+                       if (n > 0 && ctx.pollfd.revents)
                                dhcpcd_dispatch(con);
                }
        }