diff options
Diffstat (limited to 'dbus')
-rw-r--r-- | dbus/dbus-connection.c | 86 | ||||
-rw-r--r-- | dbus/dbus-connection.h | 22 | ||||
-rw-r--r-- | dbus/dbus-errors.c | 2 | ||||
-rw-r--r-- | dbus/dbus-errors.h | 3 | ||||
-rw-r--r-- | dbus/dbus-message-internal.h | 14 | ||||
-rw-r--r-- | dbus/dbus-message.c | 115 | ||||
-rw-r--r-- | dbus/dbus-message.h | 11 | ||||
-rw-r--r-- | dbus/dbus-protocol.h | 3 |
8 files changed, 221 insertions, 35 deletions
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 25114964..0cae7601 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -59,6 +59,9 @@ * @{ */ +/** default timeout value when waiting for a message reply */ +#define DEFAULT_TIMEOUT_VALUE (15 * 1000) + /** Opaque typedef for DBusDataSlot */ typedef struct DBusDataSlot DBusDataSlot; /** DBusDataSlot is used to store application data on the connection */ @@ -615,14 +618,19 @@ dbus_connection_get_is_authenticated (DBusConnection *connection) * * @param connection the connection. * @param message the message to write. + * @param client_serial return location for client serial. * @param result address where result code can be placed. * @returns #TRUE on success. */ dbus_bool_t dbus_connection_send_message (DBusConnection *connection, DBusMessage *message, + dbus_int32_t *client_serial, DBusResultCode *result) -{ + +{ + dbus_int32_t serial; + if (!_dbus_list_prepend (&connection->outgoing_messages, message)) { @@ -636,7 +644,12 @@ dbus_connection_send_message (DBusConnection *connection, _dbus_verbose ("Message %p added to outgoing queue, %d pending to send\n", message, connection->n_outgoing); - _dbus_message_set_client_serial (message, _dbus_connection_get_next_client_serial (connection)); + serial = _dbus_connection_get_next_client_serial (connection); + _dbus_message_set_client_serial (message, serial); + + if (client_serial) + *client_serial = serial; + _dbus_message_lock (message); if (connection->n_outgoing == 1) @@ -688,12 +701,6 @@ dbus_connection_send_message (DBusConnection *connection, * install a timeout. Then install a timeout which is the shortest * timeout of any pending reply. * - * @todo implement non-reentrant "block for reply" variant. i.e. send - * a message, block until we get a reply, then pull reply out of - * message queue and return it, *without dispatching any handlers for - * any other messages* - used for non-reentrant "method calls" We can - * block properly for this using _dbus_connection_do_iteration(). - * */ dbus_bool_t dbus_connection_send_message_with_reply (DBusConnection *connection, @@ -703,7 +710,68 @@ dbus_connection_send_message_with_reply (DBusConnection *connection, DBusResultCode *result) { /* FIXME */ - return dbus_connection_send_message (connection, message, result); + return dbus_connection_send_message (connection, message, NULL, result); +} + +/** + * Sends a message and blocks a certain time period while waiting for a reply. + * This function does not dispatch any message handlers until the main loop + * has been reached. This function is used to do non-reentrant "method calls." + * + * @param connection the connection + * @param message the message to send + * @param timeout_milliseconds timeout in milliseconds or -1 for default + * @param result return location for result code + * @returns the message that is the reply or #NULL with an error code if the + * function fails. + */ +DBusMessage * +dbus_connection_send_message_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusResultCode *result) +{ + dbus_int32_t client_serial; + DBusList *link; + + if (timeout_milliseconds == -1) + timeout_milliseconds = DEFAULT_TIMEOUT_VALUE; + + if (!dbus_connection_send_message (connection, message, &client_serial, result)) + return NULL; + + /* Flush message queue */ + dbus_connection_flush (connection); + + /* Now we wait... */ + _dbus_connection_do_iteration (connection, + DBUS_ITERATION_DO_READING | + DBUS_ITERATION_BLOCK, + timeout_milliseconds); + + /* Check if we've gotten a reply */ + link = _dbus_list_get_first_link (&connection->incoming_messages); + + while (link != NULL) + { + DBusMessage *reply = link->data; + + if (_dbus_message_get_reply_serial (reply) == client_serial) + { + dbus_message_ref (message); + + if (result) + *result = DBUS_RESULT_SUCCESS; + + return reply; + } + link = _dbus_list_get_next_link (&connection->incoming_messages, link); + } + + if (result) + *result = DBUS_RESULT_NO_REPLY; + + return NULL; } /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 2a888ec1..036d6776 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -82,14 +82,20 @@ DBusMessage* dbus_connection_peek_message (DBusConnection *connection DBusMessage* dbus_connection_pop_message (DBusConnection *connection); dbus_bool_t dbus_connection_dispatch_message (DBusConnection *connection); -dbus_bool_t dbus_connection_send_message (DBusConnection *connection, - DBusMessage *message, - DBusResultCode *result); -dbus_bool_t dbus_connection_send_message_with_reply (DBusConnection *connection, - DBusMessage *message, - DBusMessageHandler *reply_handler, - int timeout_milliseconds, - DBusResultCode *result); +dbus_bool_t dbus_connection_send_message (DBusConnection *connection, + DBusMessage *message, + dbus_int32_t *client_serial, + DBusResultCode *result); +dbus_bool_t dbus_connection_send_message_with_reply (DBusConnection *connection, + DBusMessage *message, + DBusMessageHandler *reply_handler, + int timeout_milliseconds, + DBusResultCode *result); +DBusMessage *dbus_connection_send_message_with_reply_and_block (DBusConnection *connection, + DBusMessage *message, + int timeout_milliseconds, + DBusResultCode *result); + void dbus_connection_set_disconnect_function (DBusConnection *connection, DBusDisconnectFunction function, diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c index 223750e7..024ddd5a 100644 --- a/dbus/dbus-errors.c +++ b/dbus/dbus-errors.c @@ -101,6 +101,8 @@ dbus_result_to_string (DBusResultCode code) return "Disconnected."; case DBUS_RESULT_INVALID_FIELDS: return "Invalid fields."; + case DBUS_RESULT_NO_REPLY: + return "Did not get a reply message."; /* no default, it would break our compiler warnings */ } diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h index 4dd87677..b1013a60 100644 --- a/dbus/dbus-errors.h +++ b/dbus/dbus-errors.h @@ -50,7 +50,8 @@ typedef enum DBUS_RESULT_NO_NETWORK, /**< Can't find the network */ DBUS_RESULT_ADDRESS_IN_USE, /**< Someone's already using the address */ DBUS_RESULT_DISCONNECTED, /**< No more connection. */ - DBUS_RESULT_INVALID_FIELDS /**< One or more invalid fields encountered. */ + DBUS_RESULT_INVALID_FIELDS, /**< One or more invalid fields encountered. */ + DBUS_RESULT_NO_REPLY, /**< Did not get a reply message. */ } DBusResultCode; void dbus_set_result (DBusResultCode *code_address, diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index 5ec7ad9d..9507a0a4 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -34,13 +34,15 @@ void _dbus_message_get_network_data (DBusMessage *message, const DBusString **header, const DBusString **body); -void _dbus_message_lock (DBusMessage *message); +void _dbus_message_lock (DBusMessage *message); +void _dbus_message_set_client_serial (DBusMessage *message, + dbus_int32_t client_serial); +void _dbus_message_set_sender (DBusMessage *message, + const char *sender); +dbus_int32_t _dbus_message_get_reply_serial (DBusMessage *message); +void _dbus_message_add_size_counter (DBusMessage *message, + DBusCounter *counter); -void _dbus_message_set_client_serial (DBusMessage *message, - dbus_int32_t client_serial); - -void _dbus_message_add_size_counter (DBusMessage *message, - DBusCounter *counter); DBusMessageLoader* _dbus_message_loader_new (void); void _dbus_message_loader_ref (DBusMessageLoader *loader); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 5767bda6..e491a7db 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -62,6 +62,7 @@ struct DBusMessage char *name; /**< Message name. */ char *service; /**< Message destination service. */ + char *sender; /**< Message sender service. */ dbus_int32_t client_serial; /**< Client serial or -1 if not set */ dbus_int32_t reply_serial; /**< Reply serial or -1 if not set */ @@ -124,6 +125,35 @@ _dbus_message_set_client_serial (DBusMessage *message, } /** + * Returns the serial that the message is + * a reply to. + * + * @param message the message + * @returns the reply serial + */ +dbus_int32_t +_dbus_message_get_reply_serial (DBusMessage *message) +{ + return message->client_serial; +} + +/** + * Sets the message sender. This can only + * be done once on a message. + * + * @param message the message + * @param sender the sender + */ +void +_dbus_message_set_sender (DBusMessage *message, + const char *sender) +{ + _dbus_assert (message->sender == NULL); + + message->sender = _dbus_strdup (sender); +} + +/** * 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. @@ -199,12 +229,24 @@ dbus_message_write_header (DBusMessage *message) /* Marshal reply serial */ if (message->reply_serial != -1) { + _dbus_string_align_length (&message->header, 4); _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); } + + /* Marshal sender */ + if (message->sender) + { + _dbus_string_align_length (&message->header, 4); + _dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_SENDER, 4); + _dbus_string_append_byte (&message->header, DBUS_TYPE_STRING); + + _dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER, + message->sender); + } /* Fill in the length */ _dbus_string_get_data_len (&message->header, &len_data, 4, 4); @@ -302,6 +344,35 @@ dbus_message_new (const char *service, return message; } +/** + * Constructs a message that is a reply to some other + * message. Returns #NULL if memory can't be allocated + * for the message. + * + * @param name the name of 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* +dbus_message_new_reply (const char *name, + DBusMessage *original_message) +{ + DBusMessage *message; + + _dbus_assert (original_message->sender != NULL); + + message = dbus_message_new (original_message->sender, name); + + if (message == NULL) + return NULL; + + message->reply_serial = original_message->client_serial; + + return message; +} + /** * Increments the reference count of a DBusMessage. @@ -1126,6 +1197,11 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader, #define DBUS_HEADER_FIELD_REPLY_AS_UINT32 \ FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y') +/** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */ +#define DBUS_HEADER_FIELD_SENDER_AS_UINT32 \ + FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r') + + /* 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," @@ -1137,8 +1213,10 @@ decode_header_data (DBusString *data, int header_len, int byte_order, dbus_int32_t *client_serial, + dbus_int32_t *reply_serial, char **service, - char **name) + char **name, + char **sender) { const char *field; int pos, new_pos; @@ -1148,6 +1226,7 @@ decode_header_data (DBusString *data, *service = NULL; *name = NULL; + *sender = NULL; /* Now handle the fields */ while (pos < header_len) @@ -1189,6 +1268,21 @@ decode_header_data (DBusString *data, *name = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos); /* FIXME check for demarshal failure SECURITY */ break; + case DBUS_HEADER_FIELD_SENDER_AS_UINT32: + if (*sender != NULL) + { + _dbus_verbose ("%s field provided twice\n", + DBUS_HEADER_FIELD_NAME); + goto failed; + } + + *sender = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos); + /* FIXME check for demarshal failure SECURITY */ + break; + case DBUS_HEADER_FIELD_REPLY_AS_UINT32: + *reply_serial = _dbus_demarshal_int32 (data, byte_order, pos + 1, &new_pos); + + break; default: _dbus_verbose ("Ignoring an unknown header field: %c%c%c%c\n", field[0], field[1], field[2], field[3]); @@ -1268,23 +1362,29 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, if (_dbus_string_get_length (&loader->data) >= header_len + body_len) { - dbus_int32_t client_serial; - char *service, *name; + dbus_int32_t client_serial, reply_serial; + char *service, *name, *sender; /* 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)) + &client_serial, &reply_serial, &service, &name, &sender)) { loader->corrupted = TRUE; return; } + message = dbus_message_new (service, name); + message->reply_serial = reply_serial; + message->client_serial = client_serial; + _dbus_message_set_sender (message, sender); + dbus_free (service); dbus_free (name); + dbus_free (sender); if (message == NULL) break; /* ugh, postpone this I guess. */ @@ -1297,7 +1397,7 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, _dbus_assert (_dbus_string_get_length (&message->header) == 0); _dbus_assert (_dbus_string_get_length (&message->body) == 0); - + if (!_dbus_string_move_len (&loader->data, 0, header_len, &message->header, 0)) { _dbus_list_remove_last (&loader->messages, message); @@ -1486,6 +1586,8 @@ _dbus_message_test (void) message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage"); message->client_serial = 1; + message->reply_serial = 0x12345678; + dbus_message_append_string (message, "Test string"); dbus_message_append_int32 (message, -0x12345678); dbus_message_append_uint32 (message, 0xedd1e); @@ -1529,6 +1631,9 @@ _dbus_message_test (void) if (!message) _dbus_assert_not_reached ("received a NULL message"); + if (message->reply_serial != 0x12345678) + _dbus_assert_not_reached ("reply serial fields differ"); + message_iter_test (message); dbus_message_unref (message); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index b8be6907..7d5ea21b 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -36,15 +36,16 @@ DBUS_BEGIN_DECLS; typedef struct DBusMessage DBusMessage; typedef struct DBusMessageIter DBusMessageIter; -DBusMessage* dbus_message_new (const char *service, - const char *name); +DBusMessage* dbus_message_new (const char *service, + const char *name); +DBusMessage* dbus_message_new_reply (const char *name, + DBusMessage *original_message); void dbus_message_ref (DBusMessage *message); void dbus_message_unref (DBusMessage *message); -const char* dbus_message_get_name (DBusMessage *message); -const char* dbus_message_get_service (DBusMessage *message); - +const char* dbus_message_get_name (DBusMessage *message); +const char* dbus_message_get_service (DBusMessage *message); dbus_bool_t dbus_message_append_fields (DBusMessage *message, int first_field_type, diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 634283c6..76ffa52c 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -51,7 +51,8 @@ extern "C" { #define DBUS_HEADER_FIELD_NAME "name" #define DBUS_HEADER_FIELD_SERVICE "srvc" #define DBUS_HEADER_FIELD_REPLY "rply" - +#define DBUS_HEADER_FIELD_SENDER "sndr" + #ifdef __cplusplus } #endif |