Modify dbus object path
[platform/core/system/libsyscommon.git] / src / libgdbus / libgdbus.c
1 /*
2  * libsyscommon
3  *
4  * Copyright (c) 2019 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <errno.h>
24 #include <string.h>
25
26 #include "shared/log.h"
27 #include "libgdbus.h"
28
29 /* 10 seconds */
30 #define DBUS_REPLY_TIMEOUT      (10000)
31
32 static GBusType g_default_bus_type = G_BUS_TYPE_SYSTEM;
33 pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
34
35 void gdbus_set_default_bus_type(GBusType bus_type)
36 {
37         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION)
38                 return ;
39
40         pthread_mutex_lock(&g_mutex);
41         g_default_bus_type = bus_type;
42         pthread_mutex_unlock(&g_mutex);
43 }
44
45 GBusType gdbus_get_default_bus_type(void)
46 {
47         GBusType type;
48
49         pthread_mutex_lock(&g_mutex);
50         type = g_default_bus_type;
51         pthread_mutex_unlock(&g_mutex);
52
53         return type;
54 }
55
56 typedef struct {
57         const char *bus_name;
58         guint id;
59 } dbus_name;
60
61 /* basic information */
62 typedef struct {
63         GDBusConnection *conn;
64         GBusType bus_type;
65         gboolean priv;
66         GList *list_names;      /* dbus_name */
67         GList *list_object;     /* dbus_object_handle_s */
68         pthread_mutex_t mutex;
69 } dbus_handle_s;
70
71 /* path + interfaces */
72 typedef struct {
73         dbus_handle_s *dh;      /* dbus handle */
74         const char *path;       /* object path */
75         GList *list_ifaces;     /* dbus_interface_s */
76 } dbus_object_handle_s;
77
78 typedef struct {
79         dbus_object_handle_s *oh;       /* object handle */
80         const char *name;       /* interface name */
81         GList *list_methods;    /* const dbus_method_s */
82         guint reg_id;
83         int modified;
84 } dbus_interface_s;
85
86 #define get_dh_from_oh(oh) ((dbus_object_handle_s*)oh)->dh
87
88 /* global shared bus : system, session */
89 static dbus_handle_s g_dh[2];
90
91 static dbus_handle_s *_gdbus_get_connection(GBusType bus_type);
92
93 dbus_handle_s * _gdbus_get_default_connection(void)
94 {
95         return _gdbus_get_connection(gdbus_get_default_bus_type());
96 }
97
98 #define gdbus_lock(handle) do {\
99         assert(handle);\
100         pthread_mutex_lock(&((handle)->mutex));\
101 } while (0);
102
103 #define gdbus_unlock(handle) do {\
104         assert(handle);\
105         pthread_mutex_unlock(&(handle)->mutex);\
106 } while (0);
107
108 #define dcl_gdbus() dbus_handle_s *dh = (dbus_handle_s *)handle;
109 #define dcl_gdbus_null_check() dbus_handle_s *dh = (dbus_handle_s *)handle;\
110         if (!dh) {\
111         _E("dbus handle is null\n");\
112         return 0;\
113         }
114
115 dbus_object_handle_s * _gdbus_lookup_object(GList *list_obj, const char *obj_path);
116 dbus_interface_s * _gdbus_lookup_interface(GList *list_iface, const char *iface_name);
117 dbus_method_s * _gdbus_lookup_method(GList *list_methods, const char *method_name);
118
119 dbus_interface_s *_iface_u_to_s(const dbus_interface_u *iface_u)
120 {
121         dbus_interface_s *iface = NULL;
122
123         if (!iface_u || !iface_u->methods) {
124                 _E("param is null");
125                 return NULL;
126         }
127
128         iface = (dbus_interface_s *)calloc(1, sizeof(dbus_interface_s));
129         if (!iface) {
130                 _E("failed to calloc");
131                 return NULL;
132         }
133
134         iface->name = iface_u->name;
135         iface->modified = TRUE;
136
137         for (int i = 0 ; i < iface_u->nr_methods; ++i) {
138                 //_D("attached %s:%p", iface_u->methods[i].member, iface_u->methods[i].func);
139                 iface->list_methods = g_list_prepend(iface->list_methods, (void*)(iface_u->methods + i));
140         }
141
142         return iface;
143 }
144
145 static GDBusConnection * _get_bus(GBusType bus_type)
146 {
147         GDBusConnection *conn = NULL;
148         GError *err = NULL;
149
150         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
151                 _E("Wrong bus_type %d", bus_type);
152                 return NULL;
153         }
154
155         conn = g_bus_get_sync(bus_type, NULL, &err);
156         if (!conn || err) {
157                 _E("failed to get bus:type:%d, %s\n", bus_type, err->message);
158                 g_error_free(err);
159                 return NULL;
160         }
161
162         return conn;
163 }
164
165 static GDBusConnection * _get_bus_private(GBusType bus_type)
166 {
167         GError *err = NULL;
168         GDBusConnection *conn = NULL;
169         const char * address;
170
171         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
172                 _E("Wrong bus_type %d", bus_type);
173                 return NULL;
174         }
175
176         address = g_dbus_address_get_for_bus_sync(bus_type, NULL, &err);
177         if (!address || err) {
178                 _E("failed to get bus address\n");
179                 g_error_free(err);
180                 return NULL;
181         }
182
183         conn = g_dbus_connection_new_for_address_sync(address,
184                         (GDBusConnectionFlags) (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
185                         G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION),
186                         NULL, /* GDBusAuthObserver */
187                         NULL,
188                         &err);
189         if (!conn || err) {
190                 _E("failed to get private bus\n");
191                 g_error_free(err);
192                 return NULL;
193         }
194
195         return conn;
196 }
197
198 /* ref cout is 1 */
199 static dbus_handle_s *_gdbus_get_connection(GBusType bus_type)
200 {
201         int ibus = bus_type - 1;
202         dbus_handle_s *dh = NULL;
203
204         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
205                 _E("Unknown bus type %d", bus_type);
206                 return NULL;
207         }
208         dh = &g_dh[ibus];
209
210         gdbus_lock(dh);
211
212         if (!dh->conn) {
213                 dh->conn = _get_bus(bus_type);
214                 if (!dh->conn) {
215                         gdbus_unlock(dh);
216                         return NULL;
217                 }
218                 dh->priv = FALSE;
219                 dh->bus_type = bus_type;
220         }
221
222         gdbus_unlock(dh);
223
224         return dh;
225 }
226
227 /* ref cout is 1 */
228 static dbus_handle_s *_gdbus_get_connection_private(GBusType bus_type)
229 {
230         dbus_handle_s * dh;
231
232         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
233                 _E("Unknown bus type %d", bus_type);
234                 return NULL;
235         }
236
237         dh = (dbus_handle_s *)calloc(1, sizeof(dbus_handle_s));
238         if (!dh) {
239                 _E("failed to allocate memory for dbus handle");
240                 return NULL;
241         }
242
243         gdbus_lock(dh);
244
245         if (!dh->conn) {
246                 dh->conn = _get_bus_private(bus_type);
247                 dh->bus_type = bus_type;
248                 if (!dh->conn)
249                         goto err;
250         }
251
252         gdbus_unlock(dh);
253
254         return dh;
255 err:
256         if (dh) {
257                 gdbus_unlock(dh);
258                 free(dh);
259         }
260         return NULL;
261 }
262
263 dbus_handle_h gdbus_get_connection(GBusType bus_type, gboolean priv)
264 {
265         dbus_handle_s *dh = NULL;
266         int i;
267
268         if (bus_type != G_BUS_TYPE_SYSTEM && bus_type != G_BUS_TYPE_SESSION) {
269                 _E("Wrong bus_type %d\n", bus_type);
270                 return dh;
271         }
272
273         for (i = 0 ; i < 3; ++i) {
274                 /* private */
275                 if (priv)
276                         dh = _gdbus_get_connection_private(bus_type);
277                 /* shared */
278                 else
279                         dh = _gdbus_get_connection(bus_type);
280
281                 if (dh)
282                         break;
283                 usleep(5000);
284         }
285
286         return dh;
287 }
288
289 static void _gdbus_add_bus_name(dbus_handle_s *handle, const char *name, guint id)
290 {
291         dbus_name *dn = NULL;
292         int locked = 0;
293
294         if (!handle || !name || !id)
295                 return ;
296
297         dn = (dbus_name*)calloc(1, sizeof(dbus_name));
298         if (!dn) {
299                 _E("failed to calloc");
300                 assert(0);
301         }
302         dn->bus_name = name;
303         dn->id = id;
304
305         // todo : delete lock ?
306         locked = pthread_mutex_trylock(&handle->mutex);
307         if (locked != 0 && locked != EBUSY) {
308                 _E("failed to lock %d\n", locked);
309                 assert(0);
310         }
311
312         handle->list_names = g_list_prepend(handle->list_names, dn);
313
314         // todo : delete lock ?
315         if (locked != EBUSY)
316                 gdbus_unlock(handle);
317 }
318
319 static gint _compare_dbus_name(gconstpointer a, gconstpointer b)
320 {
321         const char *bus_name = ((dbus_name *)a)->bus_name;
322         if (!bus_name || !b)
323                 return -1;
324         return strcmp(bus_name, (const char *)b);
325 }
326
327 dbus_name * _gdbus_lookup_dbus_name(GList *list_name, const char *bus_name)
328 {
329         if (!list_name || !bus_name)
330                 return NULL;
331
332         GList *item = g_list_find_custom(list_name, bus_name, _compare_dbus_name);
333         if (!item)
334                 return NULL;
335
336         return (dbus_name *)item->data;
337 }
338
339 #define dh_to_ds(x) ((dbus_handle_s*)x)
340
341 /* remove dbus_name from dbus handle */
342 static void _gdbus_remove_bus_name(dbus_handle_s *handle, const char *bus_name)
343 {
344         dcl_gdbus();
345         dbus_name *dn = NULL;
346
347         if (!bus_name) {
348                 _E("wrong bus_name is null");
349                 return ;
350         }
351         if (!dh) {
352                 dh = _gdbus_get_default_connection();
353                 if (!dh) {
354                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
355                         return ;
356                 }
357         }
358
359         gdbus_lock(dh);
360         dn = _gdbus_lookup_dbus_name(dh->list_names, bus_name);
361         if (!dn) {
362                 _E("failed to find dbus name %s", bus_name);
363                 goto out;
364         }
365         dh->list_names = g_list_remove(dh->list_names, dn);
366         free(dn);
367 out:
368         gdbus_unlock(dh);
369 }
370
371 //extern void booting_done(void);
372
373 /* default handler */
374 static void _name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
375 {
376         dbus_handle_s *dh = (dbus_handle_s *)user_data;
377
378         _D("name %s", name);
379
380         if (!dh) {
381                 _E("%s:%d:dbus handle is null\n", __func__, __LINE__);
382                 return ;
383         }
384
385         // todo: add bus name?
386         //dh->bus_name = name;
387 }
388
389 /* default handler */
390 static void _name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
391 {
392         _E("%s:%d:%s\n", __func__, __LINE__, name);
393         dbus_handle_s *dh = (dbus_handle_s *)user_data;
394         if (!dh) {
395                 _E("%s:%d:dbus handle is null\n", __func__, __LINE__);
396                 return ;
397         }
398         _gdbus_remove_bus_name(dh, name);
399 }
400
401 int gdbus_request_name(dbus_handle_h handle,
402                                 const char *bus_name,
403                                 GBusNameAcquiredCallback acquired_handler,
404                                 GBusNameLostCallback lost_handler)
405 {
406         dcl_gdbus();
407         int id = -1;
408         GList *item = NULL;
409
410         if (!bus_name) {
411                 _E("bus_name is NULL");
412                 return -1;
413         }
414
415         /* get shared connection */
416         if (!dh) {
417                 dh = _gdbus_get_default_connection();
418                 if (!dh) {
419                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
420                         return -1;
421                 }
422         }
423
424         gdbus_lock(dh);
425         if (!dh->conn) {
426                 _E("failed to register name: connection is null\n");
427                 goto out;
428         }
429
430         /* todo : search name on connection */
431         item = g_list_find_custom(dh->list_names, bus_name, _compare_dbus_name);
432         if (item) {
433                 id = ((dbus_name*)(item->data))->id;
434                 _E("name already exist:%u", id);
435                 goto out;
436         }
437
438         id = g_bus_own_name_on_connection(dh->conn,
439                                         bus_name,
440                                         G_BUS_NAME_OWNER_FLAGS_NONE,
441                                         acquired_handler ? acquired_handler : _name_acquired,
442                                         lost_handler ? lost_handler : _name_lost,
443                                         dh,
444                                         NULL);
445         if (!id) {
446                 _E("failed to own name:%s\n", bus_name);
447                 goto out;
448         }
449
450         _gdbus_add_bus_name(dh, bus_name, id);
451
452 out:
453         gdbus_unlock(dh);
454         return id;
455 }
456
457 /* !! _name_lost handler callback is disabled by g_bus_unown_name : ubuntu */
458 int gdbus_release_name(dbus_handle_h handle, const char *bus_name)
459 {
460         dcl_gdbus();
461         dbus_name *dn = NULL;
462
463         if (!bus_name) {
464                 _E("Wrong bus name");
465                 return -1;
466         }
467
468         if (!dh) {
469                 dh = _gdbus_get_default_connection();
470                 if (!dh) {
471                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
472                         return -1;
473                 }
474         }
475
476         dn = _gdbus_lookup_dbus_name(dh->list_names, bus_name);
477         if (!dn) {
478                 _E("failed to find bus_name %s on dbus handle", bus_name);
479                 return -1;
480         }
481
482         _E("unown name %d", dn->id);
483         /* _name_lost handler is disabled by g_bus_unown_name : ubuntu */
484         g_bus_unown_name(dn->id);
485
486         gdbus_lock(dh);
487         dh->list_names = g_list_remove(dh->list_names, dn);
488         free(dn);
489         gdbus_unlock(dh);
490
491         return 0;
492 }
493
494 void gdbus_unwatch_name(guint id)
495 {
496         if (id == 0) {
497                 _E("wrong id %d", id);
498                 return;
499         }
500         g_bus_unwatch_name(id);
501 }
502
503 // g_strfreev(strv)
504 char **gdbus_get_owner_list(dbus_handle_h handle, const char *bus_name)
505 {
506         dcl_gdbus();
507         GError *err = NULL;
508         GVariant *reply = NULL;
509         GVariantIter *iter = NULL;
510         gchar **strv = NULL;
511         gchar *str = NULL;
512         int i = 0;
513
514         if (!bus_name) {
515                 _E("wrong parameter bus_name is null");
516                 return NULL;
517         }
518
519         if (!dh) {
520                 dh = _gdbus_get_default_connection();
521                 if (!dh) {
522                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
523                         return NULL;
524                 }
525         }
526
527         reply = g_dbus_connection_call_sync(dh->conn,
528                                         DBUS_BUS_NAME,
529                                         DBUS_OBJECT_PATH,
530                                         DBUS_INTERFACE_NAME,
531                                         "ListQueuedOwners",
532                                         g_variant_new("(s)", bus_name),
533                                         NULL,
534                                         G_DBUS_CALL_FLAGS_NONE,
535                                         DBUS_REPLY_TIMEOUT,
536                                         NULL,
537                                         &err);
538         if (!reply || err) {
539                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
540                 g_error_free(err);
541                 return NULL;
542         }
543
544         g_variant_get(reply, "(as)", &iter);
545         strv = g_new(gchar *, g_variant_iter_n_children(iter) + 1);
546
547         i = 0;
548         while (g_variant_iter_loop(iter, "s", &str))
549                 strv[i++] = g_strdup(str);
550         strv[i] = NULL;
551
552         g_variant_iter_free(iter);
553         g_variant_unref(reply);
554
555         return strv;
556 }
557
558 int gdbus_free_connection(dbus_handle_h handle)
559 {
560         dcl_gdbus();
561         dbus_handle_s *pdh = NULL;
562         GError *err = NULL;
563         GList *item = NULL;
564
565         if (!dh) {
566                 dh = _gdbus_get_default_connection();
567                 if (!dh) {
568                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
569                         return -1;
570                 }
571         }
572
573         if (!dh->conn) {
574                 _E("connection is NULL");
575                 return 0;
576         }
577
578         pdh = dh;
579
580         /* disable dbus handler */
581         gdbus_lock(dh);
582         if (!pdh->conn) {
583                 _E("conn is null");
584                 free(pdh);
585                 return 0;
586         }
587
588         /* flush everything */
589         if (!g_dbus_connection_flush_sync(pdh->conn, NULL, &err)) {
590                 _E("failed to flush %s\n", err->message);
591                 g_error_free(err);
592                 err = NULL;
593         }
594
595         _D("list_names %u", g_list_length(pdh->list_names));
596
597         /* unown every well-knwon name */
598         if (pdh->list_names) {
599                 dbus_name *dn = NULL;
600                 for (item = g_list_first(pdh->list_names); item != NULL; item = g_list_next(item)) {
601                         dn = (dbus_name *)item->data;
602                         if (!dn)
603                                 continue;
604
605                         /* _name_lost handler is disabled by g_bus_unown_name : ubuntu */
606                         _D("unown name id : %u", dn->id);
607                         g_bus_unown_name(dn->id);
608                         free(dn);
609                 }
610                 g_list_free(pdh->list_names);
611                 pdh->list_names = NULL;
612         }
613
614         _D("list_object %u", g_list_length(pdh->list_object));
615
616         /* unregister every object */
617         if (pdh->list_object) {
618                 dbus_object_handle_s * oh = NULL;
619                 //g_list_foreach(pdh->list_object, [] (gpointer data, gpointer user_data) {}, NULL);
620                 for (item = g_list_first(pdh->list_object); item != NULL; item = g_list_next(item)) {
621                         oh = (dbus_object_handle_s *)item->data;
622                         if (!oh || !oh->list_ifaces)
623                                 continue;
624
625                         _D("delete object path %s", oh->path);
626
627                         /* unregister every interface, method handles */
628                         for (GList *iface = g_list_first(oh->list_ifaces); iface != NULL; iface = g_list_next(iface)) {
629                                 dbus_interface_s *ih = (dbus_interface_s *)iface->data;
630                                 if (!ih)
631                                         continue;
632
633                                 _D("delete object iface %s", ih->name);
634
635                                 if (ih->reg_id)
636                                         g_dbus_connection_unregister_object(pdh->conn, ih->reg_id);
637                         }
638                 }
639         }
640
641         /* close connection */
642         if (pdh->priv) {
643                 _E("close private connection\n");
644
645                 if (!g_dbus_connection_close_sync(pdh->conn, NULL, &err)) {
646                         _E("Error closing connection %s\n", err->message);
647                         g_error_free(err);
648                         err = NULL;
649                 }
650         }
651
652         /* _free_func_object callback free the data */
653         //assert(g_list_length(pdh->list_names) == 0);
654         //assert(g_list_length(pdh->list_object) == 0);
655
656         g_object_unref(pdh->conn);
657
658         gdbus_unlock(dh);
659
660         if (dh->priv)
661                 free(dh);
662
663         return 0;
664
665         // todo: signal ?
666 }
667
668 #define buf_cal_free_space(size, nwrite) ((size - nwrite - 1) > 0 ? (size - nwrite - 1) : 0)
669 #define buf_block_size 8192
670
671 #define buf_check_space_realloc(buf, nwrite, buf_len) do {\
672         if ((nwrite >= buf_len - 1024)) {\
673                 if (buf_len >= buf_block_size * 10) {\
674                         _E("buf is too big to allocate. %d", buf_len);\
675                 } else {\
676                         _E("buf_check_space_realloc");\
677                         char *tmp = NULL;\
678                         buf_len += buf_block_size;\
679                         tmp = (char *)realloc(buf, buf_len);\
680                         if (!tmp) {\
681                                 _E("failed to realloc");\
682                         } else\
683                                 buf = tmp;\
684                 } \
685         } \
686 } while (0);
687
688 /* cal index of end of brace */
689 static int _check_brace(const char * expr)
690 {
691         int len = 0;
692         char qu[128];
693         int qucnt = 0;
694
695         if (!expr)
696                 return -1;
697
698         len = strlen(expr);
699
700         if (expr[0] != '(' && expr[0] != '{')
701                 return -1;
702
703         for (int i = 0 ; i < len; ++i) {
704
705                 if (expr[i] == '(' || expr[i] == '{') {
706                         qu[qucnt++] = expr[i];
707                         if (qucnt >= sizeof(qu)) {
708                                 _E("queue is too large. %s", expr);
709                                 return -1;
710                         }
711                         continue;
712                 }
713
714                 if (expr[i] == ')' || expr[i] == '}') {
715                         char ch;
716
717                         if (qucnt > 0)
718                                 ch = qu[qucnt-1];
719                         else
720                                 return -1;
721
722                         if (expr[i] == ')') {
723                                 if (ch == '(')
724                                         --qucnt;
725                                 else
726                                         return -1;
727                         } else if (expr[i] == '}') {
728                                 if (ch == '{')
729                                         --qucnt;
730                                 else
731                                         return -1;
732                         } else
733                                 return -1;
734
735                         if (qucnt == 0)
736                                 return i + 1;
737                 }
738         }
739
740         return -1;
741 }
742
743 /*
744 in : interface_s
745 out : xml format
746 */
747 static int _get_xml_from_interfaces(char **xml, const dbus_interface_s *interfaces)
748 {
749         int nwrite = 0;
750         int len_args;
751         char *buf = NULL;
752         const dbus_method_s *pmethod;
753         int buf_len = buf_block_size;
754
755         if (!interfaces) {
756                 _E("interfaces is null");
757                 return -1;
758         }
759
760         // todo : check dbus naming rule for interface name. ?
761         if (!interfaces->name) {
762                 _E("wrong interface name");
763                 return -1;
764         }
765         if (!interfaces->list_methods) {
766                 _E("no methods");
767                 return -1;
768         }
769
770         buf = (char *)malloc(buf_len);
771         if (!buf) {
772                 _E("buf is null. not enough memory\n");
773                 return -1;
774         }
775
776         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "<node>""\n""\t""<interface name='%s'>""\n", interfaces->name);
777
778         /* members */
779         for (GList *item = g_list_first(interfaces->list_methods); item != NULL; item = g_list_next(item)) {
780                 pmethod = (const dbus_method_s *)item->data;
781                 if (!pmethod)
782                         continue;
783
784                 /* check free space of buf */
785                 buf_check_space_realloc(buf, nwrite, buf_len);
786
787                 if (pmethod->signature_in == NULL && pmethod->signature_out == NULL) {
788                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""<method name='%s'/>""\n", pmethod->member);
789                         continue;
790                 }
791
792                 /* <method name='###'> */
793                 nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""<method name='%s'>""\n", pmethod->member);
794
795                 /* in args */
796                 len_args = pmethod->signature_in ? strlen(pmethod->signature_in) : 0;
797                 for (int m = 0; m < len_args; ++m) {
798                         // todo
799                         // array a(), as, ay ?
800                         if (pmethod->signature_in[m] == 'a') {
801                                 int ei; //end index
802                                 ei = _check_brace(pmethod->signature_in + m + 1);
803                                 if (ei > 0) {
804                                         char tmp[128] = {0,};
805                                         strncpy(tmp, pmethod->signature_in + m, ei + 1);
806                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%s' name='arg%d' direction='in'/>""\n", tmp, m);
807                                         m += ei;
808                                         continue;
809                                 } else {
810                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c%c' name='arg%d' direction='in'/>""\n", pmethod->signature_in[m], pmethod->signature_in[m+1], m);
811                                         m += 1;
812                                         continue;
813                                 }
814                         }
815                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c' name='arg%d' direction='in'/>""\n", pmethod->signature_in[m], m);
816                 }
817
818                 /* out args */
819                 len_args = pmethod->signature_out ? strlen(pmethod->signature_out) : 0;
820                 for (int m = 0; m < len_args; ++m) {
821                         // array
822                         // todo: container type
823                         if (pmethod->signature_out[m] == 'a') {
824                                 int ei; //end index
825                                 ei = _check_brace(pmethod->signature_out + m + 1);
826                                 if (ei > 0) {
827                                         char tmp[128] = {0,};
828                                         strncpy(tmp, pmethod->signature_out + m, ei + 1);
829                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%s' name='arg%d' direction='out'/>""\n", tmp, m);
830                                         m += ei;
831                                         continue;
832                                 } else {
833                                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c%c' name='arg%d' direction='out'/>""\n", pmethod->signature_out[m], pmethod->signature_out[m+1], m);
834                                         m += 1;
835                                         continue;
836                                 }
837                         }
838                         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t\t""<arg type='%c' name='arg%d' direction='out'/>""\n", pmethod->signature_out[m], m);
839                 }
840
841                 /* </method> */
842                 nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t\t""</method>""\n");
843         }
844
845         nwrite += snprintf(buf + nwrite, buf_cal_free_space(buf_len, nwrite), "\t""</interface>""\n""</node>""");
846
847         *xml = buf;
848
849         /* todo: delete log */
850 #if 0
851         if (nwrite <= 512)
852                 _E("%s", buf);
853         else
854                 _E("%s", buf + nwrite - 512);
855 #endif
856         return 0;
857 }
858
859 static gint _compare_dbus_object(gconstpointer a, gconstpointer b)
860 {
861         dbus_object_handle_s * pa = (dbus_object_handle_s *)a;
862         if (!pa->path || !((const char*)b))
863                 return -1;
864         return strcmp(pa->path, (const char*)b);
865 }
866
867 static gint _compare_dbus_interface(gconstpointer a, gconstpointer b)
868 {
869         dbus_interface_s * pa = (dbus_interface_s *)a;
870         if (!pa->name || !((const char*)b))
871                 return -1;
872         return strcmp(pa->name, (const char*)b);
873 }
874
875 static gint _compare_dbus_interface_by_id(gconstpointer a, gconstpointer b)
876 {
877         dbus_interface_s * pa = (dbus_interface_s *)a;
878         if (!pa->reg_id || !((guint*)b))
879                 return -1;
880         return !(pa->reg_id == *((guint*)b));
881 }
882
883 static gint _compare_dbus_method(gconstpointer a, gconstpointer b)
884 {
885         dbus_method_s *pa = (dbus_method_s*)a;
886         if (!pa->member || !((const char*)b))
887                 return -1;
888         return strcmp(pa->member, (const char*)b);
889 }
890
891 dbus_object_handle_s * _gdbus_lookup_object(GList *list_obj, const char *obj_path)
892 {
893         if (!list_obj || !obj_path)
894                 return NULL;
895
896         GList *item = g_list_find_custom(list_obj, obj_path, _compare_dbus_object);
897         if (!item)
898                 return NULL;
899
900         return (dbus_object_handle_s *)item->data;
901 }
902
903 dbus_interface_s * _gdbus_lookup_interface(GList *list_iface, const char *iface_name)
904 {
905         if (!list_iface || !iface_name)
906                 return NULL;
907
908         GList *item = g_list_find_custom(list_iface, iface_name, _compare_dbus_interface);
909         if (!item)
910                 return NULL;
911
912         return (dbus_interface_s *)item->data;
913 }
914
915 dbus_interface_s * _gdbus_lookup_interface_by_id(GList *list_iface, guint id)
916 {
917         if (!list_iface || !id)
918                 return NULL;
919
920         GList *item = g_list_find_custom(list_iface, &id, _compare_dbus_interface_by_id);
921         if (!item)
922                 return NULL;
923
924         return (dbus_interface_s *)item->data;
925 }
926
927 dbus_method_s * _gdbus_lookup_method(GList *list_methods, const char *method_name)
928 {
929         if (!list_methods || !method_name)
930                 return NULL;
931
932         GList *item = g_list_find_custom(list_methods, method_name, _compare_dbus_method);
933         if (!item)
934                 return NULL;
935
936         return (dbus_method_s *)item->data;
937 }
938
939 static void _free_func_object(gpointer data)
940 {
941         dbus_interface_s *ih = (dbus_interface_s *)data;
942         dbus_object_handle_s *oh = NULL;
943
944         if (!ih) {
945                 _E("interface handle is null");
946                 assert(0); // something wrong
947                 return ;
948         }
949
950         _E("unregister interface %s", ih->name);
951
952         /* just free list, not data(static dbus_method_s) */
953         g_list_free(ih->list_methods);
954
955         oh = ih->oh;
956         if (!oh) {
957                 _E("object handle is null");
958                 assert(0); // something wrong
959                 return ;
960         }
961
962         /* remove ih from list_ifaces */
963         oh->list_ifaces = g_list_remove(oh->list_ifaces, ih);
964
965         /* interface_s is copy of interface_u */
966         free(ih);
967
968         /* remove oh from list_object */
969         if (!oh->list_ifaces) {
970                 oh->dh->list_object = g_list_remove(oh->dh->list_object, oh);
971                 free(oh);
972         }
973 }
974
975 static int _gdbus_attach_object(dbus_handle_s *dh, const char *obj_path, dbus_interface_s *iface)
976 {
977         dbus_object_handle_s *oh = NULL;
978
979         if (!dh || !obj_path || !iface) {
980                 _E("failed to attache object. wrong parameter");
981                 return -1;
982         }
983
984         /* find object handle */
985         if (dh->list_object)
986                 oh = _gdbus_lookup_object(dh->list_object, obj_path);
987
988         if (!oh) {
989                 oh = (dbus_object_handle_s*)calloc(1, sizeof(dbus_object_handle_s));
990                 if (!oh) {
991                         _E("failed to calloc");
992                         return -1;
993                 }
994                 oh->dh = dh;
995                 oh->path = obj_path;
996
997                 /* attach object */
998                 dh->list_object = g_list_prepend(dh->list_object, oh);
999         }
1000
1001         iface->oh = oh;
1002         /* attach interface */
1003         oh->list_ifaces = g_list_prepend(oh->list_ifaces, iface);
1004
1005         return 0;
1006 }
1007
1008 /*
1009 _method_call_handler
1010
1011 libgio verify path and interface of incoming message.
1012 --> just check method name.
1013
1014 # parameters - member of invocation struct
1015 every parameters of this function are member of GDBusMethodInvocation *invocation.
1016 There are no reason to using g_dbus_method_invocation_get_* apis to get inforamtion from message.
1017 just use params - sender, path, iface, name and param.
1018
1019
1020 # user defined handler #
1021
1022 1. synchronous handling
1023         1) with return value
1024                 handler() {
1025                         return g_variant_new("(i)", ret);
1026                 }
1027
1028         2) without return value
1029                 handler() {
1030                         return dbus_handle_new_g_variant_tuple(); // g_variant_new_tuple(NULL, 0)
1031                 }
1032
1033 2. asynchronous handling
1034    handler MUST call 'g_dbus_method_invocation_return_value' itself. otherwise, LEAK !!
1035
1036         handler() {
1037                 return NULL;
1038         }
1039
1040         # if handler return NULL, assume asynchronous handling. do nothing.
1041
1042         thread() {
1043                 do something;
1044
1045         1) with return value
1046                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", ret));
1047
1048         2) without return value
1049                 g_dbus_method_invocation_return_value(invocation, NULL);
1050         }
1051
1052
1053 */
1054 static void _method_call_handler(GDBusConnection *conn,
1055                                 const gchar *sender,
1056                                 const gchar *path,
1057                                 const gchar *iface,
1058                                 const gchar *name,
1059                                 GVariant *param,
1060                                 GDBusMethodInvocation *invocation,
1061                                 gpointer user_data)
1062 {
1063         dbus_interface_s *iface_s = (dbus_interface_s *)user_data;
1064         const dbus_method_s *methods;
1065         GVariant *reply = NULL;
1066
1067         /* todo: ghash ? */
1068         methods = _gdbus_lookup_method(iface_s->list_methods, name);
1069         if (methods) {
1070                 reply = methods->func(conn, sender, path, iface, name, param, invocation, get_dh_from_oh(iface_s->oh));
1071
1072                 /* async, maybe they will reply...maybe.. */
1073                 if (!reply)
1074                         return;
1075         } else {
1076                 _E("no methods");
1077         }
1078
1079         g_dbus_method_invocation_return_value(invocation, reply);
1080 }
1081
1082 static GDBusInterfaceVTable path_vtable = {_method_call_handler};
1083
1084
1085 /*
1086 before register object, attach object into dbus handle
1087 _gdbus_attach_object()
1088 */
1089 static int _gdbus_register_object(dbus_handle_h handle, const char *obj_path, dbus_interface_s *iface)
1090 {
1091         dcl_gdbus();
1092         int ret = 0;
1093         char *buf = NULL;
1094         GError *err = NULL;
1095         GDBusNodeInfo * nodeinfo = NULL;
1096         GDBusInterfaceInfo *ifaceinfo = NULL;
1097
1098         if (!obj_path || !iface) {
1099                 _E("wrong parameter\n");
1100                 return -1;
1101         }
1102         if (!dh) {
1103                 dh = _gdbus_get_default_connection();
1104                 if (!dh) {
1105                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1106                         return -1;
1107                 }
1108         }
1109         if (!dh->conn) {
1110                 _E("connection is null\n");
1111                 return -1;
1112         }
1113
1114         ret = _get_xml_from_interfaces(&buf, iface);
1115         if (ret < 0) {
1116                 _E("failed to make xml format");
1117                 goto err;
1118         }
1119
1120         /* todo: delete this */
1121 #if 0
1122         if (strlen(buf) <= 512) {
1123                 _E("%s", buf);
1124         } else {
1125                 _E("%s", buf + strlen(buf) - 512);
1126         }
1127 #endif
1128
1129         nodeinfo = g_dbus_node_info_new_for_xml(buf, &err);
1130         if (!nodeinfo || err) {
1131                 _E("failed to make introspection data:err:%s:xml:%s\n", err->message, buf);
1132                 ret = -1;
1133                 goto err;
1134         }
1135
1136         ifaceinfo = g_dbus_node_info_lookup_interface(nodeinfo, iface->name);
1137         if (!ifaceinfo) {
1138                 _E("failed to g_dbus_node_info_lookup_interface");
1139                 ret = -1;
1140                 goto err;
1141         }
1142
1143         /*
1144                 path own single interface
1145                 if interface is already registered, then failed.
1146                 g_dbus_connection_register_object ref(ifaceinfo) now, unref if object is unregistered
1147         */
1148         ret = g_dbus_connection_register_object(dh->conn,
1149                                                 obj_path,
1150                                                 ifaceinfo/*ref 2*/,
1151                                                 &path_vtable,
1152                                                 (void*)iface,
1153                                                 _free_func_object,
1154                                                 &err);
1155         if (err) {
1156                 _E("failed to register object:err:%s:\n", err->message);
1157                 ret = -1;
1158                 goto err;
1159         }
1160
1161         iface->reg_id = ret;
1162         iface->modified = FALSE;
1163
1164 err:
1165         /* todo: detach object */
1166         //_dbus_handle_detach_object(dh, obj_path, iface);
1167         /* attach interface before register object */
1168         /*ret = _dbus_handle_detach_object(dh, obj_path, iface);
1169         if (ret < 0) {
1170                 _E("failed to attach object");
1171                 goto err;
1172         }*/
1173
1174         if (nodeinfo)
1175                 g_dbus_node_info_unref(nodeinfo);
1176         if (buf)
1177                 free(buf);
1178         if (err)
1179                 g_error_free(err);
1180
1181         return ret;
1182 }
1183
1184 /*
1185 register same interface at once
1186
1187 if interface is constructed by multiple methods,
1188 also it is not possible to make methods struct at once,
1189
1190 use gdbus_add_object(), gdbus_register_object_all().
1191
1192 return reg_id
1193 */
1194 int gdbus_register_object(dbus_handle_h handle, const char *obj_path, const dbus_interface_u *iface_u)
1195 {
1196         dcl_gdbus();
1197         int ret = 0;
1198         dbus_interface_s *iface = NULL;
1199
1200         if (!obj_path || !iface_u) {
1201                 _E("wrong parameter\n");
1202                 return -1;
1203         }
1204         if (!dh) {
1205                 dh = _gdbus_get_default_connection();
1206                 if (!dh) {
1207                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1208                         return -1;
1209                 }
1210         }
1211         if (!dh->conn) {
1212                 _E("connection is null\n");
1213                 return -1;
1214         }
1215
1216         /* check registered interface */
1217         if (dh->list_object) {
1218                 dbus_object_handle_s *oh = _gdbus_lookup_object(dh->list_object, obj_path);
1219                 if (oh) {
1220                         dbus_interface_s *ih = _gdbus_lookup_interface(oh->list_ifaces, iface_u->name);
1221                         if (ih) {
1222                                 _E("path %s, interface %s already registered", obj_path, iface_u->name);
1223                                 return -1;
1224                         }
1225                 }
1226         }
1227
1228         iface = _iface_u_to_s(iface_u);
1229         if (!iface) {
1230                 _E("failed to _iface_u_to_s");
1231                 return -1;
1232         }
1233
1234         /* attach interface before register object */
1235         ret = _gdbus_attach_object(dh, obj_path, iface);
1236         if (ret < 0) {
1237                 _E("failed to attach object");
1238                 goto err;
1239         }
1240
1241         ret = _gdbus_register_object(dh, obj_path, iface);
1242         if (ret <= 0) {
1243                 _E("failed to register dbus object%d", ret);
1244                 goto err;
1245         }
1246 err:
1247         return ret;
1248 }
1249
1250 int gdbus_unregister_object(dbus_handle_h handle, const char *obj_path)
1251 {
1252         dcl_gdbus();
1253         dbus_object_handle_s *oh = NULL;
1254         int ret = 0;
1255
1256         if (!obj_path)
1257                 return -1;
1258
1259         if (!dh) {
1260                 dh = _gdbus_get_default_connection();
1261                 if (!dh) {
1262                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1263                         return -1;
1264                 }
1265         }
1266         if (!dh->list_object) {
1267                 _E("list_object is empty");
1268                 return 0;
1269         }
1270
1271         oh = _gdbus_lookup_object(dh->list_object, obj_path);
1272         if (!oh) {
1273                 _E("no object with name %s", obj_path);
1274                 return -1;
1275         }
1276
1277         /* unregister every interface of object*/
1278         for (GList *item = g_list_first(oh->list_ifaces); item != NULL; item = g_list_next(item)) {
1279                 dbus_interface_s *ih = item->data;
1280                 if (!ih) {
1281                         _E("this is error");
1282                         assert(0);
1283                 }
1284
1285                 /* remove ih from list_ifaces */
1286                 if (!ih->reg_id) {
1287                         item = g_list_previous(item);
1288
1289                         /* remove and free link */
1290                         oh->list_ifaces = g_list_remove(oh->list_ifaces, ih);
1291
1292                         /* free list_methods */
1293                         g_list_free(ih->list_methods);
1294
1295                         /* free data */
1296                         free(ih);
1297                         continue;
1298                 }
1299
1300                 /* unregister object by id */
1301                 ret = g_dbus_connection_unregister_object(dh->conn, ih->reg_id);
1302                 if (!ret)
1303                         _E("failed to unregister object %s, interface %s, regid %d", oh->path, ih->name, ih->reg_id);
1304         }
1305
1306         return 0;
1307 }
1308
1309 int dbus_handle_unregister_dbus_object(dbus_handle_h handle, const char *obj_path)
1310 {
1311         dcl_gdbus();
1312         dbus_object_handle_s *oh = NULL;
1313         int ret = 0;
1314
1315         if (!obj_path)
1316                 return -1;
1317
1318         if (!dh) {
1319                 dh = _gdbus_get_default_connection();
1320                 if (!dh) {
1321                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1322                         return -1;
1323                 }
1324         }
1325         if (!dh->list_object) {
1326                 _E("list_object is empty");
1327                 return 0;
1328         }
1329
1330         oh = _gdbus_lookup_object(dh->list_object, obj_path);
1331         if (!oh) {
1332                 _E("no object with name %s", obj_path);
1333                 return -1;
1334         }
1335
1336         /* unregister every interface of object*/
1337         for (GList *item = g_list_first(oh->list_ifaces); item != NULL; item = g_list_next(item)) {
1338                 dbus_interface_s *ih = item->data;
1339                 if (!ih) {
1340                         _E("this is error");
1341                         assert(0);
1342                 }
1343
1344                 /* remove ih from list_ifaces */
1345                 if (!ih->reg_id) {
1346                         item = g_list_previous(item);
1347
1348                         /* remove and free link */
1349                         oh->list_ifaces = g_list_remove(oh->list_ifaces, ih);
1350
1351                         /* free list_methods */
1352                         g_list_free(ih->list_methods);
1353
1354                         /* free data */
1355                         free(ih);
1356                         continue;
1357                 }
1358
1359                 /* unregister object by id */
1360                 ret = g_dbus_connection_unregister_object(dh->conn, ih->reg_id);
1361                 if (!ret)
1362                         _E("failed to unregister object %s, interface %s, regid %d", oh->path, ih->name, ih->reg_id);
1363         }
1364
1365         return 0;
1366 }
1367
1368 /*
1369 add object temporarily.
1370 gdbus_register_object_all register every objects on connection.
1371
1372 return registered method count
1373 */
1374 int gdbus_add_object(dbus_handle_h handle, const char *obj_path, const dbus_interface_u *iface_u)
1375 {
1376         dcl_gdbus();
1377         dbus_object_handle_s *oh = NULL;
1378         dbus_interface_s *ih = NULL;
1379         int cnt;
1380
1381         if (!obj_path || !iface_u) {
1382                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1383                 return -1;
1384         }
1385         if (iface_u && (!iface_u->name || !iface_u->methods)) {
1386                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1387                 return -1;
1388         }
1389
1390         cnt = iface_u->nr_methods;
1391
1392         if (!dh) {
1393                 dh = _gdbus_get_default_connection();
1394                 if (!dh) {
1395                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1396                         return -1;
1397                 }
1398         }
1399
1400         if (!dh->conn) {
1401                 _E("failed to register method. connection is null\n");
1402                 return -1;
1403         }
1404
1405         /* if there are no object list, just add */
1406         if (!dh->list_object) {
1407                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1408                         _E("failed to attach object");
1409                         return -1;
1410                 }
1411                 goto out;
1412         }
1413
1414         oh = _gdbus_lookup_object(dh->list_object, obj_path);
1415         /* if there are no matched object, just add */
1416         if (!oh) {
1417                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1418                         _E("failed to attach object");
1419                         return -1;
1420                 }
1421                 goto out;
1422         }
1423
1424         /* this is an error, interface must have one or more item ? */
1425         if (!oh->list_ifaces) {
1426                 _E("error. list_ifaces is null\n");
1427                 assert(0);
1428                 goto out;
1429         }
1430
1431         ih = _gdbus_lookup_interface(oh->list_ifaces, iface_u->name);
1432         /* if there are no matched interface, just add */
1433         if (!ih) {
1434                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1435                         _E("failed to attach object");
1436                         return -1;
1437                 }
1438                 goto out;
1439         }
1440
1441         /*  todo:
1442                 1. unregister interface
1443                 2. update interface and methods
1444                 3. register interface
1445         */
1446         if (ih->reg_id) {
1447                 _E("interface already registered, ignore new interface");
1448                 return -1;
1449         }
1450
1451         /* attach new methods */
1452         cnt = 0;
1453         for (int i = 0; i < iface_u->nr_methods; ++i) {
1454                 GList *item = g_list_find_custom(g_list_first(ih->list_methods), iface_u->methods[i].member, _compare_dbus_method);
1455                 if (!item) {
1456                         //_D("attached %s", iface_u->methods[i].member);
1457                         ih->list_methods = g_list_prepend(ih->list_methods, (void*)(iface_u->methods + i));
1458                         ++cnt;
1459                 }
1460         }
1461
1462         if (cnt)
1463                 ih->modified = TRUE;
1464
1465 out:
1466         /*todo: delete debugging log */
1467         //if (dh && dh->list_object)
1468         //      _D("obj list len %d", g_list_length(dh->list_object));
1469         //if (oh && oh->list_ifaces)
1470         //      _D("iface list len %d", g_list_length(oh->list_ifaces));
1471         //if (ih && ih->list_methods)
1472         //      _D("method list len %d", g_list_length(ih->list_methods));
1473
1474         return cnt;
1475 }
1476
1477 int dbus_handle_add_dbus_object(dbus_handle_h handle, const char *obj_path, const dbus_interface_u *iface_u)
1478 {
1479         dcl_gdbus();
1480         dbus_object_handle_s *oh = NULL;
1481         dbus_interface_s *ih = NULL;
1482         int cnt;
1483
1484         if (!obj_path || !iface_u) {
1485                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1486                 return -1;
1487         }
1488         if (iface_u && (!iface_u->name || !iface_u->methods)) {
1489                 _E("wrong parameter path %s, iface_u %p\n", obj_path, iface_u);
1490                 return -1;
1491         }
1492
1493         cnt = iface_u->nr_methods;
1494
1495         if (!dh) {
1496                 dh = _gdbus_get_default_connection();
1497                 if (!dh) {
1498                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1499                         return -1;
1500                 }
1501         }
1502
1503         if (!dh->conn) {
1504                 _E("failed to register method. connection is null\n");
1505                 return -1;
1506         }
1507
1508         /* if there are no object list, just add */
1509         if (!dh->list_object) {
1510                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1511                         _E("failed to attach object");
1512                         return -1;
1513                 }
1514                 goto out;
1515         }
1516
1517         oh = _gdbus_lookup_object(dh->list_object, obj_path);
1518         /* if there are no matched object, just add */
1519         if (!oh) {
1520                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1521                         _E("failed to attach object");
1522                         return -1;
1523                 }
1524                 goto out;
1525         }
1526
1527         /* this is an error, interface must have one or more item ? */
1528         if (!oh->list_ifaces) {
1529                 _E("error. list_ifaces is null\n");
1530                 assert(0);
1531                 goto out;
1532         }
1533
1534         ih = _gdbus_lookup_interface(oh->list_ifaces, iface_u->name);
1535         /* if there are no matched interface, just add */
1536         if (!ih) {
1537                 if (_gdbus_attach_object(dh, obj_path, _iface_u_to_s(iface_u))) {
1538                         _E("failed to attach object");
1539                         return -1;
1540                 }
1541                 goto out;
1542         }
1543
1544         /*  todo:
1545                 1. unregister interface
1546                 2. update interface and methods
1547                 3. register interface
1548         */
1549         if (ih->reg_id) {
1550                 _E("interface already registered, ignore new interface");
1551                 return -1;
1552         }
1553
1554         /* attach new methods */
1555         cnt = 0;
1556         for (int i = 0; i < iface_u->nr_methods; ++i) {
1557                 GList *item = g_list_find_custom(g_list_first(ih->list_methods), iface_u->methods[i].member, _compare_dbus_method);
1558                 if (!item) {
1559                         //_D("attached %s", iface_u->methods[i].member);
1560                         ih->list_methods = g_list_prepend(ih->list_methods, (void*)(iface_u->methods + i));
1561                         ++cnt;
1562                 }
1563         }
1564
1565         if (cnt)
1566                 ih->modified = TRUE;
1567
1568 out:
1569         /*todo: delete debugging log */
1570         //if (dh && dh->list_object)
1571         //      _D("obj list len %d", g_list_length(dh->list_object));
1572         //if (oh && oh->list_ifaces)
1573         //      _D("iface list len %d", g_list_length(oh->list_ifaces));
1574         //if (ih && ih->list_methods)
1575         //      _D("method list len %d", g_list_length(ih->list_methods));
1576
1577         return cnt;
1578 }
1579
1580 int gdbus_register_object_all(dbus_handle_h handle)
1581 {
1582         dcl_gdbus();
1583         dbus_object_handle_s *oh = NULL;
1584         dbus_interface_s *ih = NULL;
1585         int ret_dbus = 0;
1586
1587         if (!dh) {
1588                 dh = _gdbus_get_default_connection();
1589                 if (!dh) {
1590                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1591                         return -1;
1592                 }
1593         }
1594         if (!dh->conn) {
1595                 _E("connection is null\n");
1596                 return -1;
1597         }
1598
1599         if (!dh->list_object) {
1600                 _E("obj list is empty");
1601                 return -1;
1602         }
1603
1604         /*if (dh && dh->list_object)
1605                 _D("obj list len %d", g_list_length(dh->list_object));*/
1606
1607         for (GList *item = g_list_first(dh->list_object); item != NULL; item = g_list_next(item)) {
1608                 oh = (dbus_object_handle_s *)item->data;
1609
1610                 if (!oh) {
1611                         _E("something wrong");
1612                         assert(0);
1613                 }
1614                 if (!oh->list_ifaces) {
1615                         _E("path %s: list_ifaces are null", oh->path);
1616                         goto err;
1617                 }
1618
1619                 //_D("iface list len %d", g_list_length(oh->list_ifaces));
1620
1621                 for (GList *li = g_list_first(oh->list_ifaces); li != NULL; li = g_list_next(li)) {
1622                         ih = (dbus_interface_s *)li->data;
1623
1624                         /* if there are no modification, goto next */
1625                         if (!ih->modified)
1626                                 continue;
1627
1628                         /* todo: if already registered interface, unregister first */
1629
1630                         /*_E("interface %s:", ih->name);
1631                         if (ih && ih->list_methods)
1632                                 _D("method list len %d", g_list_length(ih->list_methods));*/
1633
1634                         ret_dbus = _gdbus_register_object(dh, oh->path, ih);
1635                         if (ret_dbus <= 0)
1636                                 _E("failed to register dbus object%d", ret_dbus);
1637
1638                 }
1639         }
1640         return 0;
1641 err:
1642
1643         // todo: delete all updates
1644
1645         return -1;
1646 }
1647
1648 int dbus_handle_register_dbus_object_all(dbus_handle_h handle)
1649 {
1650         dcl_gdbus();
1651         dbus_object_handle_s *oh = NULL;
1652         dbus_interface_s *ih = NULL;
1653         int ret_dbus = 0;
1654
1655         if (!dh) {
1656                 dh = _gdbus_get_default_connection();
1657                 if (!dh) {
1658                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1659                         return -1;
1660                 }
1661         }
1662         if (!dh->conn) {
1663                 _E("connection is null\n");
1664                 return -1;
1665         }
1666
1667         if (!dh->list_object) {
1668                 _E("obj list is empty");
1669                 return -1;
1670         }
1671
1672         /*if (dh && dh->list_object)
1673                 _D("obj list len %d", g_list_length(dh->list_object));*/
1674
1675         for (GList *item = g_list_first(dh->list_object); item != NULL; item = g_list_next(item)) {
1676                 oh = (dbus_object_handle_s *)item->data;
1677
1678                 if (!oh) {
1679                         _E("something wrong");
1680                         assert(0);
1681                 }
1682                 if (!oh->list_ifaces) {
1683                         _E("path %s: list_ifaces are null", oh->path);
1684                         goto err;
1685                 }
1686
1687                 //_D("iface list len %d", g_list_length(oh->list_ifaces));
1688
1689                 for (GList *li = g_list_first(oh->list_ifaces); li != NULL; li = g_list_next(li)) {
1690                         ih = (dbus_interface_s *)li->data;
1691
1692                         /* if there are no modification, goto next */
1693                         if (!ih->modified)
1694                                 continue;
1695
1696                         /* todo: if already registered interface, unregister first */
1697
1698                         /*_E("interface %s:", ih->name);
1699                         if (ih && ih->list_methods)
1700                                 _D("method list len %d", g_list_length(ih->list_methods));*/
1701
1702                         ret_dbus = _gdbus_register_object(dh, oh->path, ih);
1703                         if (ret_dbus <= 0)
1704                                 _E("failed to register dbus object%d", ret_dbus);
1705
1706                 }
1707         }
1708         return 0;
1709 err:
1710
1711         // todo: delete all updates
1712
1713         return -1;
1714 }
1715
1716 guint gdbus_signal_subscribe(dbus_handle_h handle, const char *path,
1717                         const char *iface, const char *name,
1718                         GDBusSignalCallback cb, void *data,
1719                         destroy_notified free_func)
1720 {
1721         dcl_gdbus();
1722
1723         if (!dh) {
1724                 dh = _gdbus_get_default_connection();
1725                 if (!dh) {
1726                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1727                         return 0;
1728                 }
1729         }
1730
1731         if (!dh->conn) {
1732                 _E("connection is null. check bus status");
1733                 return 0;
1734         }
1735         return g_dbus_connection_signal_subscribe(dh->conn, NULL, iface, name, path, NULL, G_DBUS_SIGNAL_FLAGS_NONE, cb, data, free_func);
1736 }
1737
1738 void gdbus_signal_unsubscribe(dbus_handle_h handle, guint id)
1739 {
1740         dcl_gdbus();
1741         if (!dh) {
1742                 dh = _gdbus_get_default_connection();
1743                 if (!dh) {
1744                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1745                         return;
1746                 }
1747         }
1748
1749         if (!dh->conn) {
1750                 _E("connection is null. check bus status");
1751                 return;
1752         }
1753
1754         g_dbus_connection_signal_unsubscribe(dh->conn, id);
1755 }
1756
1757 static void _signal_reply_sync_cb(GDBusConnection  *conn,
1758         const gchar *sender,
1759         const gchar *path,
1760         const gchar *iface,
1761         const gchar *name,
1762         GVariant *param,
1763         gpointer data)
1764 {
1765         sig_ctx *ctx = data;
1766         if (!ctx) {
1767                 _E("user data is null");
1768                 assert(0);
1769         }
1770
1771         ctx->param = g_variant_ref(param);
1772         ctx->quit_reason = CTX_QUIT_NORMAL;
1773
1774         if (ctx->timeout_src) {
1775                 g_source_destroy(ctx->timeout_src);
1776                 ctx->timeout_src = NULL;
1777         }
1778         g_main_loop_quit(ctx->loop);
1779 }
1780
1781 sig_ctx *gdbus_signal_ctx_new(void)
1782 {
1783         sig_ctx *ctx;
1784
1785         ctx = (sig_ctx *)malloc(sizeof(sig_ctx));
1786         if (!ctx) {
1787                 _E("failed to alloc mem");
1788                 return NULL;
1789         }
1790
1791         ctx->sig_id = 0;
1792
1793         ctx->context = g_main_context_new();
1794         if (!ctx->context) {
1795                 _E("failed to alloc context");
1796                 free(ctx);
1797                 return NULL;
1798         }
1799         ctx->loop = g_main_loop_new(ctx->context, FALSE);
1800         if (!ctx->loop) {
1801                 _E("failed to alloc main loop");
1802                 g_main_context_unref(ctx->context);
1803                 free(ctx);
1804                 return NULL;
1805         }
1806         ctx->timeout_src = NULL;
1807         ctx->param = NULL;
1808         ctx->quit_reason = CTX_QUIT_UNKNOWN;
1809         ctx->user_data = NULL;
1810
1811         return ctx;
1812 }
1813
1814 void gdbus_signal_ctx_free(sig_ctx *ctx)
1815 {
1816         if (!ctx)
1817                 return ;
1818
1819         if (ctx->param) {
1820                 g_variant_unref(ctx->param);
1821                 ctx->param = NULL;
1822         }
1823         if (ctx->sig_id) {
1824                 gdbus_signal_unsubscribe(NULL, ctx->sig_id);
1825                 ctx->sig_id = 0;
1826         }
1827         if (ctx->timeout_src) {
1828                 g_source_destroy(ctx->timeout_src);
1829                 ctx->timeout_src = NULL;
1830         }
1831         if (ctx->context) {
1832                 g_main_context_pop_thread_default(ctx->context);
1833                 g_main_context_unref(ctx->context);
1834                 ctx->context = NULL;
1835         }
1836         if (ctx->loop) {
1837                 g_main_loop_unref(ctx->loop);
1838                 ctx->loop = NULL;
1839         }
1840         free(ctx);
1841 }
1842
1843 static gboolean _cb_ctx_timeout(gpointer user_data)
1844 {
1845         sig_ctx *ctx = user_data;
1846
1847         if (!ctx) {
1848                 _E("user_data is null");
1849                 return FALSE;
1850         }
1851
1852         ctx->quit_reason = CTX_QUIT_TIMEOUT;
1853         /* if cb return FALSE, source will be destroyed */
1854         ctx->timeout_src = NULL;
1855
1856         gdbus_signal_unsubscribe(NULL, ctx->sig_id);
1857         ctx->sig_id = 0;
1858
1859         g_main_loop_quit(ctx->loop);
1860
1861         return FALSE;
1862 }
1863
1864 #define CTX_MAX_TIMEOUT 25000
1865
1866 int gdbus_signal_ctx_add_timeout(sig_ctx *ctx, int timeout_msec)
1867 {
1868         GSource *src = NULL;
1869
1870         if (!ctx)
1871                 return -EINVAL;
1872         if (timeout_msec < -1)
1873                 return -EINVAL;
1874
1875         if (timeout_msec == -1 || timeout_msec >= CTX_MAX_TIMEOUT)
1876                 timeout_msec = CTX_MAX_TIMEOUT;
1877
1878         src = g_timeout_source_new(timeout_msec);
1879         if (!src)
1880                 return -ENOMEM;
1881
1882         g_source_set_callback(src, _cb_ctx_timeout, ctx, NULL);
1883         g_source_attach(src, ctx->context);
1884         g_source_unref(src);
1885
1886         ctx->timeout_src = src;
1887
1888         return 0;
1889 }
1890
1891 guint gdbus_signal_ctx_subscribe(dbus_handle_h handle, sig_ctx *ctx,
1892                 const char *sender,     const char *path,
1893                 const char *iface, const char *name,
1894                 GDBusSignalCallback _cb)
1895 {
1896         dcl_gdbus();
1897
1898         if (!ctx) {
1899                 _E("wrong param ctx is null");
1900                 return 0;
1901         }
1902
1903         if (!dh) {
1904                 dh = _gdbus_get_default_connection();
1905                 if (!dh) {
1906                         _E("failed to get default connection, bustype:%d",
1907                                         (int)gdbus_get_default_bus_type());
1908                         return 0;
1909                 }
1910         }
1911
1912         if (!dh->conn) {
1913                 _E("connection is null. check bus status");
1914                 return 0;
1915         }
1916
1917         if (!_cb)
1918                 _cb = _signal_reply_sync_cb;
1919
1920         /* change context before subscribe */
1921         g_main_context_push_thread_default(ctx->context);
1922
1923         ctx->sig_id = g_dbus_connection_signal_subscribe(dh->conn,
1924                         sender, iface, name, path, NULL,
1925                         G_DBUS_SIGNAL_FLAGS_NONE, _cb,
1926                         (void*)ctx, NULL);
1927
1928         if (!ctx->sig_id)
1929                 _E("failed to subscribe signal");
1930
1931         return ctx->sig_id;
1932 }
1933
1934 int gdbus_signal_ctx_wait(sig_ctx *ctx)
1935 {
1936         if (!ctx || !ctx->loop)
1937                 return -EINVAL;
1938
1939         g_main_loop_run(ctx->loop);
1940
1941         _D("quit g_main_loop");
1942
1943         return ctx->quit_reason;
1944 }
1945
1946 int _check_type_string_is_container(const char *signature)
1947 {
1948         if (!signature)
1949                 return FALSE;
1950
1951         switch (signature[0]) {
1952         case 'a':
1953         case 'm':
1954         case 'r':
1955         case '(':
1956         case '{':
1957         case 'v':
1958                 return TRUE;
1959         default:
1960                 return FALSE;
1961         }
1962
1963         return TRUE;
1964 }
1965
1966 int gdbus_signal_emit(const char *dest,
1967                                         const char *path,
1968                                         const char *iface,
1969                                         const char *name,
1970                                         GVariant *param)
1971 {
1972         dbus_handle_s *dh = NULL;
1973         GError *err = NULL;
1974         gboolean ret = 0;
1975
1976         dh = _gdbus_get_default_connection();
1977         if (!dh) {
1978                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
1979                 return -1;
1980         }
1981
1982         ret = g_dbus_connection_emit_signal(dh->conn, dest, path, iface, name, param, &err);
1983         if (err) {
1984                 _E("%d %s\n", ret, err ? err->message : "NULL");
1985                 g_error_free(err);
1986         }
1987
1988         return ret;
1989 }
1990
1991 int gdbus_signal_emit_sync(const char *dest,
1992                                         const char *path,
1993                                         const char *iface,
1994                                         const char *name,
1995                                         GVariant *param)
1996 {
1997         dbus_handle_s *dh = NULL;
1998         GError *err = NULL;
1999         gboolean ret = 0;
2000
2001         dh = _gdbus_get_default_connection();
2002         if (!dh) {
2003                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2004                 return -1;
2005         }
2006
2007         ret = g_dbus_connection_emit_signal(dh->conn, dest, path, iface, name, param, &err);
2008         if (!ret) {
2009                 _E("%d %s\n", ret, err ? err->message : "NULL");
2010                 g_error_free(err);
2011         }
2012
2013         ret = g_dbus_connection_flush_sync(dh->conn, NULL, &err);
2014         if (!ret) {
2015                 _E("%d %s\n", ret, err ? err->message : "NULL");
2016                 g_error_free(err);
2017         }
2018
2019         return ret;
2020 }
2021
2022 int gdbus_flush_sync(dbus_handle_h handle)
2023 {
2024         dcl_gdbus();
2025         GError *err = NULL;
2026         gboolean ret = 0;
2027
2028         if (!dh) {
2029                 dh = _gdbus_get_default_connection();
2030                 if (!dh) {
2031                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2032                         return 0;
2033                 }
2034         }
2035
2036         ret = g_dbus_connection_flush_sync(dh->conn, NULL, &err);
2037         if (!ret) {
2038                 _E("%d %s\n", ret, err ? err->message : "NULL");
2039                 g_error_free(err);
2040         }
2041
2042         return ret;
2043 }
2044
2045 int gdbus_call_sync_with_reply(const char *dest,
2046                                                 const char *path,
2047                                                 const char *iface,
2048                                                 const char *method,
2049                                                 GVariant *param,
2050                                                 GVariant **out_reply)
2051 {
2052         GError *err = NULL;
2053         GVariant *reply = NULL;
2054         int ret = 0;
2055         dbus_handle_s *dh = NULL;
2056
2057         if (!dest || !path || !iface || !method) {
2058                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2059                 if (param)
2060                         g_variant_unref(param);
2061                 return -EINVAL;
2062         }
2063
2064         dh = _gdbus_get_default_connection();
2065         if (!dh) {
2066                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2067                 if (param)
2068                         g_variant_unref(param);
2069                 return -ECOMM;
2070         }
2071
2072         reply = g_dbus_connection_call_sync(dh->conn,
2073                         dest, path, iface, method,
2074                         param, NULL,
2075                         G_DBUS_CALL_FLAGS_NONE,
2076                         DBUS_REPLY_TIMEOUT,
2077                         NULL,
2078                         &err);
2079         if (!reply || err) {
2080                 if (err) {
2081                         _E("failed to g_dbus_connection_call_sync:%s", err->message);
2082                         if (g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED))
2083                                 ret = -EPERM;
2084                         else
2085                                 ret = -ECOMM;
2086                         g_error_free(err);
2087                         return ret;
2088                 } else {
2089                         _E("failed to g_dbus_connection_call_sync");
2090                 }
2091                 return -ECOMM;
2092         }
2093
2094         if(out_reply)
2095                 *out_reply = reply;
2096         else
2097                 g_variant_unref(reply);
2098
2099         return ret;
2100 }
2101
2102 int gdbus_call_sync_with_reply_timeout(const char *dest, const char *path,
2103         const char *iface, const char *method, GVariant *param, GVariant **out_reply, int timeout)
2104 {
2105         GError *err = NULL;
2106         GVariant *reply;
2107         dbus_handle_s *dh = NULL;
2108
2109         if (!dest || !path || !iface || !method) {
2110                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2111                 if (param)
2112                         g_variant_unref(param);
2113                 return -EINVAL;
2114         }
2115
2116         dh = _gdbus_get_default_connection();
2117         if (!dh) {
2118                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2119                 if (param)
2120                         g_variant_unref(param);
2121                 return -ECOMM;
2122         }
2123
2124         reply = g_dbus_connection_call_sync(dh->conn,
2125                                         dest, path, iface, method,
2126                                         param, NULL,
2127                                         G_DBUS_CALL_FLAGS_NONE,
2128                                         timeout,
2129                                         NULL,
2130                                         &err);
2131         if (!reply || err) {
2132                 if (err) {
2133                         _E("failed to g_dbus_connection_call_sync:%s", err->message);
2134                         g_error_free(err);
2135                 } else {
2136                         _E("failed to g_dbus_connection_call_sync");
2137                 }
2138                 return -ECOMM;
2139         }
2140
2141         if(out_reply)
2142                 *out_reply = reply;
2143         else
2144                 g_variant_unref(reply);
2145
2146         return 0;
2147 }
2148
2149 int gdbus_call_pairs_sync_with_reply_int(const char *dest,
2150                                         const char *path,
2151                                         const char *iface,
2152                                         const char *method,
2153                                         int num,
2154                                         va_list args)
2155 {
2156         GError *err = NULL;
2157         GVariant *reply = NULL;
2158         char *key, *value;
2159         int ret = 0;
2160         GVariant *var;
2161         GVariantBuilder *builder;
2162         dbus_handle_s *dh = NULL;
2163
2164         if (!dest || !path || !iface || !method) {
2165                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2166                 return -1;
2167         }
2168
2169         dh = _gdbus_get_default_connection();
2170         if (!dh) {
2171                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2172                 return -1;
2173         }
2174
2175         builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
2176
2177         for (int i = 0 ; i < num ; i = i + 2) {
2178                 key = va_arg(args, char *);
2179                 value = va_arg(args, char *);
2180                 _I("key(%s), value(%s)", key, value);
2181                 g_variant_builder_add(builder, "{ss}", key, value);
2182         }
2183
2184         var = g_variant_new("(a{ss})", builder);
2185         g_variant_builder_unref(builder);
2186
2187         reply = g_dbus_connection_call_sync(dh->conn,
2188                 dest, path, iface, method,
2189                 var, NULL, G_DBUS_CALL_FLAGS_NONE, DBUS_REPLY_TIMEOUT, NULL, &err);
2190         if (!reply || err) {
2191                 _E("failed to g_dbus_connection_call_sync");
2192                 return -1;
2193         }
2194
2195         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0)
2196                 g_variant_get(reply, "(i)", &ret);
2197         else
2198                 ret = -ENOMSG;
2199
2200         g_variant_unref(reply);
2201
2202         return ret;
2203 }
2204
2205 int gdbus_call_pairs_async(const char *dest,
2206                                         const char *path,
2207                                         const char *iface,
2208                                         const char *method,
2209                                         int num,
2210                                         va_list args)
2211 {
2212         char *key, *value;
2213         GVariant *var;
2214         GVariantBuilder *builder;
2215         dbus_handle_s *dh = NULL;
2216
2217         if (!dest || !path || !iface || !method) {
2218                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2219                 return -1;
2220         }
2221
2222         dh = _gdbus_get_default_connection();
2223         if (!dh) {
2224                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2225                 return -1;
2226         }
2227
2228         // dict
2229         builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
2230
2231         for (int i = 0 ; i < num ; i = i + 2) {
2232                 key = va_arg(args, char *);
2233                 value = va_arg(args, char *);
2234                 _I("key(%s), value(%s)", key, value);
2235                 g_variant_builder_add(builder, "{ss}", key, value);
2236         }
2237
2238         var = g_variant_new("(a{ss})", builder);
2239         g_variant_builder_unref(builder);
2240
2241         g_dbus_connection_call(dh->conn,
2242                                 dest, path, iface, method,
2243                                 var, NULL,
2244                                 G_DBUS_CALL_FLAGS_NONE,
2245                                 -1,
2246                                 NULL,
2247                                 NULL,
2248                                 NULL);
2249
2250         return 0;
2251 }
2252
2253 gint* gdbus_get_unix_fd_list(GDBusMethodInvocation *invocation, int *size)
2254 {
2255         GUnixFDList *fd_list = NULL;
2256         int length = 0;
2257
2258         fd_list = g_dbus_message_get_unix_fd_list(g_dbus_method_invocation_get_message(invocation));
2259
2260         if (!fd_list) {
2261                 _E("failed to g_unix_fd_list_get_length: fd_list is null");
2262                 return NULL;
2263         }
2264
2265         length = g_unix_fd_list_get_length(fd_list);
2266         if (length == 0) {
2267                 _E("failed to g_unix_fd_list_get_length: list size is 0");
2268                 return NULL;
2269         }
2270         if (size)
2271                 *size = length;
2272
2273         return g_unix_fd_list_steal_fds(fd_list, NULL);
2274 }
2275
2276 int gdbus_call_unix_fd_list_sync_with_reply(const char *dest,
2277                                                                 const char *path,
2278                                                                 const char *iface,
2279                                                                 const char *method,
2280                                                                 GVariant *param,
2281                                                                 GVariant **out_reply,
2282                                                                 int *in_fdlist,
2283                                                                 int in_size,
2284                                                                 int **out_fdlist,
2285                                                                 int *out_size)
2286 {
2287         int ret = 0;
2288         GVariant *reply = NULL;
2289         GError *err = NULL;
2290         dbus_handle_s *dh = NULL;
2291         GUnixFDList *g_infdlist = NULL;
2292         GUnixFDList *g_outfdlist = NULL;
2293
2294         if (!dest || !path || !iface || !method) {
2295                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2296                 return -EINVAL;
2297         }
2298         if (in_fdlist && in_size == 0) {
2299                 _E("wrong in_fdlist is not null but in_size is 0");
2300                 return -EINVAL;
2301         }
2302
2303         dh = _gdbus_get_default_connection();
2304         if (!dh) {
2305                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2306                 return -EAGAIN;
2307         }
2308
2309         /* append fd */
2310         if (in_fdlist) {
2311                 g_infdlist = g_unix_fd_list_new_from_array(in_fdlist, in_size);
2312                 if (!g_infdlist) {
2313                         _E("failed to g_unix_fd_list_new_from_array\n");
2314                         ret = -EAGAIN;
2315                         goto out;
2316                 }
2317                 //g_infdlist = g_unix_fd_list_new();
2318                 //if (g_unix_fd_list_append(g_infdlist, in_fdlist[0], &err) < 0) {
2319         }
2320
2321         /* send message */
2322         reply = g_dbus_connection_call_with_unix_fd_list_sync(dh->conn,
2323                 dest, path, iface, method,
2324                 param, NULL,
2325                 G_DBUS_CALL_FLAGS_NONE,
2326                 -1,
2327                 g_infdlist, &g_outfdlist,
2328                 NULL, &err);
2329         if (!reply || err) {
2330                 if (err) {
2331                         _E("failed to g_dbus_connection_call_with_unix_fd_list_sync:%s", err->message);
2332                         g_error_free(err);
2333                 } else {
2334                         _E("failed to g_dbus_connection_call_with_unix_fd_list_sync:");
2335                         if (param)
2336                                 g_variant_unref(param);
2337                         if (g_infdlist)
2338                                 g_object_unref(g_infdlist);
2339                 }
2340                 ret = -EAGAIN;
2341                 goto out;
2342         }
2343
2344         if(out_reply)
2345                 *out_reply = reply;
2346         else
2347                 g_variant_unref(reply);
2348
2349         /* copy fds to out array */
2350         if (g_outfdlist) {
2351                 *out_size = g_unix_fd_list_get_length(g_outfdlist);
2352                 if (*out_size == 0)
2353                         goto out;
2354                 *out_fdlist = g_unix_fd_list_steal_fds(g_outfdlist, NULL);
2355         }
2356 out:
2357         if (g_outfdlist)
2358                 g_object_unref(g_outfdlist);
2359         return ret;
2360 }
2361
2362 int gdbus_call_sync_with_reply_int(const char *dest,
2363                                 const char *path,
2364                                 const char *iface,
2365                                 const char *method,
2366                                 GVariant *param,
2367                                 int *output)
2368 {
2369         int ret = 0;
2370         int result;
2371         gboolean result_bool;
2372         GVariant *reply = NULL;
2373
2374         if (!dest || !path || !iface || !method) {
2375                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2376                 return -EINVAL;
2377         }
2378
2379         ret = gdbus_call_sync_with_reply(dest, path, iface, method, param, &reply);
2380         if (ret < 0)
2381                 return ret;
2382
2383         if (!reply)
2384                 return -ECOMM;
2385
2386         if (g_strcmp0("(i)", g_variant_get_type_string(reply)) == 0) {
2387                 g_variant_get(reply, "(i)", &result);
2388                 if(output)
2389                         *output = result;
2390         } else if (g_strcmp0("(b)", g_variant_get_type_string(reply)) == 0) {
2391                 g_variant_get(reply, "(b)", &result_bool);
2392                 if(output)
2393                         *output = (int)result_bool;
2394         } else {
2395                 ret = -ENOMSG;
2396         }
2397
2398         g_variant_unref(reply);
2399
2400         return ret;
2401 }
2402
2403 int gdbus_call_async(const char *dest,
2404                                         const char *path,
2405                                         const char *iface,
2406                                         const char *method,
2407                                         GVariant *param)
2408 {
2409         dbus_handle_s *dh = NULL;
2410
2411         if (!dest || !path || !iface || !method) {
2412                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2413                 return -1;
2414         }
2415
2416         dh = _gdbus_get_default_connection();
2417         if (!dh) {
2418                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2419                 return -1;
2420         }
2421
2422         g_dbus_connection_call(dh->conn,
2423                                 dest, path, iface, method,
2424                                 param, NULL,
2425                                 G_DBUS_CALL_FLAGS_NONE,
2426                                 -1,
2427                                 NULL,
2428                                 NULL,
2429                                 NULL);
2430
2431         return 0;
2432 }
2433
2434 /* callback should free gvariant */
2435 static void _cb_pending(GDBusConnection *conn,
2436                         GAsyncResult *res,
2437                         gpointer user_data)
2438 {
2439         GVariant *reply = NULL;
2440         GError *err = NULL;
2441         pending_call_data *data = (pending_call_data *)user_data;
2442
2443         reply = g_dbus_connection_call_finish(conn, res, &err);
2444         if (!reply || err) {
2445                 if (!err)
2446                         g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED,
2447                                 "Error during g_dbus_connection_call");
2448
2449                 if (data && data->func)
2450                         data->func(NULL, data->data, err);
2451                 goto out;
2452         }
2453
2454         if (data && data->func)
2455                 data->func(reply, data->data, err);
2456 out:
2457         if (err)
2458                 g_error_free(err);
2459         if (data)
2460                 free(data);
2461 }
2462
2463 int gdbus_call_async_with_reply(const char *dest,
2464                                         const char *path,
2465                                         const char *iface,
2466                                         const char *method,
2467                                         GVariant *param,
2468                                         dbus_pending_cb cb,
2469                                         int timeout_msec,
2470                                         void *data)
2471 {
2472         dbus_handle_s *dh = NULL;
2473         pending_call_data *pdata = NULL;
2474         int ret = 0;
2475
2476         if (!dest || !path || !iface || !method) {
2477                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2478                 return -1;
2479         }
2480
2481         if (timeout_msec < -1) {
2482                 _E("wrong timeout %d", timeout_msec);
2483                 return -1;
2484         }
2485
2486         dh = _gdbus_get_default_connection();
2487         if (!dh) {
2488                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2489                 return -EPERM;
2490         }
2491
2492         if (cb) {
2493                 pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
2494                 if (!pdata) {
2495                         ret = -ENOMEM;
2496                         goto err;
2497                 }
2498
2499                 pdata->func = cb;
2500                 pdata->data = data;
2501         }
2502         g_dbus_connection_call(dh->conn,
2503                                 dest, path, iface, method,
2504                                 param, NULL,
2505                                 G_DBUS_CALL_FLAGS_NONE,
2506                                 timeout_msec,
2507                                 NULL,
2508                                 (GAsyncReadyCallback)_cb_pending,
2509                                 pdata);
2510
2511         return ret;
2512 err:
2513         if (param)
2514                 g_variant_unref(param);
2515         return ret;
2516 }
2517
2518 int gdbus_call_pairs_async_with_reply(const char *dest,
2519                                                 const char *path,
2520                                                 const char *iface,
2521                                                 const char *method,
2522                                                 int num,
2523                                                 va_list args,
2524                                                 dbus_pending_cb cb,
2525                                                 int timeout_msec,
2526                                                 void *data)
2527 {
2528         dbus_handle_s *dh = NULL;
2529         pending_call_data *pdata = NULL;
2530         GVariantBuilder *builder;
2531         char *key, *value;
2532         GVariant *param;
2533         int ret = 0;
2534
2535         if (!dest || !path || !iface || !method) {
2536                 _E("wrong parameters dest(%s) path(%s) iface(%s) method(%s)", dest, path, iface, method);
2537                 return -1;
2538         }
2539
2540         if (timeout_msec < -1) {
2541                 _E("wrong timeout %d", timeout_msec);
2542                 return -1;
2543         }
2544
2545         dh = _gdbus_get_default_connection();
2546         if (!dh) {
2547                 _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2548                 return -EPERM;
2549         }
2550
2551         // dict
2552         builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
2553
2554         for (int i = 0 ; i < num ; i = i + 2) {
2555                 key = va_arg(args, char *);
2556                 value = va_arg(args, char *);
2557                 _I("key(%s), value(%s)", key, value);
2558                 g_variant_builder_add(builder, "{ss}", key, value);
2559         }
2560
2561         param = g_variant_new("(a{ss})", builder);
2562         g_variant_builder_unref(builder);
2563
2564         if (cb) {
2565                 pdata = (pending_call_data*)malloc(sizeof(pending_call_data));
2566                 if (!pdata) {
2567                         ret = -ENOMEM;
2568                         goto err;
2569                 }
2570
2571                 pdata->func = cb;
2572                 pdata->data = data;
2573         }
2574         g_dbus_connection_call(dh->conn,
2575                                 dest, path, iface, method,
2576                                 param, NULL,
2577                                 G_DBUS_CALL_FLAGS_NONE,
2578                                 timeout_msec,
2579                                 NULL,
2580                                 (GAsyncReadyCallback)_cb_pending,
2581                                 pdata);
2582
2583         return ret;
2584 err:
2585         if (param)
2586                 g_variant_unref(param);
2587         return ret;
2588 }
2589
2590 int gdbus_connection_get_sender_pid(GDBusConnection *conn, const char * sender)
2591 {
2592         GError *err = NULL;
2593         GVariant *reply = NULL;
2594         pid_t pid = 0;
2595
2596         if (!conn) {
2597                 _E("connection is null");
2598                 return -1;
2599         }
2600         if (!sender) {
2601                 _E("sender is null");
2602                 return -1;
2603         }
2604
2605         reply = g_dbus_connection_call_sync(conn,
2606                         DBUS_BUS_NAME, DBUS_OBJECT_PATH, DBUS_INTERFACE_NAME,
2607                         "GetConnectionUnixProcessID",
2608                         g_variant_new("(s)", sender), NULL,
2609                         G_DBUS_CALL_FLAGS_NONE,
2610                         DBUS_REPLY_TIMEOUT,
2611                         NULL,
2612                         &err);
2613         if (!reply || err) {
2614                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2615                 g_error_free(err);
2616                 return -1;
2617         }
2618
2619         g_variant_get(reply, "(u)", &pid);
2620         g_variant_unref(reply);
2621
2622         return pid;
2623 }
2624
2625 int gdbus_get_sender_pid(dbus_handle_h handle, const char * sender)
2626 {
2627         dcl_gdbus();
2628
2629         if (!dh) {
2630                 dh = _gdbus_get_default_connection();
2631                 if (!dh) {
2632                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2633                         return -1;
2634                 }
2635         }
2636         if (!dh->conn) {
2637                 _E("wrong dbus handle. connection is null");
2638                 assert(0);
2639                 return -1;
2640         }
2641
2642         return gdbus_connection_get_sender_pid(dh->conn, sender);
2643 }
2644
2645 int gdbus_get_sender_credentials(dbus_handle_h handle, const char *name, GDBusCredentials *creds)
2646 {
2647         dcl_gdbus();
2648         GVariant *reply = NULL;
2649         GError *err = NULL;
2650         GVariantIter *iter = NULL;
2651         char * item;
2652         GVariant *sub;
2653
2654         if (!dh) {
2655                 dh = _gdbus_get_default_connection();
2656                 if (!dh) {
2657                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2658                         return -1;
2659                 }
2660         }
2661         reply = g_dbus_connection_call_sync(dh->conn,
2662                                         DBUS_BUS_NAME,
2663                                         DBUS_OBJECT_PATH,
2664                                         DBUS_INTERFACE_NAME,
2665                                         "GetConnectionCredentials",
2666                                         g_variant_new("(s)", name),
2667                                         NULL,
2668                                         G_DBUS_CALL_FLAGS_NONE,
2669                                         DBUS_REPLY_TIMEOUT,
2670                                         NULL,
2671                                         &err);
2672         if (!reply || err) {
2673                 _E("failed to g_dbus_connection_call_sync:%s", err->message);
2674                 return -1;
2675         }
2676
2677         g_variant_get(reply, "(a{sv})", &iter);
2678
2679         while (g_variant_iter_loop(iter, "{sv}", &item, &sub)) {
2680                 if (!g_strcmp0(item, "UnixUserID")) {
2681                         g_variant_get(sub, "u", &creds->uid);
2682                         //_D("UnixUserID %u", creds->uid);
2683                 } else if (!g_strcmp0(item, "ProcessID")) {
2684                         g_variant_get(sub, "u", &creds->pid);
2685                         //_D("ProcessID %u", creds->pid);
2686                 } else if (!g_strcmp0(item, "LinuxSecurityLabel")) {
2687                         g_variant_get(sub, "^ay", &creds->sec_label);
2688                         //_D("%s", creds->sec_label);
2689                 }
2690         }
2691
2692         if (iter)
2693                 g_variant_iter_free(iter);
2694         if (reply)
2695                 g_variant_unref(reply);
2696
2697         return 0;
2698 }
2699
2700 void _destroy_notify_watch_name(gpointer data)
2701 {
2702 //      if (data)
2703 //              free(data);
2704 }
2705
2706 int gdbus_watch_name(const char *name,
2707                         GBusNameAppearedCallback  name_appeared_handler,
2708                         GBusNameVanishedCallback  name_vanished_handler,
2709                         void *user_data,
2710                         GDestroyNotify user_data_free_func)
2711 {
2712         guint id = 0;
2713
2714         if (!name) {
2715                 _E("wrong name name is null");
2716                 return -1;
2717         }
2718         if (!name_appeared_handler && !name_vanished_handler) {
2719                 _E("both function pointers are null");
2720                 return -1;
2721         }
2722
2723         id = g_bus_watch_name(gdbus_get_default_bus_type(),
2724                                 name,
2725                                 G_BUS_NAME_WATCHER_FLAGS_NONE,
2726                                 name_appeared_handler,
2727                                 name_vanished_handler,
2728                                 user_data,
2729                                 user_data_free_func ? user_data_free_func : _destroy_notify_watch_name);
2730         if (!id) {
2731                 _E("failed to g_bus_watch_name");
2732                 return -1;
2733         }
2734
2735         return id;
2736 }
2737
2738 int _get_cmdline_name(pid_t pid, char *cmdline, size_t cmdline_size)
2739 {
2740         int fd, ret_file;
2741         char buf[PATH_MAX + 1];
2742         char *filename;
2743
2744         snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
2745         fd = open(buf, O_RDONLY);
2746         if (fd < 0) {
2747                 errno = ESRCH;
2748                 return -1;
2749         }
2750
2751         ret_file = read(fd, buf, PATH_MAX);
2752         close(fd);
2753         if (ret_file < 0)
2754                 return -1;
2755
2756         buf[PATH_MAX] = '\0';
2757
2758         filename = strrchr(buf, '/');
2759         if (filename == NULL)
2760                 filename = buf;
2761         else
2762                 filename = filename + 1;
2763
2764         if (cmdline_size < strlen(filename) + 1) {
2765                 errno = EOVERFLOW;
2766                 return -1;
2767         }
2768
2769         strncpy(cmdline, filename, cmdline_size - 1);
2770         cmdline[cmdline_size - 1] = '\0';
2771         return 0;
2772 }
2773
2774 void gdbus_check_name_owner(dbus_handle_h handle, const char *owner_name)
2775 {
2776         dcl_gdbus();
2777         char exe_name[PATH_MAX];
2778         int pid;
2779         char **strv = NULL;
2780         int i;
2781
2782         if (!dh) {
2783                 dh = _gdbus_get_default_connection();
2784                 if (!dh) {
2785                         _E("failed to get default connection, bustype:%d", (int)gdbus_get_default_bus_type());
2786                         return ;
2787                 }
2788         }
2789
2790         strv = gdbus_get_owner_list(dh, owner_name);
2791         if (!strv) {
2792                 _E("failed to get owner list of %s", owner_name);
2793                 return ;
2794         }
2795
2796         for (i = 0; strv[i] != NULL; ++i) {
2797                 pid = gdbus_get_sender_pid(dh, strv[i]);
2798                 if (_get_cmdline_name(pid, exe_name, PATH_MAX) != 0)
2799                         break;
2800                 _I("%s(%d)", exe_name, pid);
2801         }
2802
2803         g_strfreev(strv);
2804 }
2805
2806 int check_systemd_active(void)
2807 {
2808         int ret = FALSE;
2809         GVariant *reply = NULL;
2810         GVariant *var = NULL;
2811         char *state;
2812
2813         _I("%s %s", "org.freedesktop.systemd1.Unit", "ActiveState");
2814
2815         ret = gdbus_call_sync_with_reply("org.freedesktop.systemd1",
2816                         "/org/freedesktop/systemd1/unit/default_2etarget",
2817                         DBUS_INTERFACE_PROPERTIES,
2818                         "Get",
2819                         g_variant_new("(ss)", "org.freedesktop.systemd1.Unit", "ActiveState"),
2820                         &reply);
2821         if (ret < 0)
2822                 return ret;
2823         if (!reply)
2824                 return -EBADMSG;
2825
2826         if (!g_variant_get_safe(reply, "(v)", &var)) {
2827                 _E("reply is not variant type");
2828                 ret = -EBADMSG;
2829                 goto out;
2830         }
2831         if (!g_variant_get_safe(var, "(s)", &state)) {
2832                 _E("variant doesn't have string (%s)", g_variant_get_type_string(var));
2833                 ret = -EBADMSG;
2834                 goto out;
2835         }
2836
2837         if (strncmp(state, "active", 6) == 0)
2838                 ret = TRUE;
2839
2840         g_free(state);
2841 out:
2842         if (var)
2843                 g_variant_unref(var);
2844         if (reply)
2845                 g_variant_unref(reply);
2846
2847         return ret;
2848 }
2849
2850 GVariant *gdbus_make_simple_array(const char *sig, int *param)
2851 {
2852         GVariantBuilder *builder = NULL;
2853         GVariant *var = NULL;
2854         char format[256];
2855         int i = 0;
2856
2857         builder = g_variant_builder_new(G_VARIANT_TYPE(sig));
2858         if (!builder) {
2859                 _E("failed to g_variant_builder_new");
2860                 return NULL;
2861         }
2862
2863         while (param[i])
2864                 g_variant_builder_add(builder, "i", param[i++]);
2865
2866         snprintf(format, sizeof(format) - 1, "(%s)", sig);
2867         var = g_variant_new(format, builder);
2868         g_variant_builder_unref(builder);
2869         return var;
2870 }