2003-01-08 Havoc Pennington <hp@pobox.com>

* dbus/dbus-string.c (_dbus_string_align_length): new function

	* dbus/dbus-test-main.c: move main() for test app here
	* dbus/dbus-test.c
	(dbus_internal_symbol_do_not_use_run_tests): we have to export a
	symbol to run tests, because dbus-test isn't in the main
	library

        Code review nitpicks.

	* dbus/dbus-message.c (dbus_message_write_header): add newlines
	for people with narrow emacs ;-). Assert client_serial was filled
	in. Assert message->name != NULL.
	(dbus_message_append_fields): have "first_field_type" arg separate
	from va list, needed for C++ binding that also uses varargs IIRC
	and helps with type safety
	(dbus_message_new): add @todo about using DBusString to store
	service/name internally
	(dbus_message_new): don't leak ->service and ->name on OOM later
	in the function
	(dbus_message_unref): free the service name
	(dbus_message_get_fields): same change to varargs
	i.e. first_field_type
	(_dbus_message_loader_return_buffer): assert that the message data
	is aligned (if not it's a bug in our code). Put in verbose griping
	about why we set corrupted = TRUE.
	(decode_header_data): add FIXME that char* is evil.  Was going to
	add FIXME about evil locale-specific string.h strncmp, but just
	switched to wacky string-as-uint32 optimization. Move check for
	"no room for field name" above get_const_data_len() to avoid
	assertion failure in get_const_data_len if we have trailing 2
	bytes or the like. Check for service and name fields being
	provided twice. Don't leak service/name on error. Require field
	names to be aligned to 4 bytes.

	* dbus/dbus-marshal.c: move byte swap stuff to header
	(_dbus_pack_int32): uscore-prefix
	(_dbus_unpack_int32): uscore-prefix
	(_dbus_unpack_uint32): export
	(_dbus_demarshal_string): add @todo complaining about use of
	memcpy()
	(_dbus_marshal_get_field_end_pos): add @todo about bad error
	handling allowing corrupt data to go unchecked
This commit is contained in:
Havoc Pennington 2003-01-09 01:31:35 +00:00
parent 509bbe9bde
commit 993be1059a
12 changed files with 417 additions and 139 deletions

View file

@ -1,3 +1,49 @@
2003-01-08 Havoc Pennington <hp@pobox.com>
* dbus/dbus-string.c (_dbus_string_align_length): new function
* dbus/dbus-test-main.c: move main() for test app here
* dbus/dbus-test.c
(dbus_internal_symbol_do_not_use_run_tests): we have to export a
symbol to run tests, because dbus-test isn't in the main
library
Code review nitpicks.
* dbus/dbus-message.c (dbus_message_write_header): add newlines
for people with narrow emacs ;-). Assert client_serial was filled
in. Assert message->name != NULL.
(dbus_message_append_fields): have "first_field_type" arg separate
from va list, needed for C++ binding that also uses varargs IIRC
and helps with type safety
(dbus_message_new): add @todo about using DBusString to store
service/name internally
(dbus_message_new): don't leak ->service and ->name on OOM later
in the function
(dbus_message_unref): free the service name
(dbus_message_get_fields): same change to varargs
i.e. first_field_type
(_dbus_message_loader_return_buffer): assert that the message data
is aligned (if not it's a bug in our code). Put in verbose griping
about why we set corrupted = TRUE.
(decode_header_data): add FIXME that char* is evil. Was going to
add FIXME about evil locale-specific string.h strncmp, but just
switched to wacky string-as-uint32 optimization. Move check for
"no room for field name" above get_const_data_len() to avoid
assertion failure in get_const_data_len if we have trailing 2
bytes or the like. Check for service and name fields being
provided twice. Don't leak service/name on error. Require field
names to be aligned to 4 bytes.
* dbus/dbus-marshal.c: move byte swap stuff to header
(_dbus_pack_int32): uscore-prefix
(_dbus_unpack_int32): uscore-prefix
(_dbus_unpack_uint32): export
(_dbus_demarshal_string): add @todo complaining about use of
memcpy()
(_dbus_marshal_get_field_end_pos): add @todo about bad error
handling allowing corrupt data to go unchecked
2003-01-08 Havoc Pennington <hp@redhat.com>
* dbus/dbus-transport-unix.c (unix_do_iteration): add read/write

View file

@ -32,6 +32,8 @@ libdbus_1_la_SOURCES= \
dbus-server-protected.h \
dbus-server-unix.c \
dbus-server-unix.h \
dbus-test.c \
dbus-test.h \
dbus-threads.c \
dbus-transport.c \
dbus-transport.h \
@ -75,8 +77,7 @@ if DBUS_BUILD_TESTS
noinst_PROGRAMS=dbus-test
dbus_test_SOURCES= \
dbus-test.c \
dbus-test.h
dbus-test-main.c
dbus_test_LDADD= $(DBUS_CLIENT_LIBS) libdbus-convenience.la libdbus-1.la

View file

@ -22,6 +22,7 @@
*/
#include "dbus-internals.h"
#include "dbus-protocol.h"
#include "dbus-test.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
@ -29,6 +30,7 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
/**
* @defgroup DBusInternals D-BUS internal implementation details

View file

@ -26,33 +26,6 @@
#include <string.h>
#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) ((dbus_uint32_t) ( \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) << 8) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >> 8) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24)))
#define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val))
#ifdef WORDS_BIGENDIAN
#define DBUS_INT32_TO_BE(val) ((dbus_int32_t) (val))
#define DBUS_UINT32_TO_BE(val) ((dbus_uint32_t) (val))
#define DBUS_INT32_TO_LE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
#define DBUS_UINT32_TO_LE(val) (DBUS_UINT32_SWAP_LE_BE (val))
#else
#define DBUS_INT32_TO_LE(val) ((dbus_int32_t) (val))
#define DBUS_UINT32_TO_LE(val) ((dbus_uint32_t) (val))
#define DBUS_INT32_TO_BE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
#define DBUS_UINT32_TO_BE(val) (DBUS_UINT32_SWAP_LE_BE (val))
#endif
/* The transformation is symmetric, so the FROM just maps to the TO. */
#define DBUS_INT32_FROM_LE(val) (DBUS_INT32_TO_LE (val))
#define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val))
#define DBUS_INT32_FROM_BE(val) (DBUS_INT32_TO_BE (val))
#define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val))
/* from ORBit */
static void
swap_bytes (unsigned char *data,
@ -72,37 +45,6 @@ swap_bytes (unsigned char *data,
}
}
static dbus_uint32_t
unpack_uint32 (int byte_order,
const unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
if (byte_order == DBUS_LITTLE_ENDIAN)
return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
else
return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
}
/**
* Unpacks a 32 bit unsigned integer from a data pointer
*
* @param byte_order The byte order to use
* @param data the data pointer
* @returns the integer
*/
dbus_int32_t
dbus_unpack_int32 (int byte_order,
const unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
if (byte_order == DBUS_LITTLE_ENDIAN)
return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
else
return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
}
/**
* @defgroup DBusMarshal marshaling and unmarshaling
* @ingroup DBusInternals
@ -114,6 +56,44 @@ dbus_unpack_int32 (int byte_order,
* @{
*/
/**
* Unpacks a 32 bit unsigned integer from a data pointer
*
* @param byte_order The byte order to use
* @param data the data pointer
* @returns the integer
*/
dbus_uint32_t
_dbus_unpack_uint32 (int byte_order,
const unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
if (byte_order == DBUS_LITTLE_ENDIAN)
return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
else
return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
}
/**
* Unpacks a 32 bit signed integer from a data pointer
*
* @param byte_order The byte order to use
* @param data the data pointer
* @returns the integer
*/
dbus_int32_t
_dbus_unpack_int32 (int byte_order,
const unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
if (byte_order == DBUS_LITTLE_ENDIAN)
return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
else
return DBUS_INT32_FROM_BE (*(dbus_int32_t*)data);
}
/**
* Packs a 32 bit unsigned integer into a data pointer.
*
@ -122,9 +102,29 @@ dbus_unpack_int32 (int byte_order,
* @param data the data pointer
*/
void
dbus_pack_int32 (dbus_int32_t value,
int byte_order,
unsigned char *data)
_dbus_pack_uint32 (dbus_uint32_t value,
int byte_order,
unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
if ((byte_order) == DBUS_LITTLE_ENDIAN)
*((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);
else
*((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value);
}
/**
* Packs a 32 bit signed integer into a data pointer.
*
* @param value the value
* @param byte_order the byte order to use
* @param data the data pointer
*/
void
_dbus_pack_int32 (dbus_int32_t value,
int byte_order,
unsigned char *data)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
@ -147,9 +147,11 @@ _dbus_marshal_double (DBusString *str,
int byte_order,
double value)
{
_dbus_assert (sizeof (double) == 8);
if (!_dbus_string_set_length (str,
_DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
sizeof (double))))
sizeof (double))))
return FALSE;
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
@ -173,7 +175,7 @@ _dbus_marshal_int32 (DBusString *str,
{
if (!_dbus_string_set_length (str,
_DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
sizeof (dbus_int32_t))))
sizeof (dbus_int32_t))))
return FALSE;
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
@ -197,7 +199,7 @@ _dbus_marshal_uint32 (DBusString *str,
{
if (!_dbus_string_set_length (str,
_DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
sizeof (dbus_uint32_t))))
sizeof (dbus_uint32_t))))
return FALSE;
if (byte_order != DBUS_COMPILER_BYTE_ORDER)
@ -323,7 +325,7 @@ _dbus_demarshal_int32 (DBusString *str,
if (new_pos)
*new_pos = pos + sizeof (dbus_int32_t);
return dbus_unpack_int32 (byte_order, buffer);
return _dbus_unpack_int32 (byte_order, buffer);
}
/**
@ -350,7 +352,7 @@ _dbus_demarshal_uint32 (DBusString *str,
if (new_pos)
*new_pos = pos + sizeof (dbus_uint32_t);
return unpack_uint32 (byte_order, buffer);
return _dbus_unpack_uint32 (byte_order, buffer);
}
/**
@ -360,6 +362,9 @@ _dbus_demarshal_uint32 (DBusString *str,
* that it's valid UTF-8, and maybe "fix" the string
* if it's broken?
*
* @todo Should probably demarshal to a DBusString,
* having memcpy() in here is Evil(tm).
*
* @param str the string containing the data
* @param byte_order the byte order
* @param pos the position in the string
@ -434,6 +439,12 @@ _dbus_demarshal_byte_array (DBusString *str,
* Returns the position right after the end position
* end position of a field
*
* @todo warns on invalid type in a message, but
* probably the whole message needs to be dumped,
* or we might even drop the connection due
* to bad protocol. Needs better error handling.
* Possible security issue.
*
* @param str a string
* @param byte_order the byte order to use
* @param pos the pos where the field starts
@ -564,8 +575,8 @@ _dbus_verbose_bytes (const unsigned char *data,
{
if (i > 3)
_dbus_verbose ("big: %d little: %d",
unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
_dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
_dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
_dbus_verbose ("\n");
}

View file

@ -39,11 +39,42 @@
#define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN
#endif
void dbus_pack_int32 (dbus_int32_t value,
int byte_order,
unsigned char *data);
dbus_int32_t dbus_unpack_int32 (int byte_order,
const unsigned char *data);
#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val) ((dbus_uint32_t) ( \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) << 8) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >> 8) | \
(((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24)))
#define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val))
#ifdef WORDS_BIGENDIAN
#define DBUS_INT32_TO_BE(val) ((dbus_int32_t) (val))
#define DBUS_UINT32_TO_BE(val) ((dbus_uint32_t) (val))
#define DBUS_INT32_TO_LE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
#define DBUS_UINT32_TO_LE(val) (DBUS_UINT32_SWAP_LE_BE (val))
#else
#define DBUS_INT32_TO_LE(val) ((dbus_int32_t) (val))
#define DBUS_UINT32_TO_LE(val) ((dbus_uint32_t) (val))
#define DBUS_INT32_TO_BE(val) ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
#define DBUS_UINT32_TO_BE(val) (DBUS_UINT32_SWAP_LE_BE (val))
#endif
/* The transformation is symmetric, so the FROM just maps to the TO. */
#define DBUS_INT32_FROM_LE(val) (DBUS_INT32_TO_LE (val))
#define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val))
#define DBUS_INT32_FROM_BE(val) (DBUS_INT32_TO_BE (val))
#define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val))
void _dbus_pack_int32 (dbus_int32_t value,
int byte_order,
unsigned char *data);
dbus_int32_t _dbus_unpack_int32 (int byte_order,
const unsigned char *data);
void _dbus_pack_uint32 (dbus_uint32_t value,
int byte_order,
unsigned char *data);
dbus_uint32_t _dbus_unpack_uint32 (int byte_order,
const unsigned char *data);
dbus_bool_t _dbus_marshal_double (DBusString *str,

View file

@ -76,6 +76,11 @@ struct DBusMessage
unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
};
/**
* @brief Internals of DBusMessageIter
*
* Object representing a position in a message. All fields are internal.
*/
struct DBusMessageIter
{
int refcount; /**< Reference count */
@ -125,7 +130,7 @@ _dbus_message_set_client_serial (DBusMessage *message,
static void
dbus_message_write_header (DBusMessage *message)
{
char *header;
char *len_data;
_dbus_assert (message->client_serial != -1);
@ -135,21 +140,28 @@ dbus_message_write_header (DBusMessage *message)
/* We just lengthen the string here and pack in the real length later */
_dbus_string_lengthen (&message->header, 4);
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, _dbus_string_get_length (&message->body));
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER,
_dbus_string_get_length (&message->body));
/* Marshal client serial */
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, message->client_serial);
_dbus_assert (message->client_serial >= 0);
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER,
message->client_serial);
/* Marshal message service */
if (message->service)
{
_dbus_string_align_length (&message->header, 4);
_dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_SERVICE, 4);
_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING);
_dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER, message->service);
_dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER,
message->service);
}
/* Marshal message name */
_dbus_assert (message->name != NULL);
_dbus_string_align_length (&message->header, 4);
_dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_NAME, 4);
_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING);
@ -161,12 +173,14 @@ dbus_message_write_header (DBusMessage *message)
_dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_REPLY, 4);
_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32);
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, message->reply_serial);
_dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER,
message->reply_serial);
}
/* Fill in the length */
_dbus_string_get_data_len (&message->header, &header, 4, 4);
dbus_pack_int32 (_dbus_string_get_length (&message->header), DBUS_COMPILER_BYTE_ORDER, header);
_dbus_string_get_data_len (&message->header, &len_data, 4, 4);
_dbus_pack_int32 (_dbus_string_get_length (&message->header),
DBUS_COMPILER_BYTE_ORDER, len_data);
}
/**
@ -213,8 +227,9 @@ _dbus_message_lock (DBusMessage *message)
* Constructs a new message. Returns #NULL if memory
* can't be allocated for the message.
*
* @todo use DBusString internally to store service and name.
*
* @param service service that the message should be sent to
* should be sent to
* @param name name of the message
* @returns a new DBusMessage, free with dbus_message_unref()
* @see dbus_message_unref()
@ -240,12 +255,16 @@ dbus_message_new (const char *service,
if (!_dbus_string_init (&message->header, _DBUS_MAX_MESSAGE_LENGTH))
{
dbus_free (message->service);
dbus_free (message->name);
dbus_free (message);
return NULL;
}
if (!_dbus_string_init (&message->body, _DBUS_MAX_MESSAGE_LENGTH))
{
dbus_free (message->service);
dbus_free (message->name);
_dbus_string_free (&message->header);
dbus_free (message);
return NULL;
@ -285,7 +304,8 @@ dbus_message_unref (DBusMessage *message)
{
_dbus_string_free (&message->header);
_dbus_string_free (&message->body);
dbus_free (message->service);
dbus_free (message->name);
dbus_free (message);
}
@ -310,18 +330,22 @@ dbus_message_get_name (DBusMessage *message)
* The list is terminated with 0.
*
* @param message the message
* @param ... list of fields.
* @param type of the first field
* @param ... value of first field, list of additional type-value pairs
* @returns #TRUE on success
*/
dbus_bool_t
dbus_message_append_fields (DBusMessage *message,
int first_field_type,
...)
{
dbus_bool_t retval;
va_list var_args;
va_start (var_args, message);
retval = dbus_message_append_fields_valist (message, var_args);
va_start (var_args, first_field_type);
retval = dbus_message_append_fields_valist (message,
first_field_type,
var_args);
va_end (var_args);
return retval;
@ -332,18 +356,20 @@ dbus_message_append_fields (DBusMessage *message,
*
* @see dbus_message_append_fields.
* @param message the message
* @param var_args list of type/value pairs
* @param first_field_type type of first field
* @param var_args value of first field, then list of type/value pairs
* @returns #TRUE on success
*/
dbus_bool_t
dbus_message_append_fields_valist (DBusMessage *message,
int first_field_type,
va_list var_args)
{
int type, old_len;
old_len = _dbus_string_get_length (&message->body);
type = va_arg (var_args, int);
type = first_field_type;
while (type != 0)
{
@ -375,9 +401,8 @@ dbus_message_append_fields_valist (DBusMessage *message,
if (!dbus_message_append_byte_array (message, data, len))
goto enomem;
break;
}
break;
default:
_dbus_warn ("Unknown field type %d\n", type);
}
@ -516,18 +541,20 @@ dbus_message_append_byte_array (DBusMessage *message,
* stored. The list is terminated with 0.
*
* @param message the message
* @param ... list of fields.
* @param first_field_type the first field type
* @param ... location for first field value, then list of type-location pairs
* @returns #TRUE on success
*/
dbus_bool_t
dbus_message_get_fields (DBusMessage *message,
int first_field_type,
...)
{
dbus_bool_t retval;
va_list var_args;
va_start (var_args, message);
retval = dbus_message_get_fields_valist (message, var_args);
va_start (var_args, first_field_type);
retval = dbus_message_get_fields_valist (message, first_field_type, var_args);
va_end (var_args);
return retval;
@ -536,13 +563,22 @@ dbus_message_get_fields (DBusMessage *message,
/**
* This function takes a va_list for use by language bindings
*
* @todo this function (or some lower-level non-convenience function)
* needs better error handling; should allow the application to
* distinguish between out of memory, and bad data from the remote
* app. It also needs to not leak a bunch of args when it gets
* to the arg that's bad, as that would be a security hole
* (allow one app to force another to leak memory)
*
* @see dbus_message_get_fields
* @param message the message
* @param var_args list of type/pointer pairs
* @param first_field_type type of the first field
* @param var_args return location for first field, followed by list of type/location pairs
* @returns #TRUE on success
*/
dbus_bool_t
dbus_message_get_fields_valist (DBusMessage *message,
int first_field_type,
va_list var_args)
{
int spec_type, msg_type, i;
@ -553,7 +589,7 @@ dbus_message_get_fields_valist (DBusMessage *message,
if (iter == NULL)
return FALSE;
spec_type = va_arg (var_args, int);
spec_type = first_field_type;
i = 0;
while (spec_type != 0)
@ -632,7 +668,7 @@ dbus_message_get_fields_valist (DBusMessage *message,
{
_dbus_warn ("More fields than exist in the message were specified\n");
dbus_message_iter_unref (iter);
dbus_message_iter_unref (iter);
return FALSE;
}
i++;
@ -646,6 +682,12 @@ dbus_message_get_fields_valist (DBusMessage *message,
* Returns a DBusMessageIter representing the fields of the
* message passed in.
*
* @todo IMO the message iter should follow the GtkTextIter pattern,
* a static object with a "stamp" value used to detect invalid
* iter uses (uninitialized or after changing the message).
* ref/unref is kind of annoying to deal with, and slower too.
* This implies not ref'ing the message from the iter.
*
* @param message the message
* @returns a new iter.
*/
@ -783,7 +825,7 @@ dbus_message_iter_get_string (DBusMessageIter *iter)
_dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING);
return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
iter->pos + 1, NULL);
iter->pos + 1, NULL);
}
/**
@ -987,6 +1029,31 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
*/
#define DBUS_MINIMUM_HEADER_SIZE 16
/** Pack four characters as in "abcd" into a uint32 */
#define FOUR_CHARS_TO_UINT32(a, b, c, d) \
((((dbus_uint32_t)a) << 24) | \
(((dbus_uint32_t)b) << 16) | \
(((dbus_uint32_t)c) << 8) | \
((dbus_uint32_t)d))
/** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
#define DBUS_HEADER_FIELD_NAME_AS_UINT32 \
FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
/** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
#define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
/** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
#define DBUS_HEADER_FIELD_REPLY_AS_UINT32 \
FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
/* FIXME should be using DBusString for the stuff we demarshal. char*
* evil. Also, out of memory handling here seems suboptimal.
* Should probably report it as a distinct error from "corrupt message,"
* so we can postpone parsing this message. Also, we aren't
* checking for demarshal failure everywhere.
*/
static dbus_bool_t
decode_header_data (DBusString *data,
int header_len,
@ -1007,27 +1074,49 @@ decode_header_data (DBusString *data,
/* Now handle the fields */
while (pos < header_len)
{
pos = _DBUS_ALIGN_VALUE (pos, 4);
if ((pos + 4) > header_len)
return FALSE;
_dbus_string_get_const_data_len (data, &field, pos, 4);
pos += 4;
if (pos > header_len)
return FALSE;
if (strncmp (field, DBUS_HEADER_FIELD_SERVICE, 4) == 0)
{
_dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
/* I believe FROM_BE is right, but if not we'll find out
* I guess. ;-)
*/
switch (DBUS_UINT32_FROM_BE (*(int*)field))
{
case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
if (*service != NULL)
{
_dbus_verbose ("%s field provided twice\n",
DBUS_HEADER_FIELD_SERVICE);
goto failed;
}
*service = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos);
}
else if (strncmp (field, DBUS_HEADER_FIELD_NAME, 4) == 0)
{
/* FIXME check for demarshal failure SECURITY */
break;
case DBUS_HEADER_FIELD_NAME_AS_UINT32:
if (*name != NULL)
{
_dbus_verbose ("%s field provided twice\n",
DBUS_HEADER_FIELD_NAME);
goto failed;
}
*name = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos);
}
else
{
_dbus_verbose ("Encountered an unknown header field: %c%c%c%c\n",
/* FIXME check for demarshal failure SECURITY */
break;
default:
_dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n",
field[0], field[1], field[2], field[3]);
if (!_dbus_marshal_get_field_end_pos (data, byte_order, pos, &new_pos))
return FALSE;
goto failed;
}
if (new_pos > header_len)
@ -1037,7 +1126,11 @@ decode_header_data (DBusString *data,
}
return TRUE;
failed:
dbus_free (*service);
dbus_free (*name);
return FALSE;
}
/**
@ -1070,22 +1163,28 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
int byte_order, header_len, body_len;
_dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
_dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
byte_order = header_data[0];
if (byte_order != DBUS_LITTLE_ENDIAN &&
byte_order != DBUS_BIG_ENDIAN)
{
_dbus_verbose ("Message with bad byte order '%c' received\n",
byte_order);
loader->corrupted = TRUE;
return;
}
header_len = dbus_unpack_int32 (byte_order, header_data + 4);
body_len = dbus_unpack_int32 (byte_order, header_data + 8);
header_len = _dbus_unpack_int32 (byte_order, header_data + 4);
body_len = _dbus_unpack_int32 (byte_order, header_data + 8);
if (header_len + body_len > _DBUS_MAX_MESSAGE_LENGTH)
{
_dbus_verbose ("Message claimed length header = %d body = %d exceeds max message length %d\n",
header_len, body_len, _DBUS_MAX_MESSAGE_LENGTH);
loader->corrupted = TRUE;
return;
}
@ -1093,21 +1192,24 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
{
dbus_int32_t client_serial;
char *service, *name;
if (!decode_header_data (&loader->data, header_len, byte_order,
/* FIXME right now if this doesn't have enough memory, the
* loader becomes corrupted. Instead we should just not
* parse this message for now.
*/
if (!decode_header_data (&loader->data, header_len, byte_order,
&client_serial, &service, &name))
{
loader->corrupted = TRUE;
return;
}
message = dbus_message_new (service, name);
dbus_free (service);
message = dbus_message_new (service, name);
dbus_free (service);
dbus_free (name);
if (message == NULL)
break; /* ugh, postpone this I guess. */
break; /* ugh, postpone this I guess. */
_dbus_string_copy (&loader->data, header_len, &message->body, 0);
_dbus_message_set_client_serial (message, client_serial);

View file

@ -46,8 +46,10 @@ const char* dbus_message_get_name (DBusMessage *message);
dbus_bool_t dbus_message_append_fields (DBusMessage *message,
int first_field_type,
...);
dbus_bool_t dbus_message_append_fields_valist (DBusMessage *message,
int first_field_type,
va_list var_args);
dbus_bool_t dbus_message_append_int32 (DBusMessage *message,
dbus_int32_t value);
@ -65,8 +67,10 @@ dbus_bool_t dbus_message_append_byte_array (DBusMessage *message,
DBusMessageIter *dbus_message_get_fields_iter (DBusMessage *message);
dbus_bool_t dbus_message_get_fields (DBusMessage *message,
int first_field_type,
...);
dbus_bool_t dbus_message_get_fields_valist (DBusMessage *message,
int first_field_type,
va_list var_args);
void dbus_message_iter_ref (DBusMessageIter *iter);

View file

@ -526,6 +526,41 @@ _dbus_string_set_length (DBusString *str,
return set_length (real, length);
}
/**
* Align the length of a string to a specific alignment (typically 4 or 8)
* by appending nul bytes to the string.
*
* @param str a string
* @param alignment the alignment
* @returns #FALSE if no memory
*/
dbus_bool_t
_dbus_string_align_length (DBusString *str,
int alignment)
{
int new_len;
int delta;
DBUS_STRING_PREAMBLE (str);
_dbus_assert (alignment >= 1);
_dbus_assert (alignment <= 16); /* arbitrary */
new_len = _DBUS_ALIGN_VALUE (real->len, alignment);
delta = new_len - real->len;
_dbus_assert (delta >= 0);
if (delta == 0)
return TRUE;
if (!set_length (real, new_len))
return FALSE;
memset (real->str + (new_len - delta),
'\0', delta);
return TRUE;
}
static dbus_bool_t
append (DBusRealString *real,
const char *buffer,

View file

@ -72,12 +72,14 @@ dbus_bool_t _dbus_string_steal_data_len (DBusString *str,
int _dbus_string_get_length (const DBusString *str);
dbus_bool_t _dbus_string_lengthen (DBusString *str,
int additional_length);
void _dbus_string_shorten (DBusString *str,
int length_to_remove);
dbus_bool_t _dbus_string_set_length (DBusString *str,
int length);
dbus_bool_t _dbus_string_lengthen (DBusString *str,
int additional_length);
void _dbus_string_shorten (DBusString *str,
int length_to_remove);
dbus_bool_t _dbus_string_set_length (DBusString *str,
int length);
dbus_bool_t _dbus_string_align_length (DBusString *str,
int alignment);
dbus_bool_t _dbus_string_append (DBusString *str,
const char *buffer);

36
dbus/dbus-test-main.c Normal file
View file

@ -0,0 +1,36 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-test.c Program to run all tests
*
* Copyright (C) 2002 Red Hat Inc.
*
* 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
*
*/
#include "dbus-types.h"
#include "dbus-test.h"
#include <stdio.h>
#include <stdlib.h>
int
main (int argc,
char **argv)
{
dbus_internal_symbol_do_not_use_run_tests ();
return 0;
}

View file

@ -21,7 +21,6 @@
*
*/
#include "dbus-types.h"
#include "dbus-test.h"
#include <stdio.h>
#include <stdlib.h>
@ -33,34 +32,41 @@ die (const char *failure)
exit (1);
}
int
main (int argc,
char **argv)
/**
* An exported symbol to be run in order to execute
* unit tests. Should not be used by
* any app other than our test app, this symbol
* won't exist in some builds of the library.
* (with --enable-tests=no)
*/
void
dbus_internal_symbol_do_not_use_run_tests (void)
{
printf ("%s: running string tests\n", argv[0]);
printf ("%s: running string tests\n", "dbus-test");
if (!_dbus_string_test ())
die ("strings");
printf ("%s: running marshalling tests\n", argv[0]);
printf ("%s: running marshalling tests\n", "dbus-test");
if (!_dbus_marshal_test ())
die ("marshalling");
printf ("%s: running message tests\n", argv[0]);
printf ("%s: running message tests\n", "dbus-test");
if (!_dbus_message_test ())
die ("messages");
printf ("%s: running memory pool tests\n", argv[0]);
printf ("%s: running memory pool tests\n", "dbus-test");
if (!_dbus_mem_pool_test ())
die ("memory pools");
printf ("%s: running linked list tests\n", argv[0]);
printf ("%s: running linked list tests\n", "dbus-test");
if (!_dbus_list_test ())
die ("lists");
printf ("%s: running hash table tests\n", argv[0]);
printf ("%s: running hash table tests\n", "dbus-test");
if (!_dbus_hash_test ())
die ("hash tables");
printf ("%s: completed successfully\n", argv[0]);
return 0;
printf ("%s: completed successfully\n", "dbus-test");
}

View file

@ -33,4 +33,6 @@ dbus_bool_t _dbus_mem_pool_test (void);
dbus_bool_t _dbus_string_test (void);
dbus_bool_t _dbus_message_test (void);
void dbus_internal_symbol_do_not_use_run_tests (void);
#endif /* DBUS_TEST_H */