1 /***************************************************************************
3 * Copyright 2012 BMW Car IT GmbH
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.
18 ****************************************************************************/
19 #include "IpcModule.h"
21 #include "DBUSConfiguration.h"
22 #include "introspection.h"
25 #include <string.h> /* strdup */
29 * =============================================================================
30 * prototypes internal functions
31 * =============================================================================
33 void handleWatchesForFds(fd_set in, fd_set out);
34 t_ilm_bool dispatchIncomingMessages();
36 void registerSignalForNotification(dbusmessage* message, char* signalName);
37 void unregisterSignalForNotification(dbusmessage* message, char* signalName);
40 * =============================================================================
42 * =============================================================================
44 t_ilm_message createMessage(t_ilm_const_string name)
46 dbusmessage* newMessage = NULL;
48 if (!gDbus.initialized)
53 newMessage = (dbusmessage*)malloc(sizeof(dbusmessage));
54 newMessage->type = IpcMessageTypeCommand;
55 newMessage->dbusNativeType = DBUS_MESSAGE_TYPE_METHOD_CALL;
56 pthread_mutex_lock(&gDbus.mutex);
57 newMessage->pMessage = dbus_message_new_method_call(ILM_SERVICE_NAME,
58 ILM_PATH_COMPOSITE_SERVICE,
59 ILM_INTERFACE_COMPOSITE_SERVICE,
61 pthread_mutex_unlock(&gDbus.mutex);
62 dbus_message_iter_init_append(newMessage->pMessage, &newMessage->iter);
63 return (t_ilm_message)newMessage;
66 t_ilm_message createResponse(t_ilm_message message)
68 dbusmessage* receivedMessage;
69 dbusmessage* newResponse;
70 const char* member = NULL;
71 const char* destination = NULL;
73 if (!gDbus.initialized)
77 receivedMessage = (dbusmessage*)message;
78 newResponse = (dbusmessage*)malloc(sizeof(dbusmessage));
80 newResponse->type = IpcMessageTypeCommand;
81 newResponse->dbusNativeType = DBUS_MESSAGE_TYPE_METHOD_RETURN;
83 pthread_mutex_lock(&gDbus.mutex);
84 newResponse->pMessage = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
85 pthread_mutex_unlock(&gDbus.mutex);
87 member = dbus_message_get_member(receivedMessage->pMessage);
88 destination = dbus_message_get_sender(receivedMessage->pMessage);
89 dbus_message_set_member(newResponse->pMessage, member);
90 dbus_message_set_destination(newResponse->pMessage, destination);
91 dbus_message_set_reply_serial(newResponse->pMessage, receivedMessage->dbusSerial);
92 dbus_message_iter_init_append(newResponse->pMessage, &newResponse->iter);
94 return (t_ilm_message)newResponse;
97 t_ilm_message createErrorResponse(t_ilm_message message)
99 dbusmessage* receivedMessage;
100 dbusmessage* newResponse;
102 char destination[256];
104 if (!gDbus.initialized)
109 receivedMessage = (dbusmessage*)message;
110 newResponse = (dbusmessage*)malloc(sizeof(dbusmessage));
111 memset(newResponse, 0, sizeof(dbusmessage));
113 newResponse->type = IpcMessageTypeError;
114 newResponse->dbusNativeType = DBUS_MESSAGE_TYPE_ERROR;
116 pthread_mutex_lock(&gDbus.mutex);
117 newResponse->pMessage = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
118 pthread_mutex_unlock(&gDbus.mutex);
120 strcpy(member, dbus_message_get_member(receivedMessage->pMessage));
121 strcpy(destination, dbus_message_get_sender(receivedMessage->pMessage));
122 dbus_message_set_member(newResponse->pMessage, member);
123 dbus_message_set_destination(newResponse->pMessage, destination);
124 dbus_message_set_error_name(newResponse->pMessage, DBUS_SERVICE_ERROR);
125 dbus_message_set_reply_serial(newResponse->pMessage, receivedMessage->dbusSerial);
126 dbus_message_iter_init_append(newResponse->pMessage, &newResponse->iter);
128 return (t_ilm_message)newResponse;
131 t_ilm_message createNotification(t_ilm_const_string name)
133 dbusmessage* newNotification;
135 if (!gDbus.initialized)
140 newNotification = (dbusmessage*)malloc(sizeof(dbusmessage));
142 newNotification->type = IpcMessageTypeNotification;
143 newNotification->dbusNativeType = DBUS_MESSAGE_TYPE_SIGNAL;
147 pthread_mutex_lock(&gDbus.mutex);
148 newNotification->pMessage = dbus_message_new_signal(ILM_PATH_COMPOSITE_SERVICE,
149 ILM_INTERFACE_COMPOSITE_SERVICE,
151 pthread_mutex_unlock(&gDbus.mutex);
152 dbus_message_iter_init_append(newNotification->pMessage, &newNotification->iter);
155 return (t_ilm_message)newNotification;
158 t_ilm_bool sendToClients(t_ilm_message message, t_ilm_client_handle* receiverList, int receiverCount)
160 dbusmessage* messageToSend;
172 messageToSend = (dbusmessage*)message;
173 serial = dbus_message_get_serial(messageToSend->pMessage);
175 dbus_message_set_path(messageToSend->pMessage, ILM_PATH_COMPOSITE_SERVICE);
176 dbus_message_set_interface(messageToSend->pMessage, ILM_INTERFACE_COMPOSITE_SERVICE);
177 pthread_mutex_lock(&gDbus.mutex);
178 success = dbus_connection_send(gDbus.connection, messageToSend->pMessage, &serial);
179 pthread_mutex_unlock(&gDbus.mutex);
182 printf("DBUSIpcModule: Out Of Memory!\n");
189 t_ilm_bool sendToService(t_ilm_message message)
191 dbusmessage* messageToSend;
201 messageToSend = (dbusmessage*)message;
203 pthread_mutex_lock(&gDbus.mutex);
204 success = dbus_connection_send(gDbus.connection, messageToSend->pMessage, &serial);
205 pthread_mutex_unlock(&gDbus.mutex);
208 printf("DBUSIpcModule: Out Of Memory!\n");
212 strcpy(msgName, dbus_message_get_member(messageToSend->pMessage));
214 if (0 == strcmp(msgName, "LayerAddNotification"))
216 registerSignalForNotification(messageToSend, "NotificationForLayer");
219 if (0 == strcmp(msgName, "LayerRemoveNotification"))
221 unregisterSignalForNotification(messageToSend, "NotificationForLayer");
224 if (0 == strcmp(msgName, "SurfaceAddNotification"))
226 registerSignalForNotification(messageToSend, "NotificationForSurface");
229 if (0 == strcmp(msgName, "SurfaceRemoveNotification"))
231 unregisterSignalForNotification(messageToSend, "NotificationForSurface");
237 t_ilm_message receive(t_ilm_int timeoutInMs)
244 gpIncomingMessage = (dbusmessage*)malloc(sizeof(dbusmessage));
245 memset(gpIncomingMessage, 0, sizeof(dbusmessage));
247 if (!gDbus.initialized)
249 return (t_ilm_message)gpIncomingMessage;
252 if (dispatchIncomingMessages())
254 return (t_ilm_message)gpIncomingMessage;
257 readFds = gDbus.incomingSockets;
258 writeFds = gDbus.outgoingSockets;
259 fdMax = (gDbus.incomingSocketsMax > gDbus.outgoingSocketsMax) ?
260 gDbus.incomingSocketsMax : gDbus.outgoingSocketsMax;
266 fdsReady = select(fdMax, &readFds, &writeFds, 0, NULL);
270 struct timeval timeoutValue;
271 timeoutValue.tv_sec = timeoutInMs / 1000;
272 timeoutValue.tv_usec = (timeoutInMs % 1000) * 1000;
273 fdsReady = select(fdMax, &readFds, &writeFds, 0, &timeoutValue);
278 case -1: /* error: select was cancelled -> shutdown */
279 gpIncomingMessage->type = IpcMessageTypeShutdown;
282 case 0: /* timeout */
283 gpIncomingMessage->type = IpcMessageTypeTimeout;
286 default: /* message or shutdown */
287 handleWatchesForFds(readFds, writeFds);
288 dispatchIncomingMessages();
292 return (t_ilm_message)gpIncomingMessage;
295 t_ilm_const_string getMessageName(t_ilm_message message)
297 dbusmessage* msg = (dbusmessage*)message;
298 return msg->pMessage ? dbus_message_get_member(msg->pMessage) : NULL;
301 t_ilm_message_type getMessageType(t_ilm_message message)
303 dbusmessage* msg = (dbusmessage*)message;
307 t_ilm_const_string getSenderName(t_ilm_message message)
309 dbusmessage* msg = (dbusmessage*)message;
310 return msg->pMessage ? dbus_message_get_sender(msg->pMessage) : NULL;
313 t_ilm_client_handle getSenderHandle(t_ilm_message message)
315 unsigned long result = 0;
317 const char* sender = getSenderName(message);
320 float f = atof(&sender[1]);
321 result = (unsigned long)(f * 1000000);
323 return (t_ilm_client_handle)result;
326 t_ilm_bool destroyMessage(t_ilm_message message)
328 dbusmessage* msg = (dbusmessage*)message;
329 if (msg && msg->pMessage)
331 pthread_mutex_lock(&gDbus.mutex);
332 dbus_message_unref(msg->pMessage);
333 pthread_mutex_unlock(&gDbus.mutex);
340 * =============================================================================
341 * prototypes internal functions
342 * =============================================================================
344 void handleWatchesForFds(fd_set in, fd_set out)
349 for (fd = 0; fd < gDbus.incomingSocketsMax; ++fd)
351 DBusWatch* activeWatch;
353 if (FD_ISSET(fd, &in))
355 activeWatch = gDbus.incomingWatch[fd];
359 pthread_mutex_lock(&gDbus.mutex);
360 success = dbus_watch_handle(activeWatch, DBUS_WATCH_READABLE);
361 pthread_mutex_unlock(&gDbus.mutex);
365 printf("incoming dbus_watch_handle() failed\n");
370 printf("no watch was found for incoming fd %d, not calling dbus_watch_handle(NULL)\n", fd);
375 for (fd = 0; fd < gDbus.outgoingSocketsMax; ++fd)
377 DBusWatch* activeWatch;
379 if (FD_ISSET(fd, &out))
381 activeWatch = gDbus.outgoingWatch[fd];
385 pthread_mutex_lock(&gDbus.mutex);
386 success = dbus_watch_handle(activeWatch, DBUS_WATCH_WRITABLE);
387 pthread_mutex_unlock(&gDbus.mutex);
391 printf("outgoing dbus_watch_handle() failed\n");
396 printf("no watch was found for outgoing fd %d, not calling dbus_watch_handle(NULL)\n", fd);
402 t_ilm_bool dispatchIncomingMessages()
404 t_ilm_bool dispatched = ILM_FALSE;
405 if (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(gDbus.connection))
407 pthread_mutex_lock(&gDbus.mutex);
408 dbus_connection_dispatch(gDbus.connection);
409 pthread_mutex_unlock(&gDbus.mutex);
410 dispatched = ILM_TRUE;
415 void registerSignalForNotification(dbusmessage* message, char* signalName)
419 dbus_message_get_args(message->pMessage, NULL,
420 DBUS_TYPE_UINT32, &id,
424 "type='signal',sender='%s',interface='%s',member='%s%u'",
425 ILM_INTERFACE_COMPOSITE_SERVICE,
426 ILM_INTERFACE_COMPOSITE_SERVICE,
431 * do not block here, race condition with receive thread.
432 * according to dbus documentation almost impossible to fail
433 * (only if out of memory)
434 * if result is important, create method call manually
435 * and use main loop for communication
437 pthread_mutex_lock(&gDbus.mutex);
438 dbus_bus_add_match(gDbus.connection, rule, NULL);
439 pthread_mutex_unlock(&gDbus.mutex);
442 void unregisterSignalForNotification(dbusmessage* message, char* signalName)
446 dbus_message_get_args(message->pMessage, NULL,
447 DBUS_TYPE_UINT32, &id,
451 "type='signal',sender='%s',interface='%s',member='%s%d'",
452 ILM_INTERFACE_COMPOSITE_SERVICE,
453 ILM_INTERFACE_COMPOSITE_SERVICE,
458 * do not block here, race condition with receive thread.
459 * according to dbus documentation almost impossible to fail
460 * (only if out of memory)
461 * if result is important, create method call manually
462 * and use main loop for communication
464 pthread_mutex_lock(&gDbus.mutex);
465 dbus_bus_remove_match(gDbus.connection, rule, NULL);
466 pthread_mutex_unlock(&gDbus.mutex);
472 * =============================================================================
473 * print debug information
474 * =============================================================================
476 void printTypeName(int type)
480 case DBUS_TYPE_ARRAY:
481 printf("DBUS_TYPE_ARRAY\n");
483 case DBUS_TYPE_BOOLEAN:
484 printf("DBUS_TYPE_BOOLEAN\n");
486 case DBUS_TYPE_DOUBLE:
487 printf("DBUS_TYPE_DOUBLE\n");
489 case DBUS_TYPE_INT32:
490 printf("DBUS_TYPE_INT32\n");
492 case DBUS_TYPE_STRING:
493 printf("DBUS_TYPE_STRING\n");
495 case DBUS_TYPE_UINT32:
496 printf("DBUS_TYPE_UINT\n");
499 printf("unknown (%s)\n", (char*)&type);