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"
35 DBusConnection *connection;
40 struct jservice *next;
42 void (*oncall)(struct jreq *, struct json_object *);
49 void (*onresp)(int status, struct json_object *response, void *data);
54 struct jservice *services;
55 DBusConnection *connection;
56 struct jrespw *waiters;
61 static const char reply_out_of_memory[] = "{\"status\":\"out of memory\"}";
62 static const char reply_invalid[] = "{\"status\":\"invalid request\"}";
63 static const char interface_jbus[] = "org.jbus";
65 static DBusHandlerResult incoming_resp(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
69 struct jrespw *jrw, **prv;
70 struct json_object *reply;
73 /* search for the waiter */
74 serial = dbus_message_get_reply_serial(message);
76 while ((jrw = *prv) != NULL && jrw->serial != serial)
79 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
82 /* retrieve the json value */
83 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
87 reply = json_tokener_parse(str);
88 status = reply ? 0 : -1;
92 jrw->onresp(status, reply, jrw->data);
94 return DBUS_HANDLER_RESULT_HANDLED;
97 static int matchitf(DBusMessage *message)
99 const char *itf = dbus_message_get_interface(message);
100 return itf != NULL && !strcmp(itf, interface_jbus);
103 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
105 struct jservice *srv;
109 struct json_object *query;
111 /* search for the service */
112 if (!matchitf(message))
113 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
114 method = dbus_message_get_member(message);
116 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
117 srv = jbus->services;
118 while(srv != NULL && strcmp(method, srv->method))
121 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
123 /* handle the message */
124 jreq = malloc(sizeof * jreq);
126 return DBUS_HANDLER_RESULT_NEED_MEMORY;
127 jreq->reply = dbus_message_new_method_return(message);
128 if (jreq->reply == NULL) {
130 return DBUS_HANDLER_RESULT_NEED_MEMORY;
132 jreq->connection = dbus_connection_ref(jbus->connection);
134 /* retrieve the json value */
135 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
136 jbus_replyj(jreq, reply_invalid);
137 return DBUS_HANDLER_RESULT_HANDLED;
139 query = json_tokener_parse(str);
141 jbus_replyj(jreq, reply_invalid);
142 return DBUS_HANDLER_RESULT_HANDLED;
146 srv->oncall(jreq, query);
147 return DBUS_HANDLER_RESULT_HANDLED;
150 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
152 switch(dbus_message_get_type(message)) {
153 case DBUS_MESSAGE_TYPE_METHOD_CALL:
154 return incoming_call(connection, message, (struct jbus*)data);
155 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
156 return incoming_resp(connection, message, (struct jbus*)data);
158 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
162 struct jbus *create_jbus(int session, const char *path)
167 /* create the context and connect */
168 jbus = calloc(1, sizeof * jbus);
174 jbus->path = strdup(path);
176 if (jbus->path == NULL) {
180 while(*path == '/') path++;
181 jbus->name = name = strdup(path);
192 while (name >= jbus->name && *name == '.')
200 jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
201 if (jbus->connection == NULL) {
204 if (!dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)) {
216 void jbus_addref(struct jbus *jbus)
221 void jbus_unref(struct jbus *jbus)
223 struct jservice *srv;
224 if (!--jbus->refcount) {
225 dbus_connection_unref(jbus->connection);
226 while((srv = jbus->services) != NULL) {
227 jbus->services = srv->next;
237 int jbus_replyj(struct jreq *jreq, const char *reply)
240 if (dbus_message_append_args(jreq->reply, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
241 if (dbus_connection_send(jreq->connection, jreq->reply, NULL))
244 dbus_message_unref(jreq->reply);
245 dbus_connection_unref(jreq->connection);
250 int jbus_reply(struct jreq *jreq, struct json_object *reply)
252 const char *str = json_object_to_json_string(reply);
253 return jbus_replyj(jreq, str ? str : reply_out_of_memory);
256 int jbus_add_service(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *jreq, struct json_object *request))
258 struct jservice *srv;
261 srv = malloc(sizeof * srv);
266 srv->method = strdup(method);
272 /* record the service */
273 srv->oncall = oncall;
274 srv->next = jbus->services;
275 jbus->services = srv;
287 int jbus_start_serving(struct jbus *jbus)
289 int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
291 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
292 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
294 case DBUS_REQUEST_NAME_REPLY_EXISTS:
295 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
302 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
304 if (dbus_connection_read_write_dispatch(jbus->connection, toms));
310 int jbus_callj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int status, struct json_object *response, void *data), void *data)
315 resp = malloc(sizeof * resp);
321 msg = dbus_message_new_method_call(jbus->name, jbus->path, interface_jbus, method);
327 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
332 if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
336 dbus_message_unref(msg);
338 resp->onresp = onresp;
339 resp->next = jbus->waiters;
340 jbus->waiters = resp;
344 dbus_message_unref(msg);
352 int jbus_call(struct jbus *jbus, const char *method, struct json_object *query, void (*onresp)(int status, struct json_object *response, void *data), void *data)
354 const char *str = json_object_to_json_string(query);
359 return jbus_callj(jbus, method, str, onresp, data);
365 void ping(struct jreq *jreq, struct json_object *request)
367 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
368 jbus_reply(jreq, request);
369 json_object_put(request);
371 void incr(struct jreq *jreq, struct json_object *request)
373 static int counter = 0;
374 struct json_object *res = json_object_new_int(++counter);
375 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
376 jbus_reply(jreq, res);
377 json_object_put(res);
378 json_object_put(request);
382 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
383 int s1 = jbus_add_service(jbus, "ping", ping);
384 int s2 = jbus_add_service(jbus, "incr", incr);
385 int s3 = jbus_start_serving(jbus);
386 printf("started %d %d %d\n", s1, s2, s3);
387 while (!jbus_read_write_dispatch (jbus, -1))
394 void onresp(int status, struct json_object *response, void *data)
396 printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
397 json_object_put(response);
401 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
404 jbus_callj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
405 jbus_callj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
406 jbus_read_write_dispatch (jbus, 1);
408 while (!jbus_read_write_dispatch (jbus, -1))