5 * Copyright (C) 2015 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 <dbus/dbus.h>
34 #include <connman/dbus.h>
36 static DBusConnection *connection;
37 static GMainLoop *main_loop;
38 static int timeout = 0;
39 static int exit_value = 0;
41 static gboolean option_version = FALSE;
42 static gchar *option_interface = NULL;
43 static gchar *option_ignore = NULL;
44 static gint option_timeout = 120;
51 static GOptionEntry options[] = {
52 { "interface", 'i', 0, G_OPTION_ARG_STRING, &option_interface,
53 "Specify networking device or interface", "DEV" },
54 { "ignore", 'I', 0, G_OPTION_ARG_STRING, &option_ignore,
55 "Specify networking device or interface to ignore", "DEV" },
56 { "timeout", 0, 0, G_OPTION_ARG_INT, &option_timeout,
57 "Time to wait for network going online. Default is 120 seconds.",
59 { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
60 "Show version information and exit" },
64 static bool compare_interface(const char *interface, struct devices *devices)
68 if (!interface || !devices)
71 for (i = 0; devices->ignore && devices->ignore[i]; i++)
72 if (!strcmp(interface, devices->ignore[i]))
75 if (!devices->interface)
78 for (i = 0; devices->interface[i]; i++)
79 if (!strcmp(interface, devices->interface[i]))
85 static bool state_online(DBusMessageIter *iter)
88 DBusMessageIter variant;
90 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
93 dbus_message_iter_get_basic(iter, &str);
94 if (strcmp(str, "State"))
97 dbus_message_iter_next(iter);
99 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
102 dbus_message_iter_recurse(iter, &variant);
104 if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_STRING)
107 dbus_message_iter_get_basic(&variant, &str);
108 if (strcmp(str, "ready") && strcmp(str, "online"))
114 static bool service_properties_online(DBusMessageIter *array_entry,
115 struct devices *devices)
117 bool interface = !devices;
119 DBusMessageIter dict, dict_entry, variant, eth_array, eth_dict,
123 for (dbus_message_iter_recurse(array_entry, &dict);
124 dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY;
125 dbus_message_iter_next(&dict)) {
127 dbus_message_iter_recurse(&dict, &dict_entry);
128 if (dbus_message_iter_get_arg_type(&dict_entry)
132 if (state_online(&dict_entry)) {
137 dbus_message_iter_recurse(&dict, &dict_entry);
139 dbus_message_iter_get_basic(&dict_entry, &str);
141 if (devices && !strcmp(str, "Ethernet")) {
142 dbus_message_iter_next(&dict_entry);
144 if (dbus_message_iter_get_arg_type(&dict_entry)
145 != DBUS_TYPE_VARIANT)
148 dbus_message_iter_recurse(&dict_entry, &variant);
149 if (dbus_message_iter_get_arg_type(&variant)
153 for (dbus_message_iter_recurse(&variant, ð_array);
154 dbus_message_iter_get_arg_type(ð_array)
155 == DBUS_TYPE_DICT_ENTRY;
156 dbus_message_iter_next(ð_array)) {
158 dbus_message_iter_recurse(ð_array, ð_dict);
160 if (dbus_message_iter_get_arg_type(ð_dict)
164 dbus_message_iter_get_basic(ð_dict, &str);
165 if (!strcmp(str, "Interface")) {
167 dbus_message_iter_next(ð_dict);
168 if (dbus_message_iter_get_arg_type(ð_dict)
169 != DBUS_TYPE_VARIANT)
172 dbus_message_iter_recurse(ð_dict,
174 if (dbus_message_iter_get_arg_type(ð_variant)
178 dbus_message_iter_get_basic(ð_variant,
180 interface = compare_interface(str,
188 if (state && interface) {
189 g_main_loop_quit(main_loop);
197 static void services_dict_online(DBusMessageIter *iter, struct devices *devices)
199 DBusMessageIter array, array_entry;
201 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
204 for (dbus_message_iter_recurse(iter, &array);
205 dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT;
206 dbus_message_iter_next(&array)) {
208 dbus_message_iter_recurse(&array, &array_entry);
210 if (dbus_message_iter_get_arg_type(&array_entry) !=
211 DBUS_TYPE_OBJECT_PATH)
214 dbus_message_iter_next(&array_entry);
216 if (dbus_message_iter_get_arg_type(&array_entry) !=
220 if (service_properties_online(&array_entry, devices))
225 static void manager_get_services_return(DBusPendingCall *call,
228 struct devices *devices = user_data;
230 DBusMessageIter iter;
232 reply = dbus_pending_call_steal_reply(call);
233 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
236 if (!dbus_message_iter_init(reply, &iter))
239 services_dict_online(&iter, devices);
242 dbus_message_unref(reply);
243 dbus_pending_call_unref(call);
246 static void manager_get_services(struct devices *devices)
248 DBusMessage *message;
249 DBusPendingCall *call;
251 message = dbus_message_new_method_call(CONNMAN_SERVICE,
252 CONNMAN_MANAGER_PATH,
253 CONNMAN_MANAGER_INTERFACE,
258 if (!dbus_connection_send_with_reply(connection, message, &call, -1))
264 dbus_pending_call_set_notify(call, manager_get_services_return,
268 dbus_message_unref(message);
271 static void manager_properties_online(DBusMessageIter *iter,
272 struct devices *devices)
274 DBusMessageIter array, dict_entry;
276 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
279 for (dbus_message_iter_recurse(iter, &array);
280 dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY;
281 dbus_message_iter_next(&array)) {
283 dbus_message_iter_recurse(&array, &dict_entry);
285 if (state_online(&dict_entry)) {
287 manager_get_services(devices);
289 g_main_loop_quit(main_loop);
296 static void manager_get_properties_return(DBusPendingCall *call, void *user_data)
298 struct devices *devices = user_data;
300 DBusMessageIter iter;
302 reply = dbus_pending_call_steal_reply(call);
303 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
306 if (!dbus_message_iter_init(reply, &iter))
309 manager_properties_online(&iter, devices);
312 dbus_message_unref(reply);
313 dbus_pending_call_unref(call);
316 static void manager_get_properties(struct devices *devices)
318 DBusMessage *message;
319 DBusPendingCall *call;
321 message = dbus_message_new_method_call(CONNMAN_SERVICE,
322 CONNMAN_MANAGER_PATH,
323 CONNMAN_MANAGER_INTERFACE,
328 if (!dbus_connection_send_with_reply(connection, message, &call, -1))
334 dbus_pending_call_set_notify(call, manager_get_properties_return,
338 dbus_message_unref(message);
341 static DBusHandlerResult manager_property_changed(DBusConnection *connection,
342 DBusMessage *message, void *user_data)
344 struct devices *devices = user_data;
345 DBusMessageIter iter;
347 if (dbus_message_is_signal(message, CONNMAN_MANAGER_INTERFACE,
348 "PropertyChanged")) {
349 dbus_message_iter_init(message, &iter);
351 if (state_online(&iter)) {
353 manager_get_services(devices);
355 g_main_loop_quit(main_loop);
359 return DBUS_HANDLER_RESULT_HANDLED;
362 static gboolean timeout_triggered(gpointer user_data)
364 exit_value = -ETIMEDOUT;
365 g_main_loop_quit(main_loop);
371 int main(int argc, char *argv[])
373 const char *filter = "type='signal',interface='"
374 CONNMAN_MANAGER_INTERFACE "'";
376 GError *g_err = NULL;
377 struct devices devices = { NULL, NULL };
379 GOptionContext *context;
381 context = g_option_context_new(NULL);
382 g_option_context_add_main_entries(context, options, NULL);
384 if (!g_option_context_parse(context, &argc, &argv, &g_err)) {
386 fprintf(stderr, "%s\n", g_err->message);
389 fprintf(stderr, "An unknown error occurred\n");
394 g_option_context_free(context);
396 if (option_interface) {
397 devices.interface = g_strsplit(option_interface, ",", -1);
398 g_free(option_interface);
402 devices.ignore = g_strsplit(option_ignore, ",", -1);
403 g_free(option_ignore);
406 if (option_version) {
407 fprintf(stdout, "%s\n", VERSION);
411 dbus_error_init(&dbus_err);
412 connection = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &dbus_err);
414 if (dbus_error_is_set(&dbus_err)) {
415 fprintf(stderr, "Error: %s\n", dbus_err.message);
421 main_loop = g_main_loop_new(NULL, FALSE);
423 dbus_connection_add_filter(connection, manager_property_changed,
426 dbus_bus_add_match(connection, filter, &dbus_err);
428 if (dbus_error_is_set(&dbus_err)) {
429 fprintf(stderr, "Error: %s\n", dbus_err.message);
436 timeout = g_timeout_add_seconds(option_timeout,
437 timeout_triggered, NULL);
439 manager_get_properties(&devices);
441 g_main_loop_run(main_loop);
445 dbus_bus_remove_match(connection, filter, NULL);
446 dbus_connection_remove_filter(connection, manager_property_changed,
449 dbus_connection_unref(connection);
450 g_main_loop_unref(main_loop);
453 dbus_error_free(&dbus_err);
455 g_strfreev(devices.interface);
456 g_strfreev(devices.ignore);
458 g_source_remove(timeout);