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:
299 int jbus_callj(struct jbus *jbus, const char *method, const char *query, void (*onresp)(int status, struct json_object *response, void *data), void *data)
305 resp = malloc(sizeof * resp);
311 msg = dbus_message_new_method_call(jbus->name, jbus->path, interface_jbus, method);
317 if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &query, DBUS_TYPE_INVALID)) {
322 if (!dbus_connection_send(jbus->connection, msg, &resp->serial)) {
326 dbus_message_unref(msg);
328 resp->onresp = onresp;
329 resp->next = jbus->waiters;
330 jbus->waiters = resp;
334 dbus_message_unref(msg);
342 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)
344 const char *str = json_object_to_json_string(query);
349 return jbus_callj(jbus, method, str, onresp, data);
355 void ping(struct jreq *jreq, struct json_object *request)
357 printf("ping(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(request));
358 jbus_reply(jreq, request);
359 json_object_put(request);
361 void incr(struct jreq *jreq, struct json_object *request)
363 static int counter = 0;
364 struct json_object *res = json_object_new_int(++counter);
365 printf("incr(%s) -> %s\n",json_object_to_json_string(request),json_object_to_json_string(res));
366 jbus_reply(jreq, res);
367 json_object_put(res);
368 json_object_put(request);
372 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
373 int s1 = jbus_add_service(jbus, "ping", ping);
374 int s2 = jbus_add_service(jbus, "incr", incr);
375 int s3 = jbus_start_serving(jbus);
376 printf("started %d %d %d\n", s1, s2, s3);
377 while (dbus_connection_read_write_dispatch (jbus->connection, -1))
384 void onresp(int status, struct json_object *response, void *data)
386 printf("resp: %d, %s, %s\n",status,(char*)data,json_object_to_json_string(response));
387 json_object_put(response);
391 struct jbus *jbus = create_jbus(1, "/bzh/iot/jdbus");
394 jbus_callj(jbus, "ping", "{\"toto\":[1,2,3,4,true,\"toto\"]}", onresp, "ping");
395 jbus_callj(jbus, "incr", "{\"doit\":\"for-me\"}", onresp, "incr");
396 dbus_connection_read_write_dispatch (jbus->connection, 1);
398 while (dbus_connection_read_write_dispatch (jbus->connection, -1))