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)
113 static void ntpdate_died(struct connman_task *task,
114 int exit_code, void *user_data)
116 struct ntpdate_task *ntpdate = user_data;
120 unlink(ntpdate->conf_path);
121 g_free(ntpdate->conf_path);
122 connman_task_destroy(ntpdate->task);
125 static void ntpdate_add_peer(struct ntpdate_task *ntpdate, char *peer)
131 conf_file = fdopen(ntpdate->conf_fd, "a+");
132 if (conf_file == NULL) {
133 connman_error("fdopen failed");
137 fprintf(conf_file, "server %s iburst\n", peer);
142 static int ntpdate(void)
147 struct ntpd_peer *peer;
148 struct ntpdate_task *ntpdate;
152 ntpdate = g_try_new0(struct ntpdate_task, 1);
156 /* ntpdate is deprecated, we use ntpd -q instead */
157 ntpdate->task = connman_task_create(NTPD);
158 if (ntpdate->task == NULL) {
163 connman_task_add_argument(ntpdate->task, "-g", NULL);
164 connman_task_add_argument(ntpdate->task, "-q", NULL);
166 /* The servers are added through a temp configuration file */
167 ntpdate->conf_fd = g_file_open_tmp("connman.ntp.conf_XXXXXX",
168 &ntpdate->conf_path, &g_err);
169 if (ntpdate->conf_fd == -1) {
175 connman_task_add_argument(ntpdate->task, "-c", ntpdate->conf_path);
177 DBG("conf path %s", ntpdate->conf_path);
179 for (list = pending_peers; list; list = list->next) {
182 ntpdate_add_peer(ntpdate, peer->server);
185 for (list = peers; list; list = list->next) {
188 ntpdate_add_peer(ntpdate, peer->server);
191 close(ntpdate->conf_fd);
193 return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
196 connman_task_destroy(ntpdate->task);
204 static int ntpd_add_peer(char *peer)
211 static void ntpd_sync(void)
218 if (g_list_length(pending_peers) == 0 &&
219 g_list_length(peers) == 0)
222 if (!ntpd_running()) {
227 /* TODO Grab ntp keys path */
229 list = g_list_first(pending_peers);
231 struct ntpd_peer *peer = list->data;
233 err = ntpd_add_peer(peer->server);
237 peers = g_list_prepend(peers, peer);
239 list = g_list_next(list);
241 pending_peers = g_list_remove(pending_peers, peer);
245 static int ntpd_append(const char *server)
247 struct ntpd_peer *peer;
254 if ((peer = find_peer(pending_peers, server)) ||
255 (peer = find_peer(peers, server))) {
256 g_atomic_int_inc(&peer->refcount);
260 peer = g_try_new0(struct ntpd_peer, 1);
264 peer->server = g_strdup(server);
265 if (peer->server == NULL) {
272 pending_peers = g_list_prepend(pending_peers, peer);
277 static int ntpd_remove(const char *server)
279 struct ntpd_peer *peer;
286 peer = find_peer(peers, server);
290 remove_peer(peers, peer);
293 /* TODO: send ntpd remove command */
295 peer = find_peer(pending_peers, server);
299 remove_peer(pending_peers, peer);
304 static struct connman_timeserver_driver ntpd_driver = {
306 .priority = CONNMAN_DRIVER_PRIORITY_DEFAULT,
307 .append = ntpd_append,
308 .remove = ntpd_remove,
312 static int ntpd_init(void)
314 return connman_timeserver_driver_register(&ntpd_driver);
317 static void ntpd_exit(void)
319 connman_timeserver_driver_unregister(&ntpd_driver);
322 CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
323 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)