Rename edbus->eldbus
[platform/upstream/eldbus.git] / src / lib / eldbus_pending.c
1 #include "eldbus_private.h"
2 #include "eldbus_private_types.h"
3 #include <dbus/dbus.h>
4
5 /* TODO: mempool of Eldbus_Pending */
6 #define ELDBUS_PENDING_CHECK(pending)                        \
7   do                                                        \
8     {                                                       \
9        EINA_SAFETY_ON_NULL_RETURN(pending);                 \
10        if (!EINA_MAGIC_CHECK(pending, ELDBUS_PENDING_MAGIC)) \
11          {                                                  \
12             EINA_MAGIC_FAIL(pending, ELDBUS_PENDING_MAGIC);  \
13             return;                                         \
14          }                                                  \
15     }                                                       \
16   while (0)
17
18 #define ELDBUS_PENDING_CHECK_RETVAL(pending, retval)         \
19   do                                                        \
20     {                                                       \
21        EINA_SAFETY_ON_NULL_RETURN_VAL(pending, retval);     \
22        if (!EINA_MAGIC_CHECK(pending, ELDBUS_PENDING_MAGIC)) \
23          {                                                  \
24             EINA_MAGIC_FAIL(pending, ELDBUS_PENDING_MAGIC);  \
25             return retval;                                  \
26          }                                                  \
27     }                                                       \
28   while (0)
29
30 static void eldbus_pending_dispatch(Eldbus_Pending *pending, Eldbus_Message *msg);
31
32 Eina_Bool
33 eldbus_pending_init(void)
34 {
35    return EINA_TRUE;
36 }
37
38 void
39 eldbus_pending_shutdown(void)
40 {
41 }
42
43 static void
44 cb_pending(DBusPendingCall *dbus_pending, void *user_data)
45 {
46    Eldbus_Message *msg;
47    Eldbus_Pending *pending = user_data;
48
49    if (!dbus_pending_call_get_completed(dbus_pending))
50      {
51         INF("timeout to pending %p", pending);
52         dbus_pending_call_cancel(dbus_pending);
53         msg = eldbus_message_error_new(pending->msg_sent,
54                                       "org.enlightenment.DBus.Timeout",
55                                       "This call was not completed.");
56         eldbus_pending_dispatch(pending, msg);
57         return;
58      }
59
60    msg = eldbus_message_new(EINA_FALSE);
61    EINA_SAFETY_ON_NULL_RETURN(msg);
62    msg->dbus_msg = dbus_pending_call_steal_reply(dbus_pending);
63    if (!msg->dbus_msg)
64      {
65         EINA_SAFETY_ON_NULL_GOTO(pending->cb, cleanup);
66
67         msg->dbus_msg = dbus_message_new_error(NULL,
68                             "org.enlightenment.DBus.NoReply",
69                             "There was no reply to this method call.");
70         EINA_SAFETY_ON_NULL_GOTO(msg->dbus_msg, cleanup);
71      }
72
73    dbus_message_iter_init(msg->dbus_msg, &msg->iterator->dbus_iterator);
74    eldbus_pending_dispatch(pending, msg);
75
76    return;
77
78 cleanup:
79    eldbus_message_unref(msg);
80 }
81
82 static void
83 _on_pending_free(void *data, const void *dead_pointer)
84 {
85    Eldbus_Connection *conn = data;
86    eldbus_connection_pending_del(conn, (void *)dead_pointer);
87 }
88
89 EAPI Eldbus_Pending *
90 eldbus_connection_send(Eldbus_Connection *conn, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout)
91 {
92    Eldbus_Pending *pending;
93
94    EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
95    EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
96
97    pending = _eldbus_connection_send(conn, msg, cb, cb_data, timeout);
98    if (!cb) return NULL;
99    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
100
101    eldbus_connection_pending_add(conn, pending);
102    eldbus_pending_free_cb_add(pending, _on_pending_free, conn);
103    return pending;
104 }
105
106 Eldbus_Pending *
107 _eldbus_connection_send(Eldbus_Connection *conn, Eldbus_Message *msg, Eldbus_Message_Cb cb, const void *cb_data, double timeout)
108 {
109    Eldbus_Pending *pending;
110    Eldbus_Message *error_msg;
111    DBG("conn=%p, msg=%p, cb=%p, cb_data=%p, timeout=%f",
112           conn, msg, cb, cb_data, timeout);
113
114    if (!cb)
115      {
116         dbus_connection_send(conn->dbus_conn, msg->dbus_msg, NULL);
117         return NULL;
118      }
119
120    pending = calloc(1, sizeof(Eldbus_Pending));
121    EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
122
123    pending->cb = cb;
124    pending->cb_data = cb_data;
125    pending->conn = conn;
126    pending->dest = eina_stringshare_add(dbus_message_get_member(msg->dbus_msg));
127    pending->interface = eina_stringshare_add(dbus_message_get_interface(msg->dbus_msg));
128    pending->method = eina_stringshare_add(dbus_message_get_member(msg->dbus_msg));
129    pending->path = eina_stringshare_add(dbus_message_get_path(msg->dbus_msg));
130    pending->msg_sent = eldbus_message_ref(msg);
131    EINA_MAGIC_SET(pending, ELDBUS_PENDING_MAGIC);
132
133    if (!dbus_connection_send_with_reply(conn->dbus_conn,
134                                         msg->dbus_msg,
135                                         &pending->dbus_pending, timeout))
136      {
137         error_msg = eldbus_message_error_new(msg, "org.enlightenment.DBus.NoConnection",
138                                             "Eldbus_Connection was closed.");
139         eldbus_pending_dispatch(pending, error_msg);
140         return NULL;
141      }
142    if (dbus_pending_call_set_notify(pending->dbus_pending, cb_pending, pending, NULL))
143      return pending;
144
145    dbus_pending_call_cancel(pending->dbus_pending);
146    error_msg = eldbus_message_error_new(pending->msg_sent,
147                                        "org.enlightenment.DBus.Error",
148                                        "Error when try set callback to message.");
149    eldbus_pending_dispatch(pending, error_msg);
150    return NULL;
151 }
152
153 EAPI void
154 eldbus_pending_data_set(Eldbus_Pending *pending, const char *key, const void *data)
155 {
156    ELDBUS_PENDING_CHECK(pending);
157    EINA_SAFETY_ON_NULL_RETURN(key);
158    EINA_SAFETY_ON_NULL_RETURN(data);
159    eldbus_data_set(&(pending->data), key, data);
160 }
161
162 EAPI void *
163 eldbus_pending_data_get(const Eldbus_Pending *pending, const char *key)
164 {
165    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
166    EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
167    return eldbus_data_get(&(((Eldbus_Pending *)pending)->data), key);
168 }
169
170 EAPI void *
171 eldbus_pending_data_del(Eldbus_Pending *pending, const char *key)
172 {
173    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
174    EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
175    return eldbus_data_del(&(((Eldbus_Pending *)pending)->data), key);
176 }
177
178 static void
179 eldbus_pending_dispatch(Eldbus_Pending *pending, Eldbus_Message *msg)
180 {
181    DBG("pending=%p msg=%p", pending, msg);
182    if (pending->cb)
183      pending->cb((void *)pending->cb_data, msg, pending);
184
185    eldbus_cbs_free_dispatch(&(pending->cbs_free), pending);
186    eldbus_data_del_all(&(pending->data));
187
188    if (msg) eldbus_message_unref(msg);
189    eldbus_message_unref(pending->msg_sent);
190    dbus_pending_call_unref(pending->dbus_pending);
191
192    pending->cb = NULL;
193    pending->dbus_pending = NULL;
194    eina_stringshare_del(pending->dest);
195    eina_stringshare_del(pending->path);
196    eina_stringshare_del(pending->interface);
197    eina_stringshare_del(pending->method);
198    EINA_MAGIC_SET(pending, EINA_MAGIC_NONE);
199    free(pending);
200 }
201
202 EAPI void
203 eldbus_pending_cancel(Eldbus_Pending *pending)
204 {
205    Eldbus_Message *error_message;
206    ELDBUS_PENDING_CHECK(pending);
207    EINA_SAFETY_ON_NULL_RETURN(pending->dbus_pending);
208
209    DBG("pending=%p", pending);
210    dbus_pending_call_cancel(pending->dbus_pending);
211
212    error_message = eldbus_message_error_new(pending->msg_sent,
213                                            "org.enlightenment.DBus.Canceled",
214                                            "Canceled by user.");
215    eldbus_pending_dispatch(pending, error_message);
216 }
217
218 EAPI void
219 eldbus_pending_free_cb_add(Eldbus_Pending *pending, Eldbus_Free_Cb cb, const void *data)
220 {
221    ELDBUS_PENDING_CHECK(pending);
222    EINA_SAFETY_ON_NULL_RETURN(cb);
223    pending->cbs_free = eldbus_cbs_free_add(pending->cbs_free, cb, data);
224 }
225
226 EAPI void
227 eldbus_pending_free_cb_del(Eldbus_Pending *pending, Eldbus_Free_Cb cb, const void *data)
228 {
229    ELDBUS_PENDING_CHECK(pending);
230    EINA_SAFETY_ON_NULL_RETURN(cb);
231    pending->cbs_free = eldbus_cbs_free_del(pending->cbs_free, cb, data);
232 }
233
234 EAPI const char *
235 eldbus_pending_destination_get(const Eldbus_Pending *pending)
236 {
237    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
238    return pending->dest;
239 }
240
241 EAPI const char *
242 eldbus_pending_path_get(const Eldbus_Pending *pending)
243 {
244    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
245    return pending->path;
246 }
247
248 EAPI const char *
249 eldbus_pending_interface_get(const Eldbus_Pending *pending)
250 {
251    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
252    return pending->interface;
253 }
254
255 EAPI const char *
256 eldbus_pending_method_get(const Eldbus_Pending *pending)
257 {
258    ELDBUS_PENDING_CHECK_RETVAL(pending, NULL);
259    return pending->method;
260 }