4 author: José Bollo <jose.bollo@iot.bzh>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <dbus/dbus.h>
28 #include "utils-jbus.h"
34 /* structure for handled requests */
36 DBusConnection *connection;
40 /* structure for recorded services */
42 struct jservice *next;
44 void (*oncall_s)(struct jreq *, const char *);
45 void (*oncall_j)(struct jreq *, struct json_object *);
48 /* structure for signal handlers */
52 void (*onsignal_s)(const char *);
53 void (*onsignal_j)(struct json_object *);
56 /* structure for recording asynchronous requests */
61 void (*onresp_s)(int, const char*, void *);
62 void (*onresp_j)(int, struct json_object*, void *);
65 /* structure for synchronous requests */
71 /* structure for handling either client or server jbus on dbus */
74 struct jservice *services;
75 DBusConnection *connection;
76 struct jsignal *signals;
77 struct jrespw *waiters;
82 /*********************** STATIC COMMON METHODS *****************/
84 static inline void free_jreq(struct jreq *jreq)
86 dbus_message_unref(jreq->request);
87 dbus_connection_unref(jreq->connection);
91 static inline int reply_out_of_memory(struct jreq *jreq)
93 static const char out_of_memory[] = "out of memory";
94 jbus_reply_error_s(jreq, out_of_memory);
99 static inline int reply_invalid_request(struct jreq *jreq)
101 static const char invalid_request[] = "invalid request";
102 jbus_reply_error_s(jreq, invalid_request);
103 return DBUS_HANDLER_RESULT_HANDLED;
106 static int matchitf(struct jbus *jbus, DBusMessage *message)
108 const char *itf = dbus_message_get_interface(message);
109 return itf != NULL && !strcmp(itf, jbus->name);
112 static int add_service(
115 void (*oncall_s)(struct jreq*, const char*),
116 void (*oncall_j)(struct jreq*, struct json_object*)
119 struct jservice *srv;
122 srv = malloc(sizeof * srv);
127 srv->method = strdup(method);
133 /* record the service */
134 srv->oncall_s = oncall_s;
135 srv->oncall_j = oncall_j;
136 srv->next = jbus->services;
137 jbus->services = srv;
147 static int add_signal(
150 void (*onsignal_s)(const char*),
151 void (*onsignal_j)(struct json_object*)
157 /* record the signal */
158 if (jbus->signals == NULL) {
159 if (0 >= asprintf(&rule, "type='signal',sender='%s',interface='%s',path='%s'", jbus->name, jbus->name, jbus->path))
161 dbus_bus_add_match(jbus->connection, rule, NULL);
166 sig = malloc(sizeof * sig);
169 sig->name = strdup(name);
173 /* record the signal */
174 sig->onsignal_s = onsignal_s;
175 sig->onsignal_j = onsignal_j;
176 sig->next = jbus->signals;
192 void (*onresp_s)(int status, const char *response, void *data),
193 void (*onresp_j)(int status, struct json_object *response, void *data),
200 resp = malloc(sizeof * resp);
206 msg = dbus_message_new_method_call(jbus->name, jbus->path, jbus->name, method);
212 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
217 if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
221 dbus_message_unref(msg);
223 resp->onresp_s = onresp_s;
224 resp->onresp_j = onresp_j;
225 resp->next = jbus->waiters;
226 jbus->waiters = resp;
230 dbus_message_unref(msg);
237 static void sync_of_replies(int status, const char *value, void *data)
239 struct respsync *s = data;
240 s->value = status ? NULL : strdup(value ? value : "");
244 static DBusHandlerResult incoming_resp(DBusConnection *connection, DBusMessage *message, struct jbus *jbus, int iserror)
248 struct jrespw *jrw, **prv;
249 struct json_object *reply;
250 dbus_uint32_t serial;
252 /* search for the waiter */
253 serial = dbus_message_get_reply_serial(message);
254 prv = &jbus->waiters;
255 while ((jrw = *prv) != NULL && jrw->serial != serial)
258 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
261 /* retrieve the string value */
262 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
270 jrw->onresp_s(iserror ? -1 : status, str, jrw->data);
272 reply = json_tokener_parse(str);
273 status = reply ? 0 : -1;
274 jrw->onresp_j(iserror ? -1 : status, reply, jrw->data);
278 return DBUS_HANDLER_RESULT_HANDLED;
281 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
283 struct jservice *srv;
287 struct json_object *query;
289 /* search for the service */
290 if (!matchitf(jbus, message))
291 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
292 method = dbus_message_get_member(message);
294 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
295 srv = jbus->services;
296 while(srv != NULL && strcmp(method, srv->method))
299 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
301 /* handle the message */
302 jreq = malloc(sizeof * jreq);
304 return DBUS_HANDLER_RESULT_NEED_MEMORY;
305 jreq->request = dbus_message_ref(message);
306 jreq->connection = dbus_connection_ref(jbus->connection);
308 /* retrieve the string value */
309 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID))
310 return reply_invalid_request(jreq);
312 /* handling strings only */
313 srv->oncall_s(jreq, str);
316 /* handling json only */
317 query = json_tokener_parse(str);
319 return reply_invalid_request(jreq);
320 srv->oncall_j(jreq, query);
322 return DBUS_HANDLER_RESULT_HANDLED;
325 static DBusHandlerResult incoming_signal(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
330 struct json_object *obj;
332 /* search for the service */
333 if (!matchitf(jbus, message))
334 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
335 name = dbus_message_get_member(message);
337 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
339 while(sig != NULL && strcmp(name, sig->name))
342 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
344 /* retrieve the string value */
345 if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
346 if (sig->onsignal_s) {
347 /* handling strings only */
348 sig->onsignal_s(str);
351 /* handling json only */
352 obj = json_tokener_parse(str);
354 sig->onsignal_j(obj);
357 return DBUS_HANDLER_RESULT_HANDLED;
360 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
362 switch(dbus_message_get_type(message)) {
363 case DBUS_MESSAGE_TYPE_METHOD_CALL:
364 return incoming_call(connection, message, (struct jbus*)data);
365 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
366 return incoming_resp(connection, message, (struct jbus*)data, 0);
367 case DBUS_MESSAGE_TYPE_ERROR:
368 return incoming_resp(connection, message, (struct jbus*)data, 1);
369 case DBUS_MESSAGE_TYPE_SIGNAL:
370 return incoming_signal(connection, message, (struct jbus*)data);
372 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
375 /************************** MAIN FUNCTIONS *****************************************/
377 struct jbus *create_jbus(int session, const char *path)
382 /* create the context and connect */
383 jbus = calloc(1, sizeof * jbus);
389 jbus->path = strdup(path);
391 if (jbus->path == NULL) {
395 while(*path == '/') path++;
396 jbus->name = name = strdup(path);
407 while (name >= jbus->name && *name == '.')
415 jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
416 if (jbus->connection == NULL) {
419 if (!dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)) {
431 void jbus_addref(struct jbus *jbus)
436 void jbus_unref(struct jbus *jbus)
438 struct jservice *srv;
439 if (!--jbus->refcount) {
440 dbus_connection_unref(jbus->connection);
441 while((srv = jbus->services) != NULL) {
442 jbus->services = srv->next;
452 int jbus_reply_error_s(struct jreq *jreq, const char *error)
455 DBusMessage *message;
457 message = dbus_message_new_error(jreq->request, DBUS_ERROR_FAILED, error);
461 if (dbus_connection_send(jreq->connection, message, NULL))
463 dbus_message_unref(message);
469 int jbus_reply_error_j(struct jreq *jreq, struct json_object *reply)
471 const char *str = json_object_to_json_string(reply);
472 return str ? jbus_reply_error_s(jreq, str) : reply_out_of_memory(jreq);
475 int jbus_reply_s(struct jreq *jreq, const char *reply)
478 DBusMessage *message;
480 message = dbus_message_new_method_return(jreq->request);
482 return reply_out_of_memory(jreq);
484 if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
485 dbus_message_unref(message);
486 return reply_out_of_memory(jreq);
489 if (dbus_connection_send(jreq->connection, message, NULL))
491 dbus_message_unref(message);
496 int jbus_reply_j(struct jreq *jreq, struct json_object *reply)
498 const char *str = json_object_to_json_string(reply);
499 return str ? jbus_reply_s(jreq, str) : reply_out_of_memory(jreq);
502 int jbus_send_signal_s(struct jbus *jbus, const char *name, const char *content)
505 DBusMessage *message;
507 message = dbus_message_new_signal(jbus->path, jbus->name, name);
511 if (!dbus_message_append_args(message, DBUS_TYPE_STRING, &content, DBUS_TYPE_INVALID)) {
512 dbus_message_unref(message);
516 if (dbus_connection_send(jbus->connection, message, NULL))
518 dbus_message_unref(message);
526 int jbus_send_signal_j(struct jbus *jbus, const char *name, struct json_object *content)
528 const char *str = json_object_to_json_string(content);
533 return jbus_send_signal_s(jbus, name, str);
536 int jbus_add_service_s(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, const char *))
538 return add_service(jbus, method, oncall, NULL);
541 int jbus_add_service_j(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *, struct json_object *))
543 return add_service(jbus, method, NULL, oncall);
546 int jbus_start_serving(struct jbus *jbus)
548 int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
550 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
551 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
553 case DBUS_REQUEST_NAME_REPLY_EXISTS:
554 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
561 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
563 if (dbus_connection_read_write_dispatch(jbus->connection, toms));
569 int jbus_call_ss(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, const char*, void*), void *data)
571 return call(jbus, method, query, onresp, NULL, data);
574 int jbus_call_sj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int, struct json_object*, void*), void *data)
576 return call(jbus, method, query, NULL, onresp, data);
579 int jbus_call_js(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, const char*, void*), void *data)
581 const char *str = json_object_to_json_string(query);
586 return call(jbus, method, str, onresp, NULL, data);
589 int jbus_call_jj(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int, struct json_object*, void*), void *data)
591 const char *str = json_object_to_json_string(query);
596 return call(jbus, method, str, NULL, onresp, data);
599 char *jbus_call_ss_sync(struct jbus *jbus, const char *method, const char *query)
601 struct respsync synchro;
602 synchro.value = NULL;
603 synchro.replied = jbus_call_ss(jbus, method, query, sync_of_replies, &synchro);
604 while (!synchro.replied && !jbus_read_write_dispatch(jbus, -1));
605 return synchro.value;
608 struct json_object *jbus_call_sj_sync(struct jbus *jbus, const char *method, const char *query)
610 const char *str = jbus_call_ss_sync(jbus, method, query);
611 return str ? json_tokener_parse(str) : NULL;
615 char *jbus_call_js_sync(struct jbus *jbus, const char *method, struct json_object *query)
617 const char *str = json_object_to_json_string(query);
622 return jbus_call_ss_sync(jbus, method, str);
625 struct json_object *jbus_call_jj_sync(struct jbus *jbus, const char *method, struct json_object *query)
627 const char *str = json_object_to_json_string(query);
632 return jbus_call_sj_sync(jbus, method, str);
635 int jbus_on_signal_s(struct jbus *jbus, const char *name, void (*onsig)(const char *))
637 return add_signal(jbus, name, onsig, NULL);
640 int jbus_on_signal_j(struct jbus *jbus, const char *name, void (*onsig)(struct json_object *))
642 return add_signal(jbus, name, NULL, onsig);
645 /************************** FEW LITTLE TESTS *****************************************/
651 void ping(struct jreq *jreq, struct json_object *request)
653 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
654 jbus_reply_j(jreq, request);
655 json_object_put(request);
657 void incr(struct jreq *jreq, struct json_object *request)
659 static int counter = 0;
660 struct json_object *res = json_object_new_int(++counter);
661 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
662 jbus_reply_j(jreq, res);
663 jbus_send_signal_j(jbus, "incremented", res);
664 json_object_put(res);
665 json_object_put(request);
670 jbus = create_jbus(1, "/bzh/iot/jdbus");
671 s1 = jbus_add_service_j(jbus, "ping", ping);
672 s2 = jbus_add_service_j(jbus, "incr", incr);
673 s3 = jbus_start_serving(jbus);
674 printf("started %d %d %d\n", s1, s2, s3);
675 while (!jbus_read_write_dispatch (jbus, -1))
683 void onresp(int status, struct json_object *response, void *data)
685 printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
686 json_object_put(response);
688 void signaled(const char *data)
690 printf("signaled with {%s}\n", data);
695 jbus = create_jbus(1, "/bzh/iot/jdbus");
696 jbus_on_signal_s(jbus, "incremented", signaled);
698 jbus_call_sj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
699 jbus_call_sj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
700 jbus_read_write_dispatch (jbus, 1);
702 printf("[[[%s]]]\n", jbus_call_ss_sync(jbus, "ping", "\"formidable!\""));
703 while (!jbus_read_write_dispatch (jbus, -1))