00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "internal.h"
00031 #include "eripc.h"
00032 #include <unistd.h>
00033 #include <errno.h>
00034 #include <assert.h>
00035 #include <string.h>
00036
00037 static char *fix_name(const char* raw_name)
00038 {
00039 char *name = strdup(raw_name);
00040 if (name == NULL) {
00041 ULOG_CRIT_F("fix_name failed: out of memory");
00042 return NULL;
00043 }
00044
00045
00046 unsigned int i;
00047 for (i=0; i<strlen(name); i++)
00048 {
00049 if (name[i] == '-')
00050 name[i] = '_';
00051 }
00052 return name;
00053 }
00054
00055 static void _get_byte_array(DBusMessageIter *iter, eripc_arg_t *arg)
00056 {
00057 arg->type = ERIPC_TYPE_DATA;
00058 dbus_message_iter_get_fixed_array(iter, &(arg->value.data),
00059 &(arg->data_len));
00060 }
00061
00062 eripc_arg_t* _get_args(DBusMessageIter *iter)
00063 {
00064 int type, idx = 0;
00065 eripc_arg_t *arg_array;
00066
00067 arg_array = calloc(1, sizeof(eripc_arg_t) * (ERIPC_MAX_ARGS + 1));
00068 if (arg_array == NULL) {
00069 ULOG_ERR_F("calloc() failed: %s", strerror(errno));
00070 return NULL;
00071 }
00072
00073 while ((type = dbus_message_iter_get_arg_type(iter))
00074 != DBUS_TYPE_INVALID) {
00075
00076 int i;
00077 unsigned int u;
00078 double d;
00079 char c, *s;
00080
00081 switch (type) {
00082 case DBUS_TYPE_BOOLEAN:
00083 arg_array[idx].type = ERIPC_TYPE_BOOL;
00084 dbus_message_iter_get_basic(iter, &i);
00085 arg_array[idx].value.b = i ? 1 : 0;
00086 ++idx;
00087 break;
00088 case DBUS_TYPE_INT32:
00089 arg_array[idx].type = ERIPC_TYPE_INT;
00090 dbus_message_iter_get_basic(iter, &i);
00091 arg_array[idx].value.i = i;
00092 ++idx;
00093 break;
00094 case DBUS_TYPE_UINT32:
00095 arg_array[idx].type = ERIPC_TYPE_UINT;
00096 dbus_message_iter_get_basic(iter, &u);
00097 arg_array[idx].value.u = u;
00098 ++idx;
00099 break;
00100 case DBUS_TYPE_DOUBLE:
00101 arg_array[idx].type = ERIPC_TYPE_DOUBLE;
00102 dbus_message_iter_get_basic(iter, &d);
00103 arg_array[idx].value.d = d;
00104 ++idx;
00105 break;
00106 case DBUS_TYPE_BYTE:
00107 arg_array[idx].type = ERIPC_TYPE_BYTE;
00108 dbus_message_iter_get_basic(iter, &c);
00109 arg_array[idx].value.by = c;
00110 ++idx;
00111 break;
00112 case DBUS_TYPE_STRING:
00113 arg_array[idx].type = ERIPC_TYPE_STRING;
00114 dbus_message_iter_get_basic(iter, &s);
00115 arg_array[idx].value.s = s;
00116 ++idx;
00117 break;
00118 case DBUS_TYPE_ARRAY:
00119
00120 if (dbus_message_iter_get_element_type(iter)
00121 == DBUS_TYPE_BYTE) {
00122 _get_byte_array(iter,
00123 &arg_array[idx]);
00124 ++idx;
00125 } else {
00126 ULOG_ERR_F("arrays of type %d not"
00127 " supported",
00128 dbus_message_iter_get_element_type(iter));
00129 }
00130 break;
00131 default:
00132 ULOG_ERR_F("type %d not supported", type);
00133 break;
00134 }
00135
00136 dbus_message_iter_next(iter);
00137 }
00138
00139 arg_array[idx].type = ERIPC_TYPE_INVALID;
00140
00141 return arg_array;
00142 }
00143
00144
00145 static void generic_signal_handler(osso_context_t *osso,
00146 DBusMessage *msg,
00147 _osso_callback_data_t *data,
00148 eripc_bus_t dbus_type)
00149 {
00150 eripc_event_info_t info;
00151 DBusMessageIter iter;
00152 eripc_handler_t *cb;
00153 char id_buf[MAX_MSGID_LEN + 1];
00154
00155 ULOG_DEBUG_F("entered");
00156 assert(osso != NULL && data != NULL);
00157
00158 memset(&info, 0, sizeof(info));
00159
00160 info.service = dbus_message_get_sender(msg);
00161 info.path = dbus_message_get_path(msg);
00162 info.interface = dbus_message_get_interface(msg);
00163 info.name = dbus_message_get_member(msg);
00164 info.event_type = data->event_type;
00165 info.bus_type = dbus_type;
00166
00167
00168
00169 if (osso->reply_dummy == NULL &&
00170 dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
00171 DBusMessage *reply;
00172 reply = dbus_message_new_method_return(msg);
00173 if (reply == NULL) {
00174 ULOG_WARN_F("could not create reply_dummy");
00175 } else {
00176 osso->reply_dummy = reply;
00177 }
00178 }
00179 if (osso->error_dummy == NULL &&
00180 dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL) {
00181 DBusMessage *reply;
00182 reply = dbus_message_new_error(msg, "org.foo.dummy", NULL);
00183 if (reply == NULL) {
00184 ULOG_WARN_F("could not create error_dummy");
00185 } else {
00186 osso->error_dummy = reply;
00187 }
00188 }
00189
00190 if ((dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL
00191 && !dbus_message_get_no_reply(msg)) ||
00192 dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
00193 _make_id(dbus_type, dbus_message_get_sender(msg),
00194 dbus_message_get_serial(msg), id_buf);
00195 info.message_id = id_buf;
00196 }
00197
00198 if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR) {
00199 info.error = dbus_message_get_error_name(msg);
00200 }
00201
00202 if (dbus_message_iter_init(msg, &iter)) {
00203 info.args = _get_args(&iter);
00204 }
00205
00206 cb = data->user_cb;
00207 (*cb)((eripc_context_t*)osso, &info, data->user_data);
00208
00209 if (info.args != NULL) {
00210 free((void*) info.args);
00211 info.args = NULL;
00212 }
00213 }
00214
00215
00216 inline static eripc_error_t _set_handler(eripc_context_t *context,
00217 const char *service,
00218 const char *object_path,
00219 const char *interface,
00220 const char *name,
00221 const char *match,
00222 const char *sys_match,
00223 _osso_handler_f *event_cb,
00224 eripc_event_t event_type,
00225 eripc_handler_t *user_handler,
00226 void *user_data,
00227 int handler_id,
00228 gboolean call_once_per_handler_id,
00229 eripc_bus_t bus_type)
00230 {
00231 DBusError error;
00232 _osso_callback_data_t *cb_data;
00233
00234 cb_data = calloc(1, sizeof(_osso_callback_data_t));
00235 if (cb_data == NULL) {
00236 ULOG_ERR_F("calloc failed");
00237 return ERIPC_ERROR_OOM;
00238 }
00239
00240 cb_data->user_cb = user_handler;
00241 cb_data->user_data = user_data;
00242 cb_data->match_rule = match;
00243 cb_data->event_type = event_type;
00244 cb_data->bus_type = bus_type;
00245 cb_data->data = cb_data;
00246
00247 if (service != NULL) {
00248 cb_data->service = strdup(service);
00249 if (cb_data->service == NULL) {
00250 goto _set_handler_oom4;
00251 }
00252 }
00253 if (object_path != NULL) {
00254 cb_data->path = strdup(object_path);
00255 if (cb_data->path == NULL) {
00256 goto _set_handler_oom3;
00257 }
00258 }
00259 if (interface != NULL) {
00260 cb_data->interface = strdup(interface);
00261 if (cb_data->interface == NULL) {
00262 goto _set_handler_oom2;
00263 }
00264 }
00265 if (name != NULL) {
00266 cb_data->name = strdup(name);
00267 if (cb_data->name == NULL) {
00268 goto _set_handler_oom1;
00269 }
00270 }
00271
00272 dbus_error_init(&error);
00273
00274 if (bus_type == ERIPC_BUS_SYSTEM || bus_type == ERIPC_BUS_BOTH) {
00275 if (!dbus_connection_get_is_connected(context->sys_conn)) {
00276 ULOG_ERR_F("connection to system bus is not open");
00277 goto _set_handler_failed_match;
00278 }
00279
00280 dbus_bus_add_match(context->sys_conn, sys_match, &error);
00281
00282 if (dbus_error_is_set(&error)) {
00283 ULOG_ERR_F("dbus_bus_add_match failed: %s",
00284 error.message);
00285 dbus_error_free(&error);
00286 goto _set_handler_failed_match;
00287 }
00288 }
00289
00290 if (bus_type == ERIPC_BUS_SESSION || bus_type == ERIPC_BUS_BOTH) {
00291 if (!dbus_connection_get_is_connected(context->conn)) {
00292 ULOG_ERR_F("connection to session bus is not open");
00293 goto _set_handler_failed_match;
00294 }
00295
00296 dbus_bus_add_match(context->conn, match, &error);
00297
00298 if (dbus_error_is_set(&error)) {
00299 ULOG_ERR_F("dbus_bus_add_match failed: %s",
00300 error.message);
00301 dbus_error_free(&error);
00302
00303 if (bus_type == ERIPC_BUS_BOTH) {
00304 dbus_bus_remove_match(context->sys_conn,
00305 match, NULL);
00306 }
00307
00308 goto _set_handler_failed_match;
00309 }
00310 }
00311
00312 if (_eripc_set_handler((_eripc_context_t*)context, event_cb,
00313 cb_data, handler_id,
00314 call_once_per_handler_id)) {
00315 return ERIPC_ERROR_SUCCESS;
00316 } else {
00317 return ERIPC_ERROR;
00318 }
00319
00320 _set_handler_oom1:
00321 free(cb_data->interface);
00322 _set_handler_oom2:
00323 free(cb_data->path);
00324 _set_handler_oom3:
00325 free(cb_data->service);
00326 _set_handler_oom4:
00327 free(cb_data);
00328 return ERIPC_ERROR_OOM;
00329
00330 _set_handler_failed_match:
00331 free(cb_data->name);
00332 free(cb_data->interface);
00333 free(cb_data->path);
00334 free(cb_data->service);
00335 free(cb_data);
00336 return ERIPC_ERROR;
00337 }
00338
00339 static eripc_error_t compose_match(const eripc_event_info_t *info,
00340 char **match)
00341 {
00342 size_t free_space = ERIPC_MAX_MATCH_SIZE;
00343 char buf[ERIPC_MAX_MATCH_SIZE + 1];
00344 buf[0] = '\0';
00345
00346 *match = malloc(ERIPC_MAX_MATCH_SIZE + 1);
00347 if (*match == NULL) {
00348 return ERIPC_ERROR_OOM;
00349 }
00350 (*match)[0] = '\0';
00351
00352 if (info->service != NULL) {
00353 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "sender='%s',",
00354 info->service);
00355 strncat(*match, buf, free_space);
00356 free_space -= strlen(buf);
00357 }
00358
00359 if (info->path != NULL) {
00360 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "path='%s',", info->path);
00361 strncat(*match, buf, free_space);
00362 free_space -= strlen(buf);
00363 }
00364 if (info->interface != NULL) {
00365 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "interface='%s',",
00366 info->interface);
00367 strncat(*match, buf, free_space);
00368 free_space -= strlen(buf);
00369 }
00370 if (info->name != NULL) {
00371 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "member='%s',",
00372 info->name);
00373 strncat(*match, buf, free_space);
00374 free_space -= strlen(buf);
00375 }
00376 if (info->event_type != 0) {
00377 switch(info->event_type)
00378 {
00379 case ERIPC_EVENT_MESSAGE:
00380 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "type='method_call',");
00381 break;
00382 case ERIPC_EVENT_SIGNAL:
00383 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "type='signal',");
00384 break;
00385 case ERIPC_EVENT_REPLY:
00386 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "type='method_reply',");
00387 break;
00388 case ERIPC_EVENT_ERROR:
00389 default:
00390 snprintf(buf, ERIPC_MAX_MATCH_SIZE, "type='error',");
00391 break;
00392 }
00393 strncat(*match, buf, free_space);
00394 free_space -= strlen(buf);
00395 }
00396
00397 if (free_space < ERIPC_MAX_MATCH_SIZE) {
00398
00399 (*match)[strlen(*match) - 1] = '\0';
00400 } else {
00401 free(*match);
00402 *match = NULL;
00403 }
00404
00405 return ERIPC_ERROR_SUCCESS;
00406 }
00407
00408
00409 eripc_error_t eripc_set_signal_handler(eripc_context_t *context,
00410 eripc_handler_t *handler,
00411 void *user_data,
00412 eripc_bus_t bus_type,
00413 const char *source,
00414 const char *name,
00415 int *handler_id)
00416 {
00417 eripc_error_t error = ERIPC_ERROR_SUCCESS;
00418 eripc_event_info_t info;
00419
00420 char *interface = fix_name(source);
00421 memset(&info, 0, sizeof(info));
00422 info.event_type = ERIPC_EVENT_SIGNAL;
00423 info.bus_type = bus_type;
00424 info.interface = interface;
00425 info.name = name;
00426
00427 error = eripc_set_event_handler(context, &info,
00428 handler, user_data, handler_id);
00429
00430 free(interface);
00431
00432 return error;
00433 }
00434
00435
00436 eripc_error_t eripc_set_message_handler(eripc_context_t *context,
00437 eripc_handler_t *handler,
00438 void *user_data,
00439 eripc_bus_t bus_type,
00440 const char *source,
00441 const char *name,
00442 int *handler_id)
00443 {
00444 eripc_error_t error = ERIPC_ERROR_SUCCESS;
00445 eripc_event_info_t info;
00446
00447 char *interface = fix_name(source);
00448 memset(&info, 0, sizeof(info));
00449 info.event_type = ERIPC_EVENT_MESSAGE;
00450 info.bus_type = bus_type;
00451 info.interface = interface;
00452 info.name = name;
00453
00454 error = eripc_set_event_handler(context, &info,
00455 handler, user_data, handler_id);
00456
00457 free(interface);
00458
00459 return error;
00460 }
00461
00462
00463 eripc_error_t eripc_set_event_handler(eripc_context_t *context,
00464 const eripc_event_info_t *info,
00465 eripc_handler_t *handler,
00466 void *user_data,
00467 int *handler_id)
00468 {
00469 eripc_error_t error = ERIPC_ERROR_SUCCESS;
00470 _osso_handler_f *event_cb = NULL;
00471 char *tmp_match = NULL, *match = NULL, *sys_match = NULL;
00472 int new_handler_id;
00473 eripc_error_t ret;
00474 eripc_bus_t bus_type;
00475
00476 ULOG_DEBUG_F("entered");
00477
00478 if (context == NULL || handler == NULL) {
00479 ULOG_ERR_F("invalid arguments");
00480 return ERIPC_ERROR_INVALID;
00481 }
00482
00483 if (info == NULL) {
00484 ULOG_ERR_F("info structure must be provided");
00485 return ERIPC_ERROR_INVALID;
00486 }
00487
00488 if (info->bus_type == ERIPC_BUS_IRRELEVANT) {
00489 bus_type = ERIPC_BUS_BOTH;
00490 } else {
00491 bus_type = info->bus_type;
00492 }
00493
00494 new_handler_id = context->next_handler_id++;
00495
00496 event_cb = generic_signal_handler;
00497
00498 ret = compose_match(info, &tmp_match);
00499 ULOG_DEBUG_F("match='%s'", tmp_match);
00500
00501 if (ret == ERIPC_ERROR_SUCCESS) {
00502 if (bus_type == ERIPC_BUS_BOTH
00503 || bus_type == ERIPC_BUS_SESSION) {
00504 match = tmp_match;
00505 }
00506 if (bus_type == ERIPC_BUS_BOTH
00507 || bus_type == ERIPC_BUS_SYSTEM) {
00508 if (match == NULL) {
00509 sys_match = tmp_match;
00510 } else {
00511 sys_match = strdup(tmp_match);
00512 if (sys_match == NULL) {
00513 ULOG_ERR_F("strdup failed");
00514 free(tmp_match);
00515 error = ERIPC_ERROR_OOM;
00516 goto _oom_exit;
00517 }
00518 }
00519 }
00520 error = _set_handler(context,
00521 info->service,
00522 info->path,
00523 info->interface,
00524 info->name,
00525 match,
00526 sys_match,
00527 event_cb,
00528 info->event_type,
00529 handler,
00530 user_data,
00531 new_handler_id,
00532 FALSE, bus_type);
00533 } else {
00534 error = ret;
00535 }
00536
00537 _oom_exit:
00538 if (handler_id != NULL) {
00539 if (error == ERIPC_ERROR_SUCCESS) {
00540 *handler_id = new_handler_id;
00541 } else {
00542 *handler_id = 0;
00543 }
00544 }
00545 return error;
00546 }
00547
00548 eripc_error_t eripc_unset_handler(eripc_context_t *context,
00549 int handler_id)
00550 {
00551 ULOG_DEBUG_F("entered");
00552
00553 if (context == NULL || handler_id == 0) {
00554 ULOG_ERR_F("invalid arguments");
00555 return ERIPC_ERROR_INVALID;
00556 }
00557
00558 if (_unset_handler((_eripc_context_t*)context, handler_id)) {
00559 return ERIPC_ERROR_SUCCESS;
00560 } else {
00561
00562 return ERIPC_ERROR_INVALID;
00563 }
00564 }