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>
35 #define CONNMAN_API_SUBJECT_TO_CHANGE
36 #include <connman/types.h>
37 #include <connman/plugin.h>
38 #include <connman/task.h>
39 #include <connman/timeserver.h>
40 #include <connman/log.h>
43 * The peers list are the peers currently added to a running ntpd,
44 * while pending_peers are the one appended but not used by ntpd yet.
46 static GList *peers = NULL;
47 static GList *pending_peers = NULL;
57 struct connman_task *task;
62 static struct ntpd_peer *find_peer(GList *peer_list, const char* server)
65 struct ntpd_peer *peer;
67 for (list = peer_list; list; list = list->next) {
70 if (g_str_equal(peer->server, server))
77 static void remove_peer(GList *peer_list, struct ntpd_peer *peer)
79 if (__sync_fetch_and_sub(&peer->refcount, 1) != 1)
84 peer_list = g_list_remove(peer_list, peer);
87 static connman_bool_t ntpd_running(void)
91 struct sockaddr_in server_addr;
93 if ((sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)) == -1)
96 server_addr.sin_family = AF_INET;
97 server_addr.sin_port = htons(NTPD_PORT);
98 server_addr.sin_addr.s_addr = INADDR_ANY;
99 memset(&(server_addr.sin_zero), 0, 8);
101 if (bind(sock, (struct sockaddr *)&server_addr,
102 sizeof(struct sockaddr)) == -1) {
103 if (errno == EADDRINUSE)
115 static void ntpdate_died(struct connman_task *task,
116 int exit_code, void *user_data)
118 struct ntpdate_task *ntpdate = user_data;
122 unlink(ntpdate->conf_path);
123 g_free(ntpdate->conf_path);
124 connman_task_destroy(ntpdate->task);
127 static void ntpdate_add_peer(struct ntpdate_task *ntpdate, char *peer)
133 conf_file = fdopen(ntpdate->conf_fd, "a+");
134 if (conf_file == NULL) {
135 connman_error("fdopen failed");
139 fprintf(conf_file, "server %s iburst\n", peer);
144 static int ntpdate(void)
149 struct ntpd_peer *peer;
150 struct ntpdate_task *ntpdate;
154 ntpdate = g_try_new0(struct ntpdate_task, 1);
158 /* ntpdate is deprecated, we use ntpd -q instead */
159 ntpdate->task = connman_task_create(NTPD);
160 if (ntpdate->task == NULL) {
165 connman_task_add_argument(ntpdate->task, "-g", NULL);
166 connman_task_add_argument(ntpdate->task, "-q", NULL);
168 /* The servers are added through a temp configuration file */
169 ntpdate->conf_fd = g_file_open_tmp("connman.ntp.conf_XXXXXX",
170 &ntpdate->conf_path, &g_err);
171 if (ntpdate->conf_fd == -1) {
177 connman_task_add_argument(ntpdate->task, "-c", ntpdate->conf_path);
179 DBG("conf path %s", ntpdate->conf_path);
181 for (list = pending_peers; list; list = list->next) {
184 ntpdate_add_peer(ntpdate, peer->server);
187 for (list = peers; list; list = list->next) {
190 ntpdate_add_peer(ntpdate, peer->server);
193 close(ntpdate->conf_fd);
195 return connman_task_run(ntpdate->task, ntpdate_died, ntpdate,
198 connman_task_destroy(ntpdate->task);
206 static int ntpd_add_peer(char *peer)
213 static void ntpd_sync(void)
220 if (g_list_length(pending_peers) == 0 &&
221 g_list_length(peers) == 0)
224 if (!ntpd_running()) {
229 /* TODO Grab ntp keys path */
231 list = g_list_first(pending_peers);
233 struct ntpd_peer *peer = list->data;
235 err = ntpd_add_peer(peer->server);
239 peers = g_list_prepend(peers, peer);
241 list = g_list_next(list);
243 pending_peers = g_list_remove(pending_peers, peer);
247 static int ntpd_append(const char *server)
249 struct ntpd_peer *peer;
256 if ((peer = find_peer(pending_peers, server)) ||
257 (peer = find_peer(peers, server))) {
258 __sync_fetch_and_add(&peer->refcount, 1);
262 peer = g_try_new0(struct ntpd_peer, 1);
266 peer->server = g_strdup(server);
267 if (peer->server == NULL) {
274 pending_peers = g_list_prepend(pending_peers, peer);
279 static int ntpd_remove(const char *server)
281 struct ntpd_peer *peer;
288 peer = find_peer(peers, server);
292 remove_peer(peers, peer);
295 /* TODO: send ntpd remove command */
297 peer = find_peer(pending_peers, server);
301 remove_peer(pending_peers, peer);
306 static struct connman_timeserver_driver ntpd_driver = {
308 .priority = CONNMAN_TIMESERVER_PRIORITY_DEFAULT,
309 .append = ntpd_append,
310 .remove = ntpd_remove,
314 static int ntpd_init(void)
316 return connman_timeserver_driver_register(&ntpd_driver);
319 static void ntpd_exit(void)
321 connman_timeserver_driver_unregister(&ntpd_driver);
324 CONNMAN_PLUGIN_DEFINE(ntpd, "ntpd plugin", VERSION,
325 CONNMAN_PLUGIN_PRIORITY_DEFAULT, ntpd_init, ntpd_exit)