1 #include "dvpnlib-internal.h"
2 #include "dvpnlib-vpn-connection.h"
4 static GList *vpn_connection_list;
5 static GHashTable *vpn_connection_hash;
7 struct connection_property_changed_cb {
8 vpn_connection_property_changed_cb property_changed_cb;
12 struct vpn_connection {
13 GDBusProxy *dbus_proxy;
21 enum vpn_connection_state state;
22 struct vpn_connection_ipv4 *ipv4;
23 struct vpn_connection_ipv6 *ipv6;
25 GSList *user_routes; /*struct vpn_connection_route */
26 GSList *server_routes; /* struct vpn_connection_route */
27 GHashTable *property_changed_cb_hash;
30 static void free_vpn_connection_ipv4(struct vpn_connection_ipv4 *ipv4_info);
31 static void free_vpn_connection_ipv6(struct vpn_connection_ipv6 *ipv6_info);
32 static void free_vpn_connection_route(gpointer data);
35 vpn_connection_set_user_routes(struct vpn_connection *connection,
36 struct vpn_connection_route **user_routes)
38 if (!connection || !user_routes)
39 return DVPNLIB_ERR_INVALID_PARAMETER;
41 GVariantBuilder user_routes_b;
42 GVariant *user_routes_v;
44 g_variant_builder_init(&user_routes_b, G_VARIANT_TYPE("a(a{sv})"));
46 while (*user_routes != NULL) {
48 g_variant_builder_open(&user_routes_b,
49 G_VARIANT_TYPE("(a{sv})"));
50 g_variant_builder_open(&user_routes_b,
51 G_VARIANT_TYPE("a{sv}"));
53 if ((*user_routes)->protocol_family) {
54 g_variant_builder_add(&user_routes_b, "{sv}",
57 (*user_routes)->protocol_family));
60 if ((*user_routes)->network) {
61 g_variant_builder_add(&user_routes_b, "{sv}",
63 g_variant_new_string((*user_routes)->network));
66 if ((*user_routes)->netmask) {
67 g_variant_builder_add(&user_routes_b, "{sv}",
69 g_variant_new_string((*user_routes)->netmask));
72 if ((*user_routes)->gateway) {
73 g_variant_builder_add(&user_routes_b, "{sv}",
75 g_variant_new_string((*user_routes)->gateway));
78 g_variant_builder_close(&user_routes_b);
79 g_variant_builder_close(&user_routes_b);
84 user_routes_v = g_variant_builder_end(&user_routes_b);
86 return common_set_property(connection->dbus_proxy, "UserRoutes",
91 static struct connection_property_changed_cb
92 *get_connection_property_changed_cb(
93 struct vpn_connection *connection,
94 enum vpn_connection_property_type type)
96 return g_hash_table_lookup(connection->property_changed_cb_hash,
97 GINT_TO_POINTER(type));
100 static void parse_connection_property_ipv4(
101 struct vpn_connection *connection,
110 g_variant_get(ipv4, "a{sv}", &iter);
111 if (g_variant_iter_n_children(iter) == 0) {
112 g_variant_iter_free(iter);
116 if (connection->ipv4)
117 free_vpn_connection_ipv4(connection->ipv4);
119 connection->ipv4 = g_try_new0(struct vpn_connection_ipv4, 1);
120 if (connection->ipv4 == NULL) {
122 g_variant_iter_free(iter);
126 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
127 if (!g_strcmp0(key, "Address")) {
128 const char *property_value =
129 g_variant_get_string(value, NULL);
130 DBG("Address is %s", property_value);
131 connection->ipv4->address = g_strdup(property_value);
132 } else if (!g_strcmp0(key, "Netmask")) {
133 const char *property_value =
134 g_variant_get_string(value, NULL);
135 DBG("Netmask is %s", property_value);
136 connection->ipv4->netmask = g_strdup(property_value);
137 } else if (!g_strcmp0(key, "Gateway")) {
138 const char *property_value =
139 g_variant_get_string(value, NULL);
140 DBG("Gateway is %s", property_value);
141 connection->ipv4->gateway = g_strdup(property_value);
142 } else if (!g_strcmp0(key, "Peer")) {
143 const char *property_value =
144 g_variant_get_string(value, NULL);
145 DBG("Peer is %s", property_value);
146 connection->ipv4->peer = g_strdup(property_value);
150 g_variant_iter_free(iter);
153 static void parse_connection_property_ipv6(
154 struct vpn_connection *connection,
163 g_variant_get(ipv6, "a{sv}", &iter);
164 if (g_variant_iter_n_children(iter) == 0) {
165 g_variant_iter_free(iter);
169 if (connection->ipv6)
170 free_vpn_connection_ipv6(connection->ipv6);
172 connection->ipv6 = g_try_new0(struct vpn_connection_ipv6, 1);
173 if (connection->ipv6 == NULL) {
175 g_variant_iter_free(iter);
179 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
180 if (!g_strcmp0(key, "Address")) {
181 const char *property_value =
182 g_variant_get_string(value, NULL);
183 DBG("Address is %s", property_value);
184 connection->ipv6->address = g_strdup(property_value);
185 } else if (!g_strcmp0(key, "PrefixLength")) {
186 const char *property_value =
187 g_variant_get_string(value, NULL);
188 DBG("PrefixLength is %s", property_value);
189 connection->ipv6->prefix_length =
190 g_strdup(property_value);
191 } else if (!g_strcmp0(key, "Gateway")) {
192 const char *property_value =
193 g_variant_get_string(value, NULL);
194 DBG("Gateway is %s", property_value);
195 connection->ipv6->gateway = g_strdup(property_value);
196 } else if (!g_strcmp0(key, "Peer")) {
197 const char *property_value =
198 g_variant_get_string(value, NULL);
199 DBG("Peer is %s", property_value);
200 connection->ipv6->peer = g_strdup(property_value);
204 g_variant_iter_free(iter);
207 static void parse_connection_property_nameservers(
208 struct vpn_connection *connection,
209 GVariant *nameservers)
217 g_variant_get(nameservers, "as", &iter);
218 if (g_variant_iter_n_children(iter) == 0) {
219 g_variant_iter_free(iter);
223 g_strfreev(connection->nameservers);
224 n = g_variant_iter_n_children(iter);
225 connection->nameservers = g_try_new0(char *, n+1);
226 if (connection->nameservers == NULL) {
228 g_variant_iter_free(iter);
232 while (g_variant_iter_loop(iter, "s", &value) && i < n) {
233 DBG("Nameserver Entry is %s", value);
234 connection->nameservers[i] = g_strdup(value);
237 connection->nameservers[n] = NULL;
239 g_variant_iter_free(iter);
242 static void print_variant(const gchar *s, GVariant *v)
244 gchar *temp = g_variant_print(v, true);
245 DBG("%s => %s", s, temp);
249 static void parse_connection_property_user_routes(
250 struct vpn_connection *connection,
251 GVariant *user_routes)
256 GVariantIter *route_entry;
258 print_variant("Incoming : ", user_routes);
260 g_variant_iter_init(&outer, user_routes);
261 if (g_variant_iter_n_children(&outer) == 0)
264 if (connection->user_routes)
265 g_slist_free_full(connection->user_routes,
266 free_vpn_connection_route);
268 while (g_variant_iter_loop(&outer, "(a{sv})", &route_entry)) {
272 if (g_variant_iter_n_children(route_entry) == 0)
275 struct vpn_connection_route *route =
276 g_try_new0(struct vpn_connection_route, 1);
282 while (g_variant_iter_loop(route_entry, "{sv}", &key, &value)) {
283 if (!g_strcmp0(key, "ProtocolFamily")) {
284 int property_value = g_variant_get_int32(value);
285 DBG("ProtocolFamily is %d", property_value);
286 route->protocol_family = property_value;
287 } else if (!g_strcmp0(key, "Network")) {
288 const char *property_value =
289 g_variant_get_string(value, NULL);
290 DBG("Network is %s", property_value);
291 route->network = g_strdup(property_value);
292 } else if (!g_strcmp0(key, "Netmask")) {
293 const char *property_value =
294 g_variant_get_string(value, NULL);
295 DBG("Netmask is %s", property_value);
296 route->netmask = g_strdup(property_value);
297 } else if (!g_strcmp0(key, "Gateway")) {
298 const char *property_value =
299 g_variant_get_string(value, NULL);
300 DBG("Gateway is %s", property_value);
301 route->gateway = g_strdup(property_value);
305 /*TODO: See if g_slist_prepend works better*/
306 connection->user_routes =
307 g_slist_append(connection->user_routes, route);
312 static void parse_connection_property_server_routes(
313 struct vpn_connection *connection,
314 GVariant *server_routes)
319 GVariantIter *route_entry;
321 g_variant_iter_init(&outer, server_routes);
322 if (g_variant_iter_n_children(&outer) == 0) {
326 if (connection->server_routes)
327 g_slist_free_full(connection->server_routes,
328 free_vpn_connection_route);
330 while (g_variant_iter_loop(&outer, "(a{sv})", &route_entry)) {
334 if (g_variant_iter_n_children(route_entry) == 0)
337 struct vpn_connection_route *route =
338 g_try_new0(struct vpn_connection_route, 1);
344 while (g_variant_iter_loop(route_entry, "{sv}", &key, &value)) {
345 if (!g_strcmp0(key, "ProtocolFamily")) {
346 int property_value = g_variant_get_int32(value);
347 DBG("ProtocolFamily is %d", property_value);
348 route->protocol_family = property_value;
349 } else if (!g_strcmp0(key, "Network")) {
350 const char *property_value =
351 g_variant_get_string(value, NULL);
352 DBG("Network is %s", property_value);
353 route->network = g_strdup(property_value);
354 } else if (!g_strcmp0(key, "Netmask")) {
355 const char *property_value =
356 g_variant_get_string(value, NULL);
357 DBG("Netmask is %s", property_value);
358 route->netmask = g_strdup(property_value);
359 } else if (!g_strcmp0(key, "Gateway")) {
360 const char *property_value =
361 g_variant_get_string(value, NULL);
362 DBG("Gateway is %s", property_value);
363 route->gateway = g_strdup(property_value);
367 /*TODO: See if g_slist_prepend works better*/
368 connection->server_routes =
369 g_slist_append(connection->server_routes, route);
373 static enum vpn_connection_property_type parse_connection_property(
374 struct vpn_connection *connection,
375 gchar *key, GVariant *value)
377 assert(connection != NULL);
378 enum vpn_connection_property_type property_type = VPN_CONN_PROP_NONE;
380 if (!g_strcmp0(key, "State")) {
381 const gchar *property_value;
382 property_value = g_variant_get_string(value, NULL);
383 DBG("connection state is %s", property_value);
384 if (!g_strcmp0(property_value, "idle"))
385 connection->state = VPN_CONN_STATE_IDLE;
386 else if (!g_strcmp0(property_value, "failure"))
387 connection->state = VPN_CONN_STATE_FAILURE;
388 else if (!g_strcmp0(property_value, "configuration"))
389 connection->state = VPN_CONN_STATE_CONFIGURATION;
390 else if (!g_strcmp0(property_value, "ready"))
391 connection->state = VPN_CONN_STATE_READY;
392 else if (!g_strcmp0(property_value, "disconnect"))
393 connection->state = VPN_CONN_STATE_DISCONNECT;
394 property_type = VPN_CONN_PROP_STATE;
395 } else if (!g_strcmp0(key, "Type")) {
396 const gchar *property_value;
397 property_value = g_variant_get_string(value, NULL);
398 DBG("connection type is %s", property_value);
399 g_free(connection->type);
400 connection->type = g_strdup(property_value);
401 property_type = VPN_CONN_PROP_TYPE;
402 } else if (!g_strcmp0(key, "Name")) {
403 const gchar *property_value;
404 property_value = g_variant_get_string(value, NULL);
405 g_free(connection->name);
406 connection->name = g_strdup(property_value);
407 property_type = VPN_CONN_PROP_NAME;
408 } else if (!g_strcmp0(key, "Domain")) {
409 const gchar *property_value;
410 property_value = g_variant_get_string(value, NULL);
411 g_free(connection->domain);
412 connection->domain = g_strdup(property_value);
413 property_type = VPN_CONN_PROP_DOMAIN;
414 } else if (!g_strcmp0(key, "Host")) {
415 const gchar *property_value;
416 property_value = g_variant_get_string(value, NULL);
417 g_free(connection->host);
418 connection->host = g_strdup(property_value);
419 property_type = VPN_CONN_PROP_HOST;
420 } else if (!g_strcmp0(key, "Immutable")) {
421 connection->immutable = g_variant_get_boolean(value);
422 property_type = VPN_CONN_PROP_IMMUTABLE;
423 } else if (!g_strcmp0(key, "Index")) {
424 connection->index = g_variant_get_int32(value);
425 property_type = VPN_CONN_PROP_INDEX;
428 * Add IPv4/IPV6/Nameservers
429 * UserRoutes/ServerRoutes
432 else if (!g_strcmp0(key, "IPv4")) {
433 parse_connection_property_ipv4(connection, value);
434 property_type = VPN_CONN_PROP_IPV4;
435 } else if (!g_strcmp0(key, "IPv6")) {
436 parse_connection_property_ipv6(connection, value);
437 property_type = VPN_CONN_PROP_IPV6;
438 } else if (!g_strcmp0(key, "Nameservers")) {
439 parse_connection_property_nameservers(connection, value);
440 property_type = VPN_CONN_PROP_USERROUTES;
441 } else if (!g_strcmp0(key, "UserRoutes")) {
442 parse_connection_property_user_routes(connection, value);
443 property_type = VPN_CONN_PROP_USERROUTES;
444 } else if (!g_strcmp0(key, "ServerRoutes")) {
445 parse_connection_property_server_routes(connection, value);
446 property_type = VPN_CONN_PROP_SERVERROUTES;
449 return property_type;
452 static void parse_connection_properties(
453 struct vpn_connection *connection,
454 GVariantIter *properties)
459 while (g_variant_iter_next(properties, "{sv}", &key, &value)) {
460 parse_connection_property(connection, key, value);
463 g_variant_unref(value);
467 static void connection_property_changed(
468 struct vpn_connection *connection,
469 GVariant *parameters)
473 enum vpn_connection_property_type property_type;
477 g_variant_get(parameters, "(sv)", &key, &value);
478 property_type = parse_connection_property(connection, key, value);
480 if (property_type != VPN_CONN_PROP_NONE) {
481 DBG("Now check property changed callback");
483 struct connection_property_changed_cb *property_changed_cb_t;
485 property_changed_cb_t = get_connection_property_changed_cb(
488 if (property_changed_cb_t != NULL) {
489 DBG("property changed callback has been set");
490 property_changed_cb_t->property_changed_cb(connection,
491 property_changed_cb_t->user_data);
496 g_variant_unref(value);
499 static void connection_signal_handler(GDBusProxy *proxy,
502 GVariant *parameters,
505 DBG("signal_name: %s", signal_name);
507 struct vpn_connection *connection = user_data;
509 if (!g_strcmp0(signal_name, "PropertyChanged"))
510 connection_property_changed(connection, parameters);
513 static void free_connection_property_changed_cb(gpointer data)
516 struct connection_property_changed_cb *property_changed_cb = data;
518 g_free(property_changed_cb);
521 void destroy_vpn_connections(void)
523 if (vpn_connection_list != NULL) {
524 g_list_free(vpn_connection_list);
525 vpn_connection_list = NULL;
527 if (vpn_connection_hash != NULL) {
528 g_hash_table_destroy(vpn_connection_hash);
529 vpn_connection_hash = NULL;
533 static struct vpn_connection *create_vpn_connection(
535 GVariantIter *properties)
537 GDBusProxy *connection_proxy;
538 struct vpn_connection *connection;
539 GError *error = NULL;
543 connection_proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
544 G_DBUS_PROXY_FLAGS_NONE, NULL,
545 VPN_NAME, object_path,
546 VPN_CONNECTION_INTERFACE, NULL, &error);
547 if (connection_proxy == NULL) {
548 ERROR("error info: %s", error->message);
553 connection = g_try_new0(struct vpn_connection, 1);
554 if (connection == NULL) {
556 g_object_unref(connection_proxy);
560 connection->dbus_proxy = connection_proxy;
561 connection->path = g_strdup(object_path);
563 parse_connection_properties(connection, properties);
565 g_hash_table_insert(vpn_connection_hash,
566 (gpointer)connection->path,
567 (gpointer)connection);
569 vpn_connection_list = g_list_append(vpn_connection_list,
572 connection->property_changed_cb_hash = g_hash_table_new_full(
573 g_direct_hash, g_direct_equal, NULL,
574 free_connection_property_changed_cb);
576 g_signal_connect(connection->dbus_proxy, "g-signal",
577 G_CALLBACK(connection_signal_handler), connection);
582 static void free_vpn_connection_ipv4(struct vpn_connection_ipv4 *ipv4_info)
586 g_free(ipv4_info->address);
587 g_free(ipv4_info->netmask);
588 g_free(ipv4_info->gateway);
589 g_free(ipv4_info->peer);
593 static void free_vpn_connection_ipv6(struct vpn_connection_ipv6 *ipv6_info)
597 g_free(ipv6_info->address);
598 g_free(ipv6_info->prefix_length);
599 g_free(ipv6_info->gateway);
600 g_free(ipv6_info->peer);
604 static void free_vpn_connection_route(gpointer data)
608 struct vpn_connection_route *route = data;
611 DBG("Nothing to Delete!");
615 g_free(route->network);
616 g_free(route->netmask);
617 g_free(route->gateway);
622 static void free_vpn_connection(gpointer data)
626 struct vpn_connection *connection = data;
628 if (connection == NULL)
631 if (connection->dbus_proxy != NULL)
632 g_object_unref(connection->dbus_proxy);
634 if (connection->property_changed_cb_hash != NULL)
635 g_hash_table_destroy(connection->property_changed_cb_hash);
637 g_free(connection->path);
638 g_free(connection->name);
639 g_free(connection->domain);
640 g_free(connection->host);
642 if (connection->ipv4)
643 free_vpn_connection_ipv4(connection->ipv4);
645 if (connection->ipv6)
646 free_vpn_connection_ipv6(connection->ipv6);
648 g_strfreev(connection->nameservers);
650 if (connection->user_routes)
651 g_slist_free_full(connection->user_routes,
652 free_vpn_connection_route);
654 if (connection->server_routes)
655 g_slist_free_full(connection->server_routes,
656 free_vpn_connection_route);
661 static void create_vpn_connections(GVariant *connections)
665 GVariantIter *properties;
667 g_variant_get(connections, "(a(oa{sv}))", &iter);
668 if (g_variant_iter_n_children(iter) == 0) {
669 g_variant_iter_free(iter);
673 while (g_variant_iter_loop(iter, "(oa{sv})", &path, &properties))
674 create_vpn_connection(path, properties);
676 g_variant_iter_free(iter);
679 struct vpn_connection *get_connection_by_path(const gchar *path)
681 DBG("path: %s", path);
683 return g_hash_table_lookup(vpn_connection_hash, (gpointer)path);
686 gboolean add_vpn_connection(GVariant **parameters,
687 struct vpn_connection **connection)
690 gchar *connection_path;
691 GVariantIter *properties;
694 g_variant_get(*parameters, "(oa{sv})", &connection_path, &properties);
696 print_str = g_variant_print(*parameters, TRUE);
697 DBG("connection path: %s, parameters: %s", connection_path, print_str);
701 * Lookup if it has existed in the hash table
703 *connection = g_hash_table_lookup(vpn_connection_hash,
704 (gpointer) connection_path);
705 if (*connection != NULL) {
706 DBG("Repetitive connection %s", (*connection)->name);
710 *connection = create_vpn_connection(connection_path,
712 if (*connection != NULL)
718 g_variant_iter_free(properties);
722 void remove_vpn_connection(struct vpn_connection *connection)
726 assert(connection != NULL);
728 vpn_connection_list = g_list_remove(vpn_connection_list,
729 (gpointer)connection);
731 g_hash_table_remove(vpn_connection_hash,
732 (gconstpointer)connection->path);
735 void sync_vpn_connections(void)
740 GVariant *connections;
741 GError *error = NULL;
743 connections = g_dbus_proxy_call_sync(get_vpn_manager_dbus_proxy(),
744 "GetConnections", NULL,
745 G_DBUS_CALL_FLAGS_NONE,
747 if (connections == NULL) {
748 ERROR("error info: %s", error->message);
753 print_str = g_variant_print(connections, TRUE);
754 DBG("connections: %s", print_str);
757 if (!vpn_connection_hash)
758 vpn_connection_hash = g_hash_table_new_full(
759 g_str_hash, g_str_equal,
760 NULL, free_vpn_connection);
761 DBG("hash: %p", vpn_connection_hash);
763 create_vpn_connections(connections);
765 g_variant_unref(connections);
769 * VPN Connection Methods
771 GList *vpn_get_connections(void)
775 return vpn_connection_list;
778 struct vpn_connection *vpn_get_connection(
779 const char *host, const char *domain)
781 if (!host || !domain)
786 for (iter = vpn_connection_list; iter != NULL;
788 struct vpn_connection *connection =
789 (struct vpn_connection *)(iter->data);
791 if (g_str_equal(connection->host, host) &&
792 g_str_equal(connection->domain, domain))
799 enum dvpnlib_err vpn_connection_clear_property(
800 struct vpn_connection *connection)
804 assert(connection != NULL);
807 * Only supported the "UserRoutes" item now;
809 value = g_variant_new("(s)", "UserRoutes");
811 return common_set_interface_call_method_sync(connection->dbus_proxy,
812 "ClearProperty", &value);
816 * Asynchronous connect callback
818 static void connect_callback(GObject *source_object,
819 GAsyncResult *res, gpointer user_data)
821 GError *error = NULL;
822 enum dvpnlib_err error_type = DVPNLIB_ERR_NONE;
824 struct common_reply_data *reply_data;
825 struct vpn_connection *connection;
827 reply_data = user_data;
831 connection = reply_data->user;
835 if (!connection->dbus_proxy)
838 ret = g_dbus_proxy_call_finish(connection->dbus_proxy, res, &error);
840 DBG("%s", error->message);
841 error_type = get_error_type(error);
845 g_variant_unref(ret);
847 if (reply_data->cb) {
848 dvpnlib_reply_cb callback = reply_data->cb;
849 callback(error_type, reply_data->data);
856 enum dvpnlib_err vpn_connection_connect(struct vpn_connection *connection,
857 dvpnlib_reply_cb callback,
862 struct common_reply_data *reply_data;
864 assert(connection != NULL);
867 common_reply_data_new(callback, user_data, connection, TRUE);
869 return common_set_interface_call_method(connection->dbus_proxy,
871 (GAsyncReadyCallback)
872 connect_callback, reply_data);
876 vpn_connection_disconnect(struct vpn_connection *connection)
880 assert(connection != NULL);
882 return common_set_interface_call_method_sync(connection->dbus_proxy,
887 const char *vpn_connection_get_type(
888 struct vpn_connection *connection)
890 assert(connection != NULL);
892 return connection->type;
895 const char *vpn_connection_get_name(
896 struct vpn_connection *connection)
898 assert(connection != NULL);
900 return connection->name;
903 const char *vpn_connection_get_path(
904 struct vpn_connection *connection)
906 assert(connection != NULL);
908 return connection->path;
911 const char *vpn_connection_get_domain(
912 struct vpn_connection *connection)
914 assert(connection != NULL);
916 return connection->domain;
919 const char *vpn_connection_get_host(
920 struct vpn_connection *connection)
922 assert(connection != NULL);
924 return connection->host;
927 bool vpn_connection_get_immutable(
928 struct vpn_connection *connection)
930 assert(connection != NULL);
932 return connection->immutable;
935 int vpn_connection_get_index(
936 struct vpn_connection *connection)
938 assert(connection != NULL);
940 return connection->index;
943 enum vpn_connection_state vpn_connection_get_state(
944 struct vpn_connection *connection)
946 assert(connection != NULL);
948 return connection->state;
951 const struct vpn_connection_ipv4 *vpn_connection_get_ipv4(
952 struct vpn_connection *connection)
954 assert(connection != NULL);
956 return connection->ipv4;
959 const struct vpn_connection_ipv6 *vpn_connection_get_ipv6(
960 struct vpn_connection *connection)
962 assert(connection != NULL);
964 return connection->ipv6;
967 char **vpn_connection_get_nameservers(
968 struct vpn_connection *connection)
970 assert(connection != NULL);
972 return connection->nameservers;
975 GSList *vpn_connection_get_user_routes(
976 struct vpn_connection *connection)
978 assert(connection != NULL);
980 return connection->user_routes;
983 GSList *vpn_connection_get_server_routes(
984 struct vpn_connection *connection)
986 assert(connection != NULL);
988 return connection->server_routes;
991 enum dvpnlib_err vpn_connection_set_property_changed_cb(
992 struct vpn_connection *connection,
993 enum vpn_connection_property_type type,
994 vpn_connection_property_changed_cb cb,
999 if (connection == NULL)
1000 return DVPNLIB_ERR_INVALID_PARAMETER;
1002 struct connection_property_changed_cb *property_changed_cb_t =
1003 g_try_new0(struct connection_property_changed_cb, 1);
1004 if (property_changed_cb_t == NULL) {
1006 return DVPNLIB_ERR_FAILED;
1008 property_changed_cb_t->property_changed_cb = cb;
1009 property_changed_cb_t->user_data = user_data;
1011 g_hash_table_insert(connection->property_changed_cb_hash,
1012 GINT_TO_POINTER(type),
1013 (gpointer)property_changed_cb_t);
1015 return DVPNLIB_ERR_NONE;
1018 enum dvpnlib_err vpn_connection_unset_property_changed_cb(
1019 struct vpn_connection *connection,
1020 enum vpn_connection_property_type type)
1024 if (connection == NULL)
1025 return DVPNLIB_ERR_INVALID_PARAMETER;
1027 struct connection_property_changed_cb *property_changed_cb_t =
1028 get_connection_property_changed_cb(connection, type);
1030 if (property_changed_cb_t == NULL) {
1031 DBG("Can't find connection property changed callback");
1032 return DVPNLIB_ERR_FAILED;
1035 g_hash_table_remove(connection->property_changed_cb_hash,
1036 GINT_TO_POINTER(type));
1038 return DVPNLIB_ERR_NONE;