dbus-message.c 139 KB
Newer Older
1 2 3
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-message.c  DBusMessage object
 *
4
 * Copyright (C) 2002, 2003  Red Hat Inc.
5
 * Copyright (C) 2002, 2003  CodeFactory AB
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * Licensed under the Academic Free License version 1.2
 * 
 * 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.
 * 
 * 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
#include "dbus-marshal.h"
27
#include "dbus-message.h"
28 29 30
#include "dbus-message-internal.h"
#include "dbus-memory.h"
#include "dbus-list.h"
31
#include "dbus-message-builder.h"
32
#include <string.h>
33

34
/**
35 36 37
 * @defgroup DBusMessageInternals DBusMessage implementation details
 * @ingroup DBusInternals
 * @brief DBusMessage private implementation details.
38
 *
39
 * The guts of DBusMessage and its methods.
40 41 42 43
 *
 * @{
 */

44 45 46 47 48 49 50 51 52 53 54 55 56
enum
{
  FIELD_HEADER_LENGTH,
  FIELD_BODY_LENGTH,
  FIELD_CLIENT_SERIAL,
  FIELD_NAME,
  FIELD_SERVICE,
  FIELD_SENDER,
  FIELD_REPLY_SERIAL,

  FIELD_LAST
};

57 58 59 60 61 62 63 64 65 66 67
static dbus_bool_t field_is_named[FIELD_LAST] =
{
  FALSE, /* FIELD_HEADER_LENGTH */
  FALSE, /* FIELD_BODY_LENGTH */
  FALSE, /* FIELD_CLIENT_SERIAL */
  TRUE,  /* FIELD_NAME */
  TRUE,  /* FIELD_SERVICE */
  TRUE,  /* FIELD_SENDER */
  TRUE   /* FIELD_REPLY_SERIAL */
};

68 69 70 71 72 73 74
typedef struct
{
  int offset; /**< Offset to start of field (location of name of field
               * for named fields)
               */
} HeaderField;

75
/**
76 77
 * @brief Internals of DBusMessage
 * 
78
 * Object representing a message received from or to be sent to
79 80
 * another application. This is an opaque object, all members
 * are private.
81
 */
82 83
struct DBusMessage
{
84
  dbus_atomic_t refcount; /**< Reference count */
85

86 87 88 89
  DBusString header; /**< Header network data, stored
                      * separately from body so we can
                      * independently realloc it.
                      */
90

91 92 93
  HeaderField header_fields[FIELD_LAST]; /**< Track the location
                                           * of each field in "header"
                                           */
94

95 96
  dbus_uint32_t client_serial; /**< Cached client serial value for speed */
  dbus_uint32_t reply_serial;  /**< Cached reply serial value for speed */
97
  
98
  int header_padding; /**< bytes of alignment in header */
99
  
100
  DBusString body;   /**< Body network data. */
101

102
  char byte_order; /**< Message byte order. */
103

104 105
  DBusList *size_counters;   /**< 0-N DBusCounter used to track message size. */
  long size_counter_delta;   /**< Size we incremented the size counters by.   */
106

107
  dbus_uint32_t changed_stamp; /**< Incremented when iterators are invalidated. */
108
  
109
  unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
110 111
};

112 113 114 115 116 117
enum {
  DBUS_MESSAGE_ITER_TYPE_MESSAGE,
  DBUS_MESSAGE_ITER_TYPE_ARRAY,
  DBUS_MESSAGE_ITER_TYPE_DICT
};

118
/** typedef for internals of message iterator */
119 120
typedef struct DBusMessageRealIter DBusMessageRealIter;

121 122 123 124 125
/**
 * @brief Internals of DBusMessageIter
 * 
 * Object representing a position in a message. All fields are internal.
 */
126
struct DBusMessageRealIter
127
{
128
  DBusMessageRealIter *parent_iter; /**< parent iter, or NULL */
129
  DBusMessage *message; /**< Message used */
130 131 132 133 134 135 136 137 138
  dbus_uint32_t changed_stamp; /**< stamp to detect invalid iters */
  
  /* This is an int instead of an enum to get a guaranteed size for the dummy: */
  int type; /**< type of iter */
  
  int pos; /**< Current position in the string */
  int end; /**< position right after the container */
  int container_start; /**< offset of the start of the container */
  int container_length_pos; /**< offset of the length of the container */
139
  
140
  int wrote_dict_key; /**< whether we wrote the dict key for the current dict element */
141 142 143

  int array_type_pos; /**< pointer to the position of the array element type */
  int array_type_done; /**< TRUE if the array type is fully finished */
144 145
};

146 147 148 149 150 151 152 153 154 155 156 157
/**
 * 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,
158 159
                                const DBusString    **header,
                                const DBusString    **body)
160 161 162
{
  _dbus_assert (message->locked);
  
163 164
  *header = &message->header;
  *body = &message->body;
165 166
}

167 168 169 170 171 172
static void
clear_header_padding (DBusMessage *message)
{
  _dbus_string_shorten (&message->header,
                        message->header_padding);
  message->header_padding = 0;
173
}              
174 175 176 177 178 179 180 181 182 183 184 185 186 187

static dbus_bool_t
append_header_padding (DBusMessage *message)
{
  int old_len;
  old_len = _dbus_string_get_length (&message->header);
  if (!_dbus_string_align_length (&message->header, 8))
    return FALSE;

  message->header_padding = _dbus_string_get_length (&message->header) - old_len;

  return TRUE;
}

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
static void
adjust_field_offsets (DBusMessage *message,
                      int          offsets_after,
                      int          delta)
{
  int i;

  if (delta == 0)
    return;
  
  i = 0;
  while (i < FIELD_LAST)
    {
      if (message->header_fields[i].offset > offsets_after)
        message->header_fields[i].offset += delta;

      ++i;
    }
}

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
#ifdef DBUS_BUILD_TESTS
/* tests-only until it's actually used */
static dbus_int32_t
get_int_field (DBusMessage *message,
               int          field)
{
  int offset;

  _dbus_assert (field < FIELD_LAST);
  
  offset = message->header_fields[field].offset;
  
  if (offset < 0)
    return -1; /* useless if -1 is a valid value of course */
  
  return _dbus_demarshal_int32 (&message->header,
                                message->byte_order,
                                offset,
                                NULL);
}
#endif

static dbus_uint32_t
get_uint_field (DBusMessage *message,
                int          field)
{
  int offset;
  
  _dbus_assert (field < FIELD_LAST);
  
  offset = message->header_fields[field].offset;
  
  if (offset < 0)
    return -1; /* useless if -1 is a valid value of course */
  
  return _dbus_demarshal_uint32 (&message->header,
                                 message->byte_order,
                                 offset,
                                 NULL);
}

249 250 251 252 253
static const char*
get_string_field (DBusMessage *message,
                  int          field,
                  int         *len)
{
254
  int offset;
255
  const char *data;
256 257 258 259

  offset = message->header_fields[field].offset;

  _dbus_assert (field < FIELD_LAST);
260 261 262 263 264 265 266 267 268 269
  
  if (offset < 0)
    return NULL;

  /* offset points to string length, string data follows it */
  /* FIXME _dbus_demarshal_const_string() that returned
   * a reference to the string plus its len might be nice.
   */
  
  if (len)
270 271 272 273
    *len = _dbus_demarshal_uint32 (&message->header,
                                   message->byte_order,
                                   offset,
                                   NULL);
274

275
  data = _dbus_string_get_const_data (&message->header);
276 277 278 279
  
  return data + (offset + 4); 
}

280
#ifdef DBUS_BUILD_TESTS
281 282 283 284 285 286 287 288 289
static dbus_bool_t
append_int_field (DBusMessage *message,
                  int          field,
                  const char  *name,
                  int          value)
{
  int orig_len;

  _dbus_assert (!message->locked);
290 291

  clear_header_padding (message);
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
  
  orig_len = _dbus_string_get_length (&message->header);
  
  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;  
  
  if (!_dbus_string_append_len (&message->header, name, 4))
    goto failed;

  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
    goto failed;

  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;
  
  message->header_fields[FIELD_REPLY_SERIAL].offset =
    _dbus_string_get_length (&message->header);
  
310
  if (!_dbus_marshal_int32 (&message->header, message->byte_order,
311 312 313
                            value))
    goto failed;

314 315 316
  if (!append_header_padding (message))
    goto failed;
  
317 318 319 320 321
  return TRUE;
  
 failed:
  message->header_fields[field].offset = -1;
  _dbus_string_set_length (&message->header, orig_len);
322 323 324 325 326 327

  /* this must succeed because it was allocated on function entry and
   * DBusString doesn't ever realloc smaller
   */
  if (!append_header_padding (message))
    _dbus_assert_not_reached ("failed to reappend header padding");
328 329
  return FALSE;
}
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
#endif

static dbus_bool_t
append_uint_field (DBusMessage *message,
                   int          field,
                   const char  *name,
                   int          value)
{
  int orig_len;

  _dbus_assert (!message->locked);

  clear_header_padding (message);
  
  orig_len = _dbus_string_get_length (&message->header);
  
  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;  
  
  if (!_dbus_string_append_len (&message->header, name, 4))
    goto failed;

  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32))
    goto failed;

  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;
  
  message->header_fields[FIELD_REPLY_SERIAL].offset =
    _dbus_string_get_length (&message->header);
  
  if (!_dbus_marshal_uint32 (&message->header, message->byte_order,
                             value))
    goto failed;

  if (!append_header_padding (message))
    goto failed;
  
  return TRUE;
  
 failed:
  message->header_fields[field].offset = -1;
  _dbus_string_set_length (&message->header, orig_len);

  /* this must succeed because it was allocated on function entry and
   * DBusString doesn't ever realloc smaller
   */
  if (!append_header_padding (message))
    _dbus_assert_not_reached ("failed to reappend header padding");
  return FALSE;
}
381 382 383 384 385 386 387 388 389 390

static dbus_bool_t
append_string_field (DBusMessage *message,
                     int          field,
                     const char  *name,
                     const char  *value)
{
  int orig_len;

  _dbus_assert (!message->locked);
391 392

  clear_header_padding (message);
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
  
  orig_len = _dbus_string_get_length (&message->header);

  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;
  
  if (!_dbus_string_append_len (&message->header, name, 4))
    goto failed;
  
  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
    goto failed;

  if (!_dbus_string_align_length (&message->header, 4))
    goto failed;
  
  message->header_fields[field].offset =
    _dbus_string_get_length (&message->header);
  
411
  if (!_dbus_marshal_string (&message->header, message->byte_order,
412 413 414
                             value))
    goto failed;

415 416 417
  if (!append_header_padding (message))
    goto failed;
  
418 419 420 421 422
  return TRUE;
  
 failed:
  message->header_fields[field].offset = -1;
  _dbus_string_set_length (&message->header, orig_len);
423 424 425 426 427 428 429

  /* this must succeed because it was allocated on function entry and
   * DBusString doesn't ever realloc smaller
   */
  if (!append_header_padding (message))
    _dbus_assert_not_reached ("failed to reappend header padding");
  
430 431 432
  return FALSE;
}

433 434 435 436
#ifdef DBUS_BUILD_TESTS
/* This isn't used, but building it when tests are enabled just to
 * keep it compiling if we need it in future
 */
437
static void
438 439
delete_int_or_uint_field (DBusMessage *message,
                          int          field)
440 441 442 443 444 445 446 447 448
{
  int offset = message->header_fields[field].offset;

  _dbus_assert (!message->locked);
  _dbus_assert (field_is_named[field]);
  
  if (offset < 0)
    return;  

449 450
  clear_header_padding (message);
  
451 452 453 454 455 456 457 458 459 460
  /* The field typecode and name take up 8 bytes */
  _dbus_string_delete (&message->header,
                       offset - 8,
                       12);

  message->header_fields[field].offset = -1;
  
  adjust_field_offsets (message,
                        offset - 8,
                        - 12);
461 462

  append_header_padding (message);
463
}
464
#endif
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479

static void
delete_string_field (DBusMessage *message,
                     int          field)
{
  int offset = message->header_fields[field].offset;
  int len;
  int delete_len;
  
  _dbus_assert (!message->locked);
  _dbus_assert (field_is_named[field]);
  
  if (offset < 0)
    return;

480 481
  clear_header_padding (message);
  
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
  get_string_field (message, field, &len);
  
  /* The field typecode and name take up 8 bytes, and the nul
   * termination is 1 bytes, string length integer is 4 bytes
   */
  delete_len = 8 + 4 + 1 + len;
  
  _dbus_string_delete (&message->header,
                       offset - 8,
                       delete_len);

  message->header_fields[field].offset = -1;
  
  adjust_field_offsets (message,
                        offset - 8,
                        - delete_len);
498 499

  append_header_padding (message);
500 501
}

502
#ifdef DBUS_BUILD_TESTS
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
static dbus_bool_t
set_int_field (DBusMessage *message,
               int          field,
               int          value)
{
  int offset = message->header_fields[field].offset;

  _dbus_assert (!message->locked);
  
  if (offset < 0)
    {
      /* need to append the field */

      switch (field)
        {
        default:
          _dbus_assert_not_reached ("appending an int field we don't support appending");
          return FALSE;
        }
    }
  else
    {
      _dbus_marshal_set_int32 (&message->header,
                               message->byte_order,
                               offset, value);

      return TRUE;
    }
}
532
#endif
533

534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
static dbus_bool_t
set_uint_field (DBusMessage  *message,
                int           field,
                dbus_uint32_t value)
{
  int offset = message->header_fields[field].offset;

  _dbus_assert (!message->locked);
  
  if (offset < 0)
    {
      /* need to append the field */

      switch (field)
        {
549 550 551 552
        case FIELD_REPLY_SERIAL:
          return append_uint_field (message, field,
                                    DBUS_HEADER_FIELD_REPLY,
                                    value);
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
        default:
          _dbus_assert_not_reached ("appending a uint field we don't support appending");
          return FALSE;
        }
    }
  else
    {
      _dbus_marshal_set_uint32 (&message->header,
                                message->byte_order,
                                offset, value);

      return TRUE;
    }
}

568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
static dbus_bool_t
set_string_field (DBusMessage *message,
                  int          field,
                  const char  *value)
{
  int offset = message->header_fields[field].offset;

  _dbus_assert (!message->locked);
  _dbus_assert (value != NULL);
  
  if (offset < 0)
    {      
      /* need to append the field */

      switch (field)
        {
        case FIELD_SENDER:
          return append_string_field (message, field,
                                      DBUS_HEADER_FIELD_SENDER,
                                      value);
        default:
          _dbus_assert_not_reached ("appending a string field we don't support appending");
          return FALSE;
        }
    }
  else
    {
      DBusString v;
      int old_len;
      int new_len;
598 599 600
      int len;
      
      clear_header_padding (message);
601 602 603
      
      old_len = _dbus_string_get_length (&message->header);

604 605
      len = strlen (value);
      
606
      _dbus_string_init_const_len (&v, value,
607
				   len + 1); /* include nul */
608 609
      if (!_dbus_marshal_set_string (&message->header,
                                     message->byte_order,
610 611 612
                                     offset, &v,
				     len))
        goto failed;
613 614 615 616 617 618 619
      
      new_len = _dbus_string_get_length (&message->header);

      adjust_field_offsets (message,
                            offset,
                            new_len - old_len);

620 621 622
      if (!append_header_padding (message))
	goto failed;
      
623
      return TRUE;
624 625 626 627 628 629 630 631 632

    failed:
      /* this must succeed because it was allocated on function entry and
       * DBusString doesn't ever realloc smaller
       */
      if (!append_header_padding (message))
	_dbus_assert_not_reached ("failed to reappend header padding");

      return FALSE;
633 634 635
    }
}

636
/**
637
 * Sets the serial number of a message. 
638
 * This can only be done once on a message.
639
 * 
640
 * @param message the message
641
 * @param serial the serial
642 643
 */
void
644 645
_dbus_message_set_serial (DBusMessage  *message,
                          dbus_int32_t  serial)
646
{
647
  _dbus_assert (!message->locked);
648
  _dbus_assert (dbus_message_get_serial (message) == 0);
649
  
650 651
  set_uint_field (message, FIELD_CLIENT_SERIAL,
                  serial);
652
  message->client_serial = serial;
653 654 655 656 657 658 659 660 661 662 663
}

/**
 * Sets the reply serial of a message (the client serial
 * of the message this is a reply to).
 *
 * @param message the message
 * @param reply_serial the client serial
 * @returns #FALSE if not enough memory
 */
dbus_bool_t
664 665
dbus_message_set_reply_serial (DBusMessage   *message,
                               dbus_uint32_t  reply_serial)
666 667 668
{
  _dbus_assert (!message->locked);

669 670
  if (set_uint_field (message, FIELD_REPLY_SERIAL,
                      reply_serial))
671 672 673 674 675 676
    {
      message->reply_serial = reply_serial;
      return TRUE;
    }
  else
    return FALSE;
677 678
}

679
/**
680 681 682
 * Returns the serial of a message or -1 if none has been specified.
 * The message's serial number is provided by the application sending
 * the message and is used to identify replies to this message.
683
 *
684 685 686
 * @param message the message
 * @returns the client serial
 */
687
dbus_uint32_t
688
dbus_message_get_serial (DBusMessage *message)
689
{
690
  return message->client_serial;
691 692
}

693 694
/**
 * Returns the serial that the message is
695
 * a reply to or 0 if none.
696 697 698 699
 *
 * @param message the message
 * @returns the reply serial
 */
700
dbus_uint32_t
701
dbus_message_get_reply_serial  (DBusMessage *message)
702
{
703
  return message->reply_serial;
704 705
}

706 707 708 709
/**
 * 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.
710 711 712 713
 * 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.
714 715
 *
 * @param message the message
716
 * @param link link with counter as data
717 718
 */
void
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
_dbus_message_add_size_counter_link (DBusMessage  *message,
                                     DBusList     *link)
{
  /* 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) +
        _dbus_string_get_length (&message->body);
      
#if 0
      _dbus_verbose ("message has size %ld\n",
                     message->size_counter_delta);
#endif
    }
  
  _dbus_list_append_link (&message->size_counters, link);
  
  _dbus_counter_adjust (link->data, message->size_counter_delta);
}

/**
 * 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
755 756 757
_dbus_message_add_size_counter (DBusMessage *message,
                                DBusCounter *counter)
{
758
  DBusList *link;
759

760 761 762
  link = _dbus_list_alloc_link (counter);
  if (link == NULL)
    return FALSE;
763

764 765
  _dbus_counter_ref (counter);
  _dbus_message_add_size_counter_link (message, link);
766

767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
  return TRUE;
}

/**
 * Removes a counter tracking the size of this message, and decrements
 * the counter by the size of this message.
 *
 * @param message the message
 * @param counter the counter
 */
void
_dbus_message_remove_size_counter (DBusMessage  *message,
                                   DBusCounter  *counter)
{
  if (!_dbus_list_remove_last (&message->size_counters,
                               counter))
    _dbus_assert_not_reached ("Removed a message size counter that was not added");

  _dbus_counter_adjust (counter, message->size_counter_delta);

  _dbus_counter_unref (counter);
788 789
}

790 791 792 793
static dbus_bool_t
dbus_message_create_header (DBusMessage *message,
                            const char  *service,
                            const char  *name)
794 795 796
{
  unsigned int flags;
  
797
  if (!_dbus_string_append_byte (&message->header, message->byte_order))
798
    return FALSE;
799 800 801 802 803 804 805 806 807

  flags = 0;
  if (!_dbus_string_append_byte (&message->header, flags))
    return FALSE;

  if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION))
    return FALSE;

  if (!_dbus_string_append_byte (&message->header, 0))
808
    return FALSE;
809

810
  message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
811
  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
812
    return FALSE;
813

814
  message->header_fields[FIELD_BODY_LENGTH].offset = 8;
815
  if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
816
    return FALSE;
817

818 819 820 821
  message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
  if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
    return FALSE;
  
822
  /* Marshal message service */
823
  if (service != NULL)
824
    {
825 826 827 828 829
      if (!append_string_field (message,
                                FIELD_SERVICE,
                                DBUS_HEADER_FIELD_SERVICE,
                                service))
        return FALSE;
830
    }
831

832 833 834 835 836 837
  _dbus_assert (name != NULL);
  if (!append_string_field (message,
                            FIELD_NAME,
                            DBUS_HEADER_FIELD_NAME,
                            name))
    return FALSE;
838
  
839
  return TRUE;
840 841
}

842 843 844 845 846 847 848 849 850 851
/**
 * 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
852
_dbus_message_lock (DBusMessage  *message)
853
{
854
  if (!message->locked)
855 856
    {
      /* Fill in our lengths */
857 858 859
      set_uint_field (message,
                      FIELD_HEADER_LENGTH,
                      _dbus_string_get_length (&message->header));
860

861 862 863
      set_uint_field (message,
                      FIELD_BODY_LENGTH,
                      _dbus_string_get_length (&message->body));
864 865 866

      message->locked = TRUE;
    }
867 868
}

869 870 871 872 873
/** @} */

/**
 * @defgroup DBusMessage DBusMessage
 * @ingroup  DBus
874
 * @brief Message to be sent or received over a DBusConnection.
875
 *
876 877 878 879
 * 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.
880 881 882 883 884 885 886 887 888 889 890
 *
 * @{
 */

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

891 892 893 894 895 896 897 898 899 900 901 902
static DBusMessage*
dbus_message_new_empty_header (void)
{
  DBusMessage *message;
  int i;
  
  message = dbus_new0 (DBusMessage, 1);
  if (message == NULL)
    return NULL;
  
  message->refcount = 1;
  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
903 904
  message->client_serial = 0;
  message->reply_serial = 0;
905 906 907 908 909 910 911 912
  
  i = 0;
  while (i < FIELD_LAST)
    {
      message->header_fields[i].offset = -1;
      ++i;
    }
  
913
  if (!_dbus_string_init (&message->header))
914 915 916 917 918
    {
      dbus_free (message);
      return NULL;
    }
  
919
  if (!_dbus_string_init (&message->body))
920 921 922 923 924 925 926 927 928 929
    {
      _dbus_string_free (&message->header);
      dbus_free (message);
      return NULL;
    }
  
  return message;
}


930
/**
931 932 933 934
 * Constructs a new message. Returns #NULL if memory can't be
 * allocated for the message. The service may be #NULL in which case
 * no service is set; this is appropriate when using D-BUS in a
 * peer-to-peer context (no message bus).
935
 *
936 937
 * @todo reverse the arguments, first 'name' then 'service'
 * as 'name' is more fundamental
938
 *
939
 * @param service service that the message should be sent to or #NULL
940 941
 * @param name name of the message
 * @returns a new DBusMessage, free with dbus_message_unref()
942 943
 * @see dbus_message_unref()
 */
944
DBusMessage*
945 946
dbus_message_new (const char *service,
		  const char *name)
947
{
948 949
  DBusMessage *message;

950
  message = dbus_message_new_empty_header ();
951 952
  if (message == NULL)
    return NULL;
953
  
954
  if (!dbus_message_create_header (message, service, name))
955
    {
956
      dbus_message_unref (message);
957 958 959
      return NULL;
    }
  
960
  return message;
961
}
962

963 964 965 966 967 968 969 970 971 972 973
/**
 * Constructs a message that is a reply to some other
 * message. Returns #NULL if memory can't be allocated
 * for the message.
 *
 * @param original_message the message which the created
 * message is a reply to.
 * @returns a new DBusMessage, free with dbus_message_unref()
 * @see dbus_message_new(), dbus_message_unref()
 */ 
DBusMessage*
974
dbus_message_new_reply (DBusMessage *original_message)
975 976
{
  DBusMessage *message;
977
  const char *sender, *name;
978 979 980

  sender = get_string_field (original_message,
                             FIELD_SENDER, NULL);
981 982
  name = get_string_field (original_message,
			   FIELD_NAME, NULL);
983 984

  /* sender is allowed to be null here in peer-to-peer case */
985
  
986
  message = dbus_message_new (sender, name);
987 988 989 990
  
  if (message == NULL)
    return NULL;

991 992
  if (!dbus_message_set_reply_serial (message,
                                      dbus_message_get_serial (original_message)))
993 994 995 996
    {
      dbus_message_unref (message);
      return NULL;
    }
997 998 999 1000

  return message;
}

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
/**
 * Creates a new message that is an error reply to a certain message.
 *
 * @param original_message the original message
 * @param error_name the error name
 * @param error_message the error message string
 * @returns a new error message
 */
DBusMessage*
dbus_message_new_error_reply (DBusMessage *original_message,
			      const char  *error_name,
			      const char  *error_message)
{
  DBusMessage *message;
  const char *sender;
1016
  DBusMessageIter iter;
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

  sender = get_string_field (original_message,
                             FIELD_SENDER, NULL);
  
  _dbus_assert (sender != NULL);
  
  message = dbus_message_new (sender, error_name);
  
  if (message == NULL)
    return NULL;

1028 1029
  if (!dbus_message_set_reply_serial (message,
                                      dbus_message_get_serial (original_message)))
1030 1031 1032 1033 1034
    {
      dbus_message_unref (message);
      return NULL;
    }

1035 1036
  dbus_message_append_iter_init (message, &iter);
  if (!dbus_message_iter_append_string (&iter, error_message))
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    {
      dbus_message_unref (message);
      return NULL;
    }

  dbus_message_set_is_error (message, TRUE);
  
  return message;
}

1047 1048 1049 1050 1051 1052
/**
 * Creates a new message that is an exact replica of the message
 * specified, except that its refcount is set to 1.
 *
 * @param message the message.
 * @returns the new message.
Anders Carlsson's avatar
Anders Carlsson committed
1053
 */
1054
DBusMessage *
1055
dbus_message_copy (const DBusMessage *message)
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
{
  DBusMessage *retval;
  int i;
  
  retval = dbus_new0 (DBusMessage, 1);
  if (retval == NULL)
    return NULL;
  
  retval->refcount = 1;
  retval->byte_order = message->byte_order;
1066 1067 1068 1069 1070
  retval->client_serial = message->client_serial;
  retval->reply_serial = message->reply_serial;
  retval->header_padding = message->header_padding;
  retval->locked = FALSE;
  
1071
  if (!_dbus_string_init (&retval->header))
1072 1073 1074 1075 1076
    {
      dbus_free (retval);
      return NULL;
    }
  
1077
  if (!_dbus_string_init (&retval->body))
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
    {
      _dbus_string_free (&retval->header);
      dbus_free (retval);
      return NULL;
    }

  if (!_dbus_string_copy (&message->header, 0,
			  &retval->header, 0))
    {
      _dbus_string_free (&retval->header);
      _dbus_string_free (&retval->body);
      dbus_free (retval);

      return NULL;
    }

  if (!_dbus_string_copy (&message->body, 0,
			  &retval->body, 0))
    {
      _dbus_string_free (&retval->header);
      _dbus_string_free (&retval->body);
      dbus_free (retval);

      return NULL;
    }

  for (i = 0; i < FIELD_LAST; i++)
    {
      retval->header_fields[i].offset = message->header_fields[i].offset;
    }
  
  return retval;
}

1112 1113 1114 1115

/**
 * Increments the reference count of a DBusMessage.
 *
1116
 * @param message The message
1117 1118 1119 1120 1121
 * @see dbus_message_unref
 */
void
dbus_message_ref (DBusMessage *message)
{
1122 1123 1124 1125
  dbus_atomic_t refcount;

  refcount = _dbus_atomic_inc (&message->refcount);
  _dbus_assert (refcount > 1);
1126 1127
}

1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
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);
}

1140 1141 1142
/**
 * Decrements the reference count of a DBusMessage.
 *
1143
 * @param message The message
1144 1145 1146 1147 1148
 * @see dbus_message_ref
 */
void
dbus_message_unref (DBusMessage *message)
{
1149
  dbus_atomic_t refcount;
1150

1151 1152 1153 1154 1155
  refcount = _dbus_atomic_dec (&message->refcount);
  
  _dbus_assert (refcount >= 0);

  if (refcount == 0)
1156
    {
1157 1158 1159
      _dbus_list_foreach (&message->size_counters,
                          free_size_counter, message);
      _dbus_list_clear (&message->size_counters);
1160
      
1161 1162
      _dbus_string_free (&message->header);
      _dbus_string_free (&message->body);
1163
      
1164 1165 1166 1167
      dbus_free (message);
    }
}

1168 1169
/**
 * Gets the name of a message.
1170
 *
1171 1172 1173 1174 1175 1176
 * @param message the message
 * @returns the message name (should not be freed)
 */
const char*
dbus_message_get_name (DBusMessage *message)
{
1177
  return get_string_field (message, FIELD_NAME, NULL);
1178 1179
}

1180 1181 1182
/**
 * Gets the destination service of a message.
 *
1183 1184 1185 1186 1187
 * @todo I think if we have set_sender/get_sender,
 * this function might be better named set_destination/
 * get_destination for clarity, as the sender
 * is also a service name.
 * 
1188 1189 1190 1191 1192 1193
 * @param message the message
 * @returns the message destination service (should not be freed)
 */
const char*
dbus_message_get_service (DBusMessage *message)
{
1194
  return get_string_field (message, FIELD_SERVICE, NULL);
1195 1196
}

1197 1198 1199
/**
 * Appends fields to a message given a variable argument
 * list. The variable argument list should contain the type
1200 1201 1202 1203 1204 1205
 * of the argument followed by the value to add.
 * Array values are specified by a int typecode followed by a pointer
 * to the array followed by an int giving the length of the array.
 * The argument list must be terminated with 0.
 *
 * This function doesn't support dicts or non-fundamental arrays.
1206 1207
 *
 * @param message the message
1208
 * @param first_arg_type type of the first argument
1209
 * @param ... value of first argument, list of additional type-value pairs
Anders Carlsson's avatar