5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <arpa/inet.h>
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/task.h>
36 #include <connman/timeserver.h>
37 #include <connman/driver.h>
38 #include <connman/log.h>
41 * The peers list are the peers currently added to a running ntpd,
42 * while pending_peers are the one appended but not used by ntpd yet.
44 static GList *peers = NULL;
45 static GList *pending_peers = NULL;
48 #define DEFAULT_NTP_PEER "ntp.meego.com"
56 struct connman_task *task;
61 static struct ntpd_peer *find_peer(GList *peer_list, const char* server)
64 struct ntpd_peer *peer;
66 for (list = peer_list; list; list = list->next) {
69 if (g_str_equal(peer->server, server))
76 static void remove_peer(GList *peer_list, struct ntpd_peer *peer)
78 if (!g_atomic_int_dec_and_test(&peer->refcount))
83 peer_list = g_list_remove(peer_list, peer);
86 static connman_bool_t ntpd_running(void)
90 struct sockaddr_in server_addr;
92 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
95 server_addr.sin_family = AF_INET;
96 server_addr.sin_port = htons(NTPD_PORT);
97 server_addr.sin_addr.s_addr = INADDR_ANY;
98 memset(&(server_addr.sin_zero), 0, 8);
100 if (bind(sock, (struct sockaddr *)&server_addr,
101 sizeof(struct sockaddr)) == -1) {
102 if (errno == EADDRINUSE)
113 static void ntpdate_died(struct connman_task *task, void *user_data)
115 struct ntpdate_task *ntpdate = user_data;
119 unlink(ntpdate->conf_path);
120 g_free(ntpdate->conf_path);
121 connman_task_destroy(ntpdate->task);
124 static void ntpdate_add_peer(struct ntpdate_task *ntpdate, char *peer)
130 conf_file = fdopen(ntpdate->conf_fd, "a+");
131 if (conf_file == NULL) {
132 connman_error("fdopen failed");
136 fprintf(conf_file, "server %s iburst\n", peer);
141 static int ntpdate(void)
146 struct ntpd_peer *peer;
147 struct ntpdate_task *ntpdate;
151 ntpdate = g_try_new0(struct ntpdate_task, 1);
155 /* ntpdate is deprecated, we use ntpd -q instead */
156 ntpdate->task = connman_task_create(NTPD);
157 if (ntpdate->task == NULL) {
162 connman_task_add_argument(ntpdate->task, "-q", NULL);
164 /* The servers are added through a temp configuration file */
165 ntpdate->conf_fd = g_file_open_tmp("connman.ntp.conf_XXXXXX",
166 &ntpdate->conf_path, &g_err);
167 if (ntpdate->conf_fd == -1) {
173 connman_task_add_argument(ntpdate->task, "-c", ntpdate->conf_path);
175 DBG("conf path %s", ntpdate->conf_path);
177 if (pending_peers == NULL && peers == NULL)
178 ntpdate_add_peer(ntpdate, DEFAULT_NTP_PEER);
180 for (list = pending_peers; list; list = list->next) {
183 ntpdate_add_peer(ntpdate, peer->server);
186 for (list = peers; list; list = list->next) {
189 ntpdate_add_peer(ntpdate, peer->server);
192 close(ntpdate->conf_fd);
194 return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
197 connman_task_destroy(ntpdate->task);
205 static int ntpd_add_peer(char *peer)
212 static void ntpd_sync(void)
219 if (!ntpd_running()) {
224 /* TODO Grab ntp keys path */
226 list = g_list_first(pending_peers);
228 struct ntpd_peer *peer = list->data;
230 err = ntpd_add_peer(peer->server);
234 peers = g_list_prepend(peers, peer);
236 list = g_list_next(list);
238 pending_peers = g_list_remove(pending_peers, peer);
242 static int ntpd_append(const char *server)
244 struct ntpd_peer *peer;
251 if ((peer = find_peer(pending_peers, server)) ||
252 (peer = find_peer(peers, server))) {
253 g_atomic_int_inc(&peer->refcount);
257 peer = g_try_new0(struct ntpd_peer, 1);
261 peer->server = g_strdup(server);
262 if (peer->server == NULL) {
269 pending_peers = g_list_prepend(pending_peers, peer);
274 static int ntpd_remove(const char *server)
276 struct ntpd_peer *peer;
283 peer = find_peer(peers, server);
287 remove_peer(peers, peer);
290 /* TODO: send ntpd remove command */
292 peer = find_peer(pending_peers, server);
296 remove_peer(pending_peers, peer);
301 static struct connman_timeserver_driver ntpd_driver = {
303 .priority = CONNMAN_DRIVER_PRIORITY_DEFAULT,
304 .append = ntpd_append,
305 .remove = ntpd_remove,
309 static int ntpd_init(void)
311 return connman_timeserver_driver_register(&ntpd_driver);
314 static void ntpd_exit(void)
316 connman_timeserver_driver_unregister(&ntpd_driver);
319 CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
320 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)