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 int send_reply(struct jreq *jreq, const char *reply)
66 if (dbus_message_append_args(jreq->reply, DBUS_TYPE_STRING, &reply, DBUS_TYPE_INVALID)) {
67 if (dbus_connection_send(jreq->connection, jreq->reply, NULL))
70 dbus_message_unref(jreq->reply);
71 dbus_connection_unref(jreq->connection);
76 static DBusHandlerResult incoming_resp(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
80 struct jrespw *jrw, **prv;
81 struct json_object *reply;
84 /* search for the waiter */
85 serial = dbus_message_get_serial(message);
87 while ((jrw = *prv) != NULL && jrw->serial != serial)
90 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
93 /* retrieve the json value */
94 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
98 reply = json_tokener_parse(str);
99 status = reply ? 0 : -1;
103 jrw->onresp(status, reply, jrw->data);
105 return DBUS_HANDLER_RESULT_HANDLED;
108 static int matchitf(DBusMessage *message)
110 const char *itf = dbus_message_get_interface(message);
111 return itf != NULL && !strcmp(itf, interface_jbus);
114 static DBusHandlerResult incoming_call(DBusConnection *connection, DBusMessage *message, struct jbus *jbus)
116 struct jservice *srv;
120 struct json_object *query;
122 /* search for the service */
123 if (!matchitf(message))
124 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
125 method = dbus_message_get_member(message);
127 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
128 srv = jbus->services;
129 while(srv != NULL && strcmp(method, srv->method))
132 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
134 /* handle the message */
135 jreq = malloc(sizeof * jreq);
137 return DBUS_HANDLER_RESULT_NEED_MEMORY;
138 jreq->reply = dbus_message_new_method_return(message);
139 if (jreq->reply == NULL) {
141 return DBUS_HANDLER_RESULT_NEED_MEMORY;
143 jreq->connection = dbus_connection_ref(jbus->connection);
145 /* retrieve the json value */
146 if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) {
147 send_reply(jreq, reply_invalid);
148 return DBUS_HANDLER_RESULT_HANDLED;
150 query = json_tokener_parse(str);
152 send_reply(jreq, reply_invalid);
153 return DBUS_HANDLER_RESULT_HANDLED;
157 srv->oncall(jreq, query);
158 return DBUS_HANDLER_RESULT_HANDLED;
161 static DBusHandlerResult incoming(DBusConnection *connection, DBusMessage *message, void *data)
163 switch(dbus_message_get_type(message)) {
164 case DBUS_MESSAGE_TYPE_METHOD_CALL:
165 return incoming_call(connection, message, (struct jbus*)data);
166 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
167 return incoming_resp(connection, message, (struct jbus*)data);
169 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
173 struct jbus *create_jbus(int session, const char *path)
178 /* create the context and connect */
179 jbus = calloc(1, sizeof * jbus);
185 jbus->path = strdup(path);
187 if (jbus->path == NULL) {
191 while(*path == '/') path++;
192 jbus->name = name = strdup(path);
203 while (name >= jbus->name && *name == '.')
211 jbus->connection = dbus_bus_get(session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, NULL);
212 if (jbus->connection == NULL) {
215 if (!dbus_connection_add_filter(jbus->connection, incoming, jbus, NULL)) {
227 void jbus_addref(struct jbus *jbus)
232 void jbus_unref(struct jbus *jbus)
234 struct jservice *srv;
235 if (!--jbus->refcount) {
236 dbus_connection_unref(jbus->connection);
237 while((srv = jbus->services) != NULL) {
238 jbus->services = srv->next;
248 int jbus_reply(struct jreq *jreq, struct json_object *reply)
250 const char *str = json_object_to_json_string(reply);
251 return send_reply(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))