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;
285 int jbus_start_serving(struct jbus *jbus)
287 int status = dbus_bus_request_name(jbus->connection, jbus->name, DBUS_NAME_FLAG_DO_NOT_QUEUE, NULL);
289 case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
290 case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
292 case DBUS_REQUEST_NAME_REPLY_EXISTS:
293 case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
300 int jbus_read_write_dispatch(struct jbus *jbus, int toms)
302 if (dbus_connection_read_write_dispatch(jbus->connection, toms));
308 int jbus_callj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int status, struct json_object *response, void *data), void *data)
313 resp = malloc(sizeof * resp);
319 msg = dbus_message_new_method_call(jbus->name, jbus->path, interface_jbus, method);
325 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
330 if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
334 dbus_message_unref(msg);
336 resp->onresp = onresp;
337 resp->next = jbus->waiters;
338 jbus->waiters = resp;
342 dbus_message_unref(msg);
350 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)
352 const char *str = json_object_to_json_string(query);
357 return jbus_callj(jbus, method, str, onresp, data);
363 void ping(struct jreq *jreq, struct json_object *request)
365 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
366 jbus_reply(jreq, request);
367 json_object_put(request);
369 void incr(struct jreq *jreq, struct json_object *request)
371 static int counter = 0;
372 struct json_object *res = json_object_new_int(++counter);
373 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
374 jbus_reply(jreq, res);
375 json_object_put(res);
376 json_object_put(request);
380 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
381 int s1 = jbus_add_service(jbus, "ping", ping);
382 int s2 = jbus_add_service(jbus, "incr", incr);
383 int s3 = jbus_start_serving(jbus);
384 printf("started %d %d %d\n", s1, s2, s3);
385 while (!jbus_read_write_dispatch (jbus, -1))
392 void onresp(int status, struct json_object *response, void *data)
394 printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
395 json_object_put(response);
399 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
402 jbus_callj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
403 jbus_callj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
404 jbus_read_write_dispatch (jbus, 1);
406 while (!jbus_read_write_dispatch (jbus, -1))