4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
24 #include <dbus/dbus.h>
26 #include "utils-jbus.h"
33 DBusConnection *connection;
38 struct jservice *next;
40 void (*oncall)(struct jreq *, struct json_object *);
47 void (*onresp)(int status, struct json_object *response, void *data);
52 struct jservice *services;
53 DBusConnection *connection;
54 struct jrespw *waiters;
59 static const char reply_out_of_memory[] = "{\"status\":\"out of memory\"}";
60 static const char reply_invalid[] = "{\"status\":\"invalid request\"}";
61 static const char interface_jbus[] = "org.jbus";
63 static DBusHandlerResult incoming_resp(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
67 struct jrespw *jrw, **prv;
68 struct json_object *reply;
71 /* search for the waiter */
72 serial = dbus_message_get_reply_serial(message);
74 while ((jrw = *prv) != NULL && jrw->serial != serial)
77 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
80 /* retrieve the json value */
81 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
85 reply = json_tokener_parse(str);
86 status = reply ? 0 : -1;
90 jrw->onresp(status, reply, jrw->data);
92 return DBUS_HANDLER_RESULT_HANDLED;
95 static int matchitf(DBusMessage *message)
97 const char *itf = dbus_message_get_interface(message);
98 return itf != NULL && !strcmp(itf, interface_jbus);
101 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
103 struct jservice *srv;
107 struct json_object *query;
109 /* search for the service */
110 if (!matchitf(message))
111 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
112 method = dbus_message_get_member(message);
114 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
115 srv = jbus->services;
116 while(srv != NULL && strcmp(method, srv->method))
119 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
121 /* handle the message */
122 jreq = malloc(sizeof * jreq);
124 return DBUS_HANDLER_RESULT_NEED_MEMORY;
125 jreq->reply = dbus_message_new_method_return(message);
126 if (jreq->reply == NULL) {
128 return DBUS_HANDLER_RESULT_NEED_MEMORY;
130 jreq->connection = dbus_connection_ref(jbus->connection);
132 /* retrieve the json value */
133 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
134 jbus_replyj(jreq, reply_invalid);
135 return DBUS_HANDLER_RESULT_HANDLED;
137 query = json_tokener_parse(str);
139 jbus_replyj(jreq, reply_invalid);
140 return DBUS_HANDLER_RESULT_HANDLED;
144 srv->oncall(jreq, query);
145 return DBUS_HANDLER_RESULT_HANDLED;
148 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
150 switch(dbus_message_get_type(message)) {
151 case DBUS_MESSAGE_TYPE_METHOD_CALL:
152 return incoming_call(connection, message, (struct jbus*)data);
153 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
154 return incoming_resp(connection, message, (struct jbus*)data);
156 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
160 struct jbus *create_jbus(int session, const char *path)
165 /* create the context and connect */
166 jbus = calloc(1, sizeof * jbus);
172 jbus->path = strdup(path);
174 if (jbus->path == NULL) {
178 while(*path == '/') path++;
179 jbus->name = name = strdup(path);
190 while (name >= jbus->name && *name == '.')
198 jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
199 if (jbus->connection == NULL) {
202 if (!dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)) {
214 void jbus_addref(struct jbus *jbus)
219 void jbus_unref(struct jbus *jbus)
221 struct jservice *srv;
222 if (!--jbus->refcount) {
223 dbus_connection_unref(jbus->connection);
224 while((srv = jbus->services) != NULL) {
225 jbus->services = srv->next;
235 int jbus_replyj(struct jreq *jreq, const char *reply)
238 if (dbus_message_append_args(jreq->reply, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
239 if (dbus_connection_send(jreq->connection, jreq->reply, NULL))
242 dbus_message_unref(jreq->reply);
243 dbus_connection_unref(jreq->connection);
248 int jbus_reply(struct jreq *jreq, struct json_object *reply)
250 const char *str = json_object_to_json_string(reply);
251 return jbus_replyj(jreq, str ? str : reply_out_of_memory);
254 int jbus_add_service(struct jbus *jbus, const char *method, void (*oncall)(struct jreq *jreq, struct json_object *request))
256 struct jservice *srv;
259 srv = malloc(sizeof * srv);
264 srv->method = strdup(method);
270 /* record the service */
271 srv->oncall = oncall;
272 srv->next = jbus->services;
273 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))