dbus-message.c 120 KB
Newer Older
1 2 3
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-message.c  DBusMessage object
 *
4
 * Copyright (C) 2002, 2003, 2004, 2005  Red Hat Inc.
5
 * Copyright (C) 2002, 2003  CodeFactory AB
6
 *
7
 * Licensed under the Academic Free License version 2.1
8
 *
9 10 11 12 13 14 15 16 17
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
18
 *
19 20 21 22 23 24
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

25
#include "dbus-internals.h"
26 27
#include "dbus-marshal-recursive.h"
#include "dbus-marshal-validate.h"
28
#include "dbus-marshal-byteswap.h"
29
#include "dbus-marshal-header.h"
30
#include "dbus-signature.h"
31
#include "dbus-message-private.h"
32
#include "dbus-object-tree.h"
33 34
#include "dbus-memory.h"
#include "dbus-list.h"
35
#include "dbus-threads-internal.h"
36
#include <string.h>
37

38 39
static void dbus_message_finalize (DBusMessage *message);

40
/**
41 42 43
 * @defgroup DBusMessageInternals DBusMessage implementation details
 * @ingroup DBusInternals
 * @brief DBusMessage private implementation details.
44
 *
45
 * The guts of DBusMessage and its methods.
46 47 48 49
 *
 * @{
 */

50
/* Not thread locked, but strictly const/read-only so should be OK
51
 */
52
/** An static string representing an empty signature */
53
_DBUS_STRING_DEFINE_STATIC(_dbus_empty_signature_str,  "");
54

55 56 57
/* these have wacky values to help trap uninitialized iterators;
 * but has to fit in 3 bits
 */
58
enum {
59 60
  DBUS_MESSAGE_ITER_TYPE_READER = 3,
  DBUS_MESSAGE_ITER_TYPE_WRITER = 7
61 62
};

63
/** typedef for internals of message iterator */
64 65
typedef struct DBusMessageRealIter DBusMessageRealIter;

66 67
/**
 * @brief Internals of DBusMessageIter
68
 *
69 70
 * Object representing a position in a message. All fields are internal.
 */
71
struct DBusMessageRealIter
72 73
{
  DBusMessage *message; /**< Message used */
74 75 76 77 78
  dbus_uint32_t changed_stamp : CHANGED_STAMP_BITS; /**< stamp to detect invalid iters */
  dbus_uint32_t iter_type : 3;      /**< whether this is a reader or writer iter */
  dbus_uint32_t sig_refcount : 8;   /**< depth of open_signature() */
  union
  {
79 80 81
    DBusTypeWriter writer; /**< writer */
    DBusTypeReader reader; /**< reader */
  } u; /**< the type writer or reader that does all the work */
82 83
};

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static void
get_const_signature (DBusHeader        *header,
                     const DBusString **type_str_p,
                     int               *type_pos_p)
{
  if (_dbus_header_get_field_raw (header,
                                  DBUS_HEADER_FIELD_SIGNATURE,
                                  type_str_p,
                                  type_pos_p))
    {
      *type_pos_p += 1; /* skip the signature length which is 1 byte */
    }
  else
    {
      *type_str_p = &_dbus_empty_signature_str;
      *type_pos_p = 0;
    }
}

/**
 * Swaps the message to compiler byte order if required
 *
 * @param message the message
 */
static void
_dbus_message_byteswap (DBusMessage *message)
{
  const DBusString *type_str;
  int type_pos;
  
  if (message->byte_order == DBUS_COMPILER_BYTE_ORDER)
    return;

  _dbus_verbose ("Swapping message into compiler byte order\n");
  
  get_const_signature (&message->header, &type_str, &type_pos);
  
  _dbus_marshal_byteswap (type_str, type_pos,
                          message->byte_order,
                          DBUS_COMPILER_BYTE_ORDER,
                          &message->body, 0);

  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
  
  _dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER);
}

131 132 133 134 135 136
/** byte-swap the message if it doesn't match our byte order.
 *  Called only when we need the message in our own byte order,
 *  normally when reading arrays of integers or doubles.
 *  Otherwise should not be called since it would do needless
 *  work.
 */
137 138 139 140
#define ensure_byte_order(message)                      \
 if (message->byte_order != DBUS_COMPILER_BYTE_ORDER)   \
   _dbus_message_byteswap (message)

141 142 143 144 145 146 147 148 149 150 151 152
/**
 * Gets the data to be sent over the network for this message.
 * The header and then the body should be written out.
 * This function is guaranteed to always return the same
 * data once a message is locked (with _dbus_message_lock()).
 *
 * @param message the message.
 * @param header return location for message header data.
 * @param body return location for message body data.
 */
void
_dbus_message_get_network_data (DBusMessage          *message,
153 154
                                const DBusString    **header,
                                const DBusString    **body)
155 156
{
  _dbus_assert (message->locked);
157 158

  *header = &message->header.data;
159
  *body = &message->body;
160 161
}

162 163 164 165 166 167 168 169 170 171
/**
 * Sets the serial number of a message.
 * This can only be done once on a message.
 *
 * @param message the message
 * @param serial the serial
 */
void
_dbus_message_set_serial (DBusMessage   *message,
                          dbus_uint32_t  serial)
172
{
173 174 175
  _dbus_assert (message != NULL);
  _dbus_assert (!message->locked);
  _dbus_assert (dbus_message_get_serial (message) == 0);
176

177
  _dbus_header_set_serial (&message->header, serial);
178 179
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
/**
 * Adds a counter to be incremented immediately with the
 * size of this message, and decremented by the size
 * of this message when this message if finalized.
 * The link contains a counter with its refcount already
 * incremented, but the counter itself not incremented.
 * Ownership of link and counter refcount is passed to
 * the message.
 *
 * @param message the message
 * @param link link with counter as data
 */
void
_dbus_message_add_size_counter_link (DBusMessage  *message,
                                     DBusList     *link)
195
{
196 197 198 199 200 201 202 203 204 205 206
  /* right now we don't recompute the delta when message
   * size changes, and that's OK for current purposes
   * I think, but could be important to change later.
   * Do recompute it whenever there are no outstanding counters,
   * since it's basically free.
   */
  if (message->size_counters == NULL)
    {
      message->size_counter_delta =
        _dbus_string_get_length (&message->header.data) +
        _dbus_string_get_length (&message->body);
207

208 209 210 211 212
#if 0
      _dbus_verbose ("message has size %ld\n",
                     message->size_counter_delta);
#endif
    }
213

214
  _dbus_list_append_link (&message->size_counters, link);
215

216
  _dbus_counter_adjust (link->data, message->size_counter_delta);
217 218
}

219 220 221 222 223 224 225 226 227 228 229 230
/**
 * Adds a counter to be incremented immediately with the
 * size of this message, and decremented by the size
 * of this message when this message if finalized.
 *
 * @param message the message
 * @param counter the counter
 * @returns #FALSE if no memory
 */
dbus_bool_t
_dbus_message_add_size_counter (DBusMessage *message,
                                DBusCounter *counter)
231
{
232 233 234 235 236 237 238 239 240 241
  DBusList *link;

  link = _dbus_list_alloc_link (counter);
  if (link == NULL)
    return FALSE;

  _dbus_counter_ref (counter);
  _dbus_message_add_size_counter_link (message, link);

  return TRUE;
242 243
}

244 245 246 247 248 249 250 251 252 253 254 255
/**
 * Removes a counter tracking the size of this message, and decrements
 * the counter by the size of this message.
 *
 * @param message the message
 * @param link_return return the link used
 * @param counter the counter
 */
void
_dbus_message_remove_size_counter (DBusMessage  *message,
                                   DBusCounter  *counter,
                                   DBusList    **link_return)
256
{
257
  DBusList *link;
258

259 260 261
  link = _dbus_list_find_last (&message->size_counters,
                               counter);
  _dbus_assert (link != NULL);
262

263 264 265 266 267 268
  _dbus_list_unlink (&message->size_counters,
                     link);
  if (link_return)
    *link_return = link;
  else
    _dbus_list_free_link (link);
269

270
  _dbus_counter_adjust (counter, - message->size_counter_delta);
271

272
  _dbus_counter_unref (counter);
273 274
}

275 276 277 278 279 280 281 282 283 284 285
/**
 * Locks a message. Allows checking that applications don't keep a
 * reference to a message in the outgoing queue and change it
 * underneath us. Messages are locked when they enter the outgoing
 * queue (dbus_connection_send_message()), and the library complains
 * if the message is modified while locked.
 *
 * @param message the message to lock.
 */
void
_dbus_message_lock (DBusMessage  *message)
286
{
287 288 289 290
  if (!message->locked)
    {
      _dbus_header_update_lengths (&message->header,
                                   _dbus_string_get_length (&message->body));
291

292 293 294
      /* must have a signature if you have a body */
      _dbus_assert (_dbus_string_get_length (&message->body) == 0 ||
                    dbus_message_get_signature (message) != NULL);
295

296
      message->locked = TRUE;
297 298 299
    }
}

300
static dbus_bool_t
301 302 303 304
set_or_delete_string_field (DBusMessage *message,
                            int          field,
                            int          typecode,
                            const char  *value)
305
{
306 307 308 309 310 311 312 313
  if (value == NULL)
    return _dbus_header_delete_field (&message->header, field);
  else
    return _dbus_header_set_field_basic (&message->header,
                                         field,
                                         typecode,
                                         &value);
}
314

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
#if 0
/* Probably we don't need to use this */
/**
 * Sets the signature of the message, i.e. the arguments in the
 * message payload. The signature includes only "in" arguments for
 * #DBUS_MESSAGE_TYPE_METHOD_CALL and only "out" arguments for
 * #DBUS_MESSAGE_TYPE_METHOD_RETURN, so is slightly different from
 * what you might expect (it does not include the signature of the
 * entire C++-style method).
 *
 * The signature is a string made up of type codes such as
 * #DBUS_TYPE_INT32. The string is terminated with nul (nul is also
 * the value of #DBUS_TYPE_INVALID). The macros such as
 * #DBUS_TYPE_INT32 evaluate to integers; to assemble a signature you
 * may find it useful to use the string forms, such as
 * #DBUS_TYPE_INT32_AS_STRING.
 *
 * An "unset" or #NULL signature is considered the same as an empty
 * signature. In fact dbus_message_get_signature() will never return
 * #NULL.
 *
 * @param message the message
 * @param signature the type signature or #NULL to unset
 * @returns #FALSE if no memory
 */
340
static dbus_bool_t
341 342
_dbus_message_set_signature (DBusMessage *message,
                             const char  *signature)
343
{
344 345 346 347 348 349 350
  _dbus_return_val_if_fail (message != NULL, FALSE);
  _dbus_return_val_if_fail (!message->locked, FALSE);
  _dbus_return_val_if_fail (signature == NULL ||
                            _dbus_check_is_valid_signature (signature));
  /* can't delete the signature if you have a message body */
  _dbus_return_val_if_fail (_dbus_string_get_length (&message->body) == 0 ||
                            signature != NULL);
351

352 353 354 355 356 357
  return set_or_delete_string_field (message,
                                     DBUS_HEADER_FIELD_SIGNATURE,
                                     DBUS_TYPE_SIGNATURE,
                                     signature);
}
#endif
358

359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
/* Message Cache
 *
 * We cache some DBusMessage to reduce the overhead of allocating
 * them.  In my profiling this consistently made about an 8%
 * difference.  It avoids the malloc for the message, the malloc for
 * the slot list, the malloc for the header string and body string,
 * and the associated free() calls. It does introduce another global
 * lock which could be a performance issue in certain cases.
 *
 * For the echo client/server the round trip time goes from around
 * .000077 to .000069 with the message cache on my laptop. The sysprof
 * change is as follows (numbers are cumulative percentage):
 *
 *  with message cache implemented as array as it is now (0.000069 per):
 *    new_empty_header           1.46
 *      mutex_lock               0.56    # i.e. _DBUS_LOCK(message_cache)
 *      mutex_unlock             0.25
 *      self                     0.41
 *    unref                      2.24
 *      self                     0.68
 *      list_clear               0.43
 *      mutex_lock               0.33    # i.e. _DBUS_LOCK(message_cache)
 *      mutex_unlock             0.25
 *
 *  with message cache implemented as list (0.000070 per roundtrip):
 *    new_empty_header           2.72
 *      list_pop_first           1.88
 *    unref                      3.3
 *      list_prepend             1.63
 *
 * without cache (0.000077 per roundtrip):
 *    new_empty_header           6.7
 *      string_init_preallocated 3.43
 *        dbus_malloc            2.43
 *      dbus_malloc0             2.59
 *
 *    unref                      4.02
 *      string_free              1.82
 *        dbus_free              1.63
 *      dbus_free                0.71
 *
 * If you implement the message_cache with a list, the primary reason
 * it's slower is that you add another thread lock (on the DBusList
 * mempool).
 */

405
/** Avoid caching huge messages */
Ross Burton's avatar
Ross Burton committed
406
#define MAX_MESSAGE_SIZE_TO_CACHE 10 * _DBUS_ONE_KILOBYTE
407 408

/** Avoid caching too many messages */
409 410 411 412 413 414 415
#define MAX_MESSAGE_CACHE_SIZE    5

_DBUS_DEFINE_GLOBAL_LOCK (message_cache);
static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
static int message_cache_count = 0;
static dbus_bool_t message_cache_shutdown_registered = FALSE;

416
static void
417
dbus_message_cache_shutdown (void *data)
418 419
{
  int i;
420 421 422

  _DBUS_LOCK (message_cache);

423
  i = 0;
424
  while (i < MAX_MESSAGE_CACHE_SIZE)
425
    {
426 427 428
      if (message_cache[i])
        dbus_message_finalize (message_cache[i]);

429
      ++i;
430
    }
431 432 433 434 435

  message_cache_count = 0;
  message_cache_shutdown_registered = FALSE;

  _DBUS_UNLOCK (message_cache);
436 437
}

438 439 440 441 442 443
/**
 * Tries to get a message from the message cache.  The retrieved
 * message will have junk in it, so it still needs to be cleared out
 * in dbus_message_new_empty_header()
 *
 * @returns the message, or #NULL if none cached
444
 */
445 446
static DBusMessage*
dbus_message_get_cached (void)
447
{
448 449 450 451 452 453 454 455
  DBusMessage *message;
  int i;

  message = NULL;

  _DBUS_LOCK (message_cache);

  _dbus_assert (message_cache_count >= 0);
456

457
  if (message_cache_count == 0)
458
    {
459 460
      _DBUS_UNLOCK (message_cache);
      return NULL;
461
    }
462 463 464 465

  /* This is not necessarily true unless count > 0, and
   * message_cache is uninitialized until the shutdown is
   * registered
466
   */
467
  _dbus_assert (message_cache_shutdown_registered);
468

469 470
  i = 0;
  while (i < MAX_MESSAGE_CACHE_SIZE)
471
    {
472
      if (message_cache[i])
473
        {
474 475 476 477
          message = message_cache[i];
          message_cache[i] = NULL;
          message_cache_count -= 1;
          break;
478
        }
479
      ++i;
480
    }
481 482 483
  _dbus_assert (message_cache_count >= 0);
  _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE);
  _dbus_assert (message != NULL);
484

485 486 487 488 489 490
  _DBUS_UNLOCK (message_cache);

  _dbus_assert (message->refcount.value == 0);
  _dbus_assert (message->size_counters == NULL);

  return message;
491
}
492

493 494 495 496 497 498 499 500 501 502 503 504
static void
free_size_counter (void *element,
                   void *data)
{
  DBusCounter *counter = element;
  DBusMessage *message = data;

  _dbus_counter_adjust (counter, - message->size_counter_delta);

  _dbus_counter_unref (counter);
}

505 506 507 508 509 510 511
/**
 * Tries to cache a message, otherwise finalize it.
 *
 * @param message the message
 */
static void
dbus_message_cache_or_finalize (DBusMessage *message)
512
{
513 514
  dbus_bool_t was_cached;
  int i;
515
  
516
  _dbus_assert (message->refcount.value == 0);
517

518 519 520 521
  /* This calls application code and has to be done first thing
   * without holding the lock
   */
  _dbus_data_slot_list_clear (&message->slot_list);
522

523 524 525 526 527 528 529 530 531
  _dbus_list_foreach (&message->size_counters,
                      free_size_counter, message);
  _dbus_list_clear (&message->size_counters);

  was_cached = FALSE;

  _DBUS_LOCK (message_cache);

  if (!message_cache_shutdown_registered)
532
    {
533 534 535 536 537 538 539 540 541 542 543 544 545
      _dbus_assert (message_cache_count == 0);

      if (!_dbus_register_shutdown_func (dbus_message_cache_shutdown, NULL))
        goto out;

      i = 0;
      while (i < MAX_MESSAGE_CACHE_SIZE)
        {
          message_cache[i] = NULL;
          ++i;
        }

      message_cache_shutdown_registered = TRUE;
546 547
    }

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
  _dbus_assert (message_cache_count >= 0);

  if ((_dbus_string_get_length (&message->header.data) +
       _dbus_string_get_length (&message->body)) >
      MAX_MESSAGE_SIZE_TO_CACHE)
    goto out;

  if (message_cache_count >= MAX_MESSAGE_CACHE_SIZE)
    goto out;

  /* Find empty slot */
  i = 0;
  while (message_cache[i] != NULL)
    ++i;

  _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE);

  _dbus_assert (message_cache[i] == NULL);
  message_cache[i] = message;
  message_cache_count += 1;
  was_cached = TRUE;
569 570 571
#ifndef DBUS_DISABLE_CHECKS
  message->in_cache = TRUE;
#endif
572 573 574 575

 out:
  _DBUS_UNLOCK (message_cache);

576 577
  _dbus_assert (message->refcount.value == 0);
  
578 579
  if (!was_cached)
    dbus_message_finalize (message);
580 581
}

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
#ifndef DBUS_DISABLE_CHECKS
static dbus_bool_t
_dbus_message_iter_check (DBusMessageRealIter *iter)
{
  if (iter == NULL)
    {
      _dbus_warn_check_failed ("dbus message iterator is NULL\n");
      return FALSE;
    }

  if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER)
    {
      if (iter->u.reader.byte_order != iter->message->byte_order)
        {
          _dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n");
          return FALSE;
        }
      /* because we swap the message into compiler order when you init an iter */
      _dbus_assert (iter->u.reader.byte_order == DBUS_COMPILER_BYTE_ORDER);
    }
  else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)
    {
      if (iter->u.writer.byte_order != iter->message->byte_order)
        {
          _dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n");
          return FALSE;
        }
      /* because we swap the message into compiler order when you init an iter */
      _dbus_assert (iter->u.writer.byte_order == DBUS_COMPILER_BYTE_ORDER);
    }
  else
    {
      _dbus_warn_check_failed ("dbus message iterator looks uninitialized or corrupted\n");
      return FALSE;
    }

  if (iter->changed_stamp != iter->message->changed_stamp)
    {
      _dbus_warn_check_failed ("dbus message iterator invalid because the message has been modified (or perhaps the iterator is just uninitialized)\n");
      return FALSE;
    }

  return TRUE;
}
#endif /* DBUS_DISABLE_CHECKS */

628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
/**
 * Implementation of the varargs arg-getting functions.
 * dbus_message_get_args() is the place to go for complete
 * documentation.
 *
 * @see dbus_message_get_args
 * @param iter the message iter
 * @param error error to be filled in
 * @param first_arg_type type of the first argument
 * @param var_args return location for first argument, followed by list of type/location pairs
 * @returns #FALSE if error was set
 */
dbus_bool_t
_dbus_message_iter_get_args_valist (DBusMessageIter *iter,
                                    DBusError       *error,
                                    int              first_arg_type,
                                    va_list          var_args)
{
  DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
  int spec_type, msg_type, i;
  dbus_bool_t retval;

  _dbus_assert (_dbus_message_iter_check (real));

  retval = FALSE;

  spec_type = first_arg_type;
  i = 0;

  while (spec_type != DBUS_TYPE_INVALID)
    {
      msg_type = dbus_message_iter_get_arg_type (iter);

      if (msg_type != spec_type)
	{
          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
                          "Argument %d is specified to be of type \"%s\", but "
                          "is actually of type \"%s\"\n", i,
                          _dbus_type_to_string (spec_type),
                          _dbus_type_to_string (msg_type));

          goto out;
	}

      if (dbus_type_is_basic (spec_type))
        {
          DBusBasicValue *ptr;

          ptr = va_arg (var_args, DBusBasicValue*);

          _dbus_assert (ptr != NULL);

          _dbus_type_reader_read_basic (&real->u.reader,
                                        ptr);
        }
      else if (spec_type == DBUS_TYPE_ARRAY)
        {
          int element_type;
          int spec_element_type;
          const DBusBasicValue **ptr;
          int *n_elements_p;
          DBusTypeReader array;

          spec_element_type = va_arg (var_args, int);
          element_type = _dbus_type_reader_get_element_type (&real->u.reader);

          if (spec_element_type != element_type)
            {
              dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
                              "Argument %d is specified to be an array of \"%s\", but "
                              "is actually an array of \"%s\"\n",
                              i,
                              _dbus_type_to_string (spec_element_type),
                              _dbus_type_to_string (element_type));

              goto out;
            }

          if (dbus_type_is_fixed (spec_element_type))
            {
              ptr = va_arg (var_args, const DBusBasicValue**);
              n_elements_p = va_arg (var_args, int*);

              _dbus_assert (ptr != NULL);
              _dbus_assert (n_elements_p != NULL);

              _dbus_type_reader_recurse (&real->u.reader, &array);

              _dbus_type_reader_read_fixed_multi (&array,
                                                  ptr, n_elements_p);
            }
          else if (spec_element_type == DBUS_TYPE_STRING ||
                   spec_element_type == DBUS_TYPE_SIGNATURE ||
                   spec_element_type == DBUS_TYPE_OBJECT_PATH)
            {
              char ***str_array_p;
              int n_elements;
              char **str_array;

              str_array_p = va_arg (var_args, char***);
              n_elements_p = va_arg (var_args, int*);

              _dbus_assert (str_array_p != NULL);
              _dbus_assert (n_elements_p != NULL);

              /* Count elements in the array */
              _dbus_type_reader_recurse (&real->u.reader, &array);

              n_elements = 0;
              while (_dbus_type_reader_get_current_type (&array) != DBUS_TYPE_INVALID)
                {
                  ++n_elements;
                  _dbus_type_reader_next (&array);
                }

              str_array = dbus_new0 (char*, n_elements + 1);
              if (str_array == NULL)
                {
                  _DBUS_SET_OOM (error);
                  goto out;
                }

              /* Now go through and dup each string */
              _dbus_type_reader_recurse (&real->u.reader, &array);

              i = 0;
              while (i < n_elements)
                {
                  const char *s;
                  _dbus_type_reader_read_basic (&array,
                                                &s);
                  
                  str_array[i] = _dbus_strdup (s);
                  if (str_array[i] == NULL)
                    {
                      dbus_free_string_array (str_array);
                      _DBUS_SET_OOM (error);
                      goto out;
                    }
                  
                  ++i;
                  
                  if (!_dbus_type_reader_next (&array))
                    _dbus_assert (i == n_elements);
                }

              _dbus_assert (_dbus_type_reader_get_current_type (&array) == DBUS_TYPE_INVALID);
              _dbus_assert (i == n_elements);
              _dbus_assert (str_array[i] == NULL);

              *str_array_p = str_array;
              *n_elements_p = n_elements;
            }
#ifndef DBUS_DISABLE_CHECKS
          else
            {
              _dbus_warn ("you can't read arrays of container types (struct, variant, array) with %s for now\n",
                          _DBUS_FUNCTION_NAME);
              goto out;
            }
#endif
        }
#ifndef DBUS_DISABLE_CHECKS
      else
        {
          _dbus_warn ("you can only read arrays and basic types with %s for now\n",
                      _DBUS_FUNCTION_NAME);
          goto out;
        }
#endif

      spec_type = va_arg (var_args, int);
      if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID)
        {
          dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
                          "Message has only %d arguments, but more were expected", i);
          goto out;
        }

      i++;
    }

  retval = TRUE;

 out:

  return retval;
}

817 818 819 820 821
/** @} */

/**
 * @defgroup DBusMessage DBusMessage
 * @ingroup  DBus
822
 * @brief Message to be sent or received over a #DBusConnection.
823 824 825 826 827 828
 *
 * A DBusMessage is the most basic unit of communication over a
 * DBusConnection. A DBusConnection represents a stream of messages
 * received from a remote application, and a stream of messages
 * sent to a remote application.
 *
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
 * A message has a message type, returned from
 * dbus_message_get_type().  This indicates whether the message is a
 * method call, a reply to a method call, a signal, or an error reply.
 *
 * A message has header fields such as the sender, destination, method
 * or signal name, and so forth. DBusMessage has accessor functions for
 * these, such as dbus_message_get_member().
 *
 * Convenience functions dbus_message_is_method_call(), dbus_message_is_signal(),
 * and dbus_message_is_error() check several header fields at once and are
 * slightly more efficient than checking the header fields with individual
 * accessor functions.
 *
 * Finally, a message has arguments. The number and types of arguments
 * are in the message's signature header field (accessed with
 * dbus_message_get_signature()).  Simple argument values are usually
 * retrieved with dbus_message_get_args() but more complex values such
 * as structs may require the use of #DBusMessageIter.
 *
 * The D-Bus specification goes into some more detail about header fields and
 * message types.
 * 
851 852 853 854 855 856 857 858 859 860 861 862 863
 * @{
 */

/**
 * @typedef DBusMessage
 *
 * Opaque data type representing a message received from or to be
 * sent to another application.
 */

/**
 * Returns the serial of a message or 0 if none has been specified.
 * The message's serial number is provided by the application sending
864 865 866 867 868 869 870
 * the message and is used to identify replies to this message.
 *
 * All messages received on a connection will have a serial provided
 * by the remote application.
 *
 * For messages you're sending, dbus_connection_send() will assign a
 * serial and return it to you.
871 872
 *
 * @param message the message
873
 * @returns the serial
874 875 876 877 878 879 880 881 882 883
 */
dbus_uint32_t
dbus_message_get_serial (DBusMessage *message)
{
  _dbus_return_val_if_fail (message != NULL, 0);

  return _dbus_header_get_serial (&message->header);
}

/**
884 885
 * Sets the reply serial of a message (the serial of the message this
 * is a reply to).
886 887
 *
 * @param message the message
888
 * @param reply_serial the serial we're replying to
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
 * @returns #FALSE if not enough memory
 */
dbus_bool_t
dbus_message_set_reply_serial (DBusMessage   *message,
                               dbus_uint32_t  reply_serial)
{
  _dbus_return_val_if_fail (message != NULL, FALSE);
  _dbus_return_val_if_fail (!message->locked, FALSE);
  _dbus_return_val_if_fail (reply_serial != 0, FALSE); /* 0 is invalid */

  return _dbus_header_set_field_basic (&message->header,
                                       DBUS_HEADER_FIELD_REPLY_SERIAL,
                                       DBUS_TYPE_UINT32,
                                       &reply_serial);
}

/**
 * Returns the serial that the message is a reply to or 0 if none.
 *
 * @param message the message
 * @returns the reply serial
 */
dbus_uint32_t
dbus_message_get_reply_serial  (DBusMessage *message)
{
  dbus_uint32_t v_UINT32;

  _dbus_return_val_if_fail (message != NULL, 0);

  if (_dbus_header_get_field_basic (&message->header,
                                    DBUS_HEADER_FIELD_REPLY_SERIAL,
                                    DBUS_TYPE_UINT32,
                                    &v_UINT32))
    return v_UINT32;
  else
    return 0;
}

static void
dbus_message_finalize (DBusMessage *message)
{
  _dbus_assert (message->refcount.value == 0);

  /* This calls application callbacks! */
  _dbus_data_slot_list_free (&message->slot_list);

  _dbus_list_foreach (&message->size_counters,
                      free_size_counter, message);
  _dbus_list_clear (&message->size_counters);

  _dbus_header_free (&message->header);
  _dbus_string_free (&message->body);

  _dbus_assert (message->refcount.value == 0);
  
  dbus_free (message);
}

947 948
static DBusMessage*
dbus_message_new_empty_header (void)
949
{
950 951
  DBusMessage *message;
  dbus_bool_t from_cache;
952

953
  message = dbus_message_get_cached ();
954

955
  if (message != NULL)
956
    {
957
      from_cache = TRUE;
958 959 960
    }
  else
    {
961 962 963 964 965 966
      from_cache = FALSE;
      message = dbus_new (DBusMessage, 1);
      if (message == NULL)
        return NULL;
#ifndef DBUS_DISABLE_CHECKS
      message->generation = _dbus_current_generation;
967
#endif
968
    }
969
  
970 971 972
  message->refcount.value = 1;
  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
  message->locked = FALSE;
973 974 975
#ifndef DBUS_DISABLE_CHECKS
  message->in_cache = FALSE;
#endif
976 977 978
  message->size_counters = NULL;
  message->size_counter_delta = 0;
  message->changed_stamp = 0;
979

980 981
  if (!from_cache)
    _dbus_data_slot_list_init (&message->slot_list);
982

983
  if (from_cache)
984
    {
985 986
      _dbus_header_reinit (&message->header, message->byte_order);
      _dbus_string_set_length (&message->body, 0);
987 988 989
    }
  else
    {
990 991 992 993 994
      if (!_dbus_header_init (&message->header, message->byte_order))
        {
          dbus_free (message);
          return NULL;
        }
995

996 997 998 999 1000 1001
      if (!_dbus_string_init_preallocated (&message->body, 32))
        {
          _dbus_header_free (&message->header);
          dbus_free (message);
          return NULL;
        }
1002
    }
1003

1004
  return message;
1005 1006
}

1007
/**
1008 1009 1010
 * Constructs a new message of the given message type.
 * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL,
 * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth.
1011
 *
1012 1013 1014 1015
 * Usually you want to use dbus_message_new_method_call(),
 * dbus_message_new_method_return(), dbus_message_new_signal(),
 * or dbus_message_new_error() instead.
 * 
1016
 * @param message_type type of message
1017
 * @returns new message or #NULL if no memory
1018
 */
1019 1020
DBusMessage*
dbus_message_new (int message_type)
1021
{
1022
  DBusMessage *message;
1023

1024
  _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL);
1025

1026 1027 1028
  message = dbus_message_new_empty_header ();
  if (message == NULL)
    return NULL;
1029

1030 1031 1032
  if (!_dbus_header_create (&message->header,
                            message_type,
                            NULL, NULL, NULL, NULL, NULL))
1033
    {
1034 1035
      dbus_message_unref (message);
      return NULL;
1036 1037
    }

1038
  return message;
1039 1040
}

1041
/**
1042 1043 1044
 * Constructs a new message to invoke a method on a remote
 * object. Returns #NULL if memory can't be allocated for the
 * message. The destination may be #NULL in which case no destination
John Palmieri's avatar
John Palmieri committed
1045
 * is set; this is appropriate when using D-Bus in a peer-to-peer
1046 1047 1048
 * context (no message bus). The interface may be #NULL, which means
 * that if multiple methods with the given name exist it is undefined
 * which one will be invoked.
1049 1050 1051 1052 1053 1054
 *
 * The path and method names may not be #NULL.
 *
 * Destination, path, interface, and method name can't contain
 * any invalid characters (see the D-Bus specification).
 * 
1055
 * @param destination name that the message should be sent to or #NULL
1056
 * @param path object path the message should be sent to
1057
 * @param interface interface to invoke method on, or #NULL
1058
 * @param method method to invoke
1059
 *
1060
 * @returns a new DBusMessage, free with dbus_message_unref()
1061
 */
1062 1063 1064 1065 1066
DBusMessage*
dbus_message_new_method_call (const char *destination,
                              const char *path,
                              const char *interface,
                              const char *method)
1067
{
1068
  DBusMessage *message;
1069

1070 1071 1072
  _dbus_return_val_if_fail (path != NULL, NULL);
  _dbus_return_val_if_fail (method != NULL, NULL);
  _dbus_return_val_if_fail (destination == NULL ||
1073
                            _dbus_check_is_valid_bus_name (destination), NULL);
1074 1075 1076 1077
  _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
  _dbus_return_val_if_fail (interface == NULL ||
                            _dbus_check_is_valid_interface (interface), NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL);
1078

1079 1080 1081
  message = dbus_message_new_empty_header ();
  if (message == NULL)
    return NULL;
1082

1083 1084 1085 1086 1087 1088 1089
  if (!_dbus_header_create (&message->header,
                            DBUS_MESSAGE_TYPE_METHOD_CALL,
                            destination, path, interface, method, NULL))
    {
      dbus_message_unref (message);
      return NULL;
    }
1090

1091
  return message;
1092 1093
}

1094
/**
1095 1096
 * Constructs a message that is a reply to a method call. Returns
 * #NULL if memory can't be allocated for the message.
1097
 *
1098
 * @param method_call the message being replied to
1099
 * @returns a new DBusMessage, free with dbus_message_unref()
1100
 */
1101 1102
DBusMessage*
dbus_message_new_method_return (DBusMessage *method_call)
1103
{
1104 1105
  DBusMessage *message;
  const char *sender;
1106

1107
  _dbus_return_val_if_fail (method_call != NULL, NULL);
1108

1109
  sender = dbus_message_get_sender (method_call);
1110

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
  /* sender is allowed to be null here in peer-to-peer case */

  message = dbus_message_new_empty_header ();
  if (message == NULL)
    return NULL;

  if (!_dbus_header_create (&message->header,
                            DBUS_MESSAGE_TYPE_METHOD_RETURN,
                            sender, NULL, NULL, NULL, NULL))
    {
      dbus_message_unref (message);
      return NULL;
    }
1124

1125
  dbus_message_set_no_reply (message, TRUE);
1126

1127 1128 1129 1130 1131 1132
  if (!dbus_message_set_reply_serial (message,
                                      dbus_message_get_serial (method_call)))
    {
      dbus_message_unref (message);
      return NULL;
    }
1133

1134
  return message;
1135 1136 1137
}

/**
1138 1139
 * Constructs a new message representing a signal emission. Returns
 * #NULL if memory can't be allocated for the message.  A signal is
1140 1141
 * identified by its originating object path, interface, and the name
 * of the signal.
1142
 *
1143 1144 1145
 * Path, interface, and signal name must all be valid (the D-Bus
 * specification defines the syntax of these fields).
 * 
1146 1147 1148 1149
 * @param path the path to the object emitting the signal
 * @param interface the interface the signal is emitted from
 * @param name name of the signal
 * @returns a new DBusMessage, free with dbus_message_unref()
1150
 */
1151 1152 1153 1154
DBusMessage*
dbus_message_new_signal (const char *path,
                         const char *interface,
                         const char *name)
1155
{
1156
  DBusMessage *message;
1157

1158 1159 1160 1161 1162 1163
  _dbus_return_val_if_fail (path != NULL, NULL);
  _dbus_return_val_if_fail (interface != NULL, NULL);
  _dbus_return_val_if_fail (name != NULL, NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_interface (interface), NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL);
1164

1165 1166 1167
  message = dbus_message_new_empty_header ();
  if (message == NULL)
    return NULL;
1168

1169 1170 1171
  if (!_dbus_header_create (&message->header,
                            DBUS_MESSAGE_TYPE_SIGNAL,
                            NULL, path, interface, name, NULL))
1172
    {
1173 1174
      dbus_message_unref (message);
      return NULL;
1175 1176
    }

1177
  dbus_message_set_no_reply (message, TRUE);
1178

1179
  return message;
1180 1181 1182
}

/**
1183 1184 1185
 * Creates a new message that is an error reply to another message.
 * Error replies are most common in response to method calls, but
 * can be returned in reply to any message.
1186
 *
1187 1188 1189 1190 1191
 * The error name must be a valid error name according to the syntax
 * given in the D-Bus specification. If you don't want to make
 * up an error name just use #DBUS_ERROR_FAILED.
 *
 * @param reply_to the message we're replying to
1192
 * @param error_name the error name
1193 1194
 * @param error_message the error message string (or #NULL for none, but please give a message)
 * @returns a new error message object, free with dbus_message_unref()
1195
 */
1196 1197 1198 1199
DBusMessage*
dbus_message_new_error (DBusMessage *reply_to,
                        const char  *error_name,
                        const char  *error_message)
1200
{
1201 1202 1203
  DBusMessage *message;
  const char *sender;
  DBusMessageIter iter;
1204

1205 1206 1207
  _dbus_return_val_if_fail (reply_to != NULL, NULL);
  _dbus_return_val_if_fail (error_name != NULL, NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL);
1208

1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221
  sender = dbus_message_get_sender (reply_to);

  /* sender may be NULL for non-message-bus case or
   * when the message bus is dealing with an unregistered
   * connection.
   */
  message = dbus_message_new_empty_header ();
  if (message == NULL)
    return NULL;

  if (!_dbus_header_create (&message->header,
                            DBUS_MESSAGE_TYPE_ERROR,
                            sender, NULL, NULL, NULL, error_name))
1222
    {
1223 1224 1225
      dbus_message_unref (message);
      return NULL;
    }
1226

1227
  dbus_message_set_no_reply (message, TRUE);
1228

1229 1230 1231 1232 1233 1234
  if (!dbus_message_set_reply_serial (message,
                                      dbus_message_get_serial (reply_to)))
    {
      dbus_message_unref (message);
      return NULL;
    }
1235

1236 1237
  if (error_message != NULL)
    {
1238
      dbus_message_iter_init_append (message, &iter);
1239 1240 1241
      if (!dbus_message_iter_append_basic (&iter,
                                           DBUS_TYPE_STRING,
                                           &error_message))
1242
        {
1243 1244
          dbus_message_unref (message);
          return NULL;
1245 1246
        }
    }
1247 1248

  return message;
1249
}
1250

1251
/**
1252 1253 1254 1255 1256
 * Creates a new message that is an error reply to another message, allowing
 * you to use printf formatting.
 *
 * See dbus_message_new_error() for details - this function is the same
 * aside from the printf formatting.
1257
 *
1258 1259 1260
 * @todo add _DBUS_GNUC_PRINTF to this (requires moving _DBUS_GNUC_PRINTF to
 * public header, see DBUS_GNUC_DEPRECATED for an example)
 * 
1261 1262 1263 1264 1265
 * @param reply_to the original message
 * @param error_name the error name
 * @param error_format the error message format as with printf
 * @param ... format string arguments
 * @returns a new error message
1266
 */
1267 1268 1269 1270 1271
DBusMessage*
dbus_message_new_error_printf (DBusMessage *reply_to,
			       const char  *error_name,
			       const char  *error_format,
			       ...)
1272
{
1273 1274 1275
  va_list args;
  DBusString str;
  DBusMessage *message;
1276

1277 1278 1279
  _dbus_return_val_if_fail (reply_to != NULL, NULL);
  _dbus_return_val_if_fail (error_name != NULL, NULL);
  _dbus_return_val_if_fail (_dbus_check_is_valid_error_name (error_name), NULL);
1280

1281 1282
  if (!_dbus_string_init (&str))
    return NULL;
1283

1284
  va_start (args, error_format);
1285