49da87d922012e9ccb0d7e5c054999d88c37a204
[profile/ivi/layer-management.git] / LayerManagerPlugins / IpcModules / DbusIpcModule / src / message.c
1 /***************************************************************************
2  *
3  * Copyright 2012 BMW Car IT GmbH
4  *
5  *
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
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  ****************************************************************************/
19 #include "IpcModule.h"
20 #include "common.h"
21 #include "DBUSConfiguration.h"
22 #include "introspection.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h> /* strdup */
26 #include <errno.h>
27
28 /*
29  * =============================================================================
30  * prototypes internal functions
31  * =============================================================================
32  */
33 void handleWatchesForFds(fd_set in, fd_set out);
34 t_ilm_bool dispatchIncomingMessages();
35
36 void registerSignalForNotification(dbusmessage* message, char* signalName);
37 void unregisterSignalForNotification(dbusmessage* message, char* signalName);
38
39 /*
40  * =============================================================================
41  * message handling
42  * =============================================================================
43  */
44 t_ilm_message createMessage(t_ilm_const_string name)
45 {
46     dbusmessage* newMessage = NULL;
47
48     if (!gDbus.initialized)
49     {
50         return 0;
51     }
52
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,
60                                                         name);
61     pthread_mutex_unlock(&gDbus.mutex);
62     dbus_message_iter_init_append(newMessage->pMessage, &newMessage->iter);
63     return (t_ilm_message)newMessage;
64 }
65
66 t_ilm_message createResponse(t_ilm_message message)
67 {
68     dbusmessage* receivedMessage;
69     dbusmessage* newResponse;
70     const char* member = NULL;
71     const char* destination = NULL;
72
73     if (!gDbus.initialized)
74     {
75         return NULL;
76     }
77     receivedMessage = (dbusmessage*)message;
78     newResponse = (dbusmessage*)malloc(sizeof(dbusmessage));
79
80     newResponse->type = IpcMessageTypeCommand;
81     newResponse->dbusNativeType = DBUS_MESSAGE_TYPE_METHOD_RETURN;
82
83     pthread_mutex_lock(&gDbus.mutex);
84     newResponse->pMessage = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
85     pthread_mutex_unlock(&gDbus.mutex);
86
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);
93
94     return (t_ilm_message)newResponse;
95 }
96
97 t_ilm_message createErrorResponse(t_ilm_message message)
98 {
99     dbusmessage* receivedMessage;
100     dbusmessage* newResponse;
101     char member[256];
102     char destination[256];
103
104     if (!gDbus.initialized)
105     {
106         return 0;
107     }
108
109     receivedMessage = (dbusmessage*)message;
110     newResponse = (dbusmessage*)malloc(sizeof(dbusmessage));
111     memset(newResponse, 0, sizeof(dbusmessage));
112
113     newResponse->type = IpcMessageTypeError;
114     newResponse->dbusNativeType = DBUS_MESSAGE_TYPE_ERROR;
115
116     pthread_mutex_lock(&gDbus.mutex);
117     newResponse->pMessage = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
118     pthread_mutex_unlock(&gDbus.mutex);
119
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);
127
128     return (t_ilm_message)newResponse;
129 }
130
131 t_ilm_message createNotification(t_ilm_const_string name)
132 {
133     dbusmessage* newNotification;
134
135     if (!gDbus.initialized)
136     {
137         return 0;
138     }
139
140     newNotification = (dbusmessage*)malloc(sizeof(dbusmessage));
141
142     newNotification->type = IpcMessageTypeNotification;
143     newNotification->dbusNativeType = DBUS_MESSAGE_TYPE_SIGNAL;
144
145     if (!gDbus.isClient)
146     {
147         pthread_mutex_lock(&gDbus.mutex);
148         newNotification->pMessage = dbus_message_new_signal(ILM_PATH_COMPOSITE_SERVICE,
149                                                             ILM_INTERFACE_COMPOSITE_SERVICE,
150                                                             name);
151         pthread_mutex_unlock(&gDbus.mutex);
152         dbus_message_iter_init_append(newNotification->pMessage, &newNotification->iter);
153     }
154
155     return (t_ilm_message)newNotification;
156 }
157
158 t_ilm_bool sendToClients(t_ilm_message message, t_ilm_client_handle* receiverList, int receiverCount)
159 {
160     dbusmessage* messageToSend;
161     t_ilm_uint serial;
162     dbus_bool_t success;
163
164     (void)receiverList;
165     (void)receiverCount;
166
167     if (gDbus.isClient)
168     {
169         return ILM_FALSE;
170     }
171
172     messageToSend = (dbusmessage*)message;
173     serial = dbus_message_get_serial(messageToSend->pMessage);
174
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);
180     if (!success)
181     {
182         printf("DBUSIpcModule: Out Of Memory!\n");
183         exit(1);
184     }
185
186     return ILM_TRUE;
187 }
188
189 t_ilm_bool sendToService(t_ilm_message message)
190 {
191     dbusmessage* messageToSend;
192     t_ilm_uint serial;
193     dbus_bool_t success;
194     char msgName[256];
195
196     if (!gDbus.isClient)
197     {
198         return ILM_FALSE;
199     }
200
201     messageToSend = (dbusmessage*)message;
202     serial = 1;
203     pthread_mutex_lock(&gDbus.mutex);
204     success = dbus_connection_send(gDbus.connection, messageToSend->pMessage, &serial);
205     pthread_mutex_unlock(&gDbus.mutex);
206     if (!success)
207     {
208         printf("DBUSIpcModule: Out Of Memory!\n");
209         exit(1);
210     }
211
212     strcpy(msgName, dbus_message_get_member(messageToSend->pMessage));
213
214     if (0 == strcmp(msgName, "LayerAddNotification"))
215     {
216         registerSignalForNotification(messageToSend, "NotificationForLayer");
217     }
218
219     if (0 == strcmp(msgName, "LayerRemoveNotification"))
220     {
221         unregisterSignalForNotification(messageToSend, "NotificationForLayer");
222     }
223
224     if (0 == strcmp(msgName, "SurfaceAddNotification"))
225     {
226         registerSignalForNotification(messageToSend, "NotificationForSurface");
227     }
228
229     if (0 == strcmp(msgName, "SurfaceRemoveNotification"))
230     {
231         unregisterSignalForNotification(messageToSend, "NotificationForSurface");
232     }
233
234     return ILM_TRUE;
235 }
236
237 t_ilm_message receive(t_ilm_int timeoutInMs)
238 {
239     fd_set readFds;
240     fd_set writeFds;
241     int fdMax;
242     int fdsReady;
243
244     gpIncomingMessage = (dbusmessage*)malloc(sizeof(dbusmessage));
245     memset(gpIncomingMessage, 0, sizeof(dbusmessage));
246
247     if (!gDbus.initialized)
248     {
249         return (t_ilm_message)gpIncomingMessage;
250     }
251
252     if (dispatchIncomingMessages())
253     {
254         return (t_ilm_message)gpIncomingMessage;
255     }
256
257     readFds = gDbus.incomingSockets;
258     writeFds = gDbus.outgoingSockets;
259     fdMax = (gDbus.incomingSocketsMax > gDbus.outgoingSocketsMax) ?
260                 gDbus.incomingSocketsMax : gDbus.outgoingSocketsMax;
261
262     fdsReady = 0;
263
264     if (timeoutInMs < 0)
265     {
266         fdsReady = select(fdMax, &readFds, &writeFds, 0, NULL);
267     }
268     else
269     {
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);
274     }
275
276     switch (fdsReady)
277     {
278     case -1: /* error: select was cancelled -> shutdown */
279         gpIncomingMessage->type = IpcMessageTypeShutdown;
280         break;
281
282     case 0: /* timeout */
283         gpIncomingMessage->type = IpcMessageTypeNone;
284         break;
285
286     default: /* message or shutdown */
287         handleWatchesForFds(readFds, writeFds);
288         dispatchIncomingMessages();
289         break;
290     }
291
292     return (t_ilm_message)gpIncomingMessage;
293 }
294
295 t_ilm_const_string getMessageName(t_ilm_message message)
296 {
297     dbusmessage* msg = (dbusmessage*)message;
298     return msg->pMessage ? dbus_message_get_member(msg->pMessage) : NULL;
299 }
300
301 t_ilm_message_type getMessageType(t_ilm_message message)
302 {
303     dbusmessage* msg = (dbusmessage*)message;
304     return msg->type;
305 }
306
307 t_ilm_const_string getSenderName(t_ilm_message message)
308 {
309     dbusmessage* msg = (dbusmessage*)message;
310     return msg->pMessage ? dbus_message_get_sender(msg->pMessage) : NULL;
311 }
312
313 t_ilm_client_handle getSenderHandle(t_ilm_message message)
314 {
315     unsigned long result = 0;
316
317     const char* sender = getSenderName(message);
318     if (sender)
319     {
320         float f = atof(&sender[1]);
321         result = (unsigned long)(f * 1000000);
322     };
323     return (t_ilm_client_handle)result;
324 }
325
326 t_ilm_bool destroyMessage(t_ilm_message message)
327 {
328     dbusmessage* msg = (dbusmessage*)message;
329     if (msg && msg->pMessage)
330     {
331         pthread_mutex_lock(&gDbus.mutex);
332         dbus_message_unref(msg->pMessage);
333         pthread_mutex_unlock(&gDbus.mutex);
334         free(msg);
335     }
336     return ILM_TRUE;
337 }
338
339 /*
340  * =============================================================================
341  * prototypes internal functions
342  * =============================================================================
343  */
344 void handleWatchesForFds(fd_set in, fd_set out)
345 {
346     int fd = 0;
347     dbus_bool_t success;
348
349     for (fd = 0; fd < gDbus.incomingSocketsMax; ++fd)
350     {
351         DBusWatch* activeWatch;
352
353         if (FD_ISSET(fd, &in))
354         {
355             activeWatch = gDbus.incomingWatch[fd];
356
357             if (activeWatch)
358             {
359                 pthread_mutex_lock(&gDbus.mutex);
360                 success = dbus_watch_handle(activeWatch, DBUS_WATCH_READABLE);
361                 pthread_mutex_unlock(&gDbus.mutex);
362
363                 if (!success)
364                 {
365                     printf("incoming dbus_watch_handle() failed\n");
366                 }
367             }
368             else
369             {
370                 printf("no watch was found for incoming fd %d, not calling dbus_watch_handle(NULL)\n", fd);
371             }
372         }
373     }
374
375     for (fd = 0; fd < gDbus.outgoingSocketsMax; ++fd)
376     {
377         DBusWatch* activeWatch;
378
379         if (FD_ISSET(fd, &out))
380         {
381             activeWatch = gDbus.outgoingWatch[fd];
382
383             if (activeWatch)
384             {
385                 pthread_mutex_lock(&gDbus.mutex);
386                 success = dbus_watch_handle(activeWatch, DBUS_WATCH_WRITABLE);
387                 pthread_mutex_unlock(&gDbus.mutex);
388
389                 if (!success)
390                 {
391                     printf("outgoing dbus_watch_handle() failed\n");
392                 }
393             }
394             else
395             {
396                 printf("no watch was found for outgoing fd %d, not calling dbus_watch_handle(NULL)\n", fd);
397             }
398         }
399     }
400 }
401
402 t_ilm_bool dispatchIncomingMessages()
403 {
404     t_ilm_bool dispatched = ILM_FALSE;
405     if (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(gDbus.connection))
406     {
407         pthread_mutex_lock(&gDbus.mutex);
408         dbus_connection_dispatch(gDbus.connection);
409         pthread_mutex_unlock(&gDbus.mutex);
410         dispatched = ILM_TRUE;
411     }
412     return dispatched;
413 }
414
415 void registerSignalForNotification(dbusmessage* message, char* signalName)
416 {
417     char rule[1024];
418     t_ilm_uint id;
419     dbus_message_get_args(message->pMessage, NULL,
420                             DBUS_TYPE_UINT32, &id,
421                             DBUS_TYPE_INVALID);
422
423     sprintf(rule,
424             "type='signal',sender='%s',interface='%s',member='%s%u'",
425             ILM_INTERFACE_COMPOSITE_SERVICE,
426             ILM_INTERFACE_COMPOSITE_SERVICE,
427             signalName,
428             id);
429
430     /*
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
436      */
437     pthread_mutex_lock(&gDbus.mutex);
438     dbus_bus_add_match(gDbus.connection, rule, NULL);
439     pthread_mutex_unlock(&gDbus.mutex);
440 }
441
442 void unregisterSignalForNotification(dbusmessage* message, char* signalName)
443 {
444     char rule[1024];
445     t_ilm_uint id;
446     dbus_message_get_args(message->pMessage, NULL,
447                             DBUS_TYPE_UINT32, &id,
448                             DBUS_TYPE_INVALID);
449
450     sprintf(rule,
451             "type='signal',sender='%s',interface='%s',member='%s%d'",
452             ILM_INTERFACE_COMPOSITE_SERVICE,
453             ILM_INTERFACE_COMPOSITE_SERVICE,
454             signalName,
455             id);
456
457     /*
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
463      */
464     pthread_mutex_lock(&gDbus.mutex);
465     dbus_bus_remove_match(gDbus.connection, rule, NULL);
466     pthread_mutex_unlock(&gDbus.mutex);
467 }
468
469
470
471 /*
472  * =============================================================================
473  * print debug information
474  * =============================================================================
475  */
476 void printTypeName(int type)
477 {
478     switch (type)
479     {
480     case DBUS_TYPE_ARRAY:
481         printf("DBUS_TYPE_ARRAY\n");
482         break;
483     case DBUS_TYPE_BOOLEAN:
484         printf("DBUS_TYPE_BOOLEAN\n");
485         break;
486     case DBUS_TYPE_DOUBLE:
487         printf("DBUS_TYPE_DOUBLE\n");
488         break;
489     case DBUS_TYPE_INT32:
490         printf("DBUS_TYPE_INT32\n");
491         break;
492     case DBUS_TYPE_STRING:
493         printf("DBUS_TYPE_STRING\n");
494         break;
495     case DBUS_TYPE_UINT32:
496         printf("DBUS_TYPE_UINT\n");
497         break;
498     default:
499         printf("unknown (%s)\n", (char*)&type);
500         break;
501     }
502 }
503