fced9c72dbbe8321b24f40dd4596f22197a5f192
[platform/upstream/dbus.git] / dbus / dbus-message.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c  DBusMessage object
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  * Copyright (C) 2002, 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-internals.h"
26 #include "dbus-marshal.h"
27 #include "dbus-message.h"
28 #include "dbus-message-internal.h"
29 #include "dbus-memory.h"
30 #include "dbus-list.h"
31 #include "dbus-message-builder.h"
32 #include <string.h>
33
34 /**
35  * @defgroup DBusMessageInternals DBusMessage implementation details
36  * @ingroup DBusInternals
37  * @brief DBusMessage private implementation details.
38  *
39  * The guts of DBusMessage and its methods.
40  *
41  * @{
42  */
43
44 enum
45 {
46   FIELD_HEADER_LENGTH,
47   FIELD_BODY_LENGTH,
48   FIELD_CLIENT_SERIAL,
49   FIELD_NAME,
50   FIELD_SERVICE,
51   FIELD_SENDER,
52   FIELD_REPLY_SERIAL,
53
54   FIELD_LAST
55 };
56
57 static dbus_bool_t field_is_named[FIELD_LAST] =
58 {
59   FALSE, /* FIELD_HEADER_LENGTH */
60   FALSE, /* FIELD_BODY_LENGTH */
61   FALSE, /* FIELD_CLIENT_SERIAL */
62   TRUE,  /* FIELD_NAME */
63   TRUE,  /* FIELD_SERVICE */
64   TRUE,  /* FIELD_SENDER */
65   TRUE   /* FIELD_REPLY_SERIAL */
66 };
67
68 typedef struct
69 {
70   int offset; /**< Offset to start of field (location of name of field
71                * for named fields)
72                */
73 } HeaderField;
74
75 /**
76  * @brief Internals of DBusMessage
77  * 
78  * Object representing a message received from or to be sent to
79  * another application. This is an opaque object, all members
80  * are private.
81  */
82 struct DBusMessage
83 {
84   dbus_atomic_t refcount; /**< Reference count */
85
86   DBusString header; /**< Header network data, stored
87                       * separately from body so we can
88                       * independently realloc it.
89                       */
90
91   HeaderField header_fields[FIELD_LAST]; /**< Track the location
92                                            * of each field in "header"
93                                            */
94   int header_padding; /**< bytes of alignment in header */
95   
96   DBusString body;   /**< Body network data. */
97
98   char byte_order; /**< Message byte order. */
99
100   DBusCounter *size_counter; /**< Counter for the size of the message, or #NULL */
101   long size_counter_delta;   /**< Size we incremented the size counter by. */
102   
103   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
104 };
105
106 /**
107  * @brief Internals of DBusMessageIter
108  * 
109  * Object representing a position in a message. All fields are internal.
110  */
111 struct DBusMessageIter
112 {
113   int refcount; /**< Reference count */
114
115   int pos; /**< Current position in the string */
116   
117   DBusMessage *message; /**< Message used */
118 };
119
120 /**
121  * Gets the data to be sent over the network for this message.
122  * The header and then the body should be written out.
123  * This function is guaranteed to always return the same
124  * data once a message is locked (with _dbus_message_lock()).
125  *
126  * @param message the message.
127  * @param header return location for message header data.
128  * @param body return location for message body data.
129  */
130 void
131 _dbus_message_get_network_data (DBusMessage          *message,
132                                 const DBusString    **header,
133                                 const DBusString    **body)
134 {
135   _dbus_assert (message->locked);
136   
137   *header = &message->header;
138   *body = &message->body;
139 }
140
141 static void
142 clear_header_padding (DBusMessage *message)
143 {
144   _dbus_string_shorten (&message->header,
145                         message->header_padding);
146   message->header_padding = 0;
147 }                      
148
149 static dbus_bool_t
150 append_header_padding (DBusMessage *message)
151 {
152   int old_len;
153   old_len = _dbus_string_get_length (&message->header);
154   if (!_dbus_string_align_length (&message->header, 8))
155     return FALSE;
156
157   message->header_padding = _dbus_string_get_length (&message->header) - old_len;
158
159   return TRUE;
160 }
161
162 static void
163 adjust_field_offsets (DBusMessage *message,
164                       int          offsets_after,
165                       int          delta)
166 {
167   int i;
168
169   if (delta == 0)
170     return;
171   
172   i = 0;
173   while (i < FIELD_LAST)
174     {
175       if (message->header_fields[i].offset > offsets_after)
176         message->header_fields[i].offset += delta;
177
178       ++i;
179     }
180 }
181
182 static const char*
183 get_string_field (DBusMessage *message,
184                   int          field,
185                   int         *len)
186 {
187   int offset = message->header_fields[field].offset;
188   const char *data;
189   
190   if (offset < 0)
191     return NULL;
192
193   /* offset points to string length, string data follows it */
194   /* FIXME _dbus_demarshal_const_string() that returned
195    * a reference to the string plus its len might be nice.
196    */
197   
198   if (len)
199     *len = _dbus_demarshal_uint32 (&message->header,
200                                    message->byte_order,
201                                    offset,
202                                    NULL);
203
204   _dbus_string_get_const_data (&message->header,
205                                &data);
206   
207   return data + (offset + 4); 
208 }
209
210 static dbus_int32_t
211 get_int_field (DBusMessage *message,
212                      int          field)
213 {
214   int offset = message->header_fields[field].offset;
215   
216   if (offset < 0)
217     return -1; /* useless if -1 is a valid value of course */
218
219   return _dbus_demarshal_int32 (&message->header,
220                                 message->byte_order,
221                                 offset,
222                                 NULL);
223 }
224
225 static dbus_bool_t
226 append_int_field (DBusMessage *message,
227                   int          field,
228                   const char  *name,
229                   int          value)
230 {
231   int orig_len;
232
233   _dbus_assert (!message->locked);
234
235   clear_header_padding (message);
236   
237   orig_len = _dbus_string_get_length (&message->header);
238   
239   if (!_dbus_string_align_length (&message->header, 4))
240     goto failed;  
241   
242   if (!_dbus_string_append_len (&message->header, name, 4))
243     goto failed;
244
245   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
246     goto failed;
247
248   if (!_dbus_string_align_length (&message->header, 4))
249     goto failed;
250   
251   message->header_fields[FIELD_REPLY_SERIAL].offset =
252     _dbus_string_get_length (&message->header);
253   
254   if (!_dbus_marshal_int32 (&message->header, message->byte_order,
255                             value))
256     goto failed;
257
258   if (!append_header_padding (message))
259     goto failed;
260   
261   return TRUE;
262   
263  failed:
264   message->header_fields[field].offset = -1;
265   _dbus_string_set_length (&message->header, orig_len);
266
267   /* this must succeed because it was allocated on function entry and
268    * DBusString doesn't ever realloc smaller
269    */
270   if (!append_header_padding (message))
271     _dbus_assert_not_reached ("failed to reappend header padding");
272   return FALSE;
273 }
274
275 static dbus_bool_t
276 append_string_field (DBusMessage *message,
277                      int          field,
278                      const char  *name,
279                      const char  *value)
280 {
281   int orig_len;
282
283   _dbus_assert (!message->locked);
284
285   clear_header_padding (message);
286   
287   orig_len = _dbus_string_get_length (&message->header);
288
289   if (!_dbus_string_align_length (&message->header, 4))
290     goto failed;
291   
292   if (!_dbus_string_append_len (&message->header, name, 4))
293     goto failed;
294   
295   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
296     goto failed;
297
298   if (!_dbus_string_align_length (&message->header, 4))
299     goto failed;
300   
301   message->header_fields[field].offset =
302     _dbus_string_get_length (&message->header);
303   
304   if (!_dbus_marshal_string (&message->header, message->byte_order,
305                              value))
306     goto failed;
307
308   if (!append_header_padding (message))
309     goto failed;
310   
311   return TRUE;
312   
313  failed:
314   message->header_fields[field].offset = -1;
315   _dbus_string_set_length (&message->header, orig_len);
316
317   /* this must succeed because it was allocated on function entry and
318    * DBusString doesn't ever realloc smaller
319    */
320   if (!append_header_padding (message))
321     _dbus_assert_not_reached ("failed to reappend header padding");
322   
323   return FALSE;
324 }
325
326 static void
327 delete_int_field (DBusMessage *message,
328                   int          field)
329 {
330   int offset = message->header_fields[field].offset;
331
332   _dbus_assert (!message->locked);
333   _dbus_assert (field_is_named[field]);
334   
335   if (offset < 0)
336     return;  
337
338   clear_header_padding (message);
339   
340   /* The field typecode and name take up 8 bytes */
341   _dbus_string_delete (&message->header,
342                        offset - 8,
343                        12);
344
345   message->header_fields[field].offset = -1;
346   
347   adjust_field_offsets (message,
348                         offset - 8,
349                         - 12);
350
351   append_header_padding (message);
352 }
353
354 static void
355 delete_string_field (DBusMessage *message,
356                      int          field)
357 {
358   int offset = message->header_fields[field].offset;
359   int len;
360   int delete_len;
361   
362   _dbus_assert (!message->locked);
363   _dbus_assert (field_is_named[field]);
364   
365   if (offset < 0)
366     return;
367
368   clear_header_padding (message);
369   
370   get_string_field (message, field, &len);
371   
372   /* The field typecode and name take up 8 bytes, and the nul
373    * termination is 1 bytes, string length integer is 4 bytes
374    */
375   delete_len = 8 + 4 + 1 + len;
376   
377   _dbus_string_delete (&message->header,
378                        offset - 8,
379                        delete_len);
380
381   message->header_fields[field].offset = -1;
382   
383   adjust_field_offsets (message,
384                         offset - 8,
385                         - delete_len);
386
387   append_header_padding (message);
388 }
389
390 static dbus_bool_t
391 set_int_field (DBusMessage *message,
392                int          field,
393                int          value)
394 {
395   int offset = message->header_fields[field].offset;
396
397   _dbus_assert (!message->locked);
398   
399   if (offset < 0)
400     {
401       /* need to append the field */
402
403       switch (field)
404         {
405         case FIELD_REPLY_SERIAL:
406           return append_int_field (message, field,
407                                    DBUS_HEADER_FIELD_REPLY,
408                                    value);
409         default:
410           _dbus_assert_not_reached ("appending an int field we don't support appending");
411           return FALSE;
412         }
413     }
414   else
415     {
416       _dbus_marshal_set_int32 (&message->header,
417                                message->byte_order,
418                                offset, value);
419
420       return TRUE;
421     }
422 }
423
424 static dbus_bool_t
425 set_uint_field (DBusMessage  *message,
426                 int           field,
427                 dbus_uint32_t value)
428 {
429   int offset = message->header_fields[field].offset;
430
431   _dbus_assert (!message->locked);
432   
433   if (offset < 0)
434     {
435       /* need to append the field */
436
437       switch (field)
438         {
439         default:
440           _dbus_assert_not_reached ("appending a uint field we don't support appending");
441           return FALSE;
442         }
443     }
444   else
445     {
446       _dbus_marshal_set_uint32 (&message->header,
447                                 message->byte_order,
448                                 offset, value);
449
450       return TRUE;
451     }
452 }
453
454 static dbus_bool_t
455 set_string_field (DBusMessage *message,
456                   int          field,
457                   const char  *value)
458 {
459   int offset = message->header_fields[field].offset;
460
461   _dbus_assert (!message->locked);
462   _dbus_assert (value != NULL);
463   
464   if (offset < 0)
465     {      
466       /* need to append the field */
467
468       switch (field)
469         {
470         case FIELD_SENDER:
471           return append_string_field (message, field,
472                                       DBUS_HEADER_FIELD_SENDER,
473                                       value);
474         default:
475           _dbus_assert_not_reached ("appending a string field we don't support appending");
476           return FALSE;
477         }
478     }
479   else
480     {
481       DBusString v;
482       int old_len;
483       int new_len;
484       
485       old_len = _dbus_string_get_length (&message->header);
486
487       _dbus_string_init_const_len (&v, value,
488                                    strlen (value) + 1); /* include nul */
489       if (!_dbus_marshal_set_string (&message->header,
490                                      message->byte_order,
491                                      offset, &v))
492         return FALSE;
493       
494       new_len = _dbus_string_get_length (&message->header);
495
496       adjust_field_offsets (message,
497                             offset,
498                             new_len - old_len);
499
500       return TRUE;
501     }
502 }
503
504 /**
505  * Sets the client serial of a message. 
506  * This can only be done once on a message.
507  *
508  * @todo client_serial should be called simply
509  * "serial"; it's in outgoing messages for both
510  * the client and the server, it's only client-specific
511  * in the message bus case. It's more like origin_serial
512  * or something.
513  * 
514  * @param message the message
515  * @param client_serial the client serial
516  */
517 void
518 _dbus_message_set_client_serial (DBusMessage  *message,
519                                  dbus_int32_t  client_serial)
520 {
521   _dbus_assert (!message->locked);
522   _dbus_assert (_dbus_message_get_client_serial (message) < 0);
523
524   set_int_field (message, FIELD_CLIENT_SERIAL,
525                  client_serial);
526 }
527
528 /**
529  * Sets the reply serial of a message (the client serial
530  * of the message this is a reply to).
531  *
532  * @param message the message
533  * @param reply_serial the client serial
534  * @returns #FALSE if not enough memory
535  */
536 dbus_bool_t
537 _dbus_message_set_reply_serial (DBusMessage  *message,
538                                 dbus_int32_t  reply_serial)
539 {
540   _dbus_assert (!message->locked);
541
542   return set_int_field (message, FIELD_REPLY_SERIAL,
543                         reply_serial);
544 }
545
546 /**
547  * Returns the client serial of a message or
548  * -1 if none has been specified.
549  *
550  * @todo see note in _dbus_message_set_client_serial()
551  * about how client_serial is a misnomer
552  *
553  * @todo this function should be public, after renaming it.
554  *
555  * @param message the message
556  * @returns the client serial
557  */
558 dbus_int32_t
559 _dbus_message_get_client_serial (DBusMessage *message)
560 {
561   return get_int_field (message, FIELD_CLIENT_SERIAL);
562 }
563
564 /**
565  * Returns the serial that the message is
566  * a reply to or -1 if none.
567  *
568  * @param message the message
569  * @returns the reply serial
570  */
571 dbus_int32_t
572 _dbus_message_get_reply_serial  (DBusMessage *message)
573 {
574   return get_int_field (message, FIELD_REPLY_SERIAL);
575 }
576
577 /**
578  * Adds a counter to be incremented immediately with the
579  * size of this message, and decremented by the size
580  * of this message when this message if finalized.
581  *
582  * @param message the message
583  * @param counter the counter
584  */
585 void
586 _dbus_message_add_size_counter (DBusMessage *message,
587                                 DBusCounter *counter)
588 {
589   _dbus_assert (message->size_counter == NULL); /* If this fails we may need to keep a list of
590                                                  * counters instead of just one
591                                                  */
592
593   message->size_counter = counter;
594   _dbus_counter_ref (message->size_counter);
595
596   /* When we can change message size, we may want to
597    * update this each time we do so, or we may want to
598    * just KISS like this.
599    */
600   message->size_counter_delta =
601     _dbus_string_get_length (&message->header) +
602     _dbus_string_get_length (&message->body);
603
604   _dbus_verbose ("message has size %ld\n",
605                  message->size_counter_delta);
606   
607   _dbus_counter_adjust (message->size_counter, message->size_counter_delta);
608 }
609
610 static dbus_bool_t
611 dbus_message_create_header (DBusMessage *message,
612                             const char  *service,
613                             const char  *name)
614 {
615   unsigned int flags;
616   
617   if (!_dbus_string_append_byte (&message->header, message->byte_order))
618     return FALSE;
619
620   flags = 0;
621   if (!_dbus_string_append_byte (&message->header, flags))
622     return FALSE;
623
624   if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION))
625     return FALSE;
626
627   if (!_dbus_string_append_byte (&message->header, 0))
628     return FALSE;
629
630   message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
631   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
632     return FALSE;
633
634   message->header_fields[FIELD_BODY_LENGTH].offset = 8;
635   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
636     return FALSE;
637
638   message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
639   if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
640     return FALSE;
641   
642   /* Marshal message service */
643   if (service != NULL)
644     {
645       if (!append_string_field (message,
646                                 FIELD_SERVICE,
647                                 DBUS_HEADER_FIELD_SERVICE,
648                                 service))
649         return FALSE;
650     }
651
652   _dbus_assert (name != NULL);
653   if (!append_string_field (message,
654                             FIELD_NAME,
655                             DBUS_HEADER_FIELD_NAME,
656                             name))
657     return FALSE;
658   
659   return TRUE;
660 }
661
662 /**
663  * Locks a message. Allows checking that applications don't keep a
664  * reference to a message in the outgoing queue and change it
665  * underneath us. Messages are locked when they enter the outgoing
666  * queue (dbus_connection_send_message()), and the library complains
667  * if the message is modified while locked.
668  *
669  * @param message the message to lock.
670  */
671 void
672 _dbus_message_lock (DBusMessage  *message)
673 {
674   if (!message->locked)
675     {
676       /* Fill in our lengths */
677       set_uint_field (message,
678                       FIELD_HEADER_LENGTH,
679                       _dbus_string_get_length (&message->header));
680
681       set_uint_field (message,
682                       FIELD_BODY_LENGTH,
683                       _dbus_string_get_length (&message->body));
684
685       message->locked = TRUE;
686     }
687 }
688
689 /** @} */
690
691 /**
692  * @defgroup DBusMessage DBusMessage
693  * @ingroup  DBus
694  * @brief Message to be sent or received over a DBusConnection.
695  *
696  * A DBusMessage is the most basic unit of communication over a
697  * DBusConnection. A DBusConnection represents a stream of messages
698  * received from a remote application, and a stream of messages
699  * sent to a remote application.
700  *
701  * @{
702  */
703
704 /**
705  * @typedef DBusMessage
706  *
707  * Opaque data type representing a message received from or to be
708  * sent to another application.
709  */
710
711 static DBusMessage*
712 dbus_message_new_empty_header (void)
713 {
714   DBusMessage *message;
715   int i;
716   
717   message = dbus_new0 (DBusMessage, 1);
718   if (message == NULL)
719     return NULL;
720   
721   message->refcount = 1;
722   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
723   
724   i = 0;
725   while (i < FIELD_LAST)
726     {
727       message->header_fields[i].offset = -1;
728       ++i;
729     }
730   
731   if (!_dbus_string_init (&message->header, _DBUS_INT_MAX))
732     {
733       dbus_free (message);
734       return NULL;
735     }
736   
737   if (!_dbus_string_init (&message->body, _DBUS_INT_MAX))
738     {
739       _dbus_string_free (&message->header);
740       dbus_free (message);
741       return NULL;
742     }
743   
744   return message;
745 }
746
747
748 /**
749  * Constructs a new message. Returns #NULL if memory can't be
750  * allocated for the message. The service may be #NULL in which case
751  * no service is set; this is appropriate when using D-BUS in a
752  * peer-to-peer context (no message bus).
753  *
754  * @todo reverse the arguments, first 'name' then 'service'
755  * as 'name' is more fundamental
756  *
757  * @param service service that the message should be sent to or #NULL
758  * @param name name of the message
759  * @returns a new DBusMessage, free with dbus_message_unref()
760  * @see dbus_message_unref()
761  */
762 DBusMessage*
763 dbus_message_new (const char *service,
764                   const char *name)
765 {
766   DBusMessage *message;
767
768   message = dbus_message_new_empty_header ();
769   if (message == NULL)
770     return NULL;
771   
772   if (!dbus_message_create_header (message, service, name))
773     {
774       dbus_message_unref (message);
775       return NULL;
776     }
777   
778   return message;
779 }
780
781 /**
782  * Constructs a message that is a reply to some other
783  * message. Returns #NULL if memory can't be allocated
784  * for the message.
785  *
786  * @param original_message the message which the created
787  * message is a reply to.
788  * @returns a new DBusMessage, free with dbus_message_unref()
789  * @see dbus_message_new(), dbus_message_unref()
790  */ 
791 DBusMessage*
792 dbus_message_new_reply (DBusMessage *original_message)
793 {
794   DBusMessage *message;
795   const char *sender, *name;
796
797   sender = get_string_field (original_message,
798                              FIELD_SENDER, NULL);
799   name = get_string_field (original_message,
800                            FIELD_NAME, NULL);
801   
802   _dbus_assert (sender != NULL);
803   
804   message = dbus_message_new (sender, name);
805   
806   if (message == NULL)
807     return NULL;
808
809   if (!_dbus_message_set_reply_serial (message,
810                                        _dbus_message_get_client_serial (original_message)))
811     {
812       dbus_message_unref (message);
813       return NULL;
814     }
815
816   return message;
817 }
818
819 /**
820  * Creates a new message that is an error reply to a certain message.
821  *
822  * @param original_message the original message
823  * @param error_name the error name
824  * @param error_message the error message string
825  * @returns a new error message
826  */
827 DBusMessage*
828 dbus_message_new_error_reply (DBusMessage *original_message,
829                               const char  *error_name,
830                               const char  *error_message)
831 {
832   DBusMessage *message;
833   const char *sender;
834
835   sender = get_string_field (original_message,
836                              FIELD_SENDER, NULL);
837   
838   _dbus_assert (sender != NULL);
839   
840   message = dbus_message_new (sender, error_name);
841   
842   if (message == NULL)
843     return NULL;
844
845   if (!_dbus_message_set_reply_serial (message,
846                                        _dbus_message_get_client_serial (original_message)))
847     {
848       dbus_message_unref (message);
849       return NULL;
850     }
851
852   if (!dbus_message_append_string (message, error_message))
853     {
854       dbus_message_unref (message);
855       return NULL;
856     }
857
858   dbus_message_set_is_error (message, TRUE);
859   
860   return message;
861 }
862
863 /**
864  * Creates a new message that is an exact replica of the message
865  * specified, except that its refcount is set to 1.
866  *
867  * @param message the message.
868  * @returns the new message.
869  */
870 DBusMessage *
871 dbus_message_new_from_message (const DBusMessage *message)
872 {
873   DBusMessage *retval;
874   int i;
875   
876   retval = dbus_new0 (DBusMessage, 1);
877   if (retval == NULL)
878     return NULL;
879   
880   retval->refcount = 1;
881   retval->byte_order = message->byte_order;
882
883   if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
884     {
885       dbus_free (retval);
886       return NULL;
887     }
888   
889   if (!_dbus_string_init (&retval->body, _DBUS_INT_MAX))
890     {
891       _dbus_string_free (&retval->header);
892       dbus_free (retval);
893       return NULL;
894     }
895
896   if (!_dbus_string_copy (&message->header, 0,
897                           &retval->header, 0))
898     {
899       _dbus_string_free (&retval->header);
900       _dbus_string_free (&retval->body);
901       dbus_free (retval);
902
903       return NULL;
904     }
905
906   if (!_dbus_string_copy (&message->body, 0,
907                           &retval->body, 0))
908     {
909       _dbus_string_free (&retval->header);
910       _dbus_string_free (&retval->body);
911       dbus_free (retval);
912
913       return NULL;
914     }
915
916   for (i = 0; i < FIELD_LAST; i++)
917     {
918       retval->header_fields[i].offset = message->header_fields[i].offset;
919     }
920   
921   return retval;
922 }
923
924
925 /**
926  * Increments the reference count of a DBusMessage.
927  *
928  * @param message The message
929  * @see dbus_message_unref
930  */
931 void
932 dbus_message_ref (DBusMessage *message)
933 {
934   dbus_atomic_t refcount;
935
936   refcount = _dbus_atomic_inc (&message->refcount);
937   _dbus_assert (refcount > 1);
938 }
939
940 /**
941  * Decrements the reference count of a DBusMessage.
942  *
943  * @param message The message
944  * @see dbus_message_ref
945  */
946 void
947 dbus_message_unref (DBusMessage *message)
948 {
949   dbus_atomic_t refcount;
950
951   refcount = _dbus_atomic_dec (&message->refcount);
952   
953   _dbus_assert (refcount >= 0);
954
955   if (refcount == 0)
956     {
957       if (message->size_counter != NULL)
958         {
959           _dbus_counter_adjust (message->size_counter,
960                                 - message->size_counter_delta);
961           _dbus_counter_unref (message->size_counter);
962         }
963       
964       _dbus_string_free (&message->header);
965       _dbus_string_free (&message->body);
966       
967       dbus_free (message);
968     }
969 }
970
971 /**
972  * Gets the name of a message.
973  *
974  * @param message the message
975  * @returns the message name (should not be freed)
976  */
977 const char*
978 dbus_message_get_name (DBusMessage *message)
979 {
980   return get_string_field (message, FIELD_NAME, NULL);
981 }
982
983 /**
984  * Gets the destination service of a message.
985  *
986  * @param message the message
987  * @returns the message destination service (should not be freed)
988  */
989 const char*
990 dbus_message_get_service (DBusMessage *message)
991 {
992   return get_string_field (message, FIELD_SERVICE, NULL);
993 }
994
995 /**
996  * Appends fields to a message given a variable argument
997  * list. The variable argument list should contain the type
998  * of the argument followed by the value to add. Array values
999  * are specified by a pointer to the array followed by an int
1000  * giving the length of the array. The list is terminated
1001  * with 0.
1002  *
1003  * @param message the message
1004  * @param first_argument_type type of the first argument
1005  * @param ... value of first argument, list of additional type-value pairs
1006  * @returns #TRUE on success
1007  */
1008 dbus_bool_t
1009 dbus_message_append_args (DBusMessage *message,
1010                           int first_arg_type,
1011                           ...)
1012 {
1013   dbus_bool_t retval;
1014   va_list var_args;
1015
1016   va_start (var_args, first_arg_type);
1017   retval = dbus_message_append_args_valist (message,
1018                                             first_arg_type,
1019                                             var_args);
1020   va_end (var_args);
1021
1022   return retval;
1023 }
1024
1025 /**
1026  * This function takes a va_list for use by language bindings
1027  *
1028  * @see dbus_message_append_args.  
1029  * @param message the message
1030  * @param first_arg_type type of first argument
1031  * @param var_args value of first argument, then list of type/value pairs
1032  * @returns #TRUE on success
1033  */
1034 dbus_bool_t
1035 dbus_message_append_args_valist (DBusMessage *message,
1036                                  int          first_arg_type,
1037                                  va_list      var_args)
1038 {
1039   int type, old_len;
1040
1041   old_len = _dbus_string_get_length (&message->body);
1042   
1043   type = first_arg_type;
1044
1045   while (type != 0)
1046     {
1047       switch (type)
1048         {
1049         case DBUS_TYPE_INT32:
1050           if (!dbus_message_append_int32 (message, va_arg (var_args, dbus_int32_t)))
1051             goto enomem;
1052           break;
1053         case DBUS_TYPE_UINT32:
1054           if (!dbus_message_append_uint32 (message, va_arg (var_args, dbus_uint32_t)))
1055             goto enomem;            
1056           break;
1057         case DBUS_TYPE_DOUBLE:
1058           if (!dbus_message_append_double (message, va_arg (var_args, double)))
1059             goto enomem;
1060           break;
1061         case DBUS_TYPE_STRING:
1062           if (!dbus_message_append_string (message, va_arg (var_args, const char *)))
1063             goto enomem;
1064           break;
1065         case DBUS_TYPE_BYTE_ARRAY:
1066           {
1067             int len;
1068             unsigned char *data;
1069
1070             data = va_arg (var_args, unsigned char *);
1071             len = va_arg (var_args, int);
1072
1073             if (!dbus_message_append_byte_array (message, data, len))
1074               goto enomem;
1075           }
1076           break;
1077         case DBUS_TYPE_STRING_ARRAY:
1078           {
1079             int len;
1080             const char **data;
1081             
1082             data = va_arg (var_args, const char **);
1083             len = va_arg (var_args, int);
1084
1085             if (!dbus_message_append_string_array (message, data, len))
1086               goto enomem;
1087           }
1088           break;
1089           
1090         default:
1091           _dbus_warn ("Unknown field type %d\n", type);
1092         }
1093
1094       type = va_arg (var_args, int);
1095     }
1096
1097   return TRUE;
1098
1099  enomem:
1100   _dbus_string_set_length (&message->body, old_len);
1101   return FALSE;
1102 }
1103
1104 /**
1105  * Appends a 32 bit signed integer to the message.
1106  *
1107  * @param message the message
1108  * @param value the integer value
1109  * @returns #TRUE on success
1110  */
1111 dbus_bool_t
1112 dbus_message_append_int32 (DBusMessage  *message,
1113                            dbus_int32_t  value)
1114 {
1115   _dbus_assert (!message->locked);
1116
1117   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
1118     {
1119       _dbus_string_shorten (&message->body, 1);
1120       return FALSE;
1121     }
1122   
1123   return _dbus_marshal_int32 (&message->body,
1124                               message->byte_order, value);
1125 }
1126
1127 /**
1128  * Appends a 32 bit unsigned integer to the message.
1129  *
1130  * @param message the message
1131  * @param value the integer value
1132  * @returns #TRUE on success
1133  */
1134 dbus_bool_t
1135 dbus_message_append_uint32 (DBusMessage   *message,
1136                             dbus_uint32_t  value)
1137 {
1138   _dbus_assert (!message->locked);
1139
1140   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UINT32))
1141     {
1142       _dbus_string_shorten (&message->body, 1);
1143       return FALSE;
1144     }
1145   
1146   return _dbus_marshal_uint32 (&message->body,
1147                                message->byte_order, value);
1148 }
1149
1150 /**
1151  * Appends a double value to the message.
1152  *
1153  * @param message the message
1154  * @param value the double value
1155  * @returns #TRUE on success
1156  */
1157 dbus_bool_t
1158 dbus_message_append_double (DBusMessage *message,
1159                             double       value)
1160 {
1161   _dbus_assert (!message->locked);
1162
1163   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_DOUBLE))
1164     {
1165       _dbus_string_shorten (&message->body, 1);
1166       return FALSE;
1167     }
1168   
1169   return _dbus_marshal_double (&message->body,
1170                                message->byte_order, value);
1171 }
1172
1173 /**
1174  * Appends a UTF-8 string to the message.
1175  *
1176  * @param message the message
1177  * @param value the string
1178  * @returns #TRUE on success
1179  */
1180 dbus_bool_t
1181 dbus_message_append_string (DBusMessage *message,
1182                             const char  *value)
1183 {
1184   _dbus_assert (!message->locked);
1185
1186   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING))
1187     {
1188       _dbus_string_shorten (&message->body, 1);
1189       return FALSE;
1190     }
1191   
1192   return _dbus_marshal_string (&message->body,
1193                                message->byte_order, value);
1194 }
1195
1196 /**
1197  * Appends a byte array to the message.
1198  *
1199  * @param message the message
1200  * @param value the array
1201  * @param len the length of the array
1202  * @returns #TRUE on success
1203  */
1204 dbus_bool_t
1205 dbus_message_append_byte_array (DBusMessage         *message,
1206                                 unsigned const char *value,
1207                                 int                 len)
1208 {
1209   _dbus_assert (!message->locked);
1210
1211   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_BYTE_ARRAY))
1212     {
1213       _dbus_string_shorten (&message->body, 1);
1214       return FALSE;
1215     }
1216   
1217   return _dbus_marshal_byte_array (&message->body,
1218                                    message->byte_order, value, len);
1219 }
1220
1221 /**
1222  * Appends a string array to the message.
1223  *
1224  * @param message the message
1225  * @param value the array
1226  * @param len the length of the array
1227  * @returns #TRUE on success
1228  */
1229 dbus_bool_t
1230 dbus_message_append_string_array (DBusMessage *message,
1231                                   const char **value,
1232                                   int          len)
1233 {
1234   _dbus_assert (!message->locked);
1235
1236   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING_ARRAY))
1237     {
1238       _dbus_string_shorten (&message->body, 1);
1239       return FALSE;
1240     }
1241   
1242   return _dbus_marshal_string_array (&message->body,
1243                                      message->byte_order, value, len);
1244 }
1245
1246 /**
1247  * Gets arguments from a message given a variable argument list.
1248  * The variable argument list should contain the type of the
1249  * argumen followed by a pointer to where the value should be
1250  * stored. The list is terminated with 0.
1251  *
1252  * @param message the message
1253  * @param first_arg_type the first argument type
1254  * @param ... location for first argument value, then list of type-location pairs
1255  * @returns result code
1256  */
1257 DBusResultCode
1258 dbus_message_get_args (DBusMessage *message,
1259                        int          first_arg_type,
1260                        ...)
1261 {
1262   DBusResultCode retval;
1263   va_list var_args;
1264
1265   va_start (var_args, first_arg_type);
1266   retval = dbus_message_get_args_valist (message, first_arg_type, var_args);
1267   va_end (var_args);
1268
1269   return retval;
1270 }
1271
1272 /**
1273  * This function takes a va_list for use by language bindings
1274  *
1275  * @todo this function (or some lower-level non-convenience function)
1276  * needs better error handling; should allow the application to
1277  * distinguish between out of memory, and bad data from the remote
1278  * app. It also needs to not leak a bunch of args when it gets
1279  * to the arg that's bad, as that would be a security hole
1280  * (allow one app to force another to leak memory)
1281  *
1282  * @todo We need to free the argument data when an error occurs.
1283  *
1284  * @see dbus_message_get_args
1285  * @param message the message
1286  * @param first_arg_type type of the first argument
1287  * @param var_args return location for first argument, followed by list of type/location pairs
1288  * @returns result code
1289  */
1290 DBusResultCode
1291 dbus_message_get_args_valist (DBusMessage *message,
1292                               int          first_arg_type,
1293                               va_list      var_args)
1294 {
1295   int spec_type, msg_type, i;
1296   DBusMessageIter *iter;
1297
1298   iter = dbus_message_get_args_iter (message);
1299
1300   if (iter == NULL)
1301     return DBUS_RESULT_NO_MEMORY;
1302   
1303   spec_type = first_arg_type;
1304   i = 0;
1305   
1306   while (spec_type != 0)
1307     {
1308       msg_type = dbus_message_iter_get_arg_type (iter);      
1309       
1310       if (msg_type != spec_type)
1311         {
1312           _dbus_verbose ("Argument %d is specified to be of type \"%s\", but "
1313                          "is actually of type \"%s\"\n", i,
1314                          _dbus_type_to_string (spec_type),
1315                          _dbus_type_to_string (msg_type));
1316           dbus_message_iter_unref (iter);
1317
1318           return DBUS_RESULT_INVALID_ARGS;
1319         }
1320
1321       switch (spec_type)
1322         {
1323         case DBUS_TYPE_INT32:
1324           {
1325             dbus_int32_t *ptr;
1326
1327             ptr = va_arg (var_args, dbus_int32_t *);
1328
1329             *ptr = dbus_message_iter_get_int32 (iter);
1330             break;
1331           }
1332         case DBUS_TYPE_UINT32:
1333           {
1334             dbus_uint32_t *ptr;
1335
1336             ptr = va_arg (var_args, dbus_uint32_t *);
1337
1338             *ptr = dbus_message_iter_get_uint32 (iter);
1339             break;
1340           }
1341
1342         case DBUS_TYPE_DOUBLE:
1343           {
1344             double *ptr;
1345
1346             ptr = va_arg (var_args, double *);
1347
1348             *ptr = dbus_message_iter_get_double (iter);
1349             break;
1350           }
1351
1352         case DBUS_TYPE_STRING:
1353           {
1354             char **ptr;
1355
1356             ptr = va_arg (var_args, char **);
1357
1358             *ptr = dbus_message_iter_get_string (iter);
1359
1360             if (!*ptr)
1361               return DBUS_RESULT_NO_MEMORY;
1362             
1363             break;
1364           }
1365
1366         case DBUS_TYPE_BYTE_ARRAY:
1367           {
1368             unsigned char **ptr;
1369             int *len;
1370
1371             ptr = va_arg (var_args, unsigned char **);
1372             len = va_arg (var_args, int *);
1373
1374             *ptr = dbus_message_iter_get_byte_array (iter, len);
1375
1376             if (!*ptr)
1377               return DBUS_RESULT_NO_MEMORY;
1378             
1379             break;
1380           }
1381         case DBUS_TYPE_STRING_ARRAY:
1382           {
1383             char ***ptr;
1384             int *len;
1385
1386             ptr = va_arg (var_args, char ***);
1387             len = va_arg (var_args, int *);
1388
1389             *ptr = dbus_message_iter_get_string_array (iter, len);
1390             
1391             if (!*ptr)
1392               return DBUS_RESULT_NO_MEMORY;
1393             
1394             break;
1395           }
1396         default:          
1397           _dbus_warn ("Unknown field type %d\n", spec_type);
1398         }
1399       
1400       spec_type = va_arg (var_args, int);
1401       if (spec_type != 0 && !dbus_message_iter_next (iter))
1402         {
1403           _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n");
1404
1405           dbus_message_iter_unref (iter);  
1406           return DBUS_RESULT_INVALID_ARGS;
1407         }
1408       i++;
1409     }
1410
1411   dbus_message_iter_unref (iter);
1412   return DBUS_RESULT_SUCCESS;
1413 }
1414
1415 /**
1416  * Returns a DBusMessageIter representing the arguments of the
1417  * message passed in.
1418  *
1419  * @todo IMO the message iter should follow the GtkTextIter pattern,
1420  * a static object with a "stamp" value used to detect invalid
1421  * iter uses (uninitialized or after changing the message).
1422  * ref/unref is kind of annoying to deal with, and slower too.
1423  * This implies not ref'ing the message from the iter.
1424  *
1425  * @param message the message
1426  * @returns a new iter.
1427  */
1428 DBusMessageIter *
1429 dbus_message_get_args_iter (DBusMessage *message)
1430 {
1431   DBusMessageIter *iter;
1432   
1433   iter = dbus_new (DBusMessageIter, 1);
1434
1435   dbus_message_ref (message);
1436   
1437   iter->refcount = 1;
1438   iter->message = message;
1439   iter->pos = 0;
1440
1441   return iter;
1442 }
1443
1444 /**
1445  * Increments the reference count of a DBusMessageIter.
1446  *
1447  * @param iter the message iter
1448  * @see dbus_message_iter_unref
1449  */
1450 void
1451 dbus_message_iter_ref (DBusMessageIter *iter)
1452 {
1453   _dbus_assert (iter->refcount > 0);
1454   
1455   iter->refcount += 1;
1456 }
1457
1458 /**
1459  * Decrements the reference count of a DBusMessageIter.
1460  *
1461  * @param iter The message iter
1462  * @see dbus_message_iter_ref
1463  */
1464 void
1465 dbus_message_iter_unref (DBusMessageIter *iter)
1466 {
1467   _dbus_assert (iter->refcount > 0);
1468
1469   iter->refcount -= 1;
1470
1471   if (iter->refcount == 0)
1472     {
1473       dbus_message_unref (iter->message);
1474
1475       dbus_free (iter);
1476     }
1477 }
1478
1479 /**
1480  * Checks if an iterator has any more fields.
1481  *
1482  * @param iter the message iter
1483  * @returns #TRUE if there are more fields
1484  * following
1485  */
1486 dbus_bool_t
1487 dbus_message_iter_has_next (DBusMessageIter *iter)
1488 {
1489   int end_pos;
1490   
1491   if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1492                                       iter->message->byte_order,
1493                                       iter->pos, &end_pos))
1494     return FALSE;
1495   
1496   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1497     return FALSE;
1498   
1499   return TRUE;  
1500 }
1501
1502 /**
1503  * Moves the iterator to the next field.
1504  *
1505  * @param iter The message iter
1506  * @returns #TRUE if the iterator was moved to the next field
1507  */
1508 dbus_bool_t
1509 dbus_message_iter_next (DBusMessageIter *iter)
1510 {
1511   int end_pos;
1512   
1513   if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1514                                       iter->message->byte_order,
1515                                       iter->pos, &end_pos))
1516     return FALSE;
1517
1518   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1519     return FALSE;
1520
1521   iter->pos = end_pos;
1522
1523   return TRUE;
1524 }
1525
1526 /**
1527  * Returns the argument type of the argument that the
1528  * message iterator points at.
1529  *
1530  * @param iter the message iter
1531  * @returns the field type
1532  */
1533 int
1534 dbus_message_iter_get_arg_type (DBusMessageIter *iter)
1535 {
1536   const char *data;
1537
1538   if (iter->pos >= _dbus_string_get_length (&iter->message->body))
1539     return DBUS_TYPE_INVALID;
1540
1541   _dbus_string_get_const_data_len (&iter->message->body, &data, iter->pos, 1);
1542
1543   if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_STRING_ARRAY)
1544     return *data;
1545
1546   return DBUS_TYPE_INVALID;
1547 }
1548
1549 /**
1550  * Returns the string value that an iterator may point to.
1551  * Note that you need to check that the iterator points to
1552  * a string value before using this function.
1553  *
1554  * @see dbus_message_iter_get_field_type
1555  * @param iter the message iter
1556  * @returns the string
1557  */
1558 char *
1559 dbus_message_iter_get_string (DBusMessageIter *iter)
1560 {
1561   _dbus_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING);
1562
1563   return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
1564                                  iter->pos + 1, NULL);
1565 }
1566
1567 /**
1568  * Returns the 32 bit signed integer value that an iterator may point to.
1569  * Note that you need to check that the iterator points to
1570  * an integer value before using this function.
1571  *
1572  * @see dbus_message_iter_get_field_type
1573  * @param iter the message iter
1574  * @returns the integer
1575  */
1576 int
1577 dbus_message_iter_get_int32 (DBusMessageIter *iter)
1578 {
1579   return _dbus_demarshal_int32 (&iter->message->body, iter->message->byte_order,
1580                                 iter->pos + 1, NULL);
1581 }
1582
1583 /**
1584  * Returns the 32 bit unsigned integer value that an iterator may point to.
1585  * Note that you need to check that the iterator points to
1586  * an unsigned integer value before using this function.
1587  *
1588  * @see dbus_message_iter_get_field_type
1589  * @param iter the message iter
1590  * @returns the integer
1591  */
1592 int
1593 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
1594 {
1595   return _dbus_demarshal_uint32 (&iter->message->body, iter->message->byte_order,
1596                                  iter->pos + 1, NULL);
1597 }
1598
1599 /**
1600  * Returns the double value that an iterator may point to.
1601  * Note that you need to check that the iterator points to
1602  * a string value before using this function.
1603  *
1604  * @see dbus_message_iter_get_field_type
1605  * @param iter the message iter
1606  * @returns the double
1607  */
1608 double
1609 dbus_message_iter_get_double (DBusMessageIter *iter)
1610 {
1611   return _dbus_demarshal_double (&iter->message->body, iter->message->byte_order,
1612                                  iter->pos + 1, NULL);
1613 }
1614
1615 /**
1616  * Returns the byte array that the iterator may point to.
1617  * Note that you need to check that the iterator points
1618  * to a byte array prior to using this function.
1619  *
1620  * @todo this function should probably take "unsigned char **" as
1621  * an out param argument, and return boolean or result code.
1622  *
1623  * @param iter the iterator
1624  * @param len return location for length of byte array
1625  * @returns the byte array
1626  */
1627 unsigned char *
1628 dbus_message_iter_get_byte_array (DBusMessageIter *iter,
1629                                   int             *len)
1630 {
1631   _dbus_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_BYTE_ARRAY);
1632
1633   return _dbus_demarshal_byte_array (&iter->message->body, iter->message->byte_order,
1634                                      iter->pos + 1, NULL, len);
1635 }
1636
1637 /**
1638  * Returns the string array that the iterator may point to.
1639  * Note that you need to check that the iterator points
1640  * to a byte array prior to using this function.
1641  *
1642  * @todo this function should probably take "char **" as
1643  * an out param argument, and return boolean or result code.
1644  *
1645  * @param iter the iterator
1646  * @param len return location for length of byte array
1647  * @returns the byte array
1648  */
1649 char **
1650 dbus_message_iter_get_string_array (DBusMessageIter *iter,
1651                                     int             *len)
1652 {
1653   _dbus_assert (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_STRING_ARRAY);
1654
1655   return _dbus_demarshal_string_array (&iter->message->body, iter->message->byte_order,
1656                                        iter->pos + 1, NULL, len);
1657 }
1658
1659 /**
1660  * Sets the message sender.
1661  *
1662  * @param message the message
1663  * @param sender the sender
1664  * @returns #FALSE if not enough memory
1665  */
1666 dbus_bool_t
1667 dbus_message_set_sender (DBusMessage  *message,
1668                          const char   *sender)
1669 {
1670   _dbus_assert (!message->locked);
1671
1672   if (sender == NULL)
1673     {
1674       delete_string_field (message, FIELD_SENDER);
1675       return TRUE;
1676     }
1677   else
1678     {
1679       return set_string_field (message,
1680                                FIELD_SENDER,
1681                                sender);
1682     }
1683 }
1684
1685 /**
1686  * Sets a flag indicating that the message is an error reply
1687  * message, i.e. an "exception" rather than a normal response.
1688  *
1689  * @param message the message
1690  * @param is_error_reply #TRUE if this is an error message.
1691  */
1692 void
1693 dbus_message_set_is_error (DBusMessage *message,
1694                            dbus_bool_t  is_error_reply)
1695 {
1696   char *header;
1697   
1698   _dbus_assert (!message->locked);
1699   
1700   _dbus_string_get_data_len (&message->header, &header, 1, 1);
1701   
1702   if (is_error_reply)
1703     *header |= DBUS_HEADER_FLAG_ERROR;
1704   else
1705     *header &= ~DBUS_HEADER_FLAG_ERROR;    
1706 }
1707
1708 /**
1709  * Returns #TRUE if the message is an error
1710  * reply to some previous message we sent.
1711  *
1712  * @param message the message
1713  * @returns #TRUE if the message is an error
1714  */
1715 dbus_bool_t
1716 dbus_message_get_is_error (DBusMessage *message)
1717 {
1718   const char *header;
1719
1720   _dbus_string_get_const_data_len (&message->header, &header, 1, 1);
1721
1722   return (*header & DBUS_HEADER_FLAG_ERROR) != 0;
1723 }
1724
1725 /**
1726  * Gets the service which originated this message,
1727  * or #NULL if unknown or inapplicable.
1728  *
1729  * @param message the message
1730  * @returns the service name or #NULL
1731  */
1732 const char*
1733 dbus_message_get_sender (DBusMessage *message)
1734 {
1735   return get_string_field (message, FIELD_SENDER, NULL);
1736 }
1737
1738 /** @} */
1739
1740 /**
1741  * @addtogroup DBusMessageInternals
1742  *
1743  * @{
1744  */
1745 /**
1746  * @typedef DBusMessageLoader
1747  *
1748  * The DBusMessageLoader object encapsulates the process of converting
1749  * a byte stream into a series of DBusMessage. It buffers the incoming
1750  * bytes as efficiently as possible, and generates a queue of
1751  * messages. DBusMessageLoader is typically used as part of a
1752  * DBusTransport implementation. The DBusTransport then hands off
1753  * the loaded messages to a DBusConnection, making the messages
1754  * visible to the application.
1755  * 
1756  */
1757
1758 /* we definitely use signed ints for sizes, so don't exceed
1759  * _DBUS_INT_MAX; and add 16 for paranoia, since a message
1760  * over 128M is pretty nuts anyhow.
1761  */
1762
1763 /**
1764  * The maximum sane message size.
1765  */
1766 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
1767
1768 /**
1769  * Implementation details of DBusMessageLoader.
1770  * All members are private.
1771  */
1772 struct DBusMessageLoader
1773 {
1774   int refcount;        /**< Reference count. */
1775
1776   DBusString data;     /**< Buffered data */
1777   
1778   DBusList *messages;  /**< Complete messages. */
1779
1780   long max_message_size; /**< Maximum size of a message */
1781   
1782   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
1783
1784   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
1785 };
1786
1787 /**
1788  * The initial buffer size of the message loader.
1789  * 
1790  * @todo this should be based on min header size plus some average
1791  * body size, or something. Or rather, the min header size only, if we
1792  * want to try to read only the header, store that in a DBusMessage,
1793  * then read only the body and store that, etc., depends on
1794  * how we optimize _dbus_message_loader_get_buffer() and what
1795  * the exact message format is.
1796  */
1797 #define INITIAL_LOADER_DATA_LEN 32
1798
1799 /**
1800  * Creates a new message loader. Returns #NULL if memory can't
1801  * be allocated.
1802  *
1803  * @returns new loader, or #NULL.
1804  */
1805 DBusMessageLoader*
1806 _dbus_message_loader_new (void)
1807 {
1808   DBusMessageLoader *loader;
1809
1810   loader = dbus_new0 (DBusMessageLoader, 1);
1811   if (loader == NULL)
1812     return NULL;
1813   
1814   loader->refcount = 1;
1815
1816   /* Try to cap message size at something that won't *totally* hose
1817    * the system if we have a couple of them.
1818    */
1819   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
1820   
1821   if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX))
1822     {
1823       dbus_free (loader);
1824       return NULL;
1825     }
1826
1827   /* preallocate the buffer for speed, ignore failure */
1828   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
1829   _dbus_string_set_length (&loader->data, 0);
1830   
1831   return loader;
1832 }
1833
1834 /**
1835  * Increments the reference count of the loader.
1836  *
1837  * @param loader the loader.
1838  */
1839 void
1840 _dbus_message_loader_ref (DBusMessageLoader *loader)
1841 {
1842   loader->refcount += 1;
1843 }
1844
1845 /**
1846  * Decrements the reference count of the loader and finalizes the
1847  * loader when the count reaches zero.
1848  *
1849  * @param loader the loader.
1850  */
1851 void
1852 _dbus_message_loader_unref (DBusMessageLoader *loader)
1853 {
1854   loader->refcount -= 1;
1855   if (loader->refcount == 0)
1856     {
1857       _dbus_list_foreach (&loader->messages,
1858                           (DBusForeachFunction) dbus_message_unref,
1859                           NULL);
1860       _dbus_list_clear (&loader->messages);
1861       _dbus_string_free (&loader->data);
1862       dbus_free (loader);
1863     }
1864 }
1865
1866 /**
1867  * Gets the buffer to use for reading data from the network.  Network
1868  * data is read directly into an allocated buffer, which is then used
1869  * in the DBusMessage, to avoid as many extra memcpy's as possible.
1870  * The buffer must always be returned immediately using
1871  * _dbus_message_loader_return_buffer(), even if no bytes are
1872  * successfully read.
1873  *
1874  * @todo this function can be a lot more clever. For example
1875  * it can probably always return a buffer size to read exactly
1876  * the body of the next message, thus avoiding any memory wastage
1877  * or reallocs.
1878  * 
1879  * @param loader the message loader.
1880  * @param buffer the buffer
1881  */
1882 void
1883 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
1884                                  DBusString        **buffer)
1885 {
1886   _dbus_assert (!loader->buffer_outstanding);
1887
1888   *buffer = &loader->data;
1889   
1890   loader->buffer_outstanding = TRUE;
1891 }
1892
1893 /**
1894  * The smallest header size that can occur. 
1895  * (It won't be valid)
1896  */
1897 #define DBUS_MINIMUM_HEADER_SIZE 16
1898
1899 /** Pack four characters as in "abcd" into a uint32 */
1900 #define FOUR_CHARS_TO_UINT32(a, b, c, d)                \
1901                       ((((dbus_uint32_t)a) << 24) |     \
1902                        (((dbus_uint32_t)b) << 16) |     \
1903                        (((dbus_uint32_t)c) << 8)  |     \
1904                        ((dbus_uint32_t)d))
1905
1906 /** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
1907 #define DBUS_HEADER_FIELD_NAME_AS_UINT32    \
1908   FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
1909
1910 /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
1911 #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
1912   FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
1913
1914 /** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
1915 #define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \
1916   FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
1917
1918 /** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
1919 #define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \
1920   FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
1921
1922 static dbus_bool_t
1923 decode_header_data (const DBusString   *data,
1924                     int                 header_len,
1925                     int                 byte_order,
1926                     HeaderField         fields[FIELD_LAST])
1927 {
1928   const char *field;
1929   int pos, new_pos;
1930   int i;
1931   
1932   if (header_len < 16)
1933     return FALSE;
1934   
1935   i = 0;
1936   while (i < FIELD_LAST)
1937     {
1938       fields[i].offset = -1;
1939       ++i;
1940     }
1941   
1942   fields[FIELD_HEADER_LENGTH].offset = 4;
1943   fields[FIELD_BODY_LENGTH].offset = 8;   
1944   fields[FIELD_CLIENT_SERIAL].offset = 12;
1945   
1946   /* Now handle the named fields. A real named field is at least 4
1947    * bytes for the name, plus a type code (1 byte) plus padding.  So
1948    * if we have less than 8 bytes left, it must be alignment padding,
1949    * not a field. While >= 8 bytes can't be entirely alignment
1950    * padding.
1951    */  
1952   pos = 16;
1953   while ((pos + 7) < header_len)
1954     {
1955       pos = _DBUS_ALIGN_VALUE (pos, 4);
1956       
1957       if ((pos + 4) > header_len)
1958         return FALSE;      
1959       
1960       _dbus_string_get_const_data_len (data, &field, pos, 4);
1961       pos += 4;
1962
1963       _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
1964
1965       /* I believe FROM_BE is right, but if not we'll find out
1966        * I guess. ;-)
1967        */
1968       switch (DBUS_UINT32_FROM_BE (*(int*)field))
1969         {
1970         case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
1971           if (fields[FIELD_SERVICE].offset >= 0)
1972             {
1973               _dbus_verbose ("%s field provided twice\n",
1974                              DBUS_HEADER_FIELD_SERVICE);
1975               return FALSE;
1976             }
1977           
1978           fields[FIELD_SERVICE].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1979           _dbus_verbose ("Found service name at offset %d\n",
1980                          fields[FIELD_SERVICE].offset);
1981           break;
1982
1983         case DBUS_HEADER_FIELD_NAME_AS_UINT32:
1984           if (fields[FIELD_NAME].offset >= 0)
1985             {
1986               _dbus_verbose ("%s field provided twice\n",
1987                              DBUS_HEADER_FIELD_NAME);
1988               return FALSE;
1989             }
1990           
1991           fields[FIELD_NAME].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1992
1993           _dbus_verbose ("Found message name at offset %d\n",
1994                          fields[FIELD_NAME].offset);
1995           break;
1996         case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
1997           if (fields[FIELD_SENDER].offset >= 0)
1998             {
1999               _dbus_verbose ("%s field provided twice\n",
2000                              DBUS_HEADER_FIELD_SENDER);
2001               return FALSE;
2002             }
2003           
2004           fields[FIELD_SENDER].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
2005
2006           _dbus_verbose ("Found sender name at offset %d\n",
2007                          fields[FIELD_NAME].offset);
2008           break;
2009           
2010         case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
2011           if (fields[FIELD_REPLY_SERIAL].offset >= 0)
2012             {
2013               _dbus_verbose ("%s field provided twice\n",
2014                              DBUS_HEADER_FIELD_REPLY);
2015               return FALSE;
2016             }
2017           
2018           fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
2019
2020           _dbus_verbose ("Found reply serial at offset %d\n",
2021                          fields[FIELD_REPLY_SERIAL].offset);
2022           break;
2023
2024         default:
2025           _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n",
2026                          field[0], field[1], field[2], field[3]);
2027         }
2028
2029       if (!_dbus_marshal_validate_arg (data, byte_order, pos, &new_pos))
2030         return FALSE;
2031
2032       if (new_pos > header_len)
2033         return FALSE;
2034       
2035       pos = new_pos;
2036     }
2037
2038   if (pos < header_len)
2039     {
2040       /* Alignment padding, verify that it's nul */
2041       _dbus_assert ((header_len - pos) < 8);
2042
2043       if (!_dbus_string_validate_nul (data,
2044                                       pos, (header_len - pos)))
2045         {
2046           _dbus_verbose ("header alignment padding is not nul\n");
2047           return FALSE;
2048         }
2049     }
2050   
2051   return TRUE;
2052 }
2053
2054 /**
2055  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
2056  * indicating to the loader how many bytes of the buffer were filled
2057  * in. This function must always be called, even if no bytes were
2058  * successfully read.
2059  *
2060  * @todo if we run out of memory in here, we offer no way for calling
2061  * code to handle it, i.e. they can't re-run the message parsing
2062  * attempt. Perhaps much of this code could be moved to pop_message()?
2063  * But then that may need to distinguish NULL return for no messages
2064  * from NULL return for errors.
2065  *
2066  * @param loader the loader.
2067  * @param buffer the buffer.
2068  * @param bytes_read number of bytes that were read into the buffer.
2069  */
2070 void
2071 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
2072                                     DBusString         *buffer,
2073                                     int                 bytes_read)
2074 {
2075   _dbus_assert (loader->buffer_outstanding);
2076   _dbus_assert (buffer == &loader->data);
2077
2078   loader->buffer_outstanding = FALSE;
2079
2080   if (loader->corrupted)
2081     return;
2082
2083   while (_dbus_string_get_length (&loader->data) >= 16)
2084     {
2085       DBusMessage *message;      
2086       const char *header_data;
2087       int byte_order, header_len, body_len;
2088       dbus_uint32_t header_len_unsigned, body_len_unsigned;
2089       
2090       _dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
2091
2092       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
2093
2094       if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION)
2095         {
2096           _dbus_verbose ("Message has protocol version %d ours is %d\n",
2097                          (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION);
2098           loader->corrupted = TRUE;
2099           return;
2100         }
2101       
2102       byte_order = header_data[0];
2103
2104       if (byte_order != DBUS_LITTLE_ENDIAN &&
2105           byte_order != DBUS_BIG_ENDIAN)
2106         {
2107           _dbus_verbose ("Message with bad byte order '%c' received\n",
2108                          byte_order);
2109           loader->corrupted = TRUE;
2110           return;
2111         }
2112
2113       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
2114       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
2115
2116       if (header_len_unsigned < 16)
2117         {
2118           _dbus_verbose ("Message had broken too-small header length %u\n",
2119                          header_len_unsigned);
2120           loader->corrupted = TRUE;
2121           return;
2122         }
2123
2124       if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE ||
2125           body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE)
2126         {
2127           _dbus_verbose ("Header or body length too large (%u %u)\n",
2128                          header_len_unsigned,
2129                          body_len_unsigned);
2130           loader->corrupted = TRUE;
2131           return;
2132         }      
2133
2134       /* Now that we know the values are in signed range, get
2135        * rid of stupid unsigned, just causes bugs
2136        */
2137       header_len = header_len_unsigned;
2138       body_len = body_len_unsigned;
2139       
2140       if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned)
2141         {
2142           _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
2143                          header_len);
2144           loader->corrupted = TRUE;
2145           return;
2146         }
2147       
2148       if (header_len + body_len > loader->max_message_size)
2149         {
2150           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
2151                          header_len, body_len, loader->max_message_size);
2152           loader->corrupted = TRUE;
2153           return;
2154         }
2155
2156       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
2157         {
2158           HeaderField fields[FIELD_LAST];
2159           int i;
2160           int next_arg;          
2161
2162           if (!decode_header_data (&loader->data, header_len, byte_order,
2163                                    fields))
2164             {
2165               loader->corrupted = TRUE;
2166               return;
2167             }
2168           
2169           next_arg = header_len;
2170           while (next_arg < (header_len + body_len))
2171             {
2172               int prev = next_arg;
2173
2174               if (!_dbus_marshal_validate_arg (&loader->data,
2175                                                byte_order,
2176                                                next_arg,
2177                                                &next_arg))
2178                 {
2179                   loader->corrupted = TRUE;
2180                   return;
2181                 }
2182
2183               _dbus_assert (next_arg > prev);
2184             }
2185           
2186           if (next_arg > (header_len + body_len))
2187             {
2188               _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
2189                              next_arg, header_len, body_len,
2190                              header_len + body_len);
2191               loader->corrupted = TRUE;
2192               return;
2193             }
2194
2195           message = dbus_message_new_empty_header ();
2196           if (message == NULL)
2197             break; /* ugh, postpone this I guess. */
2198
2199           message->byte_order = byte_order;
2200           
2201           /* Copy in the offsets we found */
2202           i = 0;
2203           while (i < FIELD_LAST)
2204             {
2205               message->header_fields[i] = fields[i];
2206               ++i;
2207             }
2208           
2209           if (!_dbus_list_append (&loader->messages, message))
2210             {
2211               dbus_message_unref (message);
2212               break;
2213             }
2214
2215           _dbus_assert (_dbus_string_get_length (&message->header) == 0);
2216           _dbus_assert (_dbus_string_get_length (&message->body) == 0);
2217
2218           _dbus_assert (_dbus_string_get_length (&loader->data) >=
2219                         (header_len + body_len));
2220           
2221           if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
2222             {
2223               _dbus_list_remove_last (&loader->messages, message);
2224               dbus_message_unref (message);
2225               break;
2226             }
2227           
2228           if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
2229             {
2230               dbus_bool_t result;
2231
2232               /* put the header back, we'll try again later */
2233               result = _dbus_string_copy_len (&message->header, 0, header_len,
2234                                               &loader->data, 0);
2235               _dbus_assert (result); /* because DBusString never reallocs smaller */
2236
2237               _dbus_list_remove_last (&loader->messages, message);
2238               dbus_message_unref (message);
2239               break;
2240             }
2241
2242           _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
2243           _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
2244
2245           _dbus_verbose ("Loaded message %p\n", message);
2246         }
2247       else
2248         break;
2249     }
2250 }
2251
2252 /**
2253  * Pops a loaded message (passing ownership of the message
2254  * to the caller). Returns #NULL if no messages have been
2255  * loaded.
2256  *
2257  * @param loader the loader.
2258  * @returns the next message, or #NULL if none.
2259  */
2260 DBusMessage*
2261 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
2262 {
2263   return _dbus_list_pop_first (&loader->messages);
2264 }
2265
2266
2267 /**
2268  * Checks whether the loader is confused due to bad data.
2269  * If messages are received that are invalid, the
2270  * loader gets confused and gives up permanently.
2271  * This state is called "corrupted."
2272  *
2273  * @param loader the loader
2274  * @returns #TRUE if the loader is hosed.
2275  */
2276 dbus_bool_t
2277 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
2278 {
2279   return loader->corrupted;
2280 }
2281
2282 /**
2283  * Sets the maximum size message we allow.
2284  *
2285  * @param loader the loader
2286  * @param size the max message size in bytes
2287  */
2288 void
2289 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
2290                                            long                size)
2291 {
2292   if (size > MAX_SANE_MESSAGE_SIZE)
2293     {
2294       _dbus_verbose ("clamping requested max message size %ld to %d\n",
2295                      size, MAX_SANE_MESSAGE_SIZE);
2296       size = MAX_SANE_MESSAGE_SIZE;
2297     }
2298   loader->max_message_size = size;
2299 }
2300
2301 /**
2302  * Gets the maximum allowed message size in bytes.
2303  *
2304  * @param loader the loader
2305  * @returns max size in bytes
2306  */
2307 long
2308 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
2309 {
2310   return loader->max_message_size;
2311 }
2312
2313 /** @} */
2314 #ifdef DBUS_BUILD_TESTS
2315 #include "dbus-test.h"
2316 #include <stdio.h>
2317
2318 static void
2319 message_iter_test (DBusMessage *message)
2320 {
2321   DBusMessageIter *iter;
2322   char *str;
2323   
2324   iter = dbus_message_get_args_iter (message);
2325
2326   /* String tests */
2327   if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_STRING)
2328     _dbus_assert_not_reached ("Argument type isn't string");
2329
2330   str = dbus_message_iter_get_string (iter);
2331   if (strcmp (str, "Test string") != 0)
2332     _dbus_assert_not_reached ("Strings differ");
2333   dbus_free (str);
2334
2335   if (!dbus_message_iter_next (iter))
2336     _dbus_assert_not_reached ("Reached end of arguments");
2337
2338   /* Signed integer tests */
2339   if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INT32)
2340     _dbus_assert_not_reached ("Argument type isn't int32");
2341
2342   if (dbus_message_iter_get_int32 (iter) != -0x12345678)
2343     _dbus_assert_not_reached ("Signed integers differ");
2344
2345   if (!dbus_message_iter_next (iter))
2346     _dbus_assert_not_reached ("Reached end of fields");
2347   
2348   /* Unsigned integer tests */
2349   if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_UINT32)
2350     _dbus_assert_not_reached ("Argument type isn't int32");
2351
2352   if (dbus_message_iter_get_int32 (iter) != 0xedd1e)
2353     _dbus_assert_not_reached ("Unsigned integers differ");
2354
2355   if (!dbus_message_iter_next (iter))
2356     _dbus_assert_not_reached ("Reached end of arguments");
2357
2358   /* Double tests */
2359   if (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_DOUBLE)
2360     _dbus_assert_not_reached ("Argument type isn't double");
2361
2362   if (dbus_message_iter_get_double (iter) != 3.14159)
2363     _dbus_assert_not_reached ("Doubles differ");
2364
2365   if (dbus_message_iter_next (iter))
2366     _dbus_assert_not_reached ("Didn't reach end of arguments");
2367   
2368   dbus_message_iter_unref (iter);
2369 }
2370
2371 static dbus_bool_t
2372 check_message_handling (DBusMessage *message)
2373 {
2374   DBusMessageIter *iter;
2375   int type;
2376   dbus_bool_t retval;
2377   dbus_int32_t client_serial;
2378   
2379   retval = FALSE;
2380   iter = NULL;
2381   
2382   client_serial = _dbus_message_get_client_serial (message);
2383
2384   /* can't use set_client_serial due to the assertions at the start of it */
2385   set_int_field (message, FIELD_CLIENT_SERIAL,
2386                  client_serial);
2387
2388   if (client_serial != _dbus_message_get_client_serial (message))
2389     {
2390       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
2391       goto failed;
2392     }
2393   
2394   /* If we implement message_set_arg (message, n, value)
2395    * then we would want to test it here
2396    */
2397   
2398   iter = dbus_message_get_args_iter (message);
2399   while ((type = dbus_message_iter_get_arg_type (iter)) != DBUS_TYPE_INVALID)
2400     {
2401       switch (type)
2402         {
2403         case DBUS_TYPE_STRING:
2404           {
2405             char *str;
2406             str = dbus_message_iter_get_string (iter);
2407             dbus_free (str);
2408           }
2409           break;
2410         }
2411       
2412       if (!dbus_message_iter_next (iter))
2413         break;
2414     }
2415
2416   retval = TRUE;
2417   
2418  failed:
2419   if (iter)
2420     dbus_message_iter_unref (iter);
2421
2422   return retval;
2423 }
2424
2425 static dbus_bool_t
2426 check_have_valid_message (DBusMessageLoader *loader)
2427 {
2428   DBusMessage *message;
2429   dbus_bool_t retval;
2430
2431   message = NULL;
2432   retval = FALSE;
2433   
2434   if (_dbus_message_loader_get_is_corrupted (loader))
2435     {
2436       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
2437       goto failed;
2438     }
2439   
2440   message = _dbus_message_loader_pop_message (loader);
2441   if (message == NULL)
2442     {
2443       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
2444       goto failed;
2445     }
2446   
2447   if (_dbus_string_get_length (&loader->data) > 0)
2448     {
2449       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
2450       goto failed;
2451     }
2452
2453   /* Verify that we're able to properly deal with the message.
2454    * For example, this would detect improper handling of messages
2455    * in nonstandard byte order.
2456    */
2457   if (!check_message_handling (message))
2458     goto failed;  
2459   
2460   retval = TRUE;
2461
2462  failed:
2463   if (message)
2464     dbus_message_unref (message);
2465   return retval;
2466 }
2467
2468 static dbus_bool_t
2469 check_invalid_message (DBusMessageLoader *loader)
2470 {
2471   dbus_bool_t retval;
2472
2473   retval = FALSE;
2474   
2475   if (!_dbus_message_loader_get_is_corrupted (loader))
2476     {
2477       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
2478       goto failed;
2479     }
2480
2481   retval = TRUE;
2482
2483  failed:
2484   return retval;
2485 }
2486
2487 static dbus_bool_t
2488 check_incomplete_message (DBusMessageLoader *loader)
2489 {
2490   DBusMessage *message;
2491   dbus_bool_t retval;
2492
2493   message = NULL;
2494   retval = FALSE;
2495   
2496   if (_dbus_message_loader_get_is_corrupted (loader))
2497     {
2498       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
2499       goto failed;
2500     }
2501   
2502   message = _dbus_message_loader_pop_message (loader);
2503   if (message != NULL)
2504     {
2505       _dbus_warn ("loaded message that was expected to be incomplete\n");
2506       goto failed;
2507     }
2508
2509   retval = TRUE;
2510
2511  failed:
2512   if (message)
2513     dbus_message_unref (message);
2514   return retval;
2515 }
2516
2517 static dbus_bool_t
2518 check_loader_results (DBusMessageLoader      *loader,
2519                       DBusMessageValidity     validity)
2520 {
2521   switch (validity)
2522     {
2523     case _DBUS_MESSAGE_VALID:
2524       return check_have_valid_message (loader);
2525     case _DBUS_MESSAGE_INVALID:
2526       return check_invalid_message (loader);
2527     case _DBUS_MESSAGE_INCOMPLETE:
2528       return check_incomplete_message (loader);
2529     case _DBUS_MESSAGE_UNKNOWN:
2530       return TRUE;
2531     }
2532
2533   _dbus_assert_not_reached ("bad DBusMessageValidity");
2534   return FALSE;
2535 }
2536
2537
2538 /**
2539  * Loads the message in the given message file.
2540  *
2541  * @param filename filename to load
2542  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
2543  * @param data string to load message into
2544  * @returns #TRUE if the message was loaded
2545  */
2546 dbus_bool_t
2547 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
2548                                             dbus_bool_t          is_raw,
2549                                             DBusString          *data)
2550 {
2551   dbus_bool_t retval;
2552
2553   retval = FALSE;  
2554
2555   if (is_raw)
2556     {
2557       DBusResultCode result;
2558
2559       result = _dbus_file_get_contents (data, filename);
2560       if (result != DBUS_RESULT_SUCCESS)
2561         {
2562           const char *s;      
2563           _dbus_string_get_const_data (filename, &s);
2564           _dbus_warn ("Could not load message file %s\n", s);
2565           goto failed;
2566         }
2567     }
2568   else
2569     {
2570       if (!_dbus_message_data_load (data, filename))
2571         {
2572           const char *s;      
2573           _dbus_string_get_const_data (filename, &s);
2574           _dbus_warn ("Could not load message file %s\n", s);
2575           goto failed;
2576         }
2577     }
2578
2579   retval = TRUE;
2580   
2581  failed:
2582
2583   return retval;
2584 }
2585
2586 /**
2587  * Tries loading the message in the given message file
2588  * and verifies that DBusMessageLoader can handle it.
2589  *
2590  * @param filename filename to load
2591  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
2592  * @param expected_validity what the message has to be like to return #TRUE
2593  * @returns #TRUE if the message has the expected validity
2594  */
2595 dbus_bool_t
2596 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
2597                                            dbus_bool_t          is_raw,
2598                                            DBusMessageValidity  expected_validity)
2599 {
2600   DBusString data;
2601   dbus_bool_t retval;
2602
2603   retval = FALSE;
2604   
2605   if (!_dbus_string_init (&data, _DBUS_INT_MAX))
2606     _dbus_assert_not_reached ("could not allocate string\n");
2607
2608   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
2609                                                    &data))
2610     goto failed;
2611
2612   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
2613
2614  failed:
2615
2616   if (!retval)
2617     {
2618       const char *s;
2619
2620       if (_dbus_string_get_length (&data) > 0)
2621         _dbus_verbose_bytes_of_string (&data, 0,
2622                                        _dbus_string_get_length (&data));
2623       
2624       _dbus_string_get_const_data (filename, &s);
2625       _dbus_warn ("Failed message loader test on %s\n",
2626                   s);
2627     }
2628   
2629   _dbus_string_free (&data);
2630
2631   return retval;
2632 }
2633
2634 /**
2635  * Tries loading the given message data.
2636  *
2637  *
2638  * @param data the message data
2639  * @param expected_validity what the message has to be like to return #TRUE
2640  * @returns #TRUE if the message has the expected validity
2641  */
2642 dbus_bool_t
2643 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
2644                                            DBusMessageValidity  expected_validity)
2645 {
2646   DBusMessageLoader *loader;
2647   dbus_bool_t retval;
2648   int len;
2649   int i;
2650
2651   loader = NULL;
2652   retval = FALSE;
2653
2654   /* Write the data one byte at a time */
2655   
2656   loader = _dbus_message_loader_new ();
2657
2658   len = _dbus_string_get_length (data);
2659   for (i = 0; i < len; i++)
2660     {
2661       DBusString *buffer;
2662
2663       _dbus_message_loader_get_buffer (loader, &buffer);
2664       _dbus_string_append_byte (buffer,
2665                                 _dbus_string_get_byte (data, i));
2666       _dbus_message_loader_return_buffer (loader, buffer, 1);
2667     }
2668   
2669   if (!check_loader_results (loader, expected_validity))
2670     goto failed;
2671
2672   _dbus_message_loader_unref (loader);
2673   loader = NULL;
2674
2675   /* Write the data all at once */
2676   
2677   loader = _dbus_message_loader_new ();
2678
2679   {
2680     DBusString *buffer;
2681     
2682     _dbus_message_loader_get_buffer (loader, &buffer);
2683     _dbus_string_copy (data, 0, buffer,
2684                        _dbus_string_get_length (buffer));
2685     _dbus_message_loader_return_buffer (loader, buffer, 1);
2686   }
2687   
2688   if (!check_loader_results (loader, expected_validity))
2689     goto failed;
2690
2691   _dbus_message_loader_unref (loader);
2692   loader = NULL;  
2693
2694   /* Write the data 2 bytes at a time */
2695   
2696   loader = _dbus_message_loader_new ();
2697
2698   len = _dbus_string_get_length (data);
2699   for (i = 0; i < len; i += 2)
2700     {
2701       DBusString *buffer;
2702
2703       _dbus_message_loader_get_buffer (loader, &buffer);
2704       _dbus_string_append_byte (buffer,
2705                                 _dbus_string_get_byte (data, i));
2706       if ((i+1) < len)
2707         _dbus_string_append_byte (buffer,
2708                                   _dbus_string_get_byte (data, i+1));
2709       _dbus_message_loader_return_buffer (loader, buffer, 1);
2710     }
2711   
2712   if (!check_loader_results (loader, expected_validity))
2713     goto failed;
2714
2715   _dbus_message_loader_unref (loader);
2716   loader = NULL;
2717   
2718   retval = TRUE;
2719   
2720  failed:
2721   
2722   if (loader)
2723     _dbus_message_loader_unref (loader);
2724   
2725   return retval;
2726 }
2727
2728 static dbus_bool_t
2729 process_test_subdir (const DBusString          *test_base_dir,
2730                      const char                *subdir,
2731                      DBusMessageValidity        validity,
2732                      DBusForeachMessageFileFunc function,
2733                      void                      *user_data)
2734 {
2735   DBusString test_directory;
2736   DBusString filename;
2737   DBusDirIter *dir;
2738   dbus_bool_t retval;
2739   DBusResultCode result;
2740
2741   retval = FALSE;
2742   dir = NULL;
2743   
2744   if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
2745     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2746
2747   _dbus_string_init_const (&filename, subdir);
2748   
2749   if (!_dbus_string_copy (test_base_dir, 0,
2750                           &test_directory, 0))
2751     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2752   
2753   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
2754     _dbus_assert_not_reached ("couldn't allocate full path");
2755
2756   _dbus_string_free (&filename);
2757   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
2758     _dbus_assert_not_reached ("didn't allocate filename string\n");
2759   
2760   dir = _dbus_directory_open (&test_directory, &result);
2761   if (dir == NULL)
2762     {
2763       const char *s;
2764       _dbus_string_get_const_data (&test_directory, &s);
2765       _dbus_warn ("Could not open %s: %s\n", s,
2766                   dbus_result_to_string (result));
2767       goto failed;
2768     }
2769
2770   printf ("Testing:\n");
2771   
2772   result = DBUS_RESULT_SUCCESS;
2773  next:
2774   while (_dbus_directory_get_next_file (dir, &filename, &result))
2775     {
2776       DBusString full_path;
2777       dbus_bool_t is_raw;
2778       
2779       if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
2780         _dbus_assert_not_reached ("couldn't init string");
2781
2782       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2783         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2784
2785       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2786         _dbus_assert_not_reached ("couldn't concat file to dir");
2787
2788       if (_dbus_string_ends_with_c_str (&filename, ".message"))
2789         is_raw = FALSE;
2790       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
2791         is_raw = TRUE;
2792       else
2793         {
2794           const char *filename_c;
2795           _dbus_string_get_const_data (&filename, &filename_c);
2796           _dbus_verbose ("Skipping non-.message file %s\n",
2797                          filename_c);
2798           _dbus_string_free (&full_path);
2799           goto next;
2800         }
2801
2802       {
2803         const char *s;
2804         _dbus_string_get_const_data (&filename, &s);
2805         printf ("    %s\n", s);
2806       }
2807       
2808       _dbus_verbose (" expecting %s\n",
2809                      validity == _DBUS_MESSAGE_VALID ? "valid" :
2810                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
2811                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")));
2812       
2813       if (! (*function) (&full_path, is_raw, validity, user_data))
2814         {
2815           _dbus_string_free (&full_path);
2816           goto failed;
2817         }
2818       else
2819         _dbus_string_free (&full_path);
2820     }
2821
2822   if (result != DBUS_RESULT_SUCCESS)
2823     {
2824       const char *s;
2825       _dbus_string_get_const_data (&test_directory, &s);
2826       _dbus_warn ("Could not get next file in %s: %s\n",
2827                   s, dbus_result_to_string (result));
2828       goto failed;
2829     }
2830     
2831   retval = TRUE;
2832   
2833  failed:
2834
2835   if (dir)
2836     _dbus_directory_close (dir);
2837   _dbus_string_free (&test_directory);
2838   _dbus_string_free (&filename);
2839
2840   return retval;
2841 }
2842                      
2843 /**
2844  * Runs the given function on every message file in the test suite.
2845  * The function should return #FALSE on test failure or fatal error.
2846  *
2847  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
2848  * @param func the function to run
2849  * @param user_data data for function
2850  * @returns #FALSE if there's a failure
2851  */
2852 dbus_bool_t
2853 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
2854                                                DBusForeachMessageFileFunc func,
2855                                                void                      *user_data)
2856 {
2857   DBusString test_directory;
2858   dbus_bool_t retval;
2859
2860   retval = FALSE;
2861   
2862   _dbus_string_init_const (&test_directory, test_data_dir);
2863
2864   if (!process_test_subdir (&test_directory, "valid-messages",
2865                             _DBUS_MESSAGE_VALID, func, user_data))
2866     goto failed;
2867
2868   if (!process_test_subdir (&test_directory, "invalid-messages",
2869                             _DBUS_MESSAGE_INVALID, func, user_data))
2870     goto failed;
2871   
2872   if (!process_test_subdir (&test_directory, "incomplete-messages",
2873                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
2874     goto failed;
2875
2876   retval = TRUE;
2877   
2878  failed:
2879
2880   _dbus_string_free (&test_directory);
2881   
2882   return retval;
2883 }
2884
2885 /**
2886  * @ingroup DBusMessageInternals
2887  * Unit test for DBusMessage.
2888  *
2889  * @returns #TRUE on success.
2890  */
2891 dbus_bool_t
2892 _dbus_message_test (const char *test_data_dir)
2893 {
2894   DBusMessage *message;
2895   DBusMessageLoader *loader;
2896   int i;
2897   const char *data;
2898   dbus_int32_t our_int;
2899   char *our_str;
2900   double our_double;
2901   
2902   /* Test the vararg functions */
2903   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2904   _dbus_message_set_client_serial (message, 1);
2905   dbus_message_append_args (message,
2906                             DBUS_TYPE_INT32, -0x12345678,
2907                             DBUS_TYPE_STRING, "Test string",
2908                             DBUS_TYPE_DOUBLE, 3.14159,
2909                             0);
2910   _dbus_verbose_bytes_of_string (&message->header, 0,
2911                                  _dbus_string_get_length (&message->header));
2912   _dbus_verbose_bytes_of_string (&message->body, 0,
2913                                  _dbus_string_get_length (&message->body));
2914   
2915   if (dbus_message_get_args (message,
2916                              DBUS_TYPE_INT32, &our_int,
2917                              DBUS_TYPE_STRING, &our_str,
2918                              DBUS_TYPE_DOUBLE, &our_double,
2919                              0) != DBUS_RESULT_SUCCESS)
2920     _dbus_assert_not_reached ("Could not get arguments");
2921
2922   if (our_int != -0x12345678)
2923     _dbus_assert_not_reached ("integers differ!");
2924
2925   if (our_double != 3.14159)
2926     _dbus_assert_not_reached ("doubles differ!");
2927
2928   if (strcmp (our_str, "Test string") != 0)
2929     _dbus_assert_not_reached ("strings differ!");
2930
2931   dbus_free (our_str);
2932   dbus_message_unref (message);
2933   
2934   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2935   _dbus_message_set_client_serial (message, 1);
2936   _dbus_message_set_reply_serial (message, 0x12345678);
2937
2938   dbus_message_append_string (message, "Test string");
2939   dbus_message_append_int32 (message, -0x12345678);
2940   dbus_message_append_uint32 (message, 0xedd1e);
2941   dbus_message_append_double (message, 3.14159);
2942
2943   message_iter_test (message);
2944
2945   /* Message loader test */
2946   _dbus_message_lock (message);
2947   loader = _dbus_message_loader_new ();
2948
2949   /* Write the header data one byte at a time */
2950   _dbus_string_get_const_data (&message->header, &data);
2951   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
2952     {
2953       DBusString *buffer;
2954
2955       _dbus_message_loader_get_buffer (loader, &buffer);
2956       _dbus_string_append_byte (buffer, data[i]);
2957       _dbus_message_loader_return_buffer (loader, buffer, 1);
2958     }
2959
2960   /* Write the body data one byte at a time */
2961   _dbus_string_get_const_data (&message->body, &data);
2962   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
2963     {
2964       DBusString *buffer;
2965
2966       _dbus_message_loader_get_buffer (loader, &buffer);
2967       _dbus_string_append_byte (buffer, data[i]);
2968       _dbus_message_loader_return_buffer (loader, buffer, 1);
2969     }
2970
2971   dbus_message_unref (message);
2972
2973   /* Now pop back the message */
2974   if (_dbus_message_loader_get_is_corrupted (loader))
2975     _dbus_assert_not_reached ("message loader corrupted");
2976   
2977   message = _dbus_message_loader_pop_message (loader);
2978   if (!message)
2979     _dbus_assert_not_reached ("received a NULL message");
2980
2981   if (_dbus_message_get_reply_serial (message) != 0x12345678)
2982     _dbus_assert_not_reached ("reply serial fields differ");
2983   
2984   message_iter_test (message);
2985   
2986   dbus_message_unref (message);
2987   _dbus_message_loader_unref (loader);
2988
2989   /* Now load every message in test_data_dir if we have one */
2990   if (test_data_dir == NULL)
2991     return TRUE;
2992
2993   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
2994                                                         (DBusForeachMessageFileFunc)
2995                                                         dbus_internal_do_not_use_try_message_file,
2996                                                         NULL);
2997 }
2998
2999 #endif /* DBUS_BUILD_TESTS */