[Hello Message] autoreply finished using worker function
[platform/upstream/glib.git] / gio / gkdbus.c
1 /*  GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2013 Samsung
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Michal Eljasiewicz <m.eljasiewic@samsung.com>
21  * Authors: Lukasz Skalski <l.skalski@partner.samsung.com>
22  */
23
24 #include "config.h"
25
26 #include "gkdbus.h"
27 #include "glib-unix.h"
28
29 #include <errno.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/mman.h>
35 #include <stdio.h>
36
37 #ifdef HAVE_SYS_FILIO_H
38 # include <sys/filio.h>
39 #endif
40
41 #ifdef HAVE_SYS_UIO_H
42 #include <sys/uio.h>
43 #endif
44
45 #include "gcancellable.h"
46 #include "gioenumtypes.h"
47 #include "ginitable.h"
48 #include "gioerror.h"
49 #include "gioenums.h"
50 #include "gioerror.h"
51 #include "glibintl.h"
52 #include "kdbus.h"
53 #include "gdbusmessage.h"
54 #include "gdbusconnection.h"
55
56 #define KDBUS_PART_FOREACH(part, head, first)                           \
57         for (part = (head)->first;                                      \
58              (guint8 *)(part) < (guint8 *)(head) + (head)->size;        \
59              part = KDBUS_PART_NEXT(part))
60 #define RECEIVE_POOL_SIZE (10 * 1024LU * 1024LU)
61
62 #define MSG_ITEM_BUILD_VEC(data, datasize)                                    \
63         item->type = KDBUS_MSG_PAYLOAD_VEC;                                     \
64         item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec);         \
65         item->vec.address = (unsigned long) data;                               \
66         item->vec.size = datasize;
67
68 #define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
69 #define KDBUS_PART_NEXT(part) \
70         (typeof(part))(((guint8 *)part) + KDBUS_ALIGN8((part)->size))
71 #define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_PART_HEADER_SIZE)
72
73 /**
74  * SECTION:gkdbus
75  * @short_description: Low-level kdbus object
76  * @include: gio/gio.h
77  * @see_also: #GInitable, <link linkend="gio-gnetworking.h">gnetworking.h</link>
78  *
79  */
80
81 static void     g_kdbus_initable_iface_init (GInitableIface  *iface);
82 static gboolean g_kdbus_initable_init       (GInitable       *initable,
83                                               GCancellable    *cancellable,
84                                               GError         **error);
85
86 G_DEFINE_TYPE_WITH_CODE (GKdbus, g_kdbus, G_TYPE_OBJECT,
87                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
88                                                 g_kdbus_initable_iface_init));
89
90 struct _GKdbusPrivate
91 {
92   gchar          *path;
93   gint            fd;
94   guint           closed : 1;
95   guint           inited : 1;
96   gchar          *buffer_ptr;
97   gint            peer_id;
98 };
99
100 // TODO:
101 static void
102 g_kdbus_get_property (GObject    *object,
103                        guint       prop_id,
104                        GValue     *value,
105                        GParamSpec *pspec)
106 {
107   //GKdbus *kdbus = G_KDBUS (object);
108
109   switch (prop_id)
110     {
111       default:
112         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113     }
114 }
115
116 // TODO:
117 static void
118 g_kdbus_set_property (GObject      *object,
119                        guint         prop_id,
120                        const GValue *value,
121                        GParamSpec   *pspec)
122 {
123   //GKdbus *kdbus = G_KDBUS (object);
124
125   switch (prop_id)
126     {
127       default:
128         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
129     }
130 }
131
132 // TODO:
133 static void
134 g_kdbus_finalize (GObject *object)
135 {
136   //GKdbus *kdbus = G_KDBUS (object);
137
138   // TODO: Posprzatac po obiekcie
139
140 }
141
142 static void
143 g_kdbus_class_init (GKdbusClass *klass)
144 {
145   GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
146
147   g_type_class_add_private (klass, sizeof (GKdbusPrivate));
148
149   gobject_class->finalize = g_kdbus_finalize;
150   gobject_class->set_property = g_kdbus_set_property;
151   gobject_class->get_property = g_kdbus_get_property;
152 }
153
154 static void
155 g_kdbus_initable_iface_init (GInitableIface *iface)
156 {
157   iface->init = g_kdbus_initable_init;
158 }
159
160 static void
161 g_kdbus_init (GKdbus *kdbus)
162 {
163   kdbus->priv = G_TYPE_INSTANCE_GET_PRIVATE (kdbus, G_TYPE_KDBUS, GKdbusPrivate);
164   kdbus->priv->fd = -1;
165   kdbus->priv->path = NULL;
166   kdbus->priv->buffer_ptr = NULL;
167   kdbus->priv->peer_id = -1;
168 }
169
170 static gboolean
171 g_kdbus_initable_init (GInitable *initable,
172                         GCancellable *cancellable,
173                         GError  **error)
174 {
175   GKdbus  *kdbus;
176
177   g_return_val_if_fail (G_IS_KDBUS (initable), FALSE);
178
179   kdbus = G_KDBUS (initable);
180
181   if (cancellable != NULL)
182     {
183       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
184                            _("Cancellable initialization not supported"));
185       return FALSE;
186     }
187
188   kdbus->priv->inited = TRUE;
189
190   return TRUE;
191 }
192
193 /**
194  * g_kdbus_get_fd:
195  * @kdbus: a #GKdbus.
196  *
197  * Returns: the file descriptor of the kdbus.
198  */
199 gint
200 g_kdbus_get_fd (GKdbus *kdbus)
201 {
202   g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
203
204   return kdbus->priv->fd;
205 }
206
207 /**
208  * g_kdbus_connect:
209  * @kdbus: a #Gkdbus.
210  */
211 gboolean
212 g_kdbus_open (GKdbus         *kdbus,
213               const gchar    *address,
214               GCancellable   *cancellable,
215               GError         **error)
216 {
217   g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
218   g_print ("ADDRESS: %s\n",address);
219   kdbus->priv->fd = open(address, O_RDWR|O_CLOEXEC|O_NONBLOCK);
220   g_print ("FD: %d\n",kdbus->priv->fd);
221   return TRUE;
222 }
223
224 /**
225  * g_kdbus_close:
226  * @kdbus: a #GKdbus
227  * @error: #GError for error reporting, or %NULL to ignore.
228  *
229  */
230 gboolean
231 g_kdbus_close (GKdbus  *kdbus,
232                 GError  **error)
233 {
234   // TODO
235
236   close(kdbus->priv->fd);
237
238   kdbus->priv->closed = TRUE;
239   kdbus->priv->fd = -1;
240   
241   return TRUE;
242 }
243
244 /**
245  * g_kdbus_is_closed:
246  * @kdbus: a #GKdbus
247  *
248  * Checks whether a kdbus is closed.
249  *
250  * Returns: %TRUE if kdbus is closed, %FALSE otherwise
251  */
252 gboolean
253 g_kdbus_is_closed (GKdbus *kdbus)
254 {
255   g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
256
257   return kdbus->priv->closed;
258 }
259
260 /**
261  * Registration on Kdbus bus.
262  * Hello message + unique name + mapping memory for incoming messages.
263  *
264  * @returns #TRUE on success
265  */
266 gboolean g_kdbus_register(GKdbus           *kdbus)
267 {
268         struct kdbus_cmd_hello __attribute__ ((__aligned__(8))) hello;
269
270         hello.conn_flags = KDBUS_HELLO_ACCEPT_FD/* |
271                            KDBUS_HELLO_ATTACH_COMM |
272                            KDBUS_HELLO_ATTACH_EXE |
273                            KDBUS_HELLO_ATTACH_CMDLINE |
274                            KDBUS_HELLO_ATTACH_CAPS |
275                            KDBUS_HELLO_ATTACH_CGROUP |
276                            KDBUS_HELLO_ATTACH_SECLABEL |
277                            KDBUS_HELLO_ATTACH_AUDIT*/;
278         hello.size = sizeof(struct kdbus_cmd_hello);
279         hello.pool_size = RECEIVE_POOL_SIZE;
280
281         if (ioctl(kdbus->priv->fd, KDBUS_CMD_HELLO, &hello))
282         {
283                 g_print("FD: %d Failed to send hello: %m, %d",kdbus->priv->fd,errno);
284                 return FALSE;
285         }
286
287   kdbus->priv->peer_id = hello.id;
288         g_print("-- Our peer ID is: %llu\n", hello.id);
289         // TODO (ASK RADEK)transportS->bloom_size = hello.bloom_size;
290
291         kdbus->priv->buffer_ptr = mmap(NULL, RECEIVE_POOL_SIZE, PROT_READ, MAP_SHARED, kdbus->priv->fd, 0);
292         if (kdbus->priv->buffer_ptr == MAP_FAILED)
293         {
294                 g_print("Error when mmap: %m, %d",errno);
295                 return FALSE;
296         }
297
298         return TRUE;
299 }
300
301 /*
302  * g_kdbus_decode_msg:
303  * @kdbus_msg: kdbus message received into buffer
304  *
305  */
306 static int 
307 g_kdbus_decode_msg(GKdbus           *kdbus,
308                    struct kdbus_msg *msg, 
309                    char             *data)
310 {
311   const struct kdbus_item *item;
312   int ret_size = 0;
313
314   KDBUS_PART_FOREACH(item, msg, items)
315         {
316                 if (item->size <= KDBUS_PART_HEADER_SIZE)
317                 {
318                         g_print("  +(%llu bytes) invalid data record\n", item->size);
319                         break;  //??? continue (because dbus will find error) or break
320                 }
321
322                 switch (item->type)
323                 {
324                         case KDBUS_MSG_PAYLOAD_OFF:
325                                 memcpy(data, (char *)kdbus->priv->buffer_ptr + item->vec.offset, item->vec.size);
326                                 data += item->vec.size;
327                                 ret_size += item->vec.size;                     
328
329                                 g_print("  + KDBUS_MSG_PAYLOAD (%llu bytes) off=%llu size=%llu\n", item->size,
330                                         (unsigned long long)item->vec.offset,
331                                         (unsigned long long)item->vec.size);
332                         break;
333
334       case KDBUS_MSG_REPLY_TIMEOUT:
335                                 g_print("  + KDBUS_MSG_REPLY_TIMEOUT (%llu bytes) cookie=%llu\n", item->size, msg->cookie_reply);
336
337                                 /* TODO
338         message = generate_local_error_message(msg->cookie_reply, DBUS_ERROR_NO_REPLY, NULL);
339                                 if(message == NULL)
340                                 {
341                                         ret_size = -1;
342                                         goto out;
343                                 }
344
345                                 ret_size = put_message_into_data(message, data);
346         */
347                         break;
348
349                         case KDBUS_MSG_REPLY_DEAD:
350                                 g_print("  + (%llu bytes) cookie=%llu\n", item->size, msg->cookie_reply);
351
352         /* TODO
353                                 message = generate_local_error_message(msg->cookie_reply, DBUS_ERROR_NAME_HAS_NO_OWNER, NULL);
354                                 if(message == NULL)
355                                 {
356                                         ret_size = -1;
357                                         goto out;
358                                 }
359         
360                                 ret_size = put_message_into_data(message, data);
361         */
362                         break;
363
364       /* case ... */
365     }
366   }
367
368   return ret_size;
369 }
370
371 /*
372  * g_kdbus_receive:
373  * @kdbus: a #GKdbus
374  *
375  * TODO handle errors
376  */
377 gssize
378 g_kdbus_receive (GKdbus       *kdbus,
379                  void         *data,
380                              GError       **error)
381 {
382   int ret_size;
383   guint64 __attribute__ ((__aligned__(8))) offset;
384   struct kdbus_msg *msg;
385
386   // get memory offset of msg
387   again:
388   if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RECV, &offset) < 0)
389   {
390           if(errno == EINTR)
391                   goto again;
392           return -1;
393   }
394
395   msg = (struct kdbus_msg *)((char*)kdbus->priv->buffer_ptr + offset);
396
397   ret_size = g_kdbus_decode_msg(kdbus, msg, (char*)data);
398
399   // Release memory occupied by msg
400   again2:
401         if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RELEASE, &offset) < 0)
402         {
403                 if(errno == EINTR)
404                         goto again2;
405                 return -1;
406         }
407   
408   return ret_size;
409 }
410
411 static gboolean
412 g_kdbus_send_reply(GDBusWorker     *worker, 
413                    GKdbus           *kdbus, 
414                    GDBusMessage    *dbus_msg)
415 {
416   GDBusMessage    *reply = NULL;
417   char            *unique_name = NULL;
418
419   reply = g_dbus_message_new_method_reply(dbus_msg);
420   g_dbus_message_set_sender(reply, "org.freedesktop.DBus");
421
422   unique_name = malloc(30); // TODO should allow for Kdbus peer ID max value ?
423   sprintf(unique_name, "%i", kdbus->priv->peer_id);
424
425   g_dbus_message_set_body(reply, g_variant_new ("(s)", unique_name));
426   
427   _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
428 }
429
430
431
432 /**
433  * g_kdbus_send_message:
434  * @kdbus: a #GKdbus
435  */
436 gssize
437 g_kdbus_send_message (GDBusWorker     *worker,
438                       GKdbus          *kdbus,
439                       GDBusMessage    *dbus_msg,
440                       gchar           *blob,
441                       gsize           blob_size,
442                                   GError          **error)
443 {
444   struct kdbus_msg* kmsg;
445   struct kdbus_item *item;
446   guint64 kmsg_size = 0;
447   const gchar *dst;
448   guint64 dst_id = KDBUS_DST_ID_BROADCAST;
449   
450   
451   // if message to org.Freedesktop.DBus then handle differently
452   if(g_strcmp0(g_dbus_message_get_member(dbus_msg), "Hello") == 0)
453   {
454     
455
456     g_print ("kdbus_send_message: sending Hello message! \n");
457   
458     if(!g_kdbus_register(kdbus))
459     {
460       g_print ("kdbus_send_message: registering failed! \n");
461       return -1;
462     }
463
464     g_kdbus_send_reply(worker, kdbus, dbus_msg);
465     
466     
467     
468     goto out;
469   }
470
471   g_print ("kdbus_send_message: blob_size: %i \n", (int)blob_size);
472   
473   // get dst name
474   dst = g_dbus_message_get_destination(dbus_msg);
475   g_print ("kdbus_send_message: destination name: %s \n", dst);
476
477   kmsg_size = sizeof(struct kdbus_msg);
478   kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); // vector for blob
479
480   if (dst)
481         kmsg_size += KDBUS_ITEM_SIZE(strlen(dst) + 1);
482   else if (dst_id == KDBUS_DST_ID_BROADCAST)
483         kmsg_size += KDBUS_PART_HEADER_SIZE + 32; /* TODO transport->bloom_size*/;
484
485   kmsg = malloc(kmsg_size);
486   if (!kmsg)
487   {
488         // TODO debug/error
489           return -1;
490   }
491
492   memset(kmsg, 0, kmsg_size);
493   kmsg->size = kmsg_size;
494   kmsg->payload_type = KDBUS_PAYLOAD_DBUS1;
495   kmsg->dst_id = dst ? 0 : dst_id;
496   kmsg->src_id = strtoull(g_dbus_message_get_sender(dbus_msg), NULL , 10);
497   kmsg->cookie = g_dbus_message_get_serial(dbus_msg);
498
499   g_print ("kdbus_send_message unique_name/message->sender: %s \n", g_dbus_message_get_sender(dbus_msg));
500
501   // build message contents
502   item = kmsg->items;
503
504   MSG_ITEM_BUILD_VEC(blob, blob_size);
505
506   if (dst)
507         {
508                 item = KDBUS_PART_NEXT(item);
509                 item->type = KDBUS_MSG_DST_NAME;
510                 item->size = KDBUS_PART_HEADER_SIZE + strlen(dst) + 1;
511                 strcpy(item->str, dst);
512         }
513         else if (dst_id == KDBUS_DST_ID_BROADCAST)
514         {
515                 item = KDBUS_PART_NEXT(item);
516                 item->type = KDBUS_MSG_BLOOM;
517                 item->size = KDBUS_PART_HEADER_SIZE + 32; /* TODO transport->bloom_size*/;
518                 // TODO (ASK RADEK) strncpy(item->data, dbus_message_get_interface(message), transport->bloom_size);
519         }
520
521 again:
522         if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg))
523         {
524                 if(errno == EINTR)
525                         goto again;
526     else
527       g_warning ("g_kdbus_send_message: ioctl error sending kdbus message: %d (%m) \n", errno);
528   }
529
530   free(kmsg);
531
532 out:
533   return blob_size;
534 }
535
536 /***************************************************************************************************************
537
538
539 /**
540  * g_kdbus_send:
541  * @kdbus: a #GKdbus
542  */
543 /*gssize
544 g_kdbus_send (GKdbus       *kdbus,
545                const gchar   *buffer,
546                gsize          size,
547                GCancellable  *cancellable,
548                GError       **error)
549 {
550   // TODO
551 }*/
552
553
554
555
556 /**
557  * g_kdbus_receive_message:
558  * @kdbus: a #Gkdbus
559  */
560 /*gssize
561 g_kdbus_receive_message (Gkdbus                 *kdbus,
562                           GkdbusAddress         **address,
563                           GInputVector            *vectors,
564                           gint                     num_vectors,
565                           GkdbusControlMessage ***messages,
566                           gint                    *num_messages,
567                           gint                    *flags,
568                           GCancellable            *cancellable,
569                           GError                 **error)
570 {
571   //TODO
572 }*/