2002-12-25 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / dbus / dbus-message.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-message.c  DBusMessage object
3  *
4  * Copyright (C) 2002  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-message.h"
26 #include "dbus-message-internal.h"
27 #include "dbus-memory.h"
28 #include "dbus-list.h"
29 #include <string.h>
30
31 /**
32  * @defgroup DBusMessageInternals DBusMessage implementation details
33  * @ingroup DBusInternals
34  * @brief DBusMessage private implementation details.
35  *
36  * The guts of DBusMessage and its methods.
37  *
38  * @{
39  */
40
41 /**
42  * The largest-length message we allow
43  *
44  * @todo match this up with whatever the protocol spec says.
45  */
46 #define _DBUS_MAX_MESSAGE_LENGTH (_DBUS_INT_MAX/16)
47
48 /**
49  * @brief Internals of DBusMessage
50  * 
51  * Object representing a message received from or to be sent to
52  * another application. This is an opaque object, all members
53  * are private.
54  */
55 struct DBusMessage
56 {
57   int refcount; /**< Reference count */
58
59   DBusString header; /**< Header network data, stored
60                       * separately from body so we can
61                       * independently realloc it.
62                       */
63
64   DBusString body;   /**< Body network data. */
65
66   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
67 };
68
69 /**
70  * Gets the data to be sent over the network for this message.
71  * The header and then the body should be written out.
72  * This function is guaranteed to always return the same
73  * data once a message is locked (with _dbus_message_lock()).
74  *
75  * @param message the message.
76  * @param header return location for message header data.
77  * @param body return location for message body data.
78  */
79 void
80 _dbus_message_get_network_data (DBusMessage          *message,
81                                 const DBusString    **header,
82                                 const DBusString    **body)
83 {
84   _dbus_assert (message->locked);
85   
86   *header = &message->header;
87   *body = &message->body;
88 }
89
90 /**
91  * Locks a message. Allows checking that applications don't keep a
92  * reference to a message in the outgoing queue and change it
93  * underneath us. Messages are locked when they enter the outgoing
94  * queue (dbus_connection_send_message()), and the library complains
95  * if the message is modified while locked.
96  *
97  * @param message the message to lock.
98  */
99 void
100 _dbus_message_lock (DBusMessage *message)
101 {
102   message->locked = TRUE;
103 }
104
105 /** @} */
106
107 /**
108  * @defgroup DBusMessage DBusMessage
109  * @ingroup  DBus
110  * @brief Message to be sent or received over a DBusConnection.
111  *
112  * A DBusMessage is the most basic unit of communication over a
113  * DBusConnection. A DBusConnection represents a stream of messages
114  * received from a remote application, and a stream of messages
115  * sent to a remote application.
116  *
117  * @{
118  */
119
120 /**
121  * @typedef DBusMessage
122  *
123  * Opaque data type representing a message received from or to be
124  * sent to another application.
125  */
126
127 /**
128  * Constructs a new message. Returns #NULL if memory
129  * can't be allocated for the message.
130  * 
131  * @return a new DBusMessage, free with dbus_message_unref()
132  * @see dbus_message_unref()
133  */
134 DBusMessage*
135 dbus_message_new (void)
136 {
137   DBusMessage *message;
138
139   message = dbus_new0 (DBusMessage, 1);
140   if (message == NULL)
141     return NULL;
142   
143   message->refcount = 1;
144
145   if (!_dbus_string_init (&message->header, _DBUS_MAX_MESSAGE_LENGTH))
146     {
147       dbus_free (message);
148       return NULL;
149     }
150
151   if (!_dbus_string_init (&message->body, _DBUS_MAX_MESSAGE_LENGTH))
152     {
153       _dbus_string_free (&message->header);
154       dbus_free (message);
155       return NULL;
156     }
157   
158   /* We need to decide what a message contains. ;-) */
159   /* (not bothering to check failure of these appends) */
160   _dbus_string_append (&message->header, "H");
161   _dbus_string_append_byte (&message->header, '\0');
162   _dbus_string_append (&message->body, "Body");
163   _dbus_string_append_byte (&message->body, '\0');
164   
165   return message;
166 }
167
168
169 /**
170  * Increments the reference count of a DBusMessage.
171  *
172  * @param message The message
173  * @see dbus_message_unref
174  */
175 void
176 dbus_message_ref (DBusMessage *message)
177 {
178   message->refcount += 1;
179 }
180
181 /**
182  * Decrements the reference count of a DBusMessage.
183  *
184  * @param message The message
185  * @see dbus_message_ref
186  */
187 void
188 dbus_message_unref (DBusMessage *message)
189 {
190   _dbus_assert (message != NULL);
191   _dbus_assert (message->refcount > 0);
192
193   message->refcount -= 1;
194   if (message->refcount == 0)
195     {
196       _dbus_string_free (&message->header);
197       _dbus_string_free (&message->body);
198       
199       dbus_free (message);
200     }
201 }
202
203 /**
204  * Gets the name of a message.
205  * @param message the message
206  * @returns the message name (should not be freed)
207  */
208 const char*
209 dbus_message_get_name (DBusMessage *message)
210 {
211   /* FIXME */
212   
213   return NULL;
214 }
215
216 /** @} */
217
218 /**
219  * @addtogroup DBusMessageInternals
220  *
221  * @{
222  */
223 /**
224  * @typedef DBusMessageLoader
225  *
226  * The DBusMessageLoader object encapsulates the process of converting
227  * a byte stream into a series of DBusMessage. It buffers the incoming
228  * bytes as efficiently as possible, and generates a queue of
229  * messages. DBusMessageLoader is typically used as part of a
230  * DBusTransport implementation. The DBusTransport then hands off
231  * the loaded messages to a DBusConnection, making the messages
232  * visible to the application.
233  * 
234  */
235
236 /**
237  * Implementation details of DBusMessageLoader.
238  * All members are private.
239  */
240 struct DBusMessageLoader
241 {
242   int refcount;        /**< Reference count. */
243
244   DBusString data;     /**< Buffered data */
245   
246   DBusList *messages;  /**< Complete messages. */
247   
248   unsigned int buffer_outstanding : 1; /**< Someone is using the buffer to read */
249 };
250
251 /**
252  * The initial buffer size of the message loader.
253  * 
254  * @todo this should be based on min header size plus some average
255  * body size, or something. Or rather, the min header size only, if we
256  * want to try to read only the header, store that in a DBusMessage,
257  * then read only the body and store that, etc., depends on
258  * how we optimize _dbus_message_loader_get_buffer() and what
259  * the exact message format is.
260  */
261 #define INITIAL_LOADER_DATA_LEN 32
262
263 /**
264  * Creates a new message loader. Returns #NULL if memory can't
265  * be allocated.
266  *
267  * @returns new loader, or #NULL.
268  */
269 DBusMessageLoader*
270 _dbus_message_loader_new (void)
271 {
272   DBusMessageLoader *loader;
273
274   loader = dbus_new0 (DBusMessageLoader, 1);
275   if (loader == NULL)
276     return NULL;
277   
278   loader->refcount = 1;  
279
280   if (!_dbus_string_init (&loader->data, _DBUS_INT_MAX))
281     {
282       dbus_free (loader);
283       return NULL;
284     }
285
286   /* preallocate the buffer for speed, ignore failure */
287   (void) _dbus_string_set_length (&loader->data, INITIAL_LOADER_DATA_LEN);
288   
289   return loader;
290 }
291
292 /**
293  * Increments the reference count of the loader.
294  *
295  * @param loader the loader.
296  */
297 void
298 _dbus_message_loader_ref (DBusMessageLoader *loader)
299 {
300   loader->refcount += 1;
301 }
302
303 /**
304  * Decrements the reference count of the loader and finalizes the
305  * loader when the count reaches zero.
306  *
307  * @param loader the loader.
308  */
309 void
310 _dbus_message_loader_unref (DBusMessageLoader *loader)
311 {
312   loader->refcount -= 1;
313   if (loader->refcount == 0)
314     {
315       _dbus_list_foreach (&loader->messages,
316                           (DBusForeachFunction) dbus_message_unref,
317                           NULL);
318       _dbus_list_clear (&loader->messages);
319       _dbus_string_free (&loader->data);
320       dbus_free (loader);
321     }
322 }
323
324 /**
325  * Gets the buffer to use for reading data from the network.  Network
326  * data is read directly into an allocated buffer, which is then used
327  * in the DBusMessage, to avoid as many extra memcpy's as possible.
328  * The buffer must always be returned immediately using
329  * _dbus_message_loader_return_buffer(), even if no bytes are
330  * successfully read.
331  *
332  * @todo this function can be a lot more clever. For example
333  * it can probably always return a buffer size to read exactly
334  * the body of the next message, thus avoiding any memory wastage
335  * or reallocs.
336  * 
337  * @param loader the message loader.
338  * @param buffer the buffer
339  */
340 void
341 _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
342                                  DBusString        **buffer)
343 {
344   _dbus_assert (!loader->buffer_outstanding);
345
346   *buffer = &loader->data;
347   
348   loader->buffer_outstanding = TRUE;
349 }
350
351 /**
352  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
353  * indicating to the loader how many bytes of the buffer were filled
354  * in. This function must always be called, even if no bytes were
355  * successfully read.
356  *
357  * @param loader the loader.
358  * @param buffer the buffer.
359  * @param bytes_read number of bytes that were read into the buffer.
360  */
361 void
362 _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
363                                     DBusString         *buffer,
364                                     int                 bytes_read)
365 {
366   _dbus_assert (loader->buffer_outstanding);
367   _dbus_assert (buffer == &loader->data);
368
369   /* FIXME fake implementation just creates a message for every 7
370    * bytes. The real implementation will pass ownership of
371    * loader->data bytes to new messages, to avoid memcpy.  We can also
372    * smart-realloc loader->data to shrink it if it's too big, though
373    * _dbus_message_loader_get_buffer() could strategically arrange for
374    * that to usually not happen.
375    */
376
377   loader->buffer_outstanding = FALSE;
378
379   while (_dbus_string_get_length (&loader->data) >= 7)
380     {
381       DBusMessage *message;
382       
383       message = dbus_message_new ();
384       if (message == NULL)
385         break; /* ugh, postpone this I guess. */
386
387       _dbus_list_append (&loader->messages, message);
388
389       _dbus_string_delete (&loader->data,
390                            0, 7);
391       
392       _dbus_verbose ("Loaded message %p\n", message);
393     }
394 }
395
396 /**
397  * Pops a loaded message (passing ownership of the message
398  * to the caller). Returns #NULL if no messages have been
399  * loaded.
400  *
401  * @param loader the loader.
402  * @returns the next message, or #NULL if none.
403  */
404 DBusMessage*
405 _dbus_message_loader_pop_message (DBusMessageLoader *loader)
406 {
407   return _dbus_list_pop_first (&loader->messages);
408 }
409
410 /** @} */