efl

Форк
0
/
eldbus_signal_handler.c 
348 строк · 10.7 Кб
1
#include "eldbus_private.h"
2
#include "eldbus_private_types.h"
3
#include <dbus/dbus.h>
4

5
/* TODO: mempool of Eldbus_Signal_Handler */
6

7
#define ELDBUS_SIGNAL_HANDLER_CHECK(handler)                        \
8
  do                                                               \
9
    {                                                              \
10
       EINA_SAFETY_ON_NULL_RETURN(handler);                        \
11
       if (!EINA_MAGIC_CHECK(handler, ELDBUS_SIGNAL_HANDLER_MAGIC)) \
12
         {                                                         \
13
            EINA_MAGIC_FAIL(handler, ELDBUS_SIGNAL_HANDLER_MAGIC);  \
14
            return;                                                \
15
         }                                                         \
16
    }                                                              \
17
  while (0)
18

19
#define ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, retval)         \
20
  do                                                               \
21
    {                                                              \
22
       EINA_SAFETY_ON_NULL_RETURN_VAL(handler, retval);            \
23
       if (!EINA_MAGIC_CHECK(handler, ELDBUS_SIGNAL_HANDLER_MAGIC)) \
24
         {                                                         \
25
            EINA_MAGIC_FAIL(handler, ELDBUS_SIGNAL_HANDLER_MAGIC);  \
26
            return retval;                                         \
27
         }                                                         \
28
    }                                                              \
29
  while (0)
30

31
static void _eldbus_signal_handler_del(Eldbus_Signal_Handler *handler);
32
static void _eldbus_signal_handler_clean(Eldbus_Signal_Handler *handler);
33

34
Eina_Bool
35
eldbus_signal_handler_init(void)
36
{
37
   return EINA_TRUE;
38
}
39

40
void
41
eldbus_signal_handler_shutdown(void)
42
{
43
}
44

45
static void
46
_match_append(Eina_Strbuf *match, const char *key, const char *value)
47
{
48
   if (!value) return;
49

50
   if ((eina_strbuf_length_get(match) + strlen(",=''") + strlen(key) + strlen(value))
51
       >= DBUS_MAXIMUM_MATCH_RULE_LENGTH)
52
     {
53
        ERR("cannot add match %s='%s' to %s: too long!", key, value,
54
            eina_strbuf_string_get(match));
55
        return;
56
     }
57

58
   eina_strbuf_append_printf(match, ",%s='%s'", key, value);
59
}
60

61
static int
62
_sort_arg(const void *d1, const void *d2)
63
{
64
   const Signal_Argument *arg1, *arg2;
65
   arg1 = d1;
66
   arg2 = d2;
67
   return arg1->index - arg2->index;
68
}
69

70
#define ARGX "arg"
71
EAPI Eina_Bool
72
eldbus_signal_handler_match_extra_vset(Eldbus_Signal_Handler *sh, va_list ap)
73
{
74
   const char *key = NULL, *read;
75
   DBusError err;
76

77
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(sh, EINA_FALSE);
78

79
   dbus_error_init(&err);
80
   dbus_bus_remove_match(sh->conn->dbus_conn,
81
                         eina_strbuf_string_get(sh->match), NULL);
82

83
   for (read = va_arg(ap, char *); read; read = va_arg(ap, char *))
84
     {
85
        Signal_Argument *arg;
86

87
        if (!key)
88
          {
89
             key = read;
90
             continue;
91
          }
92
        arg = calloc(1, sizeof(Signal_Argument));
93
        EINA_SAFETY_ON_NULL_GOTO(arg, error);
94
        if (!strncmp(key, ARGX, strlen(ARGX)))
95
          {
96
             int id = atoi(key + strlen(ARGX));
97
             arg->index = (unsigned short) id;
98
             arg->value = eina_stringshare_add(read);
99
             sh->args = eina_inlist_sorted_state_insert(sh->args,
100
                                                        EINA_INLIST_GET(arg),
101
                                                        _sort_arg,
102
                                                        sh->state_args);
103
             _match_append(sh->match, key, read);
104
          }
105
        else
106
          {
107
             ERR("%s not supported", key);
108
             free(arg);
109
          }
110
        key = NULL;
111
     }
112

113
   dbus_bus_add_match(sh->conn->dbus_conn,
114
                      eina_strbuf_string_get(sh->match), NULL);
115
   return EINA_TRUE;
116

117
error:
118
   dbus_bus_add_match(sh->conn->dbus_conn,
119
                      eina_strbuf_string_get(sh->match), NULL);
120
   return EINA_FALSE;
121
}
122

123
EAPI Eina_Bool
124
eldbus_signal_handler_match_extra_set(Eldbus_Signal_Handler *sh, ...)
125
{
126
   Eina_Bool ret;
127
   va_list ap;
128

129
   va_start(ap, sh);
130
   ret = eldbus_signal_handler_match_extra_vset(sh, ap);
131
   va_end(ap);
132
   return ret;
133
}
134

135
static void _on_handler_of_conn_free(void *data, const void *dead_pointer);
136

137
static void
138
_on_connection_free(void *data, const void *dead_pointer EINA_UNUSED)
139
{
140
   Eldbus_Signal_Handler *sh = data;
141
   eldbus_signal_handler_free_cb_del(sh, _on_handler_of_conn_free, sh->conn);
142
   eldbus_signal_handler_del(sh);
143
}
144

145
static void
146
_on_handler_of_conn_free(void *data, const void *dead_pointer)
147
{
148
   Eldbus_Connection *conn = data;
149
   eldbus_connection_free_cb_del(conn, _on_connection_free, dead_pointer);
150
}
151

152
EAPI Eldbus_Signal_Handler *
153
eldbus_signal_handler_add(Eldbus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, Eldbus_Signal_Cb cb, const void *cb_data)
154
{
155
   Eldbus_Signal_Handler *sh;
156
   sh = _eldbus_signal_handler_add(conn, sender, path, interface, member, cb, cb_data);
157
   EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL);
158
   eldbus_connection_free_cb_add(conn, _on_connection_free, sh);
159
   eldbus_signal_handler_free_cb_add(sh, _on_handler_of_conn_free, conn);
160
   return sh;
161
}
162

163
Eldbus_Signal_Handler *
164
_eldbus_signal_handler_add(Eldbus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, Eldbus_Signal_Cb cb, const void *cb_data)
165
{
166
   Eldbus_Signal_Handler *sh;
167
   Eina_Strbuf *match;
168

169
   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
170
   EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
171
   DBG("conn=%p, sender=%s, path=%s, interface=%s, member=%s, cb=%p %p",
172
       conn, sender, path, interface, member, cb, cb_data);
173

174
   sh = calloc(1, sizeof(Eldbus_Signal_Handler));
175
   EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL);
176

177
   match = eina_strbuf_new();
178
   EINA_SAFETY_ON_NULL_GOTO(match, cleanup_create_strbuf);
179
   eina_strbuf_append(match, "type='signal'");
180
   _match_append(match, "sender", sender);
181
   _match_append(match, "path", path);
182
   _match_append(match, "interface", interface);
183
   _match_append(match, "member", member);
184

185
   dbus_bus_add_match(conn->dbus_conn, eina_strbuf_string_get(match), NULL);
186

187
   if (sender)
188
     {
189
        sh->bus = eldbus_connection_name_get(conn, sender);
190
        if (!sh->bus) goto cleanup;
191
        eldbus_connection_name_ref(sh->bus);
192
     }
193

194
   sh->cb = cb;
195
   sh->cb_data = cb_data;
196
   sh->conn = conn;
197
   sh->interface = eina_stringshare_add(interface);
198
   sh->member = eina_stringshare_add(member);
199
   sh->path = eina_stringshare_add(path);
200
   sh->sender = eina_stringshare_add(sender);
201
   sh->match = match;
202
   sh->refcount = 1;
203
   sh->dangling = EINA_FALSE;
204
   sh->state_args = eina_inlist_sorted_state_new();
205
   EINA_MAGIC_SET(sh, ELDBUS_SIGNAL_HANDLER_MAGIC);
206

207
   eldbus_connection_signal_handler_add(conn, sh);
208
   return sh;
209

210
cleanup:
211
   eina_strbuf_free(match);
212
cleanup_create_strbuf:
213
   free(sh);
214

215
   return NULL;
216
}
217

218
static void
219
_eldbus_signal_handler_clean(Eldbus_Signal_Handler *handler)
220
{
221
   DBusError err;
222

223
   if (handler->dangling) return;
224
   DBG("clean handler=%p path=%p cb=%p", handler, handler->path, handler->cb);
225
   dbus_error_init(&err);
226
   dbus_bus_remove_match(handler->conn->dbus_conn,
227
                         eina_strbuf_string_get(handler->match), NULL);
228
   handler->dangling = EINA_TRUE;
229
}
230

231
static void
232
_eldbus_signal_handler_del(Eldbus_Signal_Handler *handler)
233
{
234
   Eina_Inlist *list;
235
   Signal_Argument *arg;
236
   DBG("handler %p, refcount=%d, conn=%p %s",
237
       handler, handler->refcount, handler->conn, handler->sender);
238
   eldbus_cbs_free_dispatch(&(handler->cbs_free), handler);
239
   eldbus_connection_signal_handler_del(handler->conn, handler);
240
   EINA_MAGIC_SET(handler, EINA_MAGIC_NONE);
241

242
   /* after cbs_free dispatch these shouldn't exit, error if they do */
243

244
   eina_stringshare_replace(&handler->sender, NULL);
245
   eina_stringshare_replace(&handler->path, NULL);
246
   eina_stringshare_replace(&handler->interface, NULL);
247
   eina_stringshare_replace(&handler->member, NULL);
248
   eina_strbuf_free(handler->match);
249
   EINA_INLIST_FOREACH_SAFE(handler->args, list, arg)
250
     {
251
        eina_stringshare_replace(&arg->value, NULL);
252
        free(arg);
253
     }
254
   eina_inlist_sorted_state_free(handler->state_args);
255

256
   if (handler->bus)
257
     eldbus_connection_name_unref(handler->conn, handler->bus);
258
   free(handler);
259
}
260

261
EAPI Eldbus_Signal_Handler *
262
eldbus_signal_handler_ref(Eldbus_Signal_Handler *handler)
263
{
264
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
265
   DBG("handler=%p, pre-refcount=%d, match=%s",
266
       handler, handler->refcount, eina_strbuf_string_get(handler->match));
267
   handler->refcount++;
268
   return handler;
269
}
270

271
EAPI void
272
eldbus_signal_handler_unref(Eldbus_Signal_Handler *handler)
273
{
274
   ELDBUS_SIGNAL_HANDLER_CHECK(handler);
275
   DBG("handler=%p, pre-refcount=%d, match=%s",
276
       handler, handler->refcount, eina_strbuf_string_get(handler->match));
277
   handler->refcount--;
278
   if (handler->refcount > 0) return;
279

280
   _eldbus_signal_handler_clean(handler);
281
   _eldbus_signal_handler_del(handler);
282
}
283

284
EAPI void
285
eldbus_signal_handler_del(Eldbus_Signal_Handler *handler)
286
{
287
   ELDBUS_SIGNAL_HANDLER_CHECK(handler);
288
   _eldbus_signal_handler_clean(handler);
289
   eldbus_signal_handler_unref(handler);
290
}
291

292
EAPI void
293
eldbus_signal_handler_free_cb_add(Eldbus_Signal_Handler *handler, Eldbus_Free_Cb cb, const void *data)
294
{
295
   ELDBUS_SIGNAL_HANDLER_CHECK(handler);
296
   EINA_SAFETY_ON_NULL_RETURN(cb);
297
   handler->cbs_free = eldbus_cbs_free_add(handler->cbs_free, cb, data);
298
}
299

300
EAPI void
301
eldbus_signal_handler_free_cb_del(Eldbus_Signal_Handler *handler, Eldbus_Free_Cb cb, const void *data)
302
{
303
   ELDBUS_SIGNAL_HANDLER_CHECK(handler);
304
   EINA_SAFETY_ON_NULL_RETURN(cb);
305
   handler->cbs_free = eldbus_cbs_free_del(handler->cbs_free, cb, data);
306
}
307

308
EAPI const char *
309
eldbus_signal_handler_sender_get(const Eldbus_Signal_Handler *handler)
310
{
311
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
312
   return handler->sender;
313
}
314

315
EAPI const char *
316
eldbus_signal_handler_path_get(const Eldbus_Signal_Handler *handler)
317
{
318
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
319
   return handler->path;
320
}
321

322
EAPI const char *
323
eldbus_signal_handler_interface_get(const Eldbus_Signal_Handler *handler)
324
{
325
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
326
   return handler->interface;
327
}
328

329
EAPI const char *
330
eldbus_signal_handler_member_get(const Eldbus_Signal_Handler *handler)
331
{
332
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
333
   return handler->member;
334
}
335

336
EAPI const char *
337
eldbus_signal_handler_match_get(const Eldbus_Signal_Handler *handler)
338
{
339
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
340
   return eina_strbuf_string_get(handler->match);
341
}
342

343
EAPI Eldbus_Connection *
344
eldbus_signal_handler_connection_get(const Eldbus_Signal_Handler *handler)
345
{
346
   ELDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
347
   return handler->conn;
348
}
349

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.