ntpd plugin
authorSamuel Ortiz <sameo@linux.intel.com>
Mon, 31 May 2010 13:09:28 +0000 (15:09 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Mon, 31 May 2010 15:39:56 +0000 (17:39 +0200)
The ntpd plugin triggers an ntpd -q task whenever a service goes online.
It either uses the meego ntp service or the one it potentially fetches
from a DHCP response.

Makefile.am
Makefile.plugins
configure.ac
plugins/ntpd.c [new file with mode: 0644]
src/service.c

index 511f088..0e98e8b 100644 (file)
@@ -186,6 +186,7 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-gtk-doc \
                                --enable-client \
                                --enable-portal \
                                --enable-hh2serial-gps \
+                               --enable-ntpd \
                                --enable-tools
 
 DISTCLEANFILES = $(pkgconfig_DATA)
index 0748c3e..7df46a4 100644 (file)
@@ -249,6 +249,18 @@ script_PROGRAMS += scripts/dhclient-script
 scripts_dhclient_script_LDADD = @DBUS_LIBS@
 endif
 
+if NTPD
+if NTPD_BUILTIN
+builtin_modules += ntpd
+builtin_sources += plugins/ntpd.c
+builtin_cflags += -DNTPD=\"@NTPD@\"
+else
+plugin_LTLIBRARIES += plugins/ntpd.la
+plugin_objects += $(plugins_ntpd_la_OBJECTS)
+plugins_ntpd_la_CFLAGS = $(plugin_cflags) -DNTPD=\"@NTPD@\"
+plugins_ntpd_la_LDFLAGS = $(plugin_ldflags)
+endif
+endif
 
 EXTRA_DIST += plugins/polkit.policy scripts/dhclient.conf
 
index fc0c519..13c1a3a 100644 (file)
@@ -280,6 +280,24 @@ AC_ARG_ENABLE(iospm, AC_HELP_STRING([--enable-iospm],
                [enable Intel OSPM support]), [enable_iospm=${enableval}])
 AM_CONDITIONAL(IOSPM, test "${enable_iospm}" = "yes")
 
+AC_ARG_WITH(ntpd, AC_HELP_STRING([--with-=PROGRAM],
+       [specify ntpd binary location]), [path_ntpd=${withval}])
+
+AC_ARG_ENABLE(ntpd,
+       AC_HELP_STRING([--enable-ntpd], [enable ntpd support]),
+                       [enable_ntpd=${enableval}], [enable_ntpd="no"])
+
+if (test "${enable_ntpd}" != "no"); then
+       if (test -z "${path_ntpd}"); then
+               AC_PATH_PROG(NTPD, [ntpd], [], $PATH:/sbin:/usr/sbin)
+       else
+               NTPD="${path_ntpd}"
+               AC_SUBST(NTPD)
+       fi
+fi
+AM_CONDITIONAL(NTPD, test "${enable_ntpd}" != "no")
+AM_CONDITIONAL(NTPD_BUILTIN, test "${enable_ntpd}" = "builtin")
+
 PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
                                AC_MSG_ERROR(GLib >= 2.16 is required))
 AC_SUBST(GLIB_CFLAGS)
diff --git a/plugins/ntpd.c b/plugins/ntpd.c
new file mode 100644 (file)
index 0000000..ce14027
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#define CONNMAN_API_SUBJECT_TO_CHANGE
+#include <connman/plugin.h>
+#include <connman/task.h>
+#include <connman/timeserver.h>
+#include <connman/driver.h>
+#include <connman/log.h>
+
+/*
+ * The peers list are the peers currently added to a running ntpd,
+ * while pending_peers are the one appended but not used by ntpd yet.
+ */
+static GList *peers = NULL;
+static GList *pending_peers = NULL;
+
+#define NTPD_PORT 123
+#define DEFAULT_NTP_PEER "ntp.meego.com"
+
+struct ntpdate_task {
+       struct connman_task *task;
+       gint conf_fd;
+       char *conf_path;
+};
+
+static connman_bool_t ntpd_running(void)
+{
+       int sock;
+       connman_bool_t ret;
+       struct sockaddr_in server_addr;
+
+       if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               return FALSE;
+
+       server_addr.sin_family = AF_INET;
+        server_addr.sin_port = htons(NTPD_PORT);
+        server_addr.sin_addr.s_addr = INADDR_ANY;
+        memset(&(server_addr.sin_zero), 0, 8);
+
+       if (bind(sock, (struct sockaddr *)&server_addr,
+                       sizeof(struct sockaddr)) == -1) {
+               if (errno == EADDRINUSE)
+                       ret = TRUE;
+               else
+                       ret = FALSE;
+        }
+
+       close(sock);
+
+       return ret;
+}
+
+static void ntpdate_died(struct connman_task *task, void *user_data)
+{
+       struct ntpdate_task *ntpdate = user_data;
+
+       DBG("");
+
+       unlink(ntpdate->conf_path);
+       g_free(ntpdate->conf_path);
+       connman_task_destroy(ntpdate->task);
+}
+
+static void ntpdate_add_peer(struct ntpdate_task *ntpdate, char *peer)
+{
+       FILE *conf_file;
+
+       DBG("%s", peer);
+
+       conf_file = fdopen(ntpdate->conf_fd, "a+");
+       if (conf_file == NULL) {
+               connman_error("fdopen failed");
+               return;
+       }
+
+       fprintf(conf_file, "server %s iburst\n", peer);
+
+       fclose(conf_file);
+}
+
+static int ntpdate(void)
+{
+       int err;
+       GError *g_err;
+       GList *list;
+       struct ntpdate_task *ntpdate;
+
+       DBG("");
+
+       ntpdate = g_try_new0(struct ntpdate_task, 1);
+       if (ntpdate == NULL)
+               return -ENOMEM;
+
+       /* ntpdate is deprecated, we use ntpd -q instead */
+       ntpdate->task = connman_task_create(NTPD);
+       if (ntpdate->task == NULL) {
+               err = -ENOMEM;
+               goto error_task;
+       }
+
+       connman_task_add_argument(ntpdate->task, "-q", NULL);
+
+       /* The servers are added through a temp configuration file */
+       ntpdate->conf_fd = g_file_open_tmp("connman.ntp.conf_XXXXXX",
+                                               &ntpdate->conf_path, &g_err);
+       if  (ntpdate->conf_fd == -1) {
+               err = g_err->code;
+               g_free(g_err);
+               goto error_open;
+       }
+
+       connman_task_add_argument(ntpdate->task, "-c", ntpdate->conf_path);
+
+       DBG("conf path %s", ntpdate->conf_path);
+
+       if (pending_peers == NULL && peers == NULL)
+               ntpdate_add_peer(ntpdate, DEFAULT_NTP_PEER);
+
+       for (list = pending_peers; list; list = list->next)
+               ntpdate_add_peer(ntpdate, list->data);
+
+       for (list = peers; list; list = list->next)
+               ntpdate_add_peer(ntpdate, list->data);
+
+       close(ntpdate->conf_fd);
+
+       return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
+                                               NULL, NULL, NULL);
+error_open:
+       connman_task_destroy(ntpdate->task);
+
+error_task:
+       g_free(ntpdate);
+
+       return err;
+}
+
+static int ntpd_add_peer(char *peer)
+{
+       DBG("%s", peer);
+
+       return 0;
+}
+
+static void ntpd_sync(void)
+{
+       int err;
+       GList *list;
+
+       DBG("");
+
+       if (!ntpd_running()) {
+               ntpdate();
+               return;
+       }
+
+       /* TODO Grab ntp keys path */
+
+       list = g_list_first(pending_peers);
+       while(list) {
+               char *peer = list->data;
+
+               err = ntpd_add_peer(peer);
+               if (err)
+                       continue;
+
+               peers = g_list_prepend(peers, peer);
+
+               list = g_list_next(list);
+
+               pending_peers = g_list_remove(pending_peers, peer);
+       };
+}
+
+static int ntpd_append(char *server)
+{
+       DBG("");
+
+       pending_peers = g_list_prepend(pending_peers, server);
+
+       return 0;
+}
+
+static int ntpd_remove(char *server)
+{
+       DBG("");
+
+       peers = g_list_remove(peers, server);
+       /* TODO: send ntpd remove command */
+
+       pending_peers = g_list_remove(pending_peers, server);
+
+       return 0;
+}
+
+static struct connman_timeserver_driver ntpd_driver = {
+       .name           = "ntpd",
+       .priority       = CONNMAN_DRIVER_PRIORITY_DEFAULT,
+       .append         = ntpd_append,
+       .remove         = ntpd_remove,
+       .sync           = ntpd_sync,
+};
+
+static int ntpd_init(void)
+{
+       return connman_timeserver_driver_register(&ntpd_driver);
+}
+
+static void ntpd_exit(void)
+{
+       connman_timeserver_driver_unregister(&ntpd_driver);
+}
+
+CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
+               CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)
index d9d3faf..1d4cde3 100644 (file)
@@ -1901,6 +1901,9 @@ int __connman_service_indicate_state(struct connman_service *service,
        service->state = state;
        state_changed(service);
 
+       if (state == CONNMAN_SERVICE_STATE_ONLINE)
+               connman_timeserver_sync();
+
        if (state == CONNMAN_SERVICE_STATE_IDLE) {
                connman_bool_t reconnect;