1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c DBusMessage object
4 * Copyright (C) 2002, 2003 Red Hat Inc.
5 * Copyright (C) 2002, 2003 CodeFactory AB
7 * Licensed under the Academic Free License version 1.2
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.
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.
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
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"
35 * @defgroup DBusMessageInternals DBusMessage implementation details
36 * @ingroup DBusInternals
37 * @brief DBusMessage private implementation details.
39 * The guts of DBusMessage and its methods.
57 static dbus_bool_t field_is_named[FIELD_LAST] =
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 */
70 int offset; /**< Offset to start of field (location of name of field
76 * @brief Internals of DBusMessage
78 * Object representing a message received from or to be sent to
79 * another application. This is an opaque object, all members
84 int refcount; /**< Reference count */
86 DBusString header; /**< Header network data, stored
87 * separately from body so we can
88 * independently realloc it.
91 HeaderField header_fields[FIELD_LAST]; /**< Track the location
92 * of each field in "header"
94 int header_padding; /**< bytes of alignment in header */
96 DBusString body; /**< Body network data. */
98 char byte_order; /**< Message byte order. */
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. */
103 unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
107 * @brief Internals of DBusMessageIter
109 * Object representing a position in a message. All fields are internal.
111 struct DBusMessageIter
113 int refcount; /**< Reference count */
115 int pos; /**< Current position in the string */
117 DBusMessage *message; /**< Message used */
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()).
126 * @param message the message.
127 * @param header return location for message header data.
128 * @param body return location for message body data.
131 _dbus_message_get_network_data (DBusMessage *message,
132 const DBusString **header,
133 const DBusString **body)
135 _dbus_assert (message->locked);
137 *header = &message->header;
138 *body = &message->body;
142 clear_header_padding (DBusMessage *message)
144 _dbus_string_shorten (&message->header,
145 message->header_padding);
146 message->header_padding = 0;
150 append_header_padding (DBusMessage *message)
153 old_len = _dbus_string_get_length (&message->header);
154 if (!_dbus_string_align_length (&message->header, 8))
157 message->header_padding = _dbus_string_get_length (&message->header) - old_len;
163 adjust_field_offsets (DBusMessage *message,
173 while (i < FIELD_LAST)
175 if (message->header_fields[i].offset > offsets_after)
176 message->header_fields[i].offset += delta;
183 get_string_field (DBusMessage *message,
187 int offset = message->header_fields[field].offset;
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.
199 *len = _dbus_demarshal_uint32 (&message->header,
204 _dbus_string_get_const_data (&message->header,
207 return data + (offset + 4);
211 get_int_field (DBusMessage *message,
214 int offset = message->header_fields[field].offset;
217 return -1; /* useless if -1 is a valid value of course */
219 return _dbus_demarshal_int32 (&message->header,
226 append_int_field (DBusMessage *message,
233 _dbus_assert (!message->locked);
235 clear_header_padding (message);
237 orig_len = _dbus_string_get_length (&message->header);
239 if (!_dbus_string_align_length (&message->header, 4))
242 if (!_dbus_string_append_len (&message->header, name, 4))
245 if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
248 if (!_dbus_string_align_length (&message->header, 4))
251 message->header_fields[FIELD_REPLY_SERIAL].offset =
252 _dbus_string_get_length (&message->header);
254 if (!_dbus_marshal_int32 (&message->header, message->byte_order,
258 if (!append_header_padding (message))
264 message->header_fields[field].offset = -1;
265 _dbus_string_set_length (&message->header, orig_len);
267 /* this must succeed because it was allocated on function entry and
268 * DBusString doesn't ever realloc smaller
270 if (!append_header_padding (message))
271 _dbus_assert_not_reached ("failed to reappend header padding");
276 append_string_field (DBusMessage *message,
283 _dbus_assert (!message->locked);
285 clear_header_padding (message);
287 orig_len = _dbus_string_get_length (&message->header);
289 if (!_dbus_string_align_length (&message->header, 4))
292 if (!_dbus_string_append_len (&message->header, name, 4))
295 if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
298 if (!_dbus_string_align_length (&message->header, 4))
301 message->header_fields[field].offset =
302 _dbus_string_get_length (&message->header);
304 if (!_dbus_marshal_string (&message->header, message->byte_order,
308 if (!append_header_padding (message))
314 message->header_fields[field].offset = -1;
315 _dbus_string_set_length (&message->header, orig_len);
317 /* this must succeed because it was allocated on function entry and
318 * DBusString doesn't ever realloc smaller
320 if (!append_header_padding (message))
321 _dbus_assert_not_reached ("failed to reappend header padding");
327 delete_int_field (DBusMessage *message,
330 int offset = message->header_fields[field].offset;
332 _dbus_assert (!message->locked);
333 _dbus_assert (field_is_named[field]);
338 clear_header_padding (message);
340 /* The field typecode and name take up 8 bytes */
341 _dbus_string_delete (&message->header,
345 message->header_fields[field].offset = -1;
347 adjust_field_offsets (message,
351 append_header_padding (message);
355 delete_string_field (DBusMessage *message,
358 int offset = message->header_fields[field].offset;
362 _dbus_assert (!message->locked);
363 _dbus_assert (field_is_named[field]);
368 clear_header_padding (message);
370 get_string_field (message, field, &len);
372 /* The field typecode and name take up 8 bytes, and the nul
373 * termination is 1 bytes, string length integer is 4 bytes
375 delete_len = 8 + 4 + 1 + len;
377 _dbus_string_delete (&message->header,
381 message->header_fields[field].offset = -1;
383 adjust_field_offsets (message,
387 append_header_padding (message);
391 set_int_field (DBusMessage *message,
395 int offset = message->header_fields[field].offset;
397 _dbus_assert (!message->locked);
401 /* need to append the field */
405 case FIELD_REPLY_SERIAL:
406 return append_int_field (message, field,
407 DBUS_HEADER_FIELD_REPLY,
410 _dbus_assert_not_reached ("appending an int field we don't support appending");
416 _dbus_marshal_set_int32 (&message->header,
425 set_string_field (DBusMessage *message,
429 int offset = message->header_fields[field].offset;
431 _dbus_assert (!message->locked);
432 _dbus_assert (value != NULL);
436 /* need to append the field */
441 return append_string_field (message, field,
442 DBUS_HEADER_FIELD_SENDER,
445 _dbus_assert_not_reached ("appending a string field we don't support appending");
455 old_len = _dbus_string_get_length (&message->header);
457 _dbus_string_init_const_len (&v, value,
458 strlen (value) + 1); /* include nul */
459 if (!_dbus_marshal_set_string (&message->header,
464 new_len = _dbus_string_get_length (&message->header);
466 adjust_field_offsets (message,
475 * Sets the client serial of a message.
476 * This can only be done once on a message.
478 * @todo client_serial should be called simply
479 * "serial"; it's in outgoing messages for both
480 * the client and the server, it's only client-specific
481 * in the message bus case. It's more like origin_serial
484 * @param message the message
485 * @param client_serial the client serial
488 _dbus_message_set_client_serial (DBusMessage *message,
489 dbus_int32_t client_serial)
491 _dbus_assert (!message->locked);
492 _dbus_assert (_dbus_message_get_client_serial (message) < 0);
494 set_int_field (message, FIELD_CLIENT_SERIAL,
499 * Sets the reply serial of a message (the client serial
500 * of the message this is a reply to).
502 * @param message the message
503 * @param reply_serial the client serial
504 * @returns #FALSE if not enough memory
507 _dbus_message_set_reply_serial (DBusMessage *message,
508 dbus_int32_t reply_serial)
510 _dbus_assert (!message->locked);
512 return set_int_field (message, FIELD_REPLY_SERIAL,
517 * Returns the client serial of a message or
518 * -1 if none has been specified.
520 * @todo see note in _dbus_message_set_client_serial()
521 * about how client_serial is a misnomer
523 * @todo this function should be public, after renaming it.
525 * @param message the message
526 * @returns the client serial
529 _dbus_message_get_client_serial (DBusMessage *message)
531 return get_int_field (message, FIELD_CLIENT_SERIAL);
535 * Returns the serial that the message is
536 * a reply to or -1 if none.
538 * @param message the message
539 * @returns the reply serial
542 _dbus_message_get_reply_serial (DBusMessage *message)
544 return get_int_field (message, FIELD_REPLY_SERIAL);
548 * Adds a counter to be incremented immediately with the
549 * size of this message, and decremented by the size
550 * of this message when this message if finalized.
552 * @param message the message
553 * @param counter the counter
556 _dbus_message_add_size_counter (DBusMessage *message,
557 DBusCounter *counter)
559 _dbus_assert (message->size_counter == NULL); /* If this fails we may need to keep a list of
560 * counters instead of just one
563 message->size_counter = counter;
564 _dbus_counter_ref (message->size_counter);
566 /* When we can change message size, we may want to
567 * update this each time we do so, or we may want to
568 * just KISS like this.
570 message->size_counter_delta =
571 _dbus_string_get_length (&message->header) +
572 _dbus_string_get_length (&message->body);
574 _dbus_verbose ("message has size %ld\n",
575 message->size_counter_delta);
577 _dbus_counter_adjust (message->size_counter, message->size_counter_delta);
581 dbus_message_create_header (DBusMessage *message,
585 if (!_dbus_string_append_byte (&message->header, message->byte_order))
588 if (!_dbus_string_append_len (&message->header, "\0\0\0", 3))
591 message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
592 if (!_dbus_marshal_int32 (&message->header, message->byte_order, 0))
595 message->header_fields[FIELD_BODY_LENGTH].offset = 8;
596 if (!_dbus_marshal_int32 (&message->header, message->byte_order, 0))
599 message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
600 if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
603 /* Marshal message service */
606 if (!append_string_field (message,
608 DBUS_HEADER_FIELD_SERVICE,
613 _dbus_assert (name != NULL);
614 if (!append_string_field (message,
616 DBUS_HEADER_FIELD_NAME,
624 * Locks a message. Allows checking that applications don't keep a
625 * reference to a message in the outgoing queue and change it
626 * underneath us. Messages are locked when they enter the outgoing
627 * queue (dbus_connection_send_message()), and the library complains
628 * if the message is modified while locked.
630 * @param message the message to lock.
633 _dbus_message_lock (DBusMessage *message)
635 if (!message->locked)
637 /* Fill in our lengths */
638 set_int_field (message,
640 _dbus_string_get_length (&message->header));
642 set_int_field (message,
644 _dbus_string_get_length (&message->body));
646 message->locked = TRUE;
653 * @defgroup DBusMessage DBusMessage
655 * @brief Message to be sent or received over a DBusConnection.
657 * A DBusMessage is the most basic unit of communication over a
658 * DBusConnection. A DBusConnection represents a stream of messages
659 * received from a remote application, and a stream of messages
660 * sent to a remote application.
666 * @typedef DBusMessage
668 * Opaque data type representing a message received from or to be
669 * sent to another application.
673 dbus_message_new_empty_header (void)
675 DBusMessage *message;
678 message = dbus_new0 (DBusMessage, 1);
682 message->refcount = 1;
683 message->byte_order = DBUS_COMPILER_BYTE_ORDER;
686 while (i < FIELD_LAST)
688 message->header_fields[i].offset = -1;
692 if (!_dbus_string_init (&message->header, _DBUS_INT_MAX))
698 if (!_dbus_string_init (&message->body, _DBUS_INT_MAX))
700 _dbus_string_free (&message->header);
710 * Constructs a new message. Returns #NULL if memory
711 * can't be allocated for the message.
713 * @todo use DBusString internally to store service and name.
715 * @param service service that the message should be sent to
716 * @param name name of the message
717 * @returns a new DBusMessage, free with dbus_message_unref()
718 * @see dbus_message_unref()
721 dbus_message_new (const char *service,
724 DBusMessage *message;
726 message = dbus_message_new_empty_header ();
730 if (!dbus_message_create_header (message, service, name))
732 dbus_message_unref (message);
740 * Constructs a message that is a reply to some other
741 * message. Returns #NULL if memory can't be allocated
744 * @param name the name of the message
745 * @param original_message the message which the created
746 * message is a reply to.
747 * @returns a new DBusMessage, free with dbus_message_unref()
748 * @see dbus_message_new(), dbus_message_unref()
751 dbus_message_new_reply (const char *name,
752 DBusMessage *original_message)
754 DBusMessage *message;
757 sender = get_string_field (original_message,
760 _dbus_assert (sender != NULL);
762 message = dbus_message_new (sender, name);
767 if (!_dbus_message_set_reply_serial (message,
768 _dbus_message_get_client_serial (original_message)))
770 dbus_message_unref (message);
778 * Creates a new message that is an exact replica of the message
779 * specified, except that its refcount is set to 1.
781 * @param message the message.
782 * @returns the new message.
784 dbus_message_new_from_message (const DBusMessage *message)
789 retval = dbus_new0 (DBusMessage, 1);
793 retval->refcount = 1;
794 retval->byte_order = message->byte_order;
796 if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
802 if (!_dbus_string_init (&retval->body, _DBUS_INT_MAX))
804 _dbus_string_free (&retval->header);
809 if (!_dbus_string_copy (&message->header, 0,
812 _dbus_string_free (&retval->header);
813 _dbus_string_free (&retval->body);
819 if (!_dbus_string_copy (&message->body, 0,
822 _dbus_string_free (&retval->header);
823 _dbus_string_free (&retval->body);
829 for (i = 0; i < FIELD_LAST; i++)
831 retval->header_fields[i].offset = message->header_fields[i].offset;
839 * Increments the reference count of a DBusMessage.
841 * @param message The message
842 * @see dbus_message_unref
845 dbus_message_ref (DBusMessage *message)
847 _dbus_assert (message->refcount > 0);
849 message->refcount += 1;
853 * Decrements the reference count of a DBusMessage.
855 * @param message The message
856 * @see dbus_message_ref
859 dbus_message_unref (DBusMessage *message)
861 _dbus_assert (message->refcount > 0);
863 message->refcount -= 1;
864 if (message->refcount == 0)
866 if (message->size_counter != NULL)
868 _dbus_counter_adjust (message->size_counter,
869 - message->size_counter_delta);
870 _dbus_counter_unref (message->size_counter);
873 _dbus_string_free (&message->header);
874 _dbus_string_free (&message->body);
881 * Gets the name of a message.
883 * @param message the message
884 * @returns the message name (should not be freed)
887 dbus_message_get_name (DBusMessage *message)
889 return get_string_field (message, FIELD_NAME, NULL);
893 * Gets the destination service of a message.
895 * @param message the message
896 * @returns the message destination service (should not be freed)
899 dbus_message_get_service (DBusMessage *message)
901 return get_string_field (message, FIELD_SERVICE, NULL);
905 * Appends fields to a message given a variable argument
906 * list. The variable argument list should contain the type
907 * of the field followed by the value to add.
908 * The list is terminated with 0.
910 * @param message the message
911 * @param first_field_type type of the first field
912 * @param ... value of first field, list of additional type-value pairs
913 * @returns #TRUE on success
916 dbus_message_append_fields (DBusMessage *message,
917 int first_field_type,
923 va_start (var_args, first_field_type);
924 retval = dbus_message_append_fields_valist (message,
933 * This function takes a va_list for use by language bindings
935 * @see dbus_message_append_fields.
936 * @param message the message
937 * @param first_field_type type of first field
938 * @param var_args value of first field, then list of type/value pairs
939 * @returns #TRUE on success
942 dbus_message_append_fields_valist (DBusMessage *message,
943 int first_field_type,
948 old_len = _dbus_string_get_length (&message->body);
950 type = first_field_type;
956 case DBUS_TYPE_INT32:
957 if (!dbus_message_append_int32 (message, va_arg (var_args, dbus_int32_t)))
960 case DBUS_TYPE_UINT32:
961 if (!dbus_message_append_uint32 (message, va_arg (var_args, dbus_uint32_t)))
964 case DBUS_TYPE_DOUBLE:
965 if (!dbus_message_append_double (message, va_arg (var_args, double)))
968 case DBUS_TYPE_STRING:
969 if (!dbus_message_append_string (message, va_arg (var_args, const char *)))
972 case DBUS_TYPE_BYTE_ARRAY:
977 data = va_arg (var_args, unsigned char *);
978 len = va_arg (var_args, int);
980 if (!dbus_message_append_byte_array (message, data, len))
984 case DBUS_TYPE_STRING_ARRAY:
989 data = va_arg (var_args, const char **);
990 len = va_arg (var_args, int);
992 if (!dbus_message_append_string_array (message, data, len))
998 _dbus_warn ("Unknown field type %d\n", type);
1001 type = va_arg (var_args, int);
1007 _dbus_string_set_length (&message->body, old_len);
1012 * Appends a 32 bit signed integer to the message.
1014 * @param message the message
1015 * @param value the integer value
1016 * @returns #TRUE on success
1019 dbus_message_append_int32 (DBusMessage *message,
1022 _dbus_assert (!message->locked);
1024 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
1026 _dbus_string_shorten (&message->body, 1);
1030 return _dbus_marshal_int32 (&message->body,
1031 message->byte_order, value);
1035 * Appends a 32 bit unsigned integer to the message.
1037 * @param message the message
1038 * @param value the integer value
1039 * @returns #TRUE on success
1042 dbus_message_append_uint32 (DBusMessage *message,
1043 dbus_uint32_t value)
1045 _dbus_assert (!message->locked);
1047 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UINT32))
1049 _dbus_string_shorten (&message->body, 1);
1053 return _dbus_marshal_uint32 (&message->body,
1054 message->byte_order, value);
1058 * Appends a double value to the message.
1060 * @param message the message
1061 * @param value the double value
1062 * @returns #TRUE on success
1065 dbus_message_append_double (DBusMessage *message,
1068 _dbus_assert (!message->locked);
1070 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_DOUBLE))
1072 _dbus_string_shorten (&message->body, 1);
1076 return _dbus_marshal_double (&message->body,
1077 message->byte_order, value);
1081 * Appends a UTF-8 string to the message.
1083 * @param message the message
1084 * @param value the string
1085 * @returns #TRUE on success
1088 dbus_message_append_string (DBusMessage *message,
1091 _dbus_assert (!message->locked);
1093 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING))
1095 _dbus_string_shorten (&message->body, 1);
1099 return _dbus_marshal_string (&message->body,
1100 message->byte_order, value);
1104 * Appends a byte array to the message.
1106 * @param message the message
1107 * @param value the array
1108 * @param len the length of the array
1109 * @returns #TRUE on success
1112 dbus_message_append_byte_array (DBusMessage *message,
1113 unsigned const char *value,
1116 _dbus_assert (!message->locked);
1118 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_BYTE_ARRAY))
1120 _dbus_string_shorten (&message->body, 1);
1124 return _dbus_marshal_byte_array (&message->body,
1125 message->byte_order, value, len);
1129 * Appends a string array to the message.
1131 * @param message the message
1132 * @param value the array
1133 * @param len the length of the array
1134 * @returns #TRUE on success
1137 dbus_message_append_string_array (DBusMessage *message,
1141 _dbus_assert (!message->locked);
1143 if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING_ARRAY))
1145 _dbus_string_shorten (&message->body, 1);
1149 return _dbus_marshal_string_array (&message->body,
1150 message->byte_order, value, len);
1154 * Gets fields from a message given a variable argument list.
1155 * The variable argument list should contain the type of the
1156 * field followed by a pointer to where the value should be
1157 * stored. The list is terminated with 0.
1159 * @todo rename get_args to avoid confusion with header fields
1161 * @param message the message
1162 * @param first_field_type the first field type
1163 * @param ... location for first field value, then list of type-location pairs
1164 * @returns result code
1167 dbus_message_get_fields (DBusMessage *message,
1168 int first_field_type,
1171 DBusResultCode retval;
1174 va_start (var_args, first_field_type);
1175 retval = dbus_message_get_fields_valist (message, first_field_type, var_args);
1182 * This function takes a va_list for use by language bindings
1184 * @todo this function (or some lower-level non-convenience function)
1185 * needs better error handling; should allow the application to
1186 * distinguish between out of memory, and bad data from the remote
1187 * app. It also needs to not leak a bunch of args when it gets
1188 * to the arg that's bad, as that would be a security hole
1189 * (allow one app to force another to leak memory)
1191 * @todo We need to free the field data when an error occurs.
1193 * @todo rename get_args_valist to avoid confusion with header fields
1195 * @see dbus_message_get_fields
1196 * @param message the message
1197 * @param first_field_type type of the first field
1198 * @param var_args return location for first field, followed by list of type/location pairs
1199 * @returns result code
1202 dbus_message_get_fields_valist (DBusMessage *message,
1203 int first_field_type,
1206 int spec_type, msg_type, i;
1207 DBusMessageIter *iter;
1209 iter = dbus_message_get_fields_iter (message);
1212 return DBUS_RESULT_NO_MEMORY;
1214 spec_type = first_field_type;
1217 while (spec_type != 0)
1219 msg_type = dbus_message_iter_get_field_type (iter);
1221 if (msg_type != spec_type)
1223 _dbus_verbose ("Field %d is specified to be of type \"%s\", but "
1224 "is actually of type \"%s\"\n", i,
1225 _dbus_type_to_string (spec_type),
1226 _dbus_type_to_string (msg_type));
1227 dbus_message_iter_unref (iter);
1229 return DBUS_RESULT_INVALID_FIELDS;
1234 case DBUS_TYPE_INT32:
1238 ptr = va_arg (var_args, dbus_int32_t *);
1240 *ptr = dbus_message_iter_get_int32 (iter);
1243 case DBUS_TYPE_UINT32:
1247 ptr = va_arg (var_args, dbus_uint32_t *);
1249 *ptr = dbus_message_iter_get_uint32 (iter);
1253 case DBUS_TYPE_DOUBLE:
1257 ptr = va_arg (var_args, double *);
1259 *ptr = dbus_message_iter_get_double (iter);
1263 case DBUS_TYPE_STRING:
1267 ptr = va_arg (var_args, char **);
1269 *ptr = dbus_message_iter_get_string (iter);
1272 return DBUS_RESULT_NO_MEMORY;
1277 case DBUS_TYPE_BYTE_ARRAY:
1279 unsigned char **ptr;
1282 ptr = va_arg (var_args, unsigned char **);
1283 len = va_arg (var_args, int *);
1285 *ptr = dbus_message_iter_get_byte_array (iter, len);
1288 return DBUS_RESULT_NO_MEMORY;
1292 case DBUS_TYPE_STRING_ARRAY:
1297 ptr = va_arg (var_args, char ***);
1298 len = va_arg (var_args, int *);
1300 *ptr = dbus_message_iter_get_string_array (iter, len);
1303 return DBUS_RESULT_NO_MEMORY;
1308 _dbus_warn ("Unknown field type %d\n", spec_type);
1311 spec_type = va_arg (var_args, int);
1312 if (spec_type != 0 && !dbus_message_iter_next (iter))
1314 _dbus_verbose ("More fields than exist in the message were specified or field is corrupt\n");
1316 dbus_message_iter_unref (iter);
1317 return DBUS_RESULT_INVALID_FIELDS;
1322 dbus_message_iter_unref (iter);
1323 return DBUS_RESULT_SUCCESS;
1327 * Returns a DBusMessageIter representing the fields of the
1328 * message passed in.
1330 * @todo IMO the message iter should follow the GtkTextIter pattern,
1331 * a static object with a "stamp" value used to detect invalid
1332 * iter uses (uninitialized or after changing the message).
1333 * ref/unref is kind of annoying to deal with, and slower too.
1334 * This implies not ref'ing the message from the iter.
1336 * @todo rename get_args_iter to avoid confusion with header fields
1338 * @param message the message
1339 * @returns a new iter.
1342 dbus_message_get_fields_iter (DBusMessage *message)
1344 DBusMessageIter *iter;
1346 iter = dbus_new (DBusMessageIter, 1);
1348 dbus_message_ref (message);
1351 iter->message = message;
1358 * Increments the reference count of a DBusMessageIter.
1360 * @param iter the message iter
1361 * @see dbus_message_iter_unref
1364 dbus_message_iter_ref (DBusMessageIter *iter)
1366 _dbus_assert (iter->refcount > 0);
1368 iter->refcount += 1;
1372 * Decrements the reference count of a DBusMessageIter.
1374 * @param iter The message iter
1375 * @see dbus_message_iter_ref
1378 dbus_message_iter_unref (DBusMessageIter *iter)
1380 _dbus_assert (iter->refcount > 0);
1382 iter->refcount -= 1;
1384 if (iter->refcount == 0)
1386 dbus_message_unref (iter->message);
1393 * Checks if an iterator has any more fields.
1395 * @param iter the message iter
1396 * @returns #TRUE if there are more fields
1400 dbus_message_iter_has_next (DBusMessageIter *iter)
1404 if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1405 iter->message->byte_order,
1406 iter->pos, &end_pos))
1409 if (end_pos >= _dbus_string_get_length (&iter->message->body))
1416 * Moves the iterator to the next field.
1418 * @param iter The message iter
1419 * @returns #TRUE if the iterator was moved to the next field
1422 dbus_message_iter_next (DBusMessageIter *iter)
1426 if (!_dbus_marshal_get_arg_end_pos (&iter->message->body,
1427 iter->message->byte_order,
1428 iter->pos, &end_pos))
1431 if (end_pos >= _dbus_string_get_length (&iter->message->body))
1434 iter->pos = end_pos;
1440 * Returns the field type of the field that the
1441 * message iterator points at.
1443 * @param iter the message iter
1444 * @returns the field type
1447 dbus_message_iter_get_field_type (DBusMessageIter *iter)
1451 if (iter->pos >= _dbus_string_get_length (&iter->message->body))
1452 return DBUS_TYPE_INVALID;
1454 _dbus_string_get_const_data_len (&iter->message->body, &data, iter->pos, 1);
1456 if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_STRING_ARRAY)
1459 return DBUS_TYPE_INVALID;
1463 * Returns the string value that an iterator may point to.
1464 * Note that you need to check that the iterator points to
1465 * a string value before using this function.
1467 * @see dbus_message_iter_get_field_type
1468 * @param iter the message iter
1469 * @returns the string
1472 dbus_message_iter_get_string (DBusMessageIter *iter)
1474 _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING);
1476 return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
1477 iter->pos + 1, NULL);
1481 * Returns the 32 bit signed integer value that an iterator may point to.
1482 * Note that you need to check that the iterator points to
1483 * a string value before using this function.
1485 * @see dbus_message_iter_get_field_type
1486 * @param iter the message iter
1487 * @returns the integer
1490 dbus_message_iter_get_int32 (DBusMessageIter *iter)
1492 return _dbus_demarshal_int32 (&iter->message->body, iter->message->byte_order,
1493 iter->pos + 1, NULL);
1497 * Returns the 32 bit unsigned integer value that an iterator may point to.
1498 * Note that you need to check that the iterator points to
1499 * a string value before using this function.
1501 * @see dbus_message_iter_get_field_type
1502 * @param iter the message iter
1503 * @returns the integer
1506 dbus_message_iter_get_uint32 (DBusMessageIter *iter)
1508 return _dbus_demarshal_uint32 (&iter->message->body, iter->message->byte_order,
1509 iter->pos + 1, NULL);
1513 * Returns the double value that an iterator may point to.
1514 * Note that you need to check that the iterator points to
1515 * a string value before using this function.
1517 * @see dbus_message_iter_get_field_type
1518 * @param iter the message iter
1519 * @returns the double
1522 dbus_message_iter_get_double (DBusMessageIter *iter)
1524 return _dbus_demarshal_double (&iter->message->body, iter->message->byte_order,
1525 iter->pos + 1, NULL);
1529 * Returns the byte array that the iterator may point to.
1530 * Note that you need to check that the iterator points
1531 * to a byte array prior to using this function.
1533 * @todo this function should probably take "unsigned char **" as
1534 * an out param argument, and return boolean or result code.
1536 * @param iter the iterator
1537 * @param len return location for length of byte array
1538 * @returns the byte array
1541 dbus_message_iter_get_byte_array (DBusMessageIter *iter,
1544 _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_BYTE_ARRAY);
1546 return _dbus_demarshal_byte_array (&iter->message->body, iter->message->byte_order,
1547 iter->pos + 1, NULL, len);
1551 * Returns the string array that the iterator may point to.
1552 * Note that you need to check that the iterator points
1553 * to a byte array prior to using this function.
1555 * @todo this function should probably take "char **" as
1556 * an out param argument, and return boolean or result code.
1558 * @param iter the iterator
1559 * @param len return location for length of byte array
1560 * @returns the byte array
1563 dbus_message_iter_get_string_array (DBusMessageIter *iter,
1566 _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING_ARRAY);
1568 return _dbus_demarshal_string_array (&iter->message->body, iter->message->byte_order,
1569 iter->pos + 1, NULL, len);
1573 * Sets the message sender.
1575 * @todo implement #NULL sender to unset
1577 * @param message the message
1578 * @param sender the sender
1579 * @returns #FALSE if not enough memory
1582 dbus_message_set_sender (DBusMessage *message,
1585 _dbus_assert (!message->locked);
1589 delete_string_field (message, FIELD_SENDER);
1594 return set_string_field (message,
1601 * Gets the service which originated this message,
1602 * or #NULL if unknown or inapplicable.
1604 * @param message the message
1605 * @returns the service name or #NULL
1608 dbus_message_get_sender (DBusMessage *message)
1610 return get_string_field (message, FIELD_SENDER, NULL);
1616 * @addtogroup DBusMessageInternals
1621 * @typedef DBusMessageLoader
1623 * The DBusMessageLoader object encapsulates the process of converting
1624 * a byte stream into a series of DBusMessage. It buffers the incoming
1625 * bytes as efficiently as possible, and generates a queue of
1626 * messages. DBusMessageLoader is typically used as part of a
1627 * DBusTransport implementation. The DBusTransport then hands off
1628 * the loaded messages to a DBusConnection, making the messages
1629 * visible to the application.
1633 /* we definitely use signed ints for sizes, so don't exceed
1634 * _DBUS_INT_MAX; and add 16 for paranoia, since a message
1635 * over 128M is pretty nuts anyhow.
1639 * The maximum sane message size.
1641 #define MAX_SANE_MESSAGE_SIZE (_DBUS_INT_MAX/16)
1644 * Implementation details of DBusMessageLoader.
1645 * All members are private.
1647 struct DBusMessageLoader
1649 int refcount; /**< Reference count. */
1651 DBusString data; /**< Buffered data */
1653 DBusList *messages; /**< Complete messages. */
1655 long max_message_size; /**< Maximum size of a message */
1657 unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
1659 unsigned int corrupted : 1; /**< We got broken data, and are no longer working */
1663 * The initial buffer size of the message loader.
1665 * @todo this should be based on min header size plus some average
1666 * body size, or something. Or rather, the min header size only, if we
1667 * want to try to read only the header, store that in a DBusMessage,
1668 * then read only the body and store that, etc., depends on
1669 * how we optimize _dbus_message_loader_get_buffer() and what
1670 * the exact message format is.
1672 #define INITIAL_LOADER_DATA_LEN 32
1675 * Creates a new message loader. Returns #NULL if memory can't
1678 * @returns new loader, or #NULL.
1681 _dbus_message_loader_new (void)
1683 DBusMessageLoader *loader;
1685 loader = dbus_new0 (DBusMessageLoader, 1);
1689 loader->refcount = 1;
1691 /* Try to cap message size at something that won't *totally* hose
1692 * the system if we have a couple of them.
1694 loader->max_message_size = _DBUS_ONE_MEGABYTE * 32;
1696 if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX))
1702 /* preallocate the buffer for speed, ignore failure */
1703 _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
1704 _dbus_string_set_length (&loader->data, 0);
1710 * Increments the reference count of the loader.
1712 * @param loader the loader.
1715 _dbus_message_loader_ref (DBusMessageLoader *loader)
1717 loader->refcount += 1;
1721 * Decrements the reference count of the loader and finalizes the
1722 * loader when the count reaches zero.
1724 * @param loader the loader.
1727 _dbus_message_loader_unref (DBusMessageLoader *loader)
1729 loader->refcount -= 1;
1730 if (loader->refcount == 0)
1732 _dbus_list_foreach (&loader->messages,
1733 (DBusForeachFunction) dbus_message_unref,
1735 _dbus_list_clear (&loader->messages);
1736 _dbus_string_free (&loader->data);
1742 * Gets the buffer to use for reading data from the network. Network
1743 * data is read directly into an allocated buffer, which is then used
1744 * in the DBusMessage, to avoid as many extra memcpy's as possible.
1745 * The buffer must always be returned immediately using
1746 * _dbus_message_loader_return_buffer(), even if no bytes are
1747 * successfully read.
1749 * @todo this function can be a lot more clever. For example
1750 * it can probably always return a buffer size to read exactly
1751 * the body of the next message, thus avoiding any memory wastage
1754 * @param loader the message loader.
1755 * @param buffer the buffer
1758 _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
1759 DBusString **buffer)
1761 _dbus_assert (!loader->buffer_outstanding);
1763 *buffer = &loader->data;
1765 loader->buffer_outstanding = TRUE;
1769 * The smallest header size that can occur.
1770 * (It won't be valid)
1772 #define DBUS_MINIMUM_HEADER_SIZE 16
1774 /** Pack four characters as in "abcd" into a uint32 */
1775 #define FOUR_CHARS_TO_UINT32(a, b, c, d) \
1776 ((((dbus_uint32_t)a) << 24) | \
1777 (((dbus_uint32_t)b) << 16) | \
1778 (((dbus_uint32_t)c) << 8) | \
1781 /** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
1782 #define DBUS_HEADER_FIELD_NAME_AS_UINT32 \
1783 FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
1785 /** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
1786 #define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
1787 FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
1789 /** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
1790 #define DBUS_HEADER_FIELD_REPLY_AS_UINT32 \
1791 FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
1793 /** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
1794 #define DBUS_HEADER_FIELD_SENDER_AS_UINT32 \
1795 FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
1798 decode_header_data (const DBusString *data,
1801 HeaderField fields[FIELD_LAST])
1807 if (header_len < 16)
1811 while (i < FIELD_LAST)
1813 fields[i].offset = -1;
1817 fields[FIELD_HEADER_LENGTH].offset = 4;
1818 fields[FIELD_BODY_LENGTH].offset = 8;
1819 fields[FIELD_CLIENT_SERIAL].offset = 12;
1821 /* Now handle the named fields. A real named field is at least 4
1822 * bytes for the name, plus a type code (1 byte) plus padding. So
1823 * if we have less than 8 bytes left, it must be alignment padding,
1824 * not a field. While >= 8 bytes can't be entirely alignment
1828 while ((pos + 7) < header_len)
1830 pos = _DBUS_ALIGN_VALUE (pos, 4);
1832 if ((pos + 4) > header_len)
1835 _dbus_string_get_const_data_len (data, &field, pos, 4);
1838 _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
1840 /* I believe FROM_BE is right, but if not we'll find out
1843 switch (DBUS_UINT32_FROM_BE (*(int*)field))
1845 case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
1846 if (fields[FIELD_SERVICE].offset >= 0)
1848 _dbus_verbose ("%s field provided twice\n",
1849 DBUS_HEADER_FIELD_SERVICE);
1853 fields[FIELD_SERVICE].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1854 _dbus_verbose ("Found service name at offset %d\n",
1855 fields[FIELD_SERVICE].offset);
1858 case DBUS_HEADER_FIELD_NAME_AS_UINT32:
1859 if (fields[FIELD_NAME].offset >= 0)
1861 _dbus_verbose ("%s field provided twice\n",
1862 DBUS_HEADER_FIELD_NAME);
1866 fields[FIELD_NAME].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1868 _dbus_verbose ("Found message name at offset %d\n",
1869 fields[FIELD_NAME].offset);
1871 case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
1872 if (fields[FIELD_SENDER].offset >= 0)
1874 _dbus_verbose ("%s field provided twice\n",
1875 DBUS_HEADER_FIELD_SENDER);
1879 fields[FIELD_SENDER].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1881 _dbus_verbose ("Found sender name at offset %d\n",
1882 fields[FIELD_NAME].offset);
1885 case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
1886 if (fields[FIELD_REPLY_SERIAL].offset >= 0)
1888 _dbus_verbose ("%s field provided twice\n",
1889 DBUS_HEADER_FIELD_REPLY);
1893 fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos + 1, 4);
1895 _dbus_verbose ("Found reply serial at offset %d\n",
1896 fields[FIELD_REPLY_SERIAL].offset);
1900 _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n",
1901 field[0], field[1], field[2], field[3]);
1904 if (!_dbus_marshal_validate_arg (data, byte_order, pos, &new_pos))
1907 if (new_pos > header_len)
1913 if (pos < header_len)
1915 /* Alignment padding, verify that it's nul */
1916 _dbus_assert ((header_len - pos) < 8);
1918 if (!_dbus_string_validate_nul (data,
1919 pos, (header_len - pos)))
1921 _dbus_verbose ("header alignment padding is not nul\n");
1930 * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
1931 * indicating to the loader how many bytes of the buffer were filled
1932 * in. This function must always be called, even if no bytes were
1933 * successfully read.
1935 * @param loader the loader.
1936 * @param buffer the buffer.
1937 * @param bytes_read number of bytes that were read into the buffer.
1940 _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
1944 _dbus_assert (loader->buffer_outstanding);
1945 _dbus_assert (buffer == &loader->data);
1947 loader->buffer_outstanding = FALSE;
1949 if (loader->corrupted)
1952 while (_dbus_string_get_length (&loader->data) >= 16)
1954 DBusMessage *message;
1955 const char *header_data;
1956 int byte_order, header_len, body_len;
1958 _dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
1960 _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
1962 byte_order = header_data[0];
1964 if (byte_order != DBUS_LITTLE_ENDIAN &&
1965 byte_order != DBUS_BIG_ENDIAN)
1967 _dbus_verbose ("Message with bad byte order '%c' received\n",
1969 loader->corrupted = TRUE;
1973 header_len = _dbus_unpack_int32 (byte_order, header_data + 4);
1974 body_len = _dbus_unpack_int32 (byte_order, header_data + 8);
1976 if (header_len < 16 || body_len < 0)
1978 _dbus_verbose ("Message had broken too-small header or body len %d %d\n",
1979 header_len, body_len);
1980 loader->corrupted = TRUE;
1984 if (_DBUS_ALIGN_VALUE (header_len, 8) != (unsigned int) header_len)
1986 _dbus_verbose ("header length %d is not aligned to 8 bytes\n",
1988 loader->corrupted = TRUE;
1992 if (header_len + body_len > loader->max_message_size)
1994 _dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
1995 header_len, body_len, loader->max_message_size);
1996 loader->corrupted = TRUE;
2000 if (_dbus_string_get_length (&loader->data) >= header_len + body_len)
2002 HeaderField fields[FIELD_LAST];
2006 if (!decode_header_data (&loader->data, header_len, byte_order,
2009 loader->corrupted = TRUE;
2013 next_arg = header_len;
2014 while (next_arg < (header_len + body_len))
2016 int prev = next_arg;
2018 if (!_dbus_marshal_validate_arg (&loader->data,
2023 loader->corrupted = TRUE;
2027 _dbus_assert (next_arg > prev);
2030 if (next_arg > (header_len + body_len))
2032 _dbus_verbose ("end of last arg at %d but message has len %d+%d=%d\n",
2033 next_arg, header_len, body_len,
2034 header_len + body_len);
2035 loader->corrupted = TRUE;
2039 message = dbus_message_new_empty_header ();
2040 if (message == NULL)
2041 break; /* ugh, postpone this I guess. */
2043 message->byte_order = byte_order;
2045 /* Copy in the offsets we found */
2047 while (i < FIELD_LAST)
2049 message->header_fields[i] = fields[i];
2053 if (!_dbus_list_append (&loader->messages, message))
2055 dbus_message_unref (message);
2059 _dbus_assert (_dbus_string_get_length (&message->header) == 0);
2060 _dbus_assert (_dbus_string_get_length (&message->body) == 0);
2062 _dbus_assert (_dbus_string_get_length (&loader->data) >=
2063 (header_len + body_len));
2065 if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0))
2067 _dbus_list_remove_last (&loader->messages, message);
2068 dbus_message_unref (message);
2072 if (!_dbus_string_move_len (&loader->data, 0, body_len, &message->body, 0))
2076 /* put the header back, we'll try again later */
2077 result = _dbus_string_copy_len (&message->header, 0, header_len,
2079 _dbus_assert (result); /* because DBusString never reallocs smaller */
2081 _dbus_list_remove_last (&loader->messages, message);
2082 dbus_message_unref (message);
2086 _dbus_assert (_dbus_string_get_length (&message->header) == header_len);
2087 _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
2089 _dbus_verbose ("Loaded message %p\n", message);
2097 * Pops a loaded message (passing ownership of the message
2098 * to the caller). Returns #NULL if no messages have been
2101 * @param loader the loader.
2102 * @returns the next message, or #NULL if none.
2105 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
2107 return _dbus_list_pop_first (&loader->messages);
2112 * Checks whether the loader is confused due to bad data.
2113 * If messages are received that are invalid, the
2114 * loader gets confused and gives up permanently.
2115 * This state is called "corrupted."
2117 * @param loader the loader
2118 * @returns #TRUE if the loader is hosed.
2121 _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
2123 return loader->corrupted;
2127 * Sets the maximum size message we allow.
2129 * @param loader the loader
2130 * @param size the max message size in bytes
2133 _dbus_message_loader_set_max_message_size (DBusMessageLoader *loader,
2136 if (size > MAX_SANE_MESSAGE_SIZE)
2138 _dbus_verbose ("clamping requested max message size %ld to %d\n",
2139 size, MAX_SANE_MESSAGE_SIZE);
2140 size = MAX_SANE_MESSAGE_SIZE;
2142 loader->max_message_size = size;
2146 * Gets the maximum allowed message size in bytes.
2148 * @param loader the loader
2149 * @returns max size in bytes
2152 _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader)
2154 return loader->max_message_size;
2158 #ifdef DBUS_BUILD_TESTS
2159 #include "dbus-test.h"
2163 message_iter_test (DBusMessage *message)
2165 DBusMessageIter *iter;
2168 iter = dbus_message_get_fields_iter (message);
2171 if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_STRING)
2172 _dbus_assert_not_reached ("Field type isn't string");
2174 str = dbus_message_iter_get_string (iter);
2175 if (strcmp (str, "Test string") != 0)
2176 _dbus_assert_not_reached ("Strings differ");
2179 if (!dbus_message_iter_next (iter))
2180 _dbus_assert_not_reached ("Reached end of fields");
2182 /* Signed integer tests */
2183 if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_INT32)
2184 _dbus_assert_not_reached ("Field type isn't int32");
2186 if (dbus_message_iter_get_int32 (iter) != -0x12345678)
2187 _dbus_assert_not_reached ("Signed integers differ");
2189 if (!dbus_message_iter_next (iter))
2190 _dbus_assert_not_reached ("Reached end of fields");
2192 /* Unsigned integer tests */
2193 if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_UINT32)
2194 _dbus_assert_not_reached ("Field type isn't int32");
2196 if (dbus_message_iter_get_int32 (iter) != 0xedd1e)
2197 _dbus_assert_not_reached ("Unsigned integers differ");
2199 if (!dbus_message_iter_next (iter))
2200 _dbus_assert_not_reached ("Reached end of fields");
2203 if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_DOUBLE)
2204 _dbus_assert_not_reached ("Field type isn't double");
2206 if (dbus_message_iter_get_double (iter) != 3.14159)
2207 _dbus_assert_not_reached ("Doubles differ");
2209 if (dbus_message_iter_next (iter))
2210 _dbus_assert_not_reached ("Didn't reach end of fields");
2212 dbus_message_iter_unref (iter);
2216 check_message_handling (DBusMessage *message)
2218 DBusMessageIter *iter;
2221 dbus_int32_t client_serial;
2226 client_serial = _dbus_message_get_client_serial (message);
2228 /* can't use set_client_serial due to the assertions at the start of it */
2229 set_int_field (message, FIELD_CLIENT_SERIAL,
2232 if (client_serial != _dbus_message_get_client_serial (message))
2234 _dbus_warn ("get/set cycle for client_serial did not succeed\n");
2238 /* If we implement message_set_field (message, n, value)
2239 * then we would want to test it here
2242 iter = dbus_message_get_fields_iter (message);
2243 while ((type = dbus_message_iter_get_field_type (iter)) != DBUS_TYPE_INVALID)
2247 case DBUS_TYPE_STRING:
2250 str = dbus_message_iter_get_string (iter);
2256 if (!dbus_message_iter_next (iter))
2264 dbus_message_iter_unref (iter);
2270 check_have_valid_message (DBusMessageLoader *loader)
2272 DBusMessage *message;
2278 if (_dbus_message_loader_get_is_corrupted (loader))
2280 _dbus_warn ("loader corrupted on message that was expected to be valid\n");
2284 message = _dbus_message_loader_pop_message (loader);
2285 if (message == NULL)
2287 _dbus_warn ("didn't load message that was expected to be valid (message not popped)\n");
2291 if (_dbus_string_get_length (&loader->data) > 0)
2293 _dbus_warn ("had leftover bytes from expected-to-be-valid single message\n");
2297 /* Verify that we're able to properly deal with the message.
2298 * For example, this would detect improper handling of messages
2299 * in nonstandard byte order.
2301 if (!check_message_handling (message))
2308 dbus_message_unref (message);
2313 check_invalid_message (DBusMessageLoader *loader)
2319 if (!_dbus_message_loader_get_is_corrupted (loader))
2321 _dbus_warn ("loader not corrupted on message that was expected to be invalid\n");
2332 check_incomplete_message (DBusMessageLoader *loader)
2334 DBusMessage *message;
2340 if (_dbus_message_loader_get_is_corrupted (loader))
2342 _dbus_warn ("loader corrupted on message that was expected to be valid (but incomplete)\n");
2346 message = _dbus_message_loader_pop_message (loader);
2347 if (message != NULL)
2349 _dbus_warn ("loaded message that was expected to be incomplete\n");
2357 dbus_message_unref (message);
2366 } ExpectedMessageValidity;
2369 check_loader_results (DBusMessageLoader *loader,
2370 ExpectedMessageValidity validity)
2375 return check_have_valid_message (loader);
2376 case MESSAGE_INVALID:
2377 return check_invalid_message (loader);
2378 case MESSAGE_INCOMPLETE:
2379 return check_incomplete_message (loader);
2382 _dbus_assert_not_reached ("bad ExpectedMessageValidity");
2387 try_message (const DBusString *filename,
2388 ExpectedMessageValidity validity)
2391 DBusMessageLoader *loader;
2395 const char *filename_c;
2397 _dbus_string_get_const_data (filename, &filename_c);
2399 if (!_dbus_string_ends_with_c_str (filename, ".message"))
2401 _dbus_verbose ("Skipping non-.message file %s\n",
2408 _dbus_string_get_const_data (filename, &s);
2409 printf (" %s\n", s);
2412 _dbus_verbose (" expecting %s\n",
2413 validity == MESSAGE_VALID ? "valid" :
2414 (validity == MESSAGE_INVALID ? "invalid" : "incomplete"));
2419 if (!_dbus_string_init (&data, _DBUS_INT_MAX))
2420 _dbus_assert_not_reached ("could not allocate string\n");
2422 if (!_dbus_message_data_load (&data, filename))
2425 _dbus_string_get_const_data (filename, &s);
2426 _dbus_warn ("Could not load message file %s\n", s);
2430 /* Write the data one byte at a time */
2432 loader = _dbus_message_loader_new ();
2434 len = _dbus_string_get_length (&data);
2435 for (i = 0; i < len; i++)
2439 _dbus_message_loader_get_buffer (loader, &buffer);
2440 _dbus_string_append_byte (buffer,
2441 _dbus_string_get_byte (&data, i));
2442 _dbus_message_loader_return_buffer (loader, buffer, 1);
2445 if (!check_loader_results (loader, validity))
2448 _dbus_message_loader_unref (loader);
2451 /* Write the data all at once */
2453 loader = _dbus_message_loader_new ();
2458 _dbus_message_loader_get_buffer (loader, &buffer);
2459 _dbus_string_copy (&data, 0, buffer,
2460 _dbus_string_get_length (buffer));
2461 _dbus_message_loader_return_buffer (loader, buffer, 1);
2464 if (!check_loader_results (loader, validity))
2467 _dbus_message_loader_unref (loader);
2470 /* Write the data 2 bytes at a time */
2472 loader = _dbus_message_loader_new ();
2474 len = _dbus_string_get_length (&data);
2475 for (i = 0; i < len; i += 2)
2479 _dbus_message_loader_get_buffer (loader, &buffer);
2480 _dbus_string_append_byte (buffer,
2481 _dbus_string_get_byte (&data, i));
2483 _dbus_string_append_byte (buffer,
2484 _dbus_string_get_byte (&data, i+1));
2485 _dbus_message_loader_return_buffer (loader, buffer, 1);
2488 if (!check_loader_results (loader, validity))
2491 _dbus_message_loader_unref (loader);
2501 if (_dbus_string_get_length (&data) > 0)
2502 _dbus_verbose_bytes_of_string (&data, 0,
2503 _dbus_string_get_length (&data));
2505 _dbus_string_get_const_data (filename, &s);
2506 _dbus_warn ("Failed message loader test on %s\n",
2511 _dbus_message_loader_unref (loader);
2512 _dbus_string_free (&data);
2518 process_test_subdir (const DBusString *test_base_dir,
2520 ExpectedMessageValidity validity)
2522 DBusString test_directory;
2523 DBusString filename;
2526 DBusResultCode result;
2531 if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
2532 _dbus_assert_not_reached ("didn't allocate test_directory\n");
2534 _dbus_string_init_const (&filename, subdir);
2536 if (!_dbus_string_copy (test_base_dir, 0,
2537 &test_directory, 0))
2538 _dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
2540 if (!_dbus_concat_dir_and_file (&test_directory, &filename))
2541 _dbus_assert_not_reached ("could't allocate full path");
2543 _dbus_string_free (&filename);
2544 if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
2545 _dbus_assert_not_reached ("didn't allocate filename string\n");
2547 dir = _dbus_directory_open (&test_directory, &result);
2551 _dbus_string_get_const_data (&test_directory, &s);
2552 _dbus_warn ("Could not open %s: %s\n", s,
2553 dbus_result_to_string (result));
2557 printf ("Testing:\n");
2559 result = DBUS_RESULT_SUCCESS;
2560 while (_dbus_directory_get_next_file (dir, &filename, &result))
2562 DBusString full_path;
2564 if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
2565 _dbus_assert_not_reached ("couldn't init string");
2567 if (!_dbus_string_copy (&test_directory, 0, &full_path, 0))
2568 _dbus_assert_not_reached ("couldn't copy dir to full_path");
2570 if (!_dbus_concat_dir_and_file (&full_path, &filename))
2571 _dbus_assert_not_reached ("couldn't concat file to dir");
2573 if (!try_message (&full_path, validity))
2575 _dbus_string_free (&full_path);
2579 _dbus_string_free (&full_path);
2582 if (result != DBUS_RESULT_SUCCESS)
2585 _dbus_string_get_const_data (&test_directory, &s);
2586 _dbus_warn ("Could not get next file in %s: %s\n",
2587 s, dbus_result_to_string (result));
2596 _dbus_directory_close (dir);
2597 _dbus_string_free (&test_directory);
2598 _dbus_string_free (&filename);
2605 * @ingroup DBusMessageInternals
2606 * Unit test for DBusMessage.
2608 * @returns #TRUE on success.
2611 _dbus_message_test (const char *test_data_dir)
2613 DBusMessage *message;
2614 DBusMessageLoader *loader;
2617 dbus_int32_t our_int;
2620 DBusString test_directory;
2623 /* Test the vararg functions */
2624 message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2625 _dbus_message_set_client_serial (message, 1);
2626 dbus_message_append_fields (message,
2627 DBUS_TYPE_INT32, -0x12345678,
2628 DBUS_TYPE_STRING, "Test string",
2629 DBUS_TYPE_DOUBLE, 3.14159,
2631 _dbus_verbose_bytes_of_string (&message->header, 0,
2632 _dbus_string_get_length (&message->header));
2633 _dbus_verbose_bytes_of_string (&message->body, 0,
2634 _dbus_string_get_length (&message->body));
2636 if (dbus_message_get_fields (message,
2637 DBUS_TYPE_INT32, &our_int,
2638 DBUS_TYPE_STRING, &our_str,
2639 DBUS_TYPE_DOUBLE, &our_double,
2640 0) != DBUS_RESULT_SUCCESS)
2641 _dbus_assert_not_reached ("Could not get fields");
2643 if (our_int != -0x12345678)
2644 _dbus_assert_not_reached ("integers differ!");
2646 if (our_double != 3.14159)
2647 _dbus_assert_not_reached ("doubles differ!");
2649 if (strcmp (our_str, "Test string") != 0)
2650 _dbus_assert_not_reached ("strings differ!");
2652 dbus_free (our_str);
2653 dbus_message_unref (message);
2655 message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
2656 _dbus_message_set_client_serial (message, 1);
2657 _dbus_message_set_reply_serial (message, 0x12345678);
2659 dbus_message_append_string (message, "Test string");
2660 dbus_message_append_int32 (message, -0x12345678);
2661 dbus_message_append_uint32 (message, 0xedd1e);
2662 dbus_message_append_double (message, 3.14159);
2664 message_iter_test (message);
2666 /* Message loader test */
2667 _dbus_message_lock (message);
2668 loader = _dbus_message_loader_new ();
2670 /* Write the header data one byte at a time */
2671 _dbus_string_get_const_data (&message->header, &data);
2672 for (i = 0; i < _dbus_string_get_length (&message->header); i++)
2676 _dbus_message_loader_get_buffer (loader, &buffer);
2677 _dbus_string_append_byte (buffer, data[i]);
2678 _dbus_message_loader_return_buffer (loader, buffer, 1);
2681 /* Write the body data one byte at a time */
2682 _dbus_string_get_const_data (&message->body, &data);
2683 for (i = 0; i < _dbus_string_get_length (&message->body); i++)
2687 _dbus_message_loader_get_buffer (loader, &buffer);
2688 _dbus_string_append_byte (buffer, data[i]);
2689 _dbus_message_loader_return_buffer (loader, buffer, 1);
2692 dbus_message_unref (message);
2694 /* Now pop back the message */
2695 if (_dbus_message_loader_get_is_corrupted (loader))
2696 _dbus_assert_not_reached ("message loader corrupted");
2698 message = _dbus_message_loader_pop_message (loader);
2700 _dbus_assert_not_reached ("received a NULL message");
2702 if (_dbus_message_get_reply_serial (message) != 0x12345678)
2703 _dbus_assert_not_reached ("reply serial fields differ");
2705 message_iter_test (message);
2707 dbus_message_unref (message);
2708 _dbus_message_loader_unref (loader);
2710 /* Now load every message in test_data_dir if we have one */
2711 if (test_data_dir == NULL)
2716 _dbus_string_init_const (&test_directory, test_data_dir);
2718 if (!process_test_subdir (&test_directory, "valid-messages",
2721 if (!process_test_subdir (&test_directory, "invalid-messages",
2725 if (!process_test_subdir (&test_directory, "incomplete-messages",
2726 MESSAGE_INCOMPLETE))
2733 _dbus_string_free (&test_directory);
2738 #endif /* DBUS_BUILD_TESTS */