c4eca849b87d3df82d9c0620311e84b76fc9fe6e
[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   int 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
750  * can't be allocated for the message.
751  *
752  * @todo use DBusString internally to store service and name.
753  *
754  * @param service service that the message should be sent to
755  * @param name name of the message
756  * @returns a new DBusMessage, free with dbus_message_unref()
757  * @see dbus_message_unref()
758  */
759 DBusMessage*
760 dbus_message_new (const char *service,
761                   const char *name)
762 {
763   DBusMessage *message;
764
765   message = dbus_message_new_empty_header ();
766   if (message == NULL)
767     return NULL;
768   
769   if (!dbus_message_create_header (message, service, name))
770     {
771       dbus_message_unref (message);
772       return NULL;
773     }
774   
775   return message;
776 }
777
778 /**
779  * Constructs a message that is a reply to some other
780  * message. Returns #NULL if memory can't be allocated
781  * for the message.
782  *
783  * @param name the name of the message
784  * @param original_message the message which the created
785  * message is a reply to.
786  * @returns a new DBusMessage, free with dbus_message_unref()
787  * @see dbus_message_new(), dbus_message_unref()
788  */ 
789 DBusMessage*
790 dbus_message_new_reply (const char  *name,
791                         DBusMessage *original_message)
792 {
793   DBusMessage *message;
794   const char *sender;
795
796   sender = get_string_field (original_message,
797                              FIELD_SENDER, NULL);
798
799   _dbus_assert (sender != NULL);
800   
801   message = dbus_message_new (sender, name);
802   
803   if (message == NULL)
804     return NULL;
805
806   if (!_dbus_message_set_reply_serial (message,
807                                        _dbus_message_get_client_serial (original_message)))
808     {
809       dbus_message_unref (message);
810       return NULL;
811     }
812
813   return message;
814 }
815
816 /**
817  * Creates a new message that is an exact replica of the message
818  * specified, except that its refcount is set to 1.
819  *
820  * @param message the message.
821  * @returns the new message.
822  */
823 DBusMessage *
824 dbus_message_new_from_message (const DBusMessage *message)
825 {
826   DBusMessage *retval;
827   int i;
828   
829   retval = dbus_new0 (DBusMessage, 1);
830   if (retval == NULL)
831     return NULL;
832   
833   retval->refcount = 1;
834   retval->byte_order = message->byte_order;
835
836   if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
837     {
838       dbus_free (retval);
839       return NULL;
840     }
841   
842   if (!_dbus_string_init (&retval->body, _DBUS_INT_MAX))
843     {
844       _dbus_string_free (&retval->header);
845       dbus_free (retval);
846       return NULL;
847     }
848
849   if (!_dbus_string_copy (&message->header, 0,
850                           &retval->header, 0))
851     {
852       _dbus_string_free (&retval->header);
853       _dbus_string_free (&retval->body);
854       dbus_free (retval);
855
856       return NULL;
857     }
858
859   if (!_dbus_string_copy (&message->body, 0,
860                           &retval->body, 0))
861     {
862       _dbus_string_free (&retval->header);
863       _dbus_string_free (&retval->body);
864       dbus_free (retval);
865
866       return NULL;
867     }
868
869   for (i = 0; i < FIELD_LAST; i++)
870     {
871       retval->header_fields[i].offset = message->header_fields[i].offset;
872     }
873   
874   return retval;
875 }
876
877
878 /**
879  * Increments the reference count of a DBusMessage.
880  *
881  * @param message The message
882  * @see dbus_message_unref
883  */
884 void
885 dbus_message_ref (DBusMessage *message)
886 {
887   _dbus_assert (message->refcount > 0);
888   
889   message->refcount += 1;
890 }
891
892 /**
893  * Decrements the reference count of a DBusMessage.
894  *
895  * @param message The message
896  * @see dbus_message_ref
897  */
898 void
899 dbus_message_unref (DBusMessage *message)
900 {
901   _dbus_assert (message->refcount > 0);
902
903   message->refcount -= 1;
904   if (message->refcount == 0)
905     {
906       if (message->size_counter != NULL)
907         {
908           _dbus_counter_adjust (message->size_counter,
909                                 - message->size_counter_delta);
910           _dbus_counter_unref (message->size_counter);
911         }
912       
913       _dbus_string_free (&message->header);
914       _dbus_string_free (&message->body);
915       
916       dbus_free (message);
917     }
918 }
919
920 /**
921  * Gets the name of a message.
922  *
923  * @param message the message
924  * @returns the message name (should not be freed)
925  */
926 const char*
927 dbus_message_get_name (DBusMessage *message)
928 {
929   return get_string_field (message, FIELD_NAME, NULL);
930 }
931
932 /**
933  * Gets the destination service of a message.
934  *
935  * @param message the message
936  * @returns the message destination service (should not be freed)
937  */
938 const char*
939 dbus_message_get_service (DBusMessage *message)
940 {
941   return get_string_field (message, FIELD_SERVICE, NULL);
942 }
943
944 /**
945  * Appends fields to a message given a variable argument
946  * list. The variable argument list should contain the type
947  * of the field followed by the value to add.
948  * The list is terminated with 0.
949  *
950  * @param message the message
951  * @param first_field_type type of the first field
952  * @param ... value of first field, list of additional type-value pairs
953  * @returns #TRUE on success
954  */
955 dbus_bool_t
956 dbus_message_append_fields (DBusMessage *message,
957                             int first_field_type,
958                             ...)
959 {
960   dbus_bool_t retval;
961   va_list var_args;
962
963   va_start (var_args, first_field_type);
964   retval = dbus_message_append_fields_valist (message,
965                                               first_field_type,
966                                               var_args);
967   va_end (var_args);
968
969   return retval;
970 }
971
972 /**
973  * This function takes a va_list for use by language bindings
974  *
975  * @see dbus_message_append_fields.  
976  * @param message the message
977  * @param first_field_type type of first field
978  * @param var_args value of first field, then list of type/value pairs
979  * @returns #TRUE on success
980  */
981 dbus_bool_t
982 dbus_message_append_fields_valist (DBusMessage *message,
983                                    int          first_field_type,
984                                    va_list      var_args)
985 {
986   int type, old_len;
987
988   old_len = _dbus_string_get_length (&message->body);
989   
990   type = first_field_type;
991
992   while (type != 0)
993     {
994       switch (type)
995         {
996         case DBUS_TYPE_INT32:
997           if (!dbus_message_append_int32 (message, va_arg (var_args, dbus_int32_t)))
998             goto enomem;
999           break;
1000         case DBUS_TYPE_UINT32:
1001           if (!dbus_message_append_uint32 (message, va_arg (var_args, dbus_uint32_t)))
1002             goto enomem;            
1003           break;
1004         case DBUS_TYPE_DOUBLE:
1005           if (!dbus_message_append_double (message, va_arg (var_args, double)))
1006             goto enomem;
1007           break;
1008         case DBUS_TYPE_STRING:
1009           if (!dbus_message_append_string (message, va_arg (var_args, const char *)))
1010             goto enomem;
1011           break;
1012         case DBUS_TYPE_BYTE_ARRAY:
1013           {
1014             int len;
1015             unsigned char *data;
1016
1017             data = va_arg (var_args, unsigned char *);
1018             len = va_arg (var_args, int);
1019
1020             if (!dbus_message_append_byte_array (message, data, len))
1021               goto enomem;
1022           }
1023           break;
1024         case DBUS_TYPE_STRING_ARRAY:
1025           {
1026             int len;
1027             const char **data;
1028             
1029             data = va_arg (var_args, const char **);
1030             len = va_arg (var_args, int);
1031
1032             if (!dbus_message_append_string_array (message, data, len))
1033               goto enomem;
1034           }
1035           break;
1036           
1037         default:
1038           _dbus_warn ("Unknown field type %d\n", type);
1039         }
1040
1041       type = va_arg (var_args, int);
1042     }
1043
1044   return TRUE;
1045
1046  enomem:
1047   _dbus_string_set_length (&message->body, old_len);
1048   return FALSE;
1049 }
1050
1051 /**
1052  * Appends a 32 bit signed integer to the message.
1053  *
1054  * @param message the message
1055  * @param value the integer value
1056  * @returns #TRUE on success
1057  */
1058 dbus_bool_t
1059 dbus_message_append_int32 (DBusMessage  *message,
1060                            dbus_int32_t  value)
1061 {
1062   _dbus_assert (!message->locked);
1063
1064   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
1065     {
1066       _dbus_string_shorten (&message->body, 1);
1067       return FALSE;
1068     }
1069   
1070   return _dbus_marshal_int32 (&message->body,
1071                               message->byte_order, value);
1072 }
1073
1074 /**
1075  * Appends a 32 bit unsigned integer to the message.
1076  *
1077  * @param message the message
1078  * @param value the integer value
1079  * @returns #TRUE on success
1080  */
1081 dbus_bool_t
1082 dbus_message_append_uint32 (DBusMessage   *message,
1083                             dbus_uint32_t  value)
1084 {
1085   _dbus_assert (!message->locked);
1086
1087   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UINT32))
1088     {
1089       _dbus_string_shorten (&message->body, 1);
1090       return FALSE;
1091     }
1092   
1093   return _dbus_marshal_uint32 (&message->body,
1094                                message->byte_order, value);
1095 }
1096
1097 /**
1098  * Appends a double value to the message.
1099  *
1100  * @param message the message
1101  * @param value the double value
1102  * @returns #TRUE on success
1103  */
1104 dbus_bool_t
1105 dbus_message_append_double (DBusMessage *message,
1106                             double       value)
1107 {
1108   _dbus_assert (!message->locked);
1109
1110   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_DOUBLE))
1111     {
1112       _dbus_string_shorten (&message->body, 1);
1113       return FALSE;
1114     }
1115   
1116   return _dbus_marshal_double (&message->body,
1117                                message->byte_order, value);
1118 }
1119
1120 /**
1121  * Appends a UTF-8 string to the message.
1122  *
1123  * @param message the message
1124  * @param value the string
1125  * @returns #TRUE on success
1126  */
1127 dbus_bool_t
1128 dbus_message_append_string (DBusMessage *message,
1129                             const char  *value)
1130 {
1131   _dbus_assert (!message->locked);
1132
1133   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING))
1134     {
1135       _dbus_string_shorten (&message->body, 1);
1136       return FALSE;
1137     }
1138   
1139   return _dbus_marshal_string (&message->body,
1140                                message->byte_order, value);
1141 }
1142
1143 /**
1144  * Appends a byte array to the message.
1145  *
1146  * @param message the message
1147  * @param value the array
1148  * @param len the length of the array
1149  * @returns #TRUE on success
1150  */
1151 dbus_bool_t
1152 dbus_message_append_byte_array (DBusMessage         *message,
1153                                 unsigned const char *value,
1154                                 int                 len)
1155 {
1156   _dbus_assert (!message->locked);
1157
1158   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_BYTE_ARRAY))
1159     {
1160       _dbus_string_shorten (&message->body, 1);
1161       return FALSE;
1162     }
1163   
1164   return _dbus_marshal_byte_array (&message->body,
1165                                    message->byte_order, value, len);
1166 }
1167
1168 /**
1169  * Appends a string array to the message.
1170  *
1171  * @param message the message
1172  * @param value the array
1173  * @param len the length of the array
1174  * @returns #TRUE on success
1175  */
1176 dbus_bool_t
1177 dbus_message_append_string_array (DBusMessage *message,
1178                                   const char **value,
1179                                   int          len)
1180 {
1181   _dbus_assert (!message->locked);
1182
1183   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING_ARRAY))
1184     {
1185       _dbus_string_shorten (&message->body, 1);
1186       return FALSE;
1187     }
1188   
1189   return _dbus_marshal_string_array (&message->body,
1190                                      message->byte_order, value, len);
1191 }
1192
1193 /**
1194  * Gets fields from a message given a variable argument list.
1195  * The variable argument list should contain the type of the
1196  * field followed by a pointer to where the value should be
1197  * stored. The list is terminated with 0.
1198  *
1199  *  @todo rename get_args to avoid confusion with header fields
1200  * 
1201  * @param message the message
1202  * @param first_field_type the first field type
1203  * @param ... location for first field value, then list of type-location pairs
1204  * @returns result code
1205  */
1206 DBusResultCode
1207 dbus_message_get_fields (DBusMessage *message,
1208                          int          first_field_type,
1209                          ...)
1210 {
1211   DBusResultCode retval;
1212   va_list var_args;
1213
1214   va_start (var_args, first_field_type);
1215   retval = dbus_message_get_fields_valist (message, first_field_type, var_args);
1216   va_end (var_args);
1217
1218   return retval;
1219 }
1220
1221 /**
1222  * This function takes a va_list for use by language bindings
1223  *
1224  * @todo this function (or some lower-level non-convenience function)
1225  * needs better error handling; should allow the application to
1226  * distinguish between out of memory, and bad data from the remote
1227  * app. It also needs to not leak a bunch of args when it gets
1228  * to the arg that's bad, as that would be a security hole
1229  * (allow one app to force another to leak memory)
1230  *
1231  * @todo We need to free the field data when an error occurs.
1232  *
1233  * @todo rename get_args_valist to avoid confusion with header fields
1234  *
1235  * @see dbus_message_get_fields
1236  * @param message the message
1237  * @param first_field_type type of the first field
1238  * @param var_args return location for first field, followed by list of type/location pairs
1239  * @returns result code
1240  */
1241 DBusResultCode
1242 dbus_message_get_fields_valist (DBusMessage *message,
1243                                 int          first_field_type,
1244                                 va_list      var_args)
1245 {
1246   int spec_type, msg_type, i;
1247   DBusMessageIter *iter;
1248
1249   iter = dbus_message_get_fields_iter (message);
1250
1251   if (iter == NULL)
1252     return DBUS_RESULT_NO_MEMORY;
1253   
1254   spec_type = first_field_type;
1255   i = 0;
1256   
1257   while (spec_type != 0)
1258     {
1259       msg_type = dbus_message_iter_get_field_type (iter);      
1260       
1261       if (msg_type != spec_type)
1262         {
1263           _dbus_verbose ("Field %d is specified to be of type \"%s\", but "
1264                          "is actually of type \"%s\"\n", i,
1265                          _dbus_type_to_string (spec_type),
1266                          _dbus_type_to_string (msg_type));
1267           dbus_message_iter_unref (iter);
1268
1269           return DBUS_RESULT_INVALID_FIELDS;
1270         }
1271
1272       switch (spec_type)
1273         {
1274         case DBUS_TYPE_INT32:
1275           {
1276             dbus_int32_t *ptr;
1277
1278             ptr = va_arg (var_args, dbus_int32_t *);
1279
1280             *ptr = dbus_message_iter_get_int32 (iter);
1281             break;
1282           }
1283         case DBUS_TYPE_UINT32:
1284           {
1285             dbus_uint32_t *ptr;
1286
1287             ptr = va_arg (var_args, dbus_uint32_t *);
1288
1289             *ptr = dbus_message_iter_get_uint32 (iter);
1290             break;
1291           }
1292
1293         case DBUS_TYPE_DOUBLE:
1294           {
1295             double *ptr;
1296
1297             ptr = va_arg (var_args, double *);
1298
1299             *ptr = dbus_message_iter_get_double (iter);
1300             break;
1301           }
1302
1303         case DBUS_TYPE_STRING:
1304           {
1305             char **ptr;
1306
1307             ptr = va_arg (var_args, char **);
1308
1309             *ptr = dbus_message_iter_get_string (iter);
1310
1311             if (!*ptr)
1312               return DBUS_RESULT_NO_MEMORY;
1313             
1314             break;
1315           }
1316
1317         case DBUS_TYPE_BYTE_ARRAY:
1318           {
1319             unsigned char **ptr;
1320             int *len;
1321
1322             ptr = va_arg (var_args, unsigned char **);
1323             len = va_arg (var_args, int *);
1324
1325             *ptr = dbus_message_iter_get_byte_array (iter, len);
1326
1327             if (!*ptr)
1328               return DBUS_RESULT_NO_MEMORY;
1329             
1330             break;
1331           }
1332         case DBUS_TYPE_STRING_ARRAY:
1333           {
1334             char ***ptr;
1335             int *len;
1336
1337             ptr = va_arg (var_args, char ***);
1338             len = va_arg (var_args, int *);
1339
1340             *ptr = dbus_message_iter_get_string_array (iter, len);
1341             
1342             if (!*ptr)
1343               return DBUS_RESULT_NO_MEMORY;
1344             
1345             break;
1346           }
1347         default:          
1348           _dbus_warn ("Unknown field type %d\n", spec_type);
1349         }
1350       
1351       spec_type = va_arg (var_args, int);
1352       if (spec_type != 0 && !dbus_message_iter_next (iter))
1353         {
1354           _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n");
1355
1356           dbus_message_iter_unref (iter);  
1357           return DBUS_RESULT_INVALID_FIELDS;
1358         }
1359       i++;
1360     }
1361
1362   dbus_message_iter_unref (iter);
1363   return DBUS_RESULT_SUCCESS;
1364 }
1365
1366 /**
1367  * Returns a DBusMessageIter representing the fields of the
1368  * message passed in.
1369  *
1370  * @todo IMO the message iter should follow the GtkTextIter pattern,
1371  * a static object with a "stamp" value used to detect invalid
1372  * iter uses (uninitialized or after changing the message).
1373  * ref/unref is kind of annoying to deal with, and slower too.
1374  * This implies not ref'ing the message from the iter.
1375  *
1376  * @todo rename get_args_iter to avoid confusion with header fields
1377  * 
1378  * @param message the message
1379  * @returns a new iter.
1380  */
1381 DBusMessageIter *
1382 dbus_message_get_fields_iter (DBusMessage *message)
1383 {
1384   DBusMessageIter *iter;
1385   
1386   iter = dbus_new (DBusMessageIter, 1);
1387
1388   dbus_message_ref (message);
1389   
1390   iter->refcount = 1;
1391   iter->message = message;
1392   iter->pos = 0;
1393
1394   return iter;
1395 }
1396
1397 /**
1398  * Increments the reference count of a DBusMessageIter.
1399  *
1400  * @param iter the message iter
1401  * @see dbus_message_iter_unref
1402  */
1403 void
1404 dbus_message_iter_ref (DBusMessageIter *iter)
1405 {
1406   _dbus_assert (iter->refcount > 0);
1407   
1408   iter->refcount += 1;
1409 }
1410
1411 /**
1412  * Decrements the reference count of a DBusMessageIter.
1413  *
1414  * @param iter The message iter
1415  * @see dbus_message_iter_ref
1416  */
1417 void
1418 dbus_message_iter_unref (DBusMessageIter *iter)
1419 {
1420   _dbus_assert (iter->refcount > 0);
1421
1422   iter->refcount -= 1;
1423
1424   if (iter->refcount == 0)
1425     {
1426       dbus_message_unref (iter->message);
1427
1428       dbus_free (iter);
1429     }
1430 }
1431
1432 /**
1433  * Checks if an iterator has any more fields.
1434  *
1435  * @param iter the message iter
1436  * @returns #TRUE if there are more fields
1437  * following
1438  */
1439 dbus_bool_t
1440 dbus_message_iter_has_next (DBusMessageIter *iter)
1441 {
1442   int end_pos;
1443   
1444   if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1445                                       iter->message->byte_order,
1446                                       iter->pos, &end_pos))
1447     return FALSE;
1448   
1449   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1450     return FALSE;
1451   
1452   return TRUE;  
1453 }
1454
1455 /**
1456  * Moves the iterator to the next field.
1457  *
1458  * @param iter The message iter
1459  * @returns #TRUE if the iterator was moved to the next field
1460  */
1461 dbus_bool_t
1462 dbus_message_iter_next (DBusMessageIter *iter)
1463 {
1464   int end_pos;
1465   
1466   if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1467                                       iter->message->byte_order,
1468                                       iter->pos, &end_pos))
1469     return FALSE;
1470
1471   if (end_pos >= _dbus_string_get_length (&iter->message->body))
1472     return FALSE;
1473
1474   iter->pos = end_pos;
1475
1476   return TRUE;
1477 }
1478
1479 /**
1480  * Returns the field type of the field that the
1481  * message iterator points at.
1482  *
1483  * @param iter the message iter
1484  * @returns the field type
1485  */
1486 int
1487 dbus_message_iter_get_field_type (DBusMessageIter *iter)
1488 {
1489   const char *data;
1490
1491   if (iter->pos >= _dbus_string_get_length (&iter->message->body))
1492     return DBUS_TYPE_INVALID;
1493
1494   _dbus_string_get_const_data_len (&iter->message->body, &data, iter->pos, 1);
1495
1496   if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_STRING_ARRAY)
1497     return *data;
1498
1499   return DBUS_TYPE_INVALID;
1500 }
1501
1502 /**
1503  * Returns the string value that an iterator may point to.
1504  * Note that you need to check that the iterator points to
1505  * a string value before using this function.
1506  *
1507  * @see dbus_message_iter_get_field_type
1508  * @param iter the message iter
1509  * @returns the string
1510  */
1511 char *
1512 dbus_message_iter_get_string (DBusMessageIter *iter)
1513 {
1514   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING);
1515
1516   return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
1517                                  iter->pos + 1, NULL);
1518 }
1519
1520 /**
1521  * Returns the 32 bit signed integer value that an iterator may point to.
1522  * Note that you need to check that the iterator points to
1523  * a string value before using this function.
1524  *
1525  * @see dbus_message_iter_get_field_type
1526  * @param iter the message iter
1527  * @returns the integer
1528  */
1529 int
1530 dbus_message_iter_get_int32 (DBusMessageIter *iter)
1531 {
1532   return _dbus_demarshal_int32 (&iter->message->body, iter->message->byte_order,
1533                                 iter->pos + 1, NULL);
1534 }
1535
1536 /**
1537  * Returns the 32 bit unsigned integer value that an iterator may point to.
1538  * Note that you need to check that the iterator points to
1539  * a string value before using this function.
1540  *
1541  * @see dbus_message_iter_get_field_type
1542  * @param iter the message iter
1543  * @returns the integer
1544  */
1545 int
1546 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
1547 {
1548   return _dbus_demarshal_uint32 (&iter->message->body, iter->message->byte_order,
1549                                  iter->pos + 1, NULL);
1550 }
1551
1552 /**
1553  * Returns the double value that an iterator may point to.
1554  * Note that you need to check that the iterator points to
1555  * a string value before using this function.
1556  *
1557  * @see dbus_message_iter_get_field_type
1558  * @param iter the message iter
1559  * @returns the double
1560  */
1561 double
1562 dbus_message_iter_get_double (DBusMessageIter *iter)
1563 {
1564   return _dbus_demarshal_double (&iter->message->body, iter->message->byte_order,
1565                                  iter->pos + 1, NULL);
1566 }
1567
1568 /**
1569  * Returns the byte array that the iterator may point to.
1570  * Note that you need to check that the iterator points
1571  * to a byte array prior to using this function.
1572  *
1573  * @todo this function should probably take "unsigned char **" as
1574  * an out param argument, and return boolean or result code.
1575  *
1576  * @param iter the iterator
1577  * @param len return location for length of byte array
1578  * @returns the byte array
1579  */
1580 unsigned char *
1581 dbus_message_iter_get_byte_array (DBusMessageIter *iter,
1582                                   int             *len)
1583 {
1584   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_BYTE_ARRAY);
1585
1586   return _dbus_demarshal_byte_array (&iter->message->body, iter->message->byte_order,
1587                                      iter->pos + 1, NULL, len);
1588 }
1589
1590 /**
1591  * Returns the string array that the iterator may point to.
1592  * Note that you need to check that the iterator points
1593  * to a byte array prior to using this function.
1594  *
1595  * @todo this function should probably take "char **" as
1596  * an out param argument, and return boolean or result code.
1597  *
1598  * @param iter the iterator
1599  * @param len return location for length of byte array
1600  * @returns the byte array
1601  */
1602 char **
1603 dbus_message_iter_get_string_array (DBusMessageIter *iter,
1604                                     int             *len)
1605 {
1606   _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING_ARRAY);
1607
1608   return _dbus_demarshal_string_array (&iter->message->body, iter->message->byte_order,
1609                                        iter->pos + 1, NULL, len);
1610 }
1611
1612 /**
1613  * Sets the message sender.
1614  *
1615  * @param message the message
1616  * @param sender the sender
1617  * @returns #FALSE if not enough memory
1618  */
1619 dbus_bool_t
1620 dbus_message_set_sender (DBusMessage  *message,
1621                          const char   *sender)
1622 {
1623   _dbus_assert (!message->locked);
1624
1625   if (sender == NULL)
1626     {
1627       delete_string_field (message, FIELD_SENDER);
1628       return TRUE;
1629     }
1630   else
1631     {
1632       return set_string_field (message,
1633                                FIELD_SENDER,
1634                                sender);
1635     }
1636 }
1637
1638 /**
1639  * Sets a flag indicating that the message is an error reply
1640  * message, i.e. an "exception" rather than a normal response.
1641  *
1642  * @param message the message
1643  * @param is_error_reply #TRUE if this is an error message.
1644  */
1645 void
1646 dbus_message_set_is_error (DBusMessage *message,
1647                            dbus_bool_t  is_error_reply)
1648 {
1649   char *header;
1650   
1651   _dbus_assert (!message->locked);
1652   
1653   _dbus_string_get_data_len (&message->header, &header, 1, 1);
1654   
1655   if (is_error_reply)
1656     *header |= DBUS_HEADER_FLAG_ERROR;
1657   else
1658     *header &= ~DBUS_HEADER_FLAG_ERROR;    
1659 }
1660
1661 /**
1662  * Returns #TRUE if the message is an error
1663  * reply to some previous message we sent.
1664  *
1665  * @param message the message
1666  * @returns #TRUE if the message is an error
1667  */
1668 dbus_bool_t
1669 dbus_message_get_is_error (DBusMessage *message)
1670 {
1671   const char *header;
1672
1673   _dbus_string_get_const_data_len (&message->header, &header, 1, 1);
1674
1675   return (*header & DBUS_HEADER_FLAG_ERROR) != 0;
1676 }
1677
1678 /**
1679  * Gets the service which originated this message,
1680  * or #NULL if unknown or inapplicable.
1681  *
1682  * @param message the message
1683  * @returns the service name or #NULL
1684  */
1685 const char*
1686 dbus_message_get_sender (DBusMessage *message)
1687 {
1688   return get_string_field (message, FIELD_SENDER, NULL);
1689 }
1690
1691 /** @} */
1692
1693 /**
1694  * @addtogroup DBusMessageInternals
1695  *
1696  * @{
1697  */
1698 /**
1699  * @typedef DBusMessageLoader
1700  *
1701  * The DBusMessageLoader object encapsulates the process of converting
1702  * a byte stream into a series of DBusMessage. It buffers the incoming
1703  * bytes as efficiently as possible, and generates a queue of
1704  * messages. DBusMessageLoader is typically used as part of a
1705  * DBusTransport implementation. The DBusTransport then hands off
1706  * the loaded messages to a DBusConnection, making the messages
1707  * visible to the application.
1708  * 
1709  */
1710
1711 /* we definitely use signed ints for sizes, so don't exceed
1712  * _DBUS_INT_MAX; and add 16 for paranoia, since a message
1713  * over 128M is pretty nuts anyhow.
1714  */
1715
1716 /**
1717  * The maximum sane message size.
1718  */
1719 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
1720
1721 /**
1722  * Implementation details of DBusMessageLoader.
1723  * All members are private.
1724  */
1725 struct DBusMessageLoader
1726 {
1727   int refcount;        /**< Reference count. */
1728
1729   DBusString data;     /**< Buffered data */
1730   
1731   DBusList *messages;  /**< Complete messages. */
1732
1733   long max_message_size; /**< Maximum size of a message */
1734   
1735   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
1736
1737   unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
1738 };
1739
1740 /**
1741  * The initial buffer size of the message loader.
1742  * 
1743  * @todo this should be based on min header size plus some average
1744  * body size, or something. Or rather, the min header size only, if we
1745  * want to try to read only the header, store that in a DBusMessage,
1746  * then read only the body and store that, etc., depends on
1747  * how we optimize _dbus_message_loader_get_buffer() and what
1748  * the exact message format is.
1749  */
1750 #define INITIAL_LOADER_DATA_LEN 32
1751
1752 /**
1753  * Creates a new message loader. Returns #NULL if memory can't
1754  * be allocated.
1755  *
1756  * @returns new loader, or #NULL.
1757  */
1758 DBusMessageLoader*
1759 _dbus_message_loader_new (void)
1760 {
1761   DBusMessageLoader *loader;
1762
1763   loader = dbus_new0 (DBusMessageLoader, 1);
1764   if (loader == NULL)
1765     return NULL;
1766   
1767   loader->refcount = 1;
1768
1769   /* Try to cap message size at something that won't *totally* hose
1770    * the system if we have a couple of them.
1771    */
1772   loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
1773   
1774   if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX))
1775     {
1776       dbus_free (loader);
1777       return NULL;
1778     }
1779
1780   /* preallocate the buffer for speed, ignore failure */
1781   _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
1782   _dbus_string_set_length (&loader->data, 0);
1783   
1784   return loader;
1785 }
1786
1787 /**
1788  * Increments the reference count of the loader.
1789  *
1790  * @param loader the loader.
1791  */
1792 void
1793 _dbus_message_loader_ref (DBusMessageLoader *loader)
1794 {
1795   loader->refcount += 1;
1796 }
1797
1798 /**
1799  * Decrements the reference count of the loader and finalizes the
1800  * loader when the count reaches zero.
1801  *
1802  * @param loader the loader.
1803  */
1804 void
1805 _dbus_message_loader_unref (DBusMessageLoader *loader)
1806 {
1807   loader->refcount -= 1;
1808   if (loader->refcount == 0)
1809     {
1810       _dbus_list_foreach (&loader->messages,
1811                           (DBusForeachFunction) dbus_message_unref,
1812                           NULL);
1813       _dbus_list_clear (&loader->messages);
1814       _dbus_string_free (&loader->data);
1815       dbus_free (loader);
1816     }
1817 }
1818
1819 /**
1820  * Gets the buffer to use for reading data from the network.  Network
1821  * data is read directly into an allocated buffer, which is then used
1822  * in the DBusMessage, to avoid as many extra memcpy's as possible.
1823  * The buffer must always be returned immediately using
1824  * _dbus_message_loader_return_buffer(), even if no bytes are
1825  * successfully read.
1826  *
1827  * @todo this function can be a lot more clever. For example
1828  * it can probably always return a buffer size to read exactly
1829  * the body of the next message, thus avoiding any memory wastage
1830  * or reallocs.
1831  * 
1832  * @param loader the message loader.
1833  * @param buffer the buffer
1834  */
1835 void
1836 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
1837                                  DBusString        **buffer)
1838 {
1839   _dbus_assert (!loader->buffer_outstanding);
1840
1841   *buffer = &loader->data;
1842   
1843   loader->buffer_outstanding = TRUE;
1844 }
1845
1846 /**
1847  * The smallest header size that can occur. 
1848  * (It won't be valid)
1849  */
1850 #define DBUS_MINIMUM_HEADER_SIZE 16
1851
1852 /** Pack four characters as in "abcd" into a uint32 */
1853 #define FOUR_CHARS_TO_UINT32(a, b, c, d)                \
1854                       ((((dbus_uint32_t)a) << 24) |     \
1855                        (((dbus_uint32_t)b) << 16) |     \
1856                        (((dbus_uint32_t)c) << 8)  |     \
1857                        ((dbus_uint32_t)d))
1858
1859 /** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
1860 #define DBUS_HEADER_FIELD_NAME_AS_UINT32    \
1861   FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
1862
1863 /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
1864 #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
1865   FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
1866
1867 /** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
1868 #define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \
1869   FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
1870
1871 /** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
1872 #define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \
1873   FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
1874
1875 static dbus_bool_t
1876 decode_header_data (const DBusString   *data,
1877                     int                 header_len,
1878                     int                 byte_order,
1879                     HeaderField         fields[FIELD_LAST])
1880 {
1881   const char *field;
1882   int pos, new_pos;
1883   int i;
1884   
1885   if (header_len < 16)
1886     return FALSE;
1887   
1888   i = 0;
1889   while (i < FIELD_LAST)
1890     {
1891       fields[i].offset = -1;
1892       ++i;
1893     }
1894   
1895   fields[FIELD_HEADER_LENGTH].offset = 4;
1896   fields[FIELD_BODY_LENGTH].offset = 8;   
1897   fields[FIELD_CLIENT_SERIAL].offset = 12;
1898   
1899   /* Now handle the named fields. A real named field is at least 4
1900    * bytes for the name, plus a type code (1 byte) plus padding.  So
1901    * if we have less than 8 bytes left, it must be alignment padding,
1902    * not a field. While >= 8 bytes can't be entirely alignment
1903    * padding.
1904    */  
1905   pos = 16;
1906   while ((pos + 7) < header_len)
1907     {
1908       pos = _DBUS_ALIGN_VALUE (pos, 4);
1909       
1910       if ((pos + 4) > header_len)
1911         return FALSE;      
1912       
1913       _dbus_string_get_const_data_len (data, &field, pos, 4);
1914       pos += 4;
1915
1916       _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
1917
1918       /* I believe FROM_BE is right, but if not we'll find out
1919        * I guess. ;-)
1920        */
1921       switch (DBUS_UINT32_FROM_BE (*(int*)field))
1922         {
1923         case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
1924           if (fields[FIELD_SERVICE].offset >= 0)
1925             {
1926               _dbus_verbose ("%s field provided twice\n",
1927                              DBUS_HEADER_FIELD_SERVICE);
1928               return FALSE;
1929             }
1930           
1931           fields[FIELD_SERVICE].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1932           _dbus_verbose ("Found service name at offset %d\n",
1933                          fields[FIELD_SERVICE].offset);
1934           break;
1935
1936         case DBUS_HEADER_FIELD_NAME_AS_UINT32:
1937           if (fields[FIELD_NAME].offset >= 0)
1938             {
1939               _dbus_verbose ("%s field provided twice\n",
1940                              DBUS_HEADER_FIELD_NAME);
1941               return FALSE;
1942             }
1943           
1944           fields[FIELD_NAME].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1945
1946           _dbus_verbose ("Found message name at offset %d\n",
1947                          fields[FIELD_NAME].offset);
1948           break;
1949         case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
1950           if (fields[FIELD_SENDER].offset >= 0)
1951             {
1952               _dbus_verbose ("%s field provided twice\n",
1953                              DBUS_HEADER_FIELD_SENDER);
1954               return FALSE;
1955             }
1956           
1957           fields[FIELD_SENDER].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1958
1959           _dbus_verbose ("Found sender name at offset %d\n",
1960                          fields[FIELD_NAME].offset);
1961           break;
1962           
1963         case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
1964           if (fields[FIELD_REPLY_SERIAL].offset >= 0)
1965             {
1966               _dbus_verbose ("%s field provided twice\n",
1967                              DBUS_HEADER_FIELD_REPLY);
1968               return FALSE;
1969             }
1970           
1971           fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1972
1973           _dbus_verbose ("Found reply serial at offset %d\n",
1974                          fields[FIELD_REPLY_SERIAL].offset);
1975           break;
1976
1977         default:
1978           _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n",
1979                          field[0], field[1], field[2], field[3]);
1980         }
1981
1982       if (!_dbus_marshal_validate_arg (data, byte_order, pos, &new_pos))
1983         return FALSE;
1984
1985       if (new_pos > header_len)
1986         return FALSE;
1987       
1988       pos = new_pos;
1989     }
1990
1991   if (pos < header_len)
1992     {
1993       /* Alignment padding, verify that it's nul */
1994       _dbus_assert ((header_len - pos) < 8);
1995
1996       if (!_dbus_string_validate_nul (data,
1997                                       pos, (header_len - pos)))
1998         {
1999           _dbus_verbose ("header alignment padding is not nul\n");
2000           return FALSE;
2001         }
2002     }
2003   
2004   return TRUE;
2005 }
2006
2007 /**
2008  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
2009  * indicating to the loader how many bytes of the buffer were filled
2010  * in. This function must always be called, even if no bytes were
2011  * successfully read.
2012  *
2013  * @param loader the loader.
2014  * @param buffer the buffer.
2015  * @param bytes_read number of bytes that were read into the buffer.
2016  */
2017 void
2018 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
2019                                     DBusString         *buffer,
2020                                     int                 bytes_read)
2021 {
2022   _dbus_assert (loader->buffer_outstanding);
2023   _dbus_assert (buffer == &loader->data);
2024
2025   loader->buffer_outstanding = FALSE;
2026
2027   if (loader->corrupted)
2028     return;
2029
2030   while (_dbus_string_get_length (&loader->data) >= 16)
2031     {
2032       DBusMessage *message;      
2033       const char *header_data;
2034       int byte_order, header_len, body_len;
2035       dbus_uint32_t header_len_unsigned, body_len_unsigned;
2036       
2037       _dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
2038
2039       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
2040
2041       if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION)
2042         {
2043           _dbus_verbose ("Message has protocol version %d ours is %d\n",
2044                          (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION);
2045           loader->corrupted = TRUE;
2046           return;
2047         }
2048       
2049       byte_order = header_data[0];
2050
2051       if (byte_order != DBUS_LITTLE_ENDIAN &&
2052           byte_order != DBUS_BIG_ENDIAN)
2053         {
2054           _dbus_verbose ("Message with bad byte order '%c' received\n",
2055                          byte_order);
2056           loader->corrupted = TRUE;
2057           return;
2058         }
2059
2060       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
2061       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
2062
2063       if (header_len_unsigned < 16)
2064         {
2065           _dbus_verbose ("Message had broken too-small header length %u\n",
2066                          header_len_unsigned);
2067           loader->corrupted = TRUE;
2068           return;
2069         }
2070
2071       if (header_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE ||
2072           body_len_unsigned > (unsigned) MAX_SANE_MESSAGE_SIZE)
2073         {
2074           _dbus_verbose ("Header or body length too large (%u %u)\n",
2075                          header_len_unsigned,
2076                          body_len_unsigned);
2077           loader->corrupted = TRUE;
2078           return;
2079         }      
2080
2081       /* Now that we know the values are in signed range, get
2082        * rid of stupid unsigned, just causes bugs
2083        */
2084       header_len = header_len_unsigned;
2085       body_len = body_len_unsigned;
2086       
2087       if (_DBUS_ALIGN_VALUE (header_len, 8) != header_len_unsigned)
2088         {
2089           _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
2090                          header_len);
2091           loader->corrupted = TRUE;
2092           return;
2093         }
2094       
2095       if (header_len + body_len > loader->max_message_size)
2096         {
2097           _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
2098                          header_len, body_len, loader->max_message_size);
2099           loader->corrupted = TRUE;
2100           return;
2101         }
2102
2103       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
2104         {
2105           HeaderField fields[FIELD_LAST];
2106           int i;
2107           int next_arg;          
2108
2109           if (!decode_header_data (&loader->data, header_len, byte_order,
2110                                    fields))
2111             {
2112               loader->corrupted = TRUE;
2113               return;
2114             }
2115           
2116           next_arg = header_len;
2117           while (next_arg < (header_len + body_len))
2118             {
2119               int prev = next_arg;
2120
2121               if (!_dbus_marshal_validate_arg (&loader->data,
2122                                                byte_order,
2123                                                next_arg,
2124                                                &next_arg))
2125                 {
2126                   loader->corrupted = TRUE;
2127                   return;
2128                 }
2129
2130               _dbus_assert (next_arg > prev);
2131             }
2132           
2133           if (next_arg > (header_len + body_len))
2134             {
2135               _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
2136                              next_arg, header_len, body_len,
2137                              header_len + body_len);
2138               loader->corrupted = TRUE;
2139               return;
2140             }
2141
2142           message = dbus_message_new_empty_header ();
2143           if (message == NULL)
2144             break; /* ugh, postpone this I guess. */
2145
2146           message->byte_order = byte_order;
2147           
2148           /* Copy in the offsets we found */
2149           i = 0;
2150           while (i < FIELD_LAST)
2151             {
2152               message->header_fields[i] = fields[i];
2153               ++i;
2154             }
2155           
2156           if (!_dbus_list_append (&loader->messages, message))
2157             {
2158               dbus_message_unref (message);
2159               break;
2160             }
2161
2162           _dbus_assert (_dbus_string_get_length (&message->header) == 0);
2163           _dbus_assert (_dbus_string_get_length (&message->body) == 0);
2164
2165           _dbus_assert (_dbus_string_get_length (&loader->data) >=
2166                         (header_len + body_len));
2167           
2168           if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
2169             {
2170               _dbus_list_remove_last (&loader->messages, message);
2171               dbus_message_unref (message);
2172               break;
2173             }
2174           
2175           if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
2176             {
2177               dbus_bool_t result;
2178
2179               /* put the header back, we'll try again later */
2180               result = _dbus_string_copy_len (&message->header, 0, header_len,
2181                                               &loader->data, 0);
2182               _dbus_assert (result); /* because DBusString never reallocs smaller */
2183
2184               _dbus_list_remove_last (&loader->messages, message);
2185               dbus_message_unref (message);
2186               break;
2187             }
2188
2189           _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
2190           _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
2191
2192           _dbus_verbose ("Loaded message %p\n", message);
2193         }
2194       else
2195         break;
2196     }
2197 }
2198
2199 /**
2200  * Pops a loaded message (passing ownership of the message
2201  * to the caller). Returns #NULL if no messages have been
2202  * loaded.
2203  *
2204  * @param loader the loader.
2205  * @returns the next message, or #NULL if none.
2206  */
2207 DBusMessage*
2208 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
2209 {
2210   return _dbus_list_pop_first (&loader->messages);
2211 }
2212
2213
2214 /**
2215  * Checks whether the loader is confused due to bad data.
2216  * If messages are received that are invalid, the
2217  * loader gets confused and gives up permanently.
2218  * This state is called "corrupted."
2219  *
2220  * @param loader the loader
2221  * @returns #TRUE if the loader is hosed.
2222  */
2223 dbus_bool_t
2224 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
2225 {
2226   return loader->corrupted;
2227 }
2228
2229 /**
2230  * Sets the maximum size message we allow.
2231  *
2232  * @param loader the loader
2233  * @param size the max message size in bytes
2234  */
2235 void
2236 _dbus_message_loader_set_max_message_size (DBusMessageLoader  *loader,
2237                                            long                size)
2238 {
2239   if (size > MAX_SANE_MESSAGE_SIZE)
2240     {
2241       _dbus_verbose ("clamping requested max message size %ld to %d\n",
2242                      size, MAX_SANE_MESSAGE_SIZE);
2243       size = MAX_SANE_MESSAGE_SIZE;
2244     }
2245   loader->max_message_size = size;
2246 }
2247
2248 /**
2249  * Gets the maximum allowed message size in bytes.
2250  *
2251  * @param loader the loader
2252  * @returns max size in bytes
2253  */
2254 long
2255 _dbus_message_loader_get_max_message_size (DBusMessageLoader  *loader)
2256 {
2257   return loader->max_message_size;
2258 }
2259
2260 /** @} */
2261 #ifdef DBUS_BUILD_TESTS
2262 #include "dbus-test.h"
2263 #include <stdio.h>
2264
2265 static void
2266 message_iter_test (DBusMessage *message)
2267 {
2268   DBusMessageIter *iter;
2269   char *str;
2270   
2271   iter = dbus_message_get_fields_iter (message);
2272
2273   /* String tests */
2274   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_STRING)
2275     _dbus_assert_not_reached ("Field type isn't string");
2276
2277   str = dbus_message_iter_get_string (iter);
2278   if (strcmp (str, "Test string") != 0)
2279     _dbus_assert_not_reached ("Strings differ");
2280   dbus_free (str);
2281
2282   if (!dbus_message_iter_next (iter))
2283     _dbus_assert_not_reached ("Reached end of fields");
2284
2285   /* Signed integer tests */
2286   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_INT32)
2287     _dbus_assert_not_reached ("Field type isn't int32");
2288
2289   if (dbus_message_iter_get_int32 (iter) != -0x12345678)
2290     _dbus_assert_not_reached ("Signed integers differ");
2291
2292   if (!dbus_message_iter_next (iter))
2293     _dbus_assert_not_reached ("Reached end of fields");
2294   
2295   /* Unsigned integer tests */
2296   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_UINT32)
2297     _dbus_assert_not_reached ("Field type isn't int32");
2298
2299   if (dbus_message_iter_get_int32 (iter) != 0xedd1e)
2300     _dbus_assert_not_reached ("Unsigned integers differ");
2301
2302   if (!dbus_message_iter_next (iter))
2303     _dbus_assert_not_reached ("Reached end of fields");
2304
2305   /* Double tests */
2306   if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_DOUBLE)
2307     _dbus_assert_not_reached ("Field type isn't double");
2308
2309   if (dbus_message_iter_get_double (iter) != 3.14159)
2310     _dbus_assert_not_reached ("Doubles differ");
2311
2312   if (dbus_message_iter_next (iter))
2313     _dbus_assert_not_reached ("Didn't reach end of fields");
2314   
2315   dbus_message_iter_unref (iter);
2316 }
2317
2318 static dbus_bool_t
2319 check_message_handling (DBusMessage *message)
2320 {
2321   DBusMessageIter *iter;
2322   int type;
2323   dbus_bool_t retval;
2324   dbus_int32_t client_serial;
2325   
2326   retval = FALSE;
2327   iter = NULL;
2328   
2329   client_serial = _dbus_message_get_client_serial (message);
2330
2331   /* can't use set_client_serial due to the assertions at the start of it */
2332   set_int_field (message, FIELD_CLIENT_SERIAL,
2333                  client_serial);
2334
2335   if (client_serial != _dbus_message_get_client_serial (message))
2336     {
2337       _dbus_warn ("get/set cycle for client_serial did not succeed\n");
2338       goto failed;
2339     }
2340   
2341   /* If we implement message_set_field (message, n, value)
2342    * then we would want to test it here
2343    */
2344   
2345   iter = dbus_message_get_fields_iter (message);
2346   while ((type = dbus_message_iter_get_field_type (iter)) != DBUS_TYPE_INVALID)
2347     {
2348       switch (type)
2349         {
2350         case DBUS_TYPE_STRING:
2351           {
2352             char *str;
2353             str = dbus_message_iter_get_string (iter);
2354             dbus_free (str);
2355           }
2356           break;
2357         }
2358       
2359       if (!dbus_message_iter_next (iter))
2360         break;
2361     }
2362
2363   retval = TRUE;
2364   
2365  failed:
2366   if (iter)
2367     dbus_message_iter_unref (iter);
2368
2369   return retval;
2370 }
2371
2372 static dbus_bool_t
2373 check_have_valid_message (DBusMessageLoader *loader)
2374 {
2375   DBusMessage *message;
2376   dbus_bool_t retval;
2377
2378   message = NULL;
2379   retval = FALSE;
2380   
2381   if (_dbus_message_loader_get_is_corrupted (loader))
2382     {
2383       _dbus_warn ("loader corrupted on message that was expected to be valid\n");
2384       goto failed;
2385     }
2386   
2387   message = _dbus_message_loader_pop_message (loader);
2388   if (message == NULL)
2389     {
2390       _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
2391       goto failed;
2392     }
2393   
2394   if (_dbus_string_get_length (&loader->data) > 0)
2395     {
2396       _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
2397       goto failed;
2398     }
2399
2400   /* Verify that we're able to properly deal with the message.
2401    * For example, this would detect improper handling of messages
2402    * in nonstandard byte order.
2403    */
2404   if (!check_message_handling (message))
2405     goto failed;  
2406   
2407   retval = TRUE;
2408
2409  failed:
2410   if (message)
2411     dbus_message_unref (message);
2412   return retval;
2413 }
2414
2415 static dbus_bool_t
2416 check_invalid_message (DBusMessageLoader *loader)
2417 {
2418   dbus_bool_t retval;
2419
2420   retval = FALSE;
2421   
2422   if (!_dbus_message_loader_get_is_corrupted (loader))
2423     {
2424       _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
2425       goto failed;
2426     }
2427
2428   retval = TRUE;
2429
2430  failed:
2431   return retval;
2432 }
2433
2434 static dbus_bool_t
2435 check_incomplete_message (DBusMessageLoader *loader)
2436 {
2437   DBusMessage *message;
2438   dbus_bool_t retval;
2439
2440   message = NULL;
2441   retval = FALSE;
2442   
2443   if (_dbus_message_loader_get_is_corrupted (loader))
2444     {
2445       _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
2446       goto failed;
2447     }
2448   
2449   message = _dbus_message_loader_pop_message (loader);
2450   if (message != NULL)
2451     {
2452       _dbus_warn ("loaded message that was expected to be incomplete\n");
2453       goto failed;
2454     }
2455
2456   retval = TRUE;
2457
2458  failed:
2459   if (message)
2460     dbus_message_unref (message);
2461   return retval;
2462 }
2463
2464 static dbus_bool_t
2465 check_loader_results (DBusMessageLoader      *loader,
2466                       DBusMessageValidity     validity)
2467 {
2468   switch (validity)
2469     {
2470     case _DBUS_MESSAGE_VALID:
2471       return check_have_valid_message (loader);
2472     case _DBUS_MESSAGE_INVALID:
2473       return check_invalid_message (loader);
2474     case _DBUS_MESSAGE_INCOMPLETE:
2475       return check_incomplete_message (loader);
2476     case _DBUS_MESSAGE_UNKNOWN:
2477       return TRUE;
2478     }
2479
2480   _dbus_assert_not_reached ("bad DBusMessageValidity");
2481   return FALSE;
2482 }
2483
2484
2485 /**
2486  * Loads the message in the given message file.
2487  *
2488  * @param filename filename to load
2489  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
2490  * @param data string to load message into
2491  * @returns #TRUE if the message was loaded
2492  */
2493 dbus_bool_t
2494 dbus_internal_do_not_use_load_message_file (const DBusString    *filename,
2495                                             dbus_bool_t          is_raw,
2496                                             DBusString          *data)
2497 {
2498   dbus_bool_t retval;
2499
2500   retval = FALSE;  
2501
2502   if (is_raw)
2503     {
2504       DBusResultCode result;
2505
2506       result = _dbus_file_get_contents (data, filename);
2507       if (result != DBUS_RESULT_SUCCESS)
2508         {
2509           const char *s;      
2510           _dbus_string_get_const_data (filename, &s);
2511           _dbus_warn ("Could not load message file %s\n", s);
2512           goto failed;
2513         }
2514     }
2515   else
2516     {
2517       if (!_dbus_message_data_load (data, filename))
2518         {
2519           const char *s;      
2520           _dbus_string_get_const_data (filename, &s);
2521           _dbus_warn ("Could not load message file %s\n", s);
2522           goto failed;
2523         }
2524     }
2525
2526   retval = TRUE;
2527   
2528  failed:
2529
2530   return retval;
2531 }
2532
2533 /**
2534  * Tries loading the message in the given message file
2535  * and verifies that DBusMessageLoader can handle it.
2536  *
2537  * @param filename filename to load
2538  * @param is_raw if #TRUE load as binary data, if #FALSE as message builder language
2539  * @param expected_validity what the message has to be like to return #TRUE
2540  * @returns #TRUE if the message has the expected validity
2541  */
2542 dbus_bool_t
2543 dbus_internal_do_not_use_try_message_file (const DBusString    *filename,
2544                                            dbus_bool_t          is_raw,
2545                                            DBusMessageValidity  expected_validity)
2546 {
2547   DBusString data;
2548   dbus_bool_t retval;
2549
2550   retval = FALSE;
2551   
2552   if (!_dbus_string_init (&data, _DBUS_INT_MAX))
2553     _dbus_assert_not_reached ("could not allocate string\n");
2554
2555   if (!dbus_internal_do_not_use_load_message_file (filename, is_raw,
2556                                                    &data))
2557     goto failed;
2558
2559   retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity);
2560
2561  failed:
2562
2563   if (!retval)
2564     {
2565       const char *s;
2566
2567       if (_dbus_string_get_length (&data) > 0)
2568         _dbus_verbose_bytes_of_string (&data, 0,
2569                                        _dbus_string_get_length (&data));
2570       
2571       _dbus_string_get_const_data (filename, &s);
2572       _dbus_warn ("Failed message loader test on %s\n",
2573                   s);
2574     }
2575   
2576   _dbus_string_free (&data);
2577
2578   return retval;
2579 }
2580
2581 /**
2582  * Tries loading the given message data.
2583  *
2584  *
2585  * @param data the message data
2586  * @param expected_validity what the message has to be like to return #TRUE
2587  * @returns #TRUE if the message has the expected validity
2588  */
2589 dbus_bool_t
2590 dbus_internal_do_not_use_try_message_data (const DBusString    *data,
2591                                            DBusMessageValidity  expected_validity)
2592 {
2593   DBusMessageLoader *loader;
2594   dbus_bool_t retval;
2595   int len;
2596   int i;
2597
2598   loader = NULL;
2599   retval = FALSE;
2600
2601   /* Write the data one byte at a time */
2602   
2603   loader = _dbus_message_loader_new ();
2604
2605   len = _dbus_string_get_length (data);
2606   for (i = 0; i < len; i++)
2607     {
2608       DBusString *buffer;
2609
2610       _dbus_message_loader_get_buffer (loader, &buffer);
2611       _dbus_string_append_byte (buffer,
2612                                 _dbus_string_get_byte (data, i));
2613       _dbus_message_loader_return_buffer (loader, buffer, 1);
2614     }
2615   
2616   if (!check_loader_results (loader, expected_validity))
2617     goto failed;
2618
2619   _dbus_message_loader_unref (loader);
2620   loader = NULL;
2621
2622   /* Write the data all at once */
2623   
2624   loader = _dbus_message_loader_new ();
2625
2626   {
2627     DBusString *buffer;
2628     
2629     _dbus_message_loader_get_buffer (loader, &buffer);
2630     _dbus_string_copy (data, 0, buffer,
2631                        _dbus_string_get_length (buffer));
2632     _dbus_message_loader_return_buffer (loader, buffer, 1);
2633   }
2634   
2635   if (!check_loader_results (loader, expected_validity))
2636     goto failed;
2637
2638   _dbus_message_loader_unref (loader);
2639   loader = NULL;  
2640
2641   /* Write the data 2 bytes at a time */
2642   
2643   loader = _dbus_message_loader_new ();
2644
2645   len = _dbus_string_get_length (data);
2646   for (i = 0; i < len; i += 2)
2647     {
2648       DBusString *buffer;
2649
2650       _dbus_message_loader_get_buffer (loader, &buffer);
2651       _dbus_string_append_byte (buffer,
2652                                 _dbus_string_get_byte (data, i));
2653       if ((i+1) < len)
2654         _dbus_string_append_byte (buffer,
2655                                   _dbus_string_get_byte (data, i+1));
2656       _dbus_message_loader_return_buffer (loader, buffer, 1);
2657     }
2658   
2659   if (!check_loader_results (loader, expected_validity))
2660     goto failed;
2661
2662   _dbus_message_loader_unref (loader);
2663   loader = NULL;
2664   
2665   retval = TRUE;
2666   
2667  failed:
2668   
2669   if (loader)
2670     _dbus_message_loader_unref (loader);
2671   
2672   return retval;
2673 }
2674
2675 static dbus_bool_t
2676 process_test_subdir (const DBusString          *test_base_dir,
2677                      const char                *subdir,
2678                      DBusMessageValidity        validity,
2679                      DBusForeachMessageFileFunc function,
2680                      void                      *user_data)
2681 {
2682   DBusString test_directory;
2683   DBusString filename;
2684   DBusDirIter *dir;
2685   dbus_bool_t retval;
2686   DBusResultCode result;
2687
2688   retval = FALSE;
2689   dir = NULL;
2690   
2691   if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
2692     _dbus_assert_not_reached ("didn't allocate test_directory\n");
2693
2694   _dbus_string_init_const (&filename, subdir);
2695   
2696   if (!_dbus_string_copy (test_base_dir, 0,
2697                           &test_directory, 0))
2698     _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2699   
2700   if (!_dbus_concat_dir_and_file (&test_directory, &filename))    
2701     _dbus_assert_not_reached ("couldn't allocate full path");
2702
2703   _dbus_string_free (&filename);
2704   if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
2705     _dbus_assert_not_reached ("didn't allocate filename string\n");
2706   
2707   dir = _dbus_directory_open (&test_directory, &result);
2708   if (dir == NULL)
2709     {
2710       const char *s;
2711       _dbus_string_get_const_data (&test_directory, &s);
2712       _dbus_warn ("Could not open %s: %s\n", s,
2713                   dbus_result_to_string (result));
2714       goto failed;
2715     }
2716
2717   printf ("Testing:\n");
2718   
2719   result = DBUS_RESULT_SUCCESS;
2720  next:
2721   while (_dbus_directory_get_next_file (dir, &filename, &result))
2722     {
2723       DBusString full_path;
2724       dbus_bool_t is_raw;
2725       
2726       if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
2727         _dbus_assert_not_reached ("couldn't init string");
2728
2729       if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2730         _dbus_assert_not_reached ("couldn't copy dir to full_path");
2731
2732       if (!_dbus_concat_dir_and_file (&full_path, &filename))
2733         _dbus_assert_not_reached ("couldn't concat file to dir");
2734
2735       if (_dbus_string_ends_with_c_str (&filename, ".message"))
2736         is_raw = FALSE;
2737       else if (_dbus_string_ends_with_c_str (&filename, ".message-raw"))
2738         is_raw = TRUE;
2739       else
2740         {
2741           const char *filename_c;
2742           _dbus_string_get_const_data (&filename, &filename_c);
2743           _dbus_verbose ("Skipping non-.message file %s\n",
2744                          filename_c);
2745           goto next;
2746         }
2747
2748       {
2749         const char *s;
2750         _dbus_string_get_const_data (&filename, &s);
2751         printf ("    %s\n", s);
2752       }
2753       
2754       _dbus_verbose (" expecting %s\n",
2755                      validity == _DBUS_MESSAGE_VALID ? "valid" :
2756                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
2757                       (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")));
2758       
2759       if (! (*function) (&full_path, is_raw, validity, user_data))
2760         {
2761           _dbus_string_free (&full_path);
2762           goto failed;
2763         }
2764       else
2765         _dbus_string_free (&full_path);
2766     }
2767
2768   if (result != DBUS_RESULT_SUCCESS)
2769     {
2770       const char *s;
2771       _dbus_string_get_const_data (&test_directory, &s);
2772       _dbus_warn ("Could not get next file in %s: %s\n",
2773                   s, dbus_result_to_string (result));
2774       goto failed;
2775     }
2776     
2777   retval = TRUE;
2778   
2779  failed:
2780
2781   if (dir)
2782     _dbus_directory_close (dir);
2783   _dbus_string_free (&test_directory);
2784   _dbus_string_free (&filename);
2785
2786   return retval;
2787 }
2788                      
2789 /**
2790  * Runs the given function on every message file in the test suite.
2791  * The function should return #FALSE on test failure or fatal error.
2792  *
2793  * @param test_data_dir root dir of the test suite data files (top_srcdir/test/data)
2794  * @param func the function to run
2795  * @param user_data data for function
2796  * @returns #FALSE if there's a failure
2797  */
2798 dbus_bool_t
2799 dbus_internal_do_not_use_foreach_message_file (const char                *test_data_dir,
2800                                                DBusForeachMessageFileFunc func,
2801                                                void                      *user_data)
2802 {
2803   DBusString test_directory;
2804   dbus_bool_t retval;
2805
2806   retval = FALSE;
2807   
2808   _dbus_string_init_const (&test_directory, test_data_dir);
2809
2810   if (!process_test_subdir (&test_directory, "valid-messages",
2811                             _DBUS_MESSAGE_VALID, func, user_data))
2812     goto failed;
2813
2814   if (!process_test_subdir (&test_directory, "invalid-messages",
2815                             _DBUS_MESSAGE_INVALID, func, user_data))
2816     goto failed;
2817   
2818   if (!process_test_subdir (&test_directory, "incomplete-messages",
2819                             _DBUS_MESSAGE_INCOMPLETE, func, user_data))
2820     goto failed;
2821
2822   retval = TRUE;
2823   
2824  failed:
2825
2826   _dbus_string_free (&test_directory);
2827   
2828   return retval;
2829 }
2830
2831 /**
2832  * @ingroup DBusMessageInternals
2833  * Unit test for DBusMessage.
2834  *
2835  * @returns #TRUE on success.
2836  */
2837 dbus_bool_t
2838 _dbus_message_test (const char *test_data_dir)
2839 {
2840   DBusMessage *message;
2841   DBusMessageLoader *loader;
2842   int i;
2843   const char *data;
2844   dbus_int32_t our_int;
2845   char *our_str;
2846   double our_double;
2847   
2848   /* Test the vararg functions */
2849   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2850   _dbus_message_set_client_serial (message, 1);
2851   dbus_message_append_fields (message,
2852                               DBUS_TYPE_INT32, -0x12345678,
2853                               DBUS_TYPE_STRING, "Test string",
2854                               DBUS_TYPE_DOUBLE, 3.14159,
2855                               0);
2856   _dbus_verbose_bytes_of_string (&message->header, 0,
2857                                  _dbus_string_get_length (&message->header));
2858   _dbus_verbose_bytes_of_string (&message->body, 0,
2859                                  _dbus_string_get_length (&message->body));
2860   
2861   if (dbus_message_get_fields (message,
2862                                DBUS_TYPE_INT32, &our_int,
2863                                DBUS_TYPE_STRING, &our_str,
2864                                DBUS_TYPE_DOUBLE, &our_double,
2865                                0) != DBUS_RESULT_SUCCESS)
2866     _dbus_assert_not_reached ("Could not get fields");
2867
2868   if (our_int != -0x12345678)
2869     _dbus_assert_not_reached ("integers differ!");
2870
2871   if (our_double != 3.14159)
2872     _dbus_assert_not_reached ("doubles differ!");
2873
2874   if (strcmp (our_str, "Test string") != 0)
2875     _dbus_assert_not_reached ("strings differ!");
2876
2877   dbus_free (our_str);
2878   dbus_message_unref (message);
2879   
2880   message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2881   _dbus_message_set_client_serial (message, 1);
2882   _dbus_message_set_reply_serial (message, 0x12345678);
2883
2884   dbus_message_append_string (message, "Test string");
2885   dbus_message_append_int32 (message, -0x12345678);
2886   dbus_message_append_uint32 (message, 0xedd1e);
2887   dbus_message_append_double (message, 3.14159);
2888
2889   message_iter_test (message);
2890
2891   /* Message loader test */
2892   _dbus_message_lock (message);
2893   loader = _dbus_message_loader_new ();
2894
2895   /* Write the header data one byte at a time */
2896   _dbus_string_get_const_data (&message->header, &data);
2897   for (i = 0; i < _dbus_string_get_length (&message->header); i++)
2898     {
2899       DBusString *buffer;
2900
2901       _dbus_message_loader_get_buffer (loader, &buffer);
2902       _dbus_string_append_byte (buffer, data[i]);
2903       _dbus_message_loader_return_buffer (loader, buffer, 1);
2904     }
2905
2906   /* Write the body data one byte at a time */
2907   _dbus_string_get_const_data (&message->body, &data);
2908   for (i = 0; i < _dbus_string_get_length (&message->body); i++)
2909     {
2910       DBusString *buffer;
2911
2912       _dbus_message_loader_get_buffer (loader, &buffer);
2913       _dbus_string_append_byte (buffer, data[i]);
2914       _dbus_message_loader_return_buffer (loader, buffer, 1);
2915     }
2916
2917   dbus_message_unref (message);
2918
2919   /* Now pop back the message */
2920   if (_dbus_message_loader_get_is_corrupted (loader))
2921     _dbus_assert_not_reached ("message loader corrupted");
2922   
2923   message = _dbus_message_loader_pop_message (loader);
2924   if (!message)
2925     _dbus_assert_not_reached ("received a NULL message");
2926
2927   if (_dbus_message_get_reply_serial (message) != 0x12345678)
2928     _dbus_assert_not_reached ("reply serial fields differ");
2929   
2930   message_iter_test (message);
2931   
2932   dbus_message_unref (message);
2933   _dbus_message_loader_unref (loader);
2934
2935   /* Now load every message in test_data_dir if we have one */
2936   if (test_data_dir == NULL)
2937     return TRUE;
2938
2939   return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
2940                                                         (DBusForeachMessageFileFunc)
2941                                                         dbus_internal_do_not_use_try_message_file,
2942                                                         NULL);
2943 }
2944
2945 #endif /* DBUS_BUILD_TESTS */