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;
55 struct connman_task *task;
60 static struct ntpd_peer *find_peer(GList *peer_list, const char* server)
63 struct ntpd_peer *peer;
65 for (list = peer_list; list; list = list->next) {
68 if (g_str_equal(peer->server, server))
75 static void remove_peer(GList *peer_list, struct ntpd_peer *peer)
77 if (!g_atomic_int_dec_and_test(&peer->refcount))
82 peer_list = g_list_remove(peer_list, peer);
85 static connman_bool_t ntpd_running(void)
89 struct sockaddr_in server_addr;
91 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
94 server_addr.sin_family = AF_INET;
95 server_addr.sin_port = htons(NTPD_PORT);
96 server_addr.sin_addr.s_addr = INADDR_ANY;
97 memset(&(server_addr.sin_zero), 0, 8);
99 if (bind(sock, (struct sockaddr *)&server_addr,
100 sizeof(struct sockaddr)) == -1) {
101 if (errno == EADDRINUSE)
112 static void ntpdate_died(struct connman_task *task, void *user_data)
114 struct ntpdate_task *ntpdate = user_data;
118 unlink(ntpdate->conf_path);
119 g_free(ntpdate->conf_path);
120 connman_task_destroy(ntpdate->task);
123 static void ntpdate_add_peer(struct ntpdate_task *ntpdate, char *peer)
129 conf_file = fdopen(ntpdate->conf_fd, "a+");
130 if (conf_file == NULL) {
131 connman_error("fdopen failed");
135 fprintf(conf_file, "server %s iburst\n", peer);
140 static int ntpdate(void)
145 struct ntpd_peer *peer;
146 struct ntpdate_task *ntpdate;
150 ntpdate = g_try_new0(struct ntpdate_task, 1);
154 /* ntpdate is deprecated, we use ntpd -q instead */
155 ntpdate->task = connman_task_create(NTPD);
156 if (ntpdate->task == NULL) {
161 connman_task_add_argument(ntpdate->task, "-g", 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 for (list = pending_peers; list; list = list->next) {
180 ntpdate_add_peer(ntpdate, peer->server);
183 for (list = peers; list; list = list->next) {
186 ntpdate_add_peer(ntpdate, peer->server);
189 close(ntpdate->conf_fd);
191 return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
194 connman_task_destroy(ntpdate->task);
202 static int ntpd_add_peer(char *peer)
209 static void ntpd_sync(void)
216 if (g_list_length(pending_peers) == 0 &&
217 g_list_length(peers) == 0)
220 if (!ntpd_running()) {
225 /* TODO Grab ntp keys path */
227 list = g_list_first(pending_peers);
229 struct ntpd_peer *peer = list->data;
231 err = ntpd_add_peer(peer->server);
235 peers = g_list_prepend(peers, peer);
237 list = g_list_next(list);
239 pending_peers = g_list_remove(pending_peers, peer);
243 static int ntpd_append(const char *server)
245 struct ntpd_peer *peer;
252 if ((peer = find_peer(pending_peers, server)) ||
253 (peer = find_peer(peers, server))) {
254 g_atomic_int_inc(&peer->refcount);
258 peer = g_try_new0(struct ntpd_peer, 1);
262 peer->server = g_strdup(server);
263 if (peer->server == NULL) {
270 pending_peers = g_list_prepend(pending_peers, peer);
275 static int ntpd_remove(const char *server)
277 struct ntpd_peer *peer;
284 peer = find_peer(peers, server);
288 remove_peer(peers, peer);
291 /* TODO: send ntpd remove command */
293 peer = find_peer(pending_peers, server);
297 remove_peer(pending_peers, peer);
302 static struct connman_timeserver_driver ntpd_driver = {
304 .priority = CONNMAN_DRIVER_PRIORITY_DEFAULT,
305 .append = ntpd_append,
306 .remove = ntpd_remove,
310 static int ntpd_init(void)
312 return connman_timeserver_driver_register(&ntpd_driver);
315 static void ntpd_exit(void)
317 connman_timeserver_driver_unregister(&ntpd_driver);
320 CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
321 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)