Default VPN CAPI Initial Code (without Connman Library)
[platform/core/api/vpn-setting.git] / dvpnlib / src / dvpnlib-vpn-connnection.c
1 #include "dvpnlib-internal.h"
2 #include "dvpnlib-vpn-connection.h"
3
4 static GList *vpn_connection_list;
5 static GHashTable *vpn_connection_hash;
6
7 struct connection_property_changed_cb {
8         vpn_connection_property_changed_cb property_changed_cb;
9         void *user_data;
10 };
11
12 struct vpn_connection {
13         GDBusProxy *dbus_proxy;
14         gchar *type;
15         gchar *path;
16         gchar *name;
17         gchar *domain;
18         gchar *host;
19         gboolean immutable;
20         gint index;
21         enum vpn_connection_state state;
22         struct vpn_connection_ipv4 *ipv4;
23         struct vpn_connection_ipv6 *ipv6;
24         gchar **nameservers;
25         GSList *user_routes; /*struct vpn_connection_route */
26         GSList *server_routes; /* struct vpn_connection_route */
27         GHashTable *property_changed_cb_hash;
28 };
29
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);
33
34 enum dvpnlib_err
35 vpn_connection_set_user_routes(struct vpn_connection *connection,
36                             struct vpn_connection_route **user_routes)
37 {
38         if (!connection || !user_routes)
39                 return DVPNLIB_ERR_INVALID_PARAMETER;
40
41         GVariantBuilder user_routes_b;
42         GVariant *user_routes_v;
43
44         g_variant_builder_init(&user_routes_b, G_VARIANT_TYPE("a(a{sv})"));
45
46         while (*user_routes != NULL) {
47
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}"));
52
53                 if ((*user_routes)->protocol_family) {
54                         g_variant_builder_add(&user_routes_b, "{sv}",
55                                 "ProtocolFamily",
56                                 g_variant_new_int32(
57                                         (*user_routes)->protocol_family));
58                 }
59
60                 if ((*user_routes)->network) {
61                         g_variant_builder_add(&user_routes_b, "{sv}",
62                                 "Network",
63                                 g_variant_new_string((*user_routes)->network));
64                 }
65
66                 if ((*user_routes)->netmask) {
67                         g_variant_builder_add(&user_routes_b, "{sv}",
68                                 "Netmask",
69                                 g_variant_new_string((*user_routes)->netmask));
70                 }
71
72                 if ((*user_routes)->gateway) {
73                         g_variant_builder_add(&user_routes_b, "{sv}",
74                                 "Gateway",
75                                 g_variant_new_string((*user_routes)->gateway));
76                 }
77
78                 g_variant_builder_close(&user_routes_b);
79                 g_variant_builder_close(&user_routes_b);
80
81                 user_routes++;
82         }
83
84         user_routes_v = g_variant_builder_end(&user_routes_b);
85
86         return common_set_property(connection->dbus_proxy, "UserRoutes",
87                         user_routes_v);
88
89 }
90
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)
95 {
96         return g_hash_table_lookup(connection->property_changed_cb_hash,
97                                         GINT_TO_POINTER(type));
98 }
99
100 static void parse_connection_property_ipv4(
101                                 struct vpn_connection *connection,
102                                 GVariant *ipv4)
103 {
104         DBG("");
105
106         GVariantIter *iter;
107         gchar *key;
108         GVariant *value;
109
110         g_variant_get(ipv4, "a{sv}", &iter);
111         if (g_variant_iter_n_children(iter) == 0) {
112                 g_variant_iter_free(iter);
113                 return;
114         }
115
116         if (connection->ipv4)
117                 free_vpn_connection_ipv4(connection->ipv4);
118
119         connection->ipv4 = g_try_new0(struct vpn_connection_ipv4, 1);
120         if (connection->ipv4 == NULL) {
121                 ERROR("no memory");
122                 g_variant_iter_free(iter);
123                 return;
124         }
125
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);
147                 }
148         }
149
150         g_variant_iter_free(iter);
151 }
152
153 static void parse_connection_property_ipv6(
154                                 struct vpn_connection *connection,
155                                 GVariant *ipv6)
156 {
157         DBG("");
158
159         GVariantIter *iter;
160         gchar *key;
161         GVariant *value;
162
163         g_variant_get(ipv6, "a{sv}", &iter);
164         if (g_variant_iter_n_children(iter) == 0) {
165                 g_variant_iter_free(iter);
166                 return;
167         }
168
169         if (connection->ipv6)
170                 free_vpn_connection_ipv6(connection->ipv6);
171
172         connection->ipv6 = g_try_new0(struct vpn_connection_ipv6, 1);
173         if (connection->ipv6 == NULL) {
174                 ERROR("no memory");
175                 g_variant_iter_free(iter);
176                 return;
177         }
178
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);
201                 }
202         }
203
204         g_variant_iter_free(iter);
205 }
206
207 static void parse_connection_property_nameservers(
208                                 struct vpn_connection *connection,
209                                 GVariant *nameservers)
210 {
211         DBG("");
212
213         GVariantIter *iter;
214         gchar *value;
215         int i = 0, n;
216
217         g_variant_get(nameservers, "as", &iter);
218         if (g_variant_iter_n_children(iter) == 0) {
219                 g_variant_iter_free(iter);
220                 return;
221         }
222
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) {
227                 ERROR("no memory");
228                 g_variant_iter_free(iter);
229                 return;
230         }
231
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);
235                 i++;
236         }
237         connection->nameservers[n] = NULL;
238
239         g_variant_iter_free(iter);
240 }
241
242 static void print_variant(const gchar *s, GVariant *v)
243 {
244         gchar *temp = g_variant_print(v, true);
245         DBG("%s => %s", s, temp);
246         g_free(temp);
247 }
248
249 static void parse_connection_property_user_routes(
250                                 struct vpn_connection *connection,
251                                 GVariant *user_routes)
252 {
253         DBG("");
254
255         GVariantIter outer;
256         GVariantIter *route_entry;
257
258         print_variant("Incoming : ", user_routes);
259
260         g_variant_iter_init(&outer, user_routes);
261         if (g_variant_iter_n_children(&outer) == 0)
262                 return;
263
264         if (connection->user_routes)
265                 g_slist_free_full(connection->user_routes,
266                                 free_vpn_connection_route);
267
268         while (g_variant_iter_loop(&outer, "(a{sv})", &route_entry)) {
269                 gchar *key;
270                 GVariant *value;
271
272                 if (g_variant_iter_n_children(route_entry) == 0)
273                         continue;
274
275                 struct vpn_connection_route *route =
276                         g_try_new0(struct vpn_connection_route, 1);
277                 if (route == NULL) {
278                         ERROR("no memory");
279                         return;
280                 }
281
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);
302                         }
303                 }
304
305                 /*TODO: See if g_slist_prepend works better*/
306                 connection->user_routes =
307                         g_slist_append(connection->user_routes, route);
308
309         }
310 }
311
312 static void parse_connection_property_server_routes(
313                                 struct vpn_connection *connection,
314                                 GVariant *server_routes)
315 {
316         DBG("");
317
318         GVariantIter outer;
319         GVariantIter *route_entry;
320
321         g_variant_iter_init(&outer, server_routes);
322         if (g_variant_iter_n_children(&outer) == 0) {
323                 return;
324         }
325
326         if (connection->server_routes)
327                 g_slist_free_full(connection->server_routes,
328                                 free_vpn_connection_route);
329
330         while (g_variant_iter_loop(&outer, "(a{sv})", &route_entry)) {
331                 gchar *key;
332                 GVariant *value;
333
334                 if (g_variant_iter_n_children(route_entry) == 0)
335                         continue;
336
337                 struct vpn_connection_route *route =
338                         g_try_new0(struct vpn_connection_route, 1);
339                 if (route == NULL) {
340                         ERROR("no memory");
341                         return;
342                 }
343
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);
364                         }
365                 }
366
367                 /*TODO: See if g_slist_prepend works better*/
368                 connection->server_routes =
369                         g_slist_append(connection->server_routes, route);
370         }
371 }
372
373 static enum vpn_connection_property_type parse_connection_property(
374                                         struct vpn_connection *connection,
375                                         gchar *key, GVariant *value)
376 {
377         assert(connection != NULL);
378         enum vpn_connection_property_type property_type = VPN_CONN_PROP_NONE;
379
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;
426         }
427         /* TODO:
428          * Add IPv4/IPV6/Nameservers
429          * UserRoutes/ServerRoutes
430          * Parsing code */
431
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;
447         }
448
449         return property_type;
450 }
451
452 static void parse_connection_properties(
453                                 struct vpn_connection *connection,
454                                 GVariantIter *properties)
455 {
456         gchar *key;
457         GVariant *value;
458
459         while (g_variant_iter_next(properties, "{sv}", &key, &value)) {
460                 parse_connection_property(connection, key, value);
461
462                 g_free(key);
463                 g_variant_unref(value);
464         }
465 }
466
467 static void connection_property_changed(
468                                 struct vpn_connection *connection,
469                                 GVariant *parameters)
470 {
471         gchar *key;
472         GVariant *value;
473         enum vpn_connection_property_type property_type;
474
475         DBG("");
476
477         g_variant_get(parameters, "(sv)", &key, &value);
478         property_type = parse_connection_property(connection, key, value);
479
480         if (property_type != VPN_CONN_PROP_NONE) {
481                 DBG("Now check property changed callback");
482
483                 struct connection_property_changed_cb *property_changed_cb_t;
484
485                 property_changed_cb_t = get_connection_property_changed_cb(
486                                                         connection,
487                                                         property_type);
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);
492                 }
493         }
494
495         g_free(key);
496         g_variant_unref(value);
497 }
498
499 static void connection_signal_handler(GDBusProxy *proxy,
500                                            gchar *sender_name,
501                                            gchar *signal_name,
502                                            GVariant *parameters,
503                                            gpointer user_data)
504 {
505         DBG("signal_name: %s", signal_name);
506
507         struct vpn_connection *connection = user_data;
508
509         if (!g_strcmp0(signal_name, "PropertyChanged"))
510                 connection_property_changed(connection, parameters);
511 }
512
513 static void free_connection_property_changed_cb(gpointer data)
514 {
515         DBG("");
516         struct connection_property_changed_cb *property_changed_cb = data;
517
518         g_free(property_changed_cb);
519 }
520
521 void destroy_vpn_connections(void)
522 {
523         if (vpn_connection_list != NULL) {
524                 g_list_free(vpn_connection_list);
525                 vpn_connection_list = NULL;
526         }
527         if (vpn_connection_hash != NULL) {
528                 g_hash_table_destroy(vpn_connection_hash);
529                 vpn_connection_hash = NULL;
530         }
531 }
532
533 static struct vpn_connection *create_vpn_connection(
534                                                 gchar *object_path,
535                                                 GVariantIter *properties)
536 {
537         GDBusProxy *connection_proxy;
538         struct vpn_connection *connection;
539         GError *error = NULL;
540
541         DBG("");
542
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);
549                 g_error_free(error);
550                 return NULL;
551         }
552
553         connection = g_try_new0(struct vpn_connection, 1);
554         if (connection == NULL) {
555                 ERROR("no memory");
556                 g_object_unref(connection_proxy);
557                 return NULL;
558         }
559
560         connection->dbus_proxy = connection_proxy;
561         connection->path = g_strdup(object_path);
562
563         parse_connection_properties(connection, properties);
564
565         g_hash_table_insert(vpn_connection_hash,
566                                 (gpointer)connection->path,
567                                 (gpointer)connection);
568
569         vpn_connection_list = g_list_append(vpn_connection_list,
570                                                 connection);
571
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);
575
576         g_signal_connect(connection->dbus_proxy, "g-signal",
577                         G_CALLBACK(connection_signal_handler), connection);
578
579         return connection;
580 }
581
582 static void free_vpn_connection_ipv4(struct vpn_connection_ipv4 *ipv4_info)
583 {
584         DBG("");
585
586         g_free(ipv4_info->address);
587         g_free(ipv4_info->netmask);
588         g_free(ipv4_info->gateway);
589         g_free(ipv4_info->peer);
590         g_free(ipv4_info);
591 }
592
593 static void free_vpn_connection_ipv6(struct vpn_connection_ipv6 *ipv6_info)
594 {
595         DBG("");
596
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);
601         g_free(ipv6_info);
602 }
603
604 static void free_vpn_connection_route(gpointer data)
605 {
606         DBG("");
607
608         struct vpn_connection_route *route = data;
609
610         if (route == NULL) {
611                 DBG("Nothing to Delete!");
612                 return;
613         }
614
615         g_free(route->network);
616         g_free(route->netmask);
617         g_free(route->gateway);
618
619         g_free(route);
620 }
621
622 static void free_vpn_connection(gpointer data)
623 {
624         DBG("");
625
626         struct vpn_connection *connection = data;
627
628         if (connection == NULL)
629                 return;
630
631         if (connection->dbus_proxy != NULL)
632                 g_object_unref(connection->dbus_proxy);
633
634         if (connection->property_changed_cb_hash != NULL)
635                 g_hash_table_destroy(connection->property_changed_cb_hash);
636
637         g_free(connection->path);
638         g_free(connection->name);
639         g_free(connection->domain);
640         g_free(connection->host);
641
642         if (connection->ipv4)
643                 free_vpn_connection_ipv4(connection->ipv4);
644
645         if (connection->ipv6)
646                 free_vpn_connection_ipv6(connection->ipv6);
647
648         g_strfreev(connection->nameservers);
649
650         if (connection->user_routes)
651                 g_slist_free_full(connection->user_routes,
652                                 free_vpn_connection_route);
653
654         if (connection->server_routes)
655                 g_slist_free_full(connection->server_routes,
656                                 free_vpn_connection_route);
657
658         g_free(connection);
659 }
660
661 static void create_vpn_connections(GVariant *connections)
662 {
663         GVariantIter *iter;
664         gchar *path;
665         GVariantIter *properties;
666
667         g_variant_get(connections, "(a(oa{sv}))", &iter);
668         if (g_variant_iter_n_children(iter) == 0) {
669                 g_variant_iter_free(iter);
670                 return;
671         }
672
673         while (g_variant_iter_loop(iter, "(oa{sv})", &path, &properties))
674                 create_vpn_connection(path, properties);
675
676         g_variant_iter_free(iter);
677 }
678
679 struct vpn_connection *get_connection_by_path(const gchar *path)
680 {
681         DBG("path: %s", path);
682
683         return g_hash_table_lookup(vpn_connection_hash, (gpointer)path);
684 }
685
686 gboolean add_vpn_connection(GVariant **parameters,
687                                 struct vpn_connection **connection)
688 {
689         gchar *print_str;
690         gchar *connection_path;
691         GVariantIter *properties;
692         gboolean ret;
693
694         g_variant_get(*parameters, "(oa{sv})", &connection_path, &properties);
695
696         print_str = g_variant_print(*parameters, TRUE);
697         DBG("connection path: %s, parameters: %s", connection_path, print_str);
698         g_free(print_str);
699
700         /*
701          * Lookup if it has existed in the hash table
702          */
703         *connection = g_hash_table_lookup(vpn_connection_hash,
704                                                 (gpointer) connection_path);
705         if (*connection != NULL) {
706                 DBG("Repetitive connection %s", (*connection)->name);
707
708                 ret = FALSE;
709         } else {
710                 *connection = create_vpn_connection(connection_path,
711                                                                 properties);
712                 if (*connection != NULL)
713                         ret = TRUE;
714                 else
715                         ret = FALSE;
716         }
717
718         g_variant_iter_free(properties);
719         return ret;
720 }
721
722 void remove_vpn_connection(struct vpn_connection *connection)
723 {
724         DBG("");
725
726         assert(connection != NULL);
727
728         vpn_connection_list = g_list_remove(vpn_connection_list,
729                                                 (gpointer)connection);
730
731         g_hash_table_remove(vpn_connection_hash,
732                         (gconstpointer)connection->path);
733 }
734
735 void sync_vpn_connections(void)
736 {
737         DBG("");
738
739         gchar *print_str;
740         GVariant *connections;
741         GError *error = NULL;
742
743         connections = g_dbus_proxy_call_sync(get_vpn_manager_dbus_proxy(),
744                                                 "GetConnections", NULL,
745                                                 G_DBUS_CALL_FLAGS_NONE,
746                                                 -1, NULL, &error);
747         if (connections == NULL) {
748                 ERROR("error info: %s", error->message);
749                 g_error_free(error);
750                 return;
751         }
752
753         print_str = g_variant_print(connections, TRUE);
754         DBG("connections: %s", print_str);
755         g_free(print_str);
756
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);
762
763         create_vpn_connections(connections);
764
765         g_variant_unref(connections);
766 }
767
768 /**
769  * VPN Connection Methods
770  */
771 GList *vpn_get_connections(void)
772 {
773         DBG("");
774
775         return vpn_connection_list;
776 }
777
778 struct vpn_connection *vpn_get_connection(
779                                         const char *host, const char *domain)
780 {
781         if (!host || !domain)
782                 return NULL;
783
784         GList *iter;
785
786         for (iter = vpn_connection_list; iter != NULL;
787              iter = iter->next) {
788                 struct vpn_connection *connection =
789                     (struct vpn_connection *)(iter->data);
790
791                 if (g_str_equal(connection->host, host) &&
792                                 g_str_equal(connection->domain, domain))
793                         return connection;
794         }
795
796         return NULL;
797 }
798
799 enum dvpnlib_err vpn_connection_clear_property(
800                                 struct vpn_connection *connection)
801 {
802         GVariant *value;
803
804         assert(connection != NULL);
805
806         /**
807          * Only supported the "UserRoutes" item now;
808          */
809         value = g_variant_new("(s)", "UserRoutes");
810
811         return common_set_interface_call_method_sync(connection->dbus_proxy,
812                                                 "ClearProperty", &value);
813 }
814
815 /**
816  * Asynchronous connect callback
817  */
818 static void connect_callback(GObject *source_object,
819                              GAsyncResult *res, gpointer user_data)
820 {
821         GError *error = NULL;
822         enum dvpnlib_err error_type = DVPNLIB_ERR_NONE;
823         GVariant *ret;
824         struct common_reply_data *reply_data;
825         struct vpn_connection *connection;
826
827         reply_data = user_data;
828         if (!reply_data)
829                 return;
830
831         connection = reply_data->user;
832         if (!connection)
833                 goto done;
834
835         if (!connection->dbus_proxy)
836                 goto done;
837
838         ret = g_dbus_proxy_call_finish(connection->dbus_proxy, res, &error);
839         if (!ret) {
840                 DBG("%s", error->message);
841                 error_type = get_error_type(error);
842
843                 g_error_free(error);
844         } else
845                 g_variant_unref(ret);
846
847         if (reply_data->cb) {
848                 dvpnlib_reply_cb callback = reply_data->cb;
849                 callback(error_type, reply_data->data);
850         }
851
852 done:
853         g_free(reply_data);
854 }
855
856 enum dvpnlib_err vpn_connection_connect(struct vpn_connection *connection,
857                                  dvpnlib_reply_cb callback,
858                                  void *user_data)
859 {
860         DBG("");
861
862         struct common_reply_data *reply_data;
863
864         assert(connection != NULL);
865
866         reply_data =
867             common_reply_data_new(callback, user_data, connection, TRUE);
868
869         return common_set_interface_call_method(connection->dbus_proxy,
870                                          "Connect", NULL,
871                                          (GAsyncReadyCallback)
872                                          connect_callback, reply_data);
873 }
874
875 enum dvpnlib_err
876 vpn_connection_disconnect(struct vpn_connection *connection)
877 {
878         DBG("");
879
880         assert(connection != NULL);
881
882         return common_set_interface_call_method_sync(connection->dbus_proxy,
883                                          "Disconnect", NULL);
884
885 }
886
887 const char *vpn_connection_get_type(
888                                         struct vpn_connection *connection)
889 {
890         assert(connection != NULL);
891
892         return connection->type;
893 }
894
895 const char *vpn_connection_get_name(
896                                         struct vpn_connection *connection)
897 {
898         assert(connection != NULL);
899
900         return connection->name;
901 }
902
903 const char *vpn_connection_get_path(
904                                 struct vpn_connection *connection)
905 {
906         assert(connection != NULL);
907
908         return connection->path;
909 }
910
911 const char *vpn_connection_get_domain(
912                                 struct vpn_connection *connection)
913 {
914         assert(connection != NULL);
915
916         return connection->domain;
917 }
918
919 const char *vpn_connection_get_host(
920                                 struct vpn_connection *connection)
921 {
922         assert(connection != NULL);
923
924         return connection->host;
925 }
926
927 bool vpn_connection_get_immutable(
928                                 struct vpn_connection *connection)
929 {
930         assert(connection != NULL);
931
932         return connection->immutable;
933 }
934
935 int vpn_connection_get_index(
936                                 struct vpn_connection *connection)
937 {
938         assert(connection != NULL);
939
940         return connection->index;
941 }
942
943 enum vpn_connection_state vpn_connection_get_state(
944                                 struct vpn_connection *connection)
945 {
946         assert(connection != NULL);
947
948         return connection->state;
949 }
950
951 const struct vpn_connection_ipv4 *vpn_connection_get_ipv4(
952                                 struct vpn_connection *connection)
953 {
954         assert(connection != NULL);
955
956         return connection->ipv4;
957 }
958
959 const struct vpn_connection_ipv6 *vpn_connection_get_ipv6(
960                                 struct vpn_connection *connection)
961 {
962         assert(connection != NULL);
963
964         return connection->ipv6;
965 }
966
967 char **vpn_connection_get_nameservers(
968                                 struct vpn_connection *connection)
969 {
970         assert(connection != NULL);
971
972         return connection->nameservers;
973 }
974
975 GSList *vpn_connection_get_user_routes(
976                                 struct vpn_connection *connection)
977 {
978         assert(connection != NULL);
979
980         return connection->user_routes;
981 }
982
983 GSList *vpn_connection_get_server_routes(
984                                 struct vpn_connection *connection)
985 {
986         assert(connection != NULL);
987
988         return connection->server_routes;
989 }
990
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,
995                                 void *user_data)
996 {
997         DBG("");
998
999         if (connection == NULL)
1000                 return DVPNLIB_ERR_INVALID_PARAMETER;
1001
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) {
1005                 ERROR("no memory");
1006                 return DVPNLIB_ERR_FAILED;
1007         }
1008         property_changed_cb_t->property_changed_cb = cb;
1009         property_changed_cb_t->user_data = user_data;
1010
1011         g_hash_table_insert(connection->property_changed_cb_hash,
1012                                 GINT_TO_POINTER(type),
1013                                 (gpointer)property_changed_cb_t);
1014
1015         return DVPNLIB_ERR_NONE;
1016 }
1017
1018 enum dvpnlib_err vpn_connection_unset_property_changed_cb(
1019                                 struct vpn_connection *connection,
1020                                 enum vpn_connection_property_type type)
1021 {
1022         DBG("");
1023
1024         if (connection == NULL)
1025                 return DVPNLIB_ERR_INVALID_PARAMETER;
1026
1027         struct connection_property_changed_cb *property_changed_cb_t =
1028                         get_connection_property_changed_cb(connection, type);
1029
1030         if (property_changed_cb_t == NULL) {
1031                 DBG("Can't find connection property changed callback");
1032                 return DVPNLIB_ERR_FAILED;
1033         }
1034
1035         g_hash_table_remove(connection->property_changed_cb_hash,
1036                                 GINT_TO_POINTER(type));
1037
1038         return DVPNLIB_ERR_NONE;
1039 }