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,
113 int exit_code, 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, "-g", NULL);
163 connman_task_add_argument(ntpdate->task, "-q", NULL);
165 /* The servers are added through a temp configuration file */
166 ntpdate->conf_fd = g_file_open_tmp("connman.ntp.conf_XXXXXX",
167 &ntpdate->conf_path, &g_err);
168 if (ntpdate->conf_fd == -1) {
174 connman_task_add_argument(ntpdate->task, "-c", ntpdate->conf_path);
176 DBG("conf path %s", ntpdate->conf_path);
178 for (list = pending_peers; list; list = list->next) {
181 ntpdate_add_peer(ntpdate, peer->server);
184 for (list = peers; list; list = list->next) {
187 ntpdate_add_peer(ntpdate, peer->server);
190 close(ntpdate->conf_fd);
192 return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
195 connman_task_destroy(ntpdate->task);
203 static int ntpd_add_peer(char *peer)
210 static void ntpd_sync(void)
217 if (g_list_length(pending_peers) == 0 &&
218 g_list_length(peers) == 0)
221 if (!ntpd_running()) {
226 /* TODO Grab ntp keys path */
228 list = g_list_first(pending_peers);
230 struct ntpd_peer *peer = list->data;
232 err = ntpd_add_peer(peer->server);
236 peers = g_list_prepend(peers, peer);
238 list = g_list_next(list);
240 pending_peers = g_list_remove(pending_peers, peer);
244 static int ntpd_append(const char *server)
246 struct ntpd_peer *peer;
253 if ((peer = find_peer(pending_peers, server)) ||
254 (peer = find_peer(peers, server))) {
255 g_atomic_int_inc(&peer->refcount);
259 peer = g_try_new0(struct ntpd_peer, 1);
263 peer->server = g_strdup(server);
264 if (peer->server == NULL) {
271 pending_peers = g_list_prepend(pending_peers, peer);
276 static int ntpd_remove(const char *server)
278 struct ntpd_peer *peer;
285 peer = find_peer(peers, server);
289 remove_peer(peers, peer);
292 /* TODO: send ntpd remove command */
294 peer = find_peer(pending_peers, server);
298 remove_peer(pending_peers, peer);
303 static struct connman_timeserver_driver ntpd_driver = {
305 .priority = CONNMAN_DRIVER_PRIORITY_DEFAULT,
306 .append = ntpd_append,
307 .remove = ntpd_remove,
311 static int ntpd_init(void)
313 return connman_timeserver_driver_register(&ntpd_driver);
316 static void ntpd_exit(void)
318 connman_timeserver_driver_unregister(&ntpd_driver);
321 CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
322 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)