1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-pending-call.c Object representing a call in progress.
3  *
4  * Copyright (C) 2002, 2003 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23 
24 #include <config.h>
25 #include "dbus-internals.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-message-internal.h"
28 #include "dbus-pending-call-internal.h"
29 #include "dbus-pending-call.h"
30 #include "dbus-list.h"
31 #include "dbus-threads.h"
32 #include "dbus-test.h"
33 
34 /**
35  * @defgroup DBusPendingCallInternals DBusPendingCall implementation details
36  * @ingroup DBusInternals
37  * @brief DBusPendingCall private implementation details.
38  *
39  * The guts of DBusPendingCall and its methods.
40  *
41  * @{
42  */
43 
44 /**
45  * @brief Internals of DBusPendingCall
46  *
47  * Opaque object representing a reply message that we're waiting for.
48  */
49 
50 /**
51  * shorter and more visible way to write _dbus_connection_lock()
52  */
53 #define CONNECTION_LOCK(connection)   _dbus_connection_lock(connection)
54 /**
55  * shorter and more visible way to write _dbus_connection_unlock()
56  */
57 #define CONNECTION_UNLOCK(connection) _dbus_connection_unlock(connection)
58 
59 /**
60  * Implementation details of #DBusPendingCall - all fields are private.
61  */
62 struct DBusPendingCall
63 {
64   DBusAtomic refcount;                            /**< reference count */
65 
66   DBusDataSlotList slot_list;                     /**< Data stored by allocated integer ID */
67 
68   DBusPendingCallNotifyFunction function;         /**< Notifier when reply arrives. */
69 
70   DBusConnection *connection;                     /**< Connections we're associated with */
71   DBusMessage *reply;                             /**< Reply (after we've received it) */
72   DBusTimeout *timeout;                           /**< Timeout */
73 
74   DBusList *timeout_link;                         /**< Preallocated timeout response */
75 
76   dbus_uint32_t reply_serial;                     /**< Expected serial of reply */
77 
78   /**
79    * TRUE if some thread has taken responsibility for completing this
80    * pending call: either the pending call has completed, or it is about
81    * to be completed. Protected by the connection lock.
82    */
83   unsigned int completed : 1;
84   /**
85    * TRUE if we have added the timeout. Protected by the connection lock.
86    */
87   unsigned int timeout_added : 1;
88 };
89 
90 static void
_dbus_pending_call_trace_ref(DBusPendingCall * pending_call,int old_refcount,int new_refcount,const char * why)91 _dbus_pending_call_trace_ref (DBusPendingCall *pending_call,
92     int old_refcount,
93     int new_refcount,
94     const char *why)
95 {
96 #ifdef DBUS_ENABLE_VERBOSE_MODE
97   static int enabled = -1;
98 
99   _dbus_trace_ref ("DBusPendingCall", pending_call, old_refcount,
100       new_refcount, why, "DBUS_PENDING_CALL_TRACE", &enabled);
101 #endif
102 }
103 
104 static dbus_int32_t notify_user_data_slot = -1;
105 
106 /**
107  * Creates a new pending reply object.
108  *
109  * @param connection connection where reply will arrive
110  * @param timeout_milliseconds length of timeout, -1 (or
111  *  #DBUS_TIMEOUT_USE_DEFAULT) for default,
112  *  #DBUS_TIMEOUT_INFINITE for no timeout
113  * @param timeout_handler timeout handler, takes pending call as data
114  * @returns a new #DBusPendingCall or #NULL if no memory.
115  */
116 DBusPendingCall*
_dbus_pending_call_new_unlocked(DBusConnection * connection,int timeout_milliseconds,DBusTimeoutHandler timeout_handler)117 _dbus_pending_call_new_unlocked (DBusConnection    *connection,
118                                  int                timeout_milliseconds,
119                                  DBusTimeoutHandler timeout_handler)
120 {
121   DBusPendingCall *pending;
122   DBusTimeout *timeout;
123 
124   _dbus_assert (timeout_milliseconds >= 0 || timeout_milliseconds == -1);
125 
126   if (timeout_milliseconds == -1)
127     timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
128 
129   if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
130     return NULL;
131 
132   pending = dbus_new0 (DBusPendingCall, 1);
133 
134   if (pending == NULL)
135     {
136       dbus_pending_call_free_data_slot (&notify_user_data_slot);
137       return NULL;
138     }
139 
140   if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
141     {
142       timeout = _dbus_timeout_new (timeout_milliseconds,
143                                    timeout_handler,
144                                    pending, NULL);
145 
146       if (timeout == NULL)
147         {
148           dbus_pending_call_free_data_slot (&notify_user_data_slot);
149           dbus_free (pending);
150           return NULL;
151         }
152 
153       pending->timeout = timeout;
154     }
155   else
156     {
157       pending->timeout = NULL;
158     }
159 
160   _dbus_atomic_inc (&pending->refcount);
161   pending->connection = connection;
162   _dbus_connection_ref_unlocked (pending->connection);
163 
164   _dbus_data_slot_list_init (&pending->slot_list);
165 
166   _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked");
167 
168   return pending;
169 }
170 
171 /**
172  * Sets the reply of a pending call with the given message,
173  * or if the message is #NULL, by timing out the pending call.
174  *
175  * @param pending the pending call
176  * @param message the message to complete the call with, or #NULL
177  *  to time out the call
178  */
179 void
_dbus_pending_call_set_reply_unlocked(DBusPendingCall * pending,DBusMessage * message)180 _dbus_pending_call_set_reply_unlocked (DBusPendingCall *pending,
181                                        DBusMessage     *message)
182 {
183   if (message == NULL)
184     {
185       message = pending->timeout_link->data;
186       _dbus_list_clear (&pending->timeout_link);
187     }
188   else
189     dbus_message_ref (message);
190 
191   _dbus_verbose ("  handing message %p (%s) to pending call serial %u\n",
192                  message,
193                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN ?
194                  "method return" :
195                  dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ?
196                  "error" : "other type",
197                  pending->reply_serial);
198 
199   _dbus_assert (pending->reply == NULL);
200   _dbus_assert (pending->reply_serial == dbus_message_get_reply_serial (message));
201   pending->reply = message;
202 }
203 
204 /**
205  * Sets the pending call to completed
206  *
207  * This method is called with the connection lock held, to protect
208  * pending->completed. It must be paired with a call to
209  * _dbus_pending_call_finish_completion() after the connection lock has
210  * been released.
211  *
212  * @param pending the pending call
213  */
214 void
_dbus_pending_call_start_completion_unlocked(DBusPendingCall * pending)215 _dbus_pending_call_start_completion_unlocked (DBusPendingCall *pending)
216 {
217   _dbus_assert (!pending->completed);
218 
219   pending->completed = TRUE;
220 }
221 
222 /**
223  * Call the notifier function for the pending call.
224  *
225  * This method must be called after the connection lock has been
226  * released, and must be paired with a call to
227  * _dbus_pending_call_start_completion_unlocked().
228  *
229  * @param pending the pending call
230  */
231 void
_dbus_pending_call_finish_completion(DBusPendingCall * pending)232 _dbus_pending_call_finish_completion (DBusPendingCall *pending)
233 {
234   _dbus_assert (pending->completed);
235 
236   if (pending->function)
237     {
238       void *user_data;
239       user_data = dbus_pending_call_get_data (pending,
240                                               notify_user_data_slot);
241 
242       (* pending->function) (pending, user_data);
243     }
244 }
245 
246 /**
247  * If the pending call hasn't been timed out, add its timeout
248  * error reply to the connection's incoming message queue.
249  *
250  * @param pending the pending call
251  * @param connection the connection the call was sent to
252  */
253 void
_dbus_pending_call_queue_timeout_error_unlocked(DBusPendingCall * pending,DBusConnection * connection)254 _dbus_pending_call_queue_timeout_error_unlocked (DBusPendingCall *pending,
255                                                  DBusConnection  *connection)
256 {
257   _dbus_assert (connection == pending->connection);
258 
259   if (pending->timeout_link)
260     {
261       _dbus_connection_queue_synthesized_message_link (connection,
262 						       pending->timeout_link);
263       pending->timeout_link = NULL;
264     }
265 }
266 
267 /**
268  * Checks to see if a timeout has been added
269  *
270  * @param pending the pending_call
271  * @returns #TRUE if there is a timeout or #FALSE if not
272  */
273 dbus_bool_t
_dbus_pending_call_is_timeout_added_unlocked(DBusPendingCall * pending)274 _dbus_pending_call_is_timeout_added_unlocked (DBusPendingCall  *pending)
275 {
276   _dbus_assert (pending != NULL);
277 
278   return pending->timeout_added;
279 }
280 
281 
282 /**
283  * Sets wether the timeout has been added
284  *
285  * @param pending the pending_call
286  * @param is_added whether or not a timeout is added
287  */
288 void
_dbus_pending_call_set_timeout_added_unlocked(DBusPendingCall * pending,dbus_bool_t is_added)289 _dbus_pending_call_set_timeout_added_unlocked (DBusPendingCall  *pending,
290                                                dbus_bool_t       is_added)
291 {
292   _dbus_assert (pending != NULL);
293 
294   pending->timeout_added = is_added;
295 }
296 
297 
298 /**
299  * Retrives the timeout
300  *
301  * @param pending the pending_call
302  * @returns a timeout object or NULL if call has no timeout
303  */
304 DBusTimeout *
_dbus_pending_call_get_timeout_unlocked(DBusPendingCall * pending)305 _dbus_pending_call_get_timeout_unlocked (DBusPendingCall  *pending)
306 {
307   _dbus_assert (pending != NULL);
308 
309   return pending->timeout;
310 }
311 
312 /**
313  * Gets the reply's serial number
314  *
315  * @param pending the pending_call
316  * @returns a serial number for the reply or 0
317  */
318 dbus_uint32_t
_dbus_pending_call_get_reply_serial_unlocked(DBusPendingCall * pending)319 _dbus_pending_call_get_reply_serial_unlocked (DBusPendingCall  *pending)
320 {
321   _dbus_assert (pending != NULL);
322 
323   return pending->reply_serial;
324 }
325 
326 /**
327  * Sets the reply's serial number
328  *
329  * @param pending the pending_call
330  * @param serial the serial number
331  */
332 void
_dbus_pending_call_set_reply_serial_unlocked(DBusPendingCall * pending,dbus_uint32_t serial)333 _dbus_pending_call_set_reply_serial_unlocked  (DBusPendingCall *pending,
334                                                dbus_uint32_t serial)
335 {
336   _dbus_assert (pending != NULL);
337   _dbus_assert (pending->reply_serial == 0);
338 
339   pending->reply_serial = serial;
340 }
341 
342 /**
343  * Gets the connection associated with this pending call.
344  *
345  * @param pending the pending_call
346  * @returns the connection associated with the pending call
347  */
348 DBusConnection *
_dbus_pending_call_get_connection_and_lock(DBusPendingCall * pending)349 _dbus_pending_call_get_connection_and_lock (DBusPendingCall *pending)
350 {
351   _dbus_assert (pending != NULL);
352 
353   CONNECTION_LOCK (pending->connection);
354   return pending->connection;
355 }
356 
357 /**
358  * Gets the connection associated with this pending call.
359  *
360  * @param pending the pending_call
361  * @returns the connection associated with the pending call
362  */
363 DBusConnection *
_dbus_pending_call_get_connection_unlocked(DBusPendingCall * pending)364 _dbus_pending_call_get_connection_unlocked (DBusPendingCall *pending)
365 {
366   _dbus_assert (pending != NULL);
367 
368   return pending->connection;
369 }
370 
371 /**
372  * Sets the reply message associated with the pending call to a timeout error
373  *
374  * @param pending the pending_call
375  * @param message the message we are sending the error reply to
376  * @param serial serial number for the reply
377  * @return #FALSE on OOM
378  */
379 dbus_bool_t
_dbus_pending_call_set_timeout_error_unlocked(DBusPendingCall * pending,DBusMessage * message,dbus_uint32_t serial)380 _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending,
381                                                DBusMessage     *message,
382                                                dbus_uint32_t    serial)
383 {
384   DBusList *reply_link;
385   DBusMessage *reply;
386 
387   reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
388                                   "Did not receive a reply. Possible causes include: "
389                                   "the remote application did not send a reply, "
390                                   "the message bus security policy blocked the reply, "
391                                   "the reply timeout expired, or "
392                                   "the network connection was broken.");
393   if (reply == NULL)
394     return FALSE;
395 
396   reply_link = _dbus_list_alloc_link (reply);
397   if (reply_link == NULL)
398     {
399       /* it's OK to unref this, nothing that could have attached a callback
400        * has ever seen it */
401       dbus_message_unref (reply);
402       return FALSE;
403     }
404 
405   pending->timeout_link = reply_link;
406 
407   _dbus_pending_call_set_reply_serial_unlocked (pending, serial);
408 
409   return TRUE;
410 }
411 
412 /**
413  * Increments the reference count on a pending call,
414  * while the lock on its connection is already held.
415  *
416  * @param pending the pending call object
417  * @returns the pending call object
418  */
419 DBusPendingCall *
_dbus_pending_call_ref_unlocked(DBusPendingCall * pending)420 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
421 {
422   dbus_int32_t old_refcount;
423 
424   old_refcount = _dbus_atomic_inc (&pending->refcount);
425   _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
426       "ref_unlocked");
427 
428   return pending;
429 }
430 
431 
432 static void
_dbus_pending_call_last_unref(DBusPendingCall * pending)433 _dbus_pending_call_last_unref (DBusPendingCall *pending)
434 {
435   DBusConnection *connection;
436 
437   /* If we get here, we should be already detached
438    * from the connection, or never attached.
439    */
440   _dbus_assert (!pending->timeout_added);
441 
442   connection = pending->connection;
443 
444   /* this assumes we aren't holding connection lock... */
445   _dbus_data_slot_list_free (&pending->slot_list);
446 
447   if (pending->timeout != NULL)
448     _dbus_timeout_unref (pending->timeout);
449 
450   if (pending->timeout_link)
451     {
452       dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
453       _dbus_list_free_link (pending->timeout_link);
454       pending->timeout_link = NULL;
455     }
456 
457   if (pending->reply)
458     {
459       dbus_message_unref (pending->reply);
460       pending->reply = NULL;
461     }
462 
463   dbus_free (pending);
464 
465   dbus_pending_call_free_data_slot (&notify_user_data_slot);
466 
467   /* connection lock should not be held. */
468   /* Free the connection last to avoid a weird state while
469    * calling out to application code where the pending exists
470    * but not the connection.
471    */
472   dbus_connection_unref (connection);
473 }
474 
475 /**
476  * Decrements the reference count on a pending call,
477  * freeing it if the count reaches 0. Assumes
478  * connection lock is already held.
479  *
480  * @param pending the pending call object
481  */
482 void
_dbus_pending_call_unref_and_unlock(DBusPendingCall * pending)483 _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending)
484 {
485   dbus_int32_t old_refcount;
486 
487   old_refcount = _dbus_atomic_dec (&pending->refcount);
488   _dbus_assert (old_refcount > 0);
489   _dbus_pending_call_trace_ref (pending, old_refcount,
490       old_refcount - 1, "unref_and_unlock");
491 
492   CONNECTION_UNLOCK (pending->connection);
493 
494   if (old_refcount == 1)
495     _dbus_pending_call_last_unref (pending);
496 }
497 
498 /**
499  * Checks whether the pending call has received a reply
500  * yet, or not. Assumes connection lock is held.
501  *
502  * @param pending the pending call
503  * @returns #TRUE if a reply has been received
504  */
505 dbus_bool_t
_dbus_pending_call_get_completed_unlocked(DBusPendingCall * pending)506 _dbus_pending_call_get_completed_unlocked (DBusPendingCall    *pending)
507 {
508   return pending->completed;
509 }
510 
511 static DBusDataSlotAllocator slot_allocator =
512   _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (pending_call_slots));
513 
514 /**
515  * Stores a pointer on a #DBusPendingCall, along
516  * with an optional function to be used for freeing
517  * the data when the data is set again, or when
518  * the pending call is finalized. The slot number
519  * must have been allocated with dbus_pending_call_allocate_data_slot().
520  *
521  * @param pending the pending_call
522  * @param slot the slot number
523  * @param data the data to store
524  * @param free_data_func finalizer function for the data
525  * @returns #TRUE if there was enough memory to store the data
526  */
527 dbus_bool_t
_dbus_pending_call_set_data_unlocked(DBusPendingCall * pending,dbus_int32_t slot,void * data,DBusFreeFunction free_data_func)528 _dbus_pending_call_set_data_unlocked (DBusPendingCall  *pending,
529                                      dbus_int32_t      slot,
530                                      void             *data,
531                                      DBusFreeFunction  free_data_func)
532 {
533   DBusFreeFunction old_free_func;
534   void *old_data;
535   dbus_bool_t retval;
536 
537   retval = _dbus_data_slot_list_set (&slot_allocator,
538                                      &pending->slot_list,
539                                      slot, data, free_data_func,
540                                      &old_free_func, &old_data);
541 
542   /* Drop locks to call out to app code */
543   CONNECTION_UNLOCK (pending->connection);
544 
545   if (retval)
546     {
547       if (old_free_func)
548         (* old_free_func) (old_data);
549     }
550 
551   CONNECTION_LOCK (pending->connection);
552 
553   return retval;
554 }
555 
556 /** @} */
557 
558 /**
559  * @defgroup DBusPendingCall DBusPendingCall
560  * @ingroup  DBus
561  * @brief Pending reply to a method call message
562  *
563  * A DBusPendingCall is an object representing an
564  * expected reply. A #DBusPendingCall can be created
565  * when you send a message that should have a reply.
566  *
567  * @{
568  */
569 
570 /**
571  * @def DBUS_TIMEOUT_INFINITE
572  *
573  * An integer constant representing an infinite timeout. This has the
574  * numeric value 0x7fffffff (the largest 32-bit signed integer).
575  *
576  * For source compatibility with D-Bus versions earlier than 1.4.12, use
577  * 0x7fffffff, or INT32_MAX (assuming your platform has it).
578  */
579 
580 /**
581  * @def DBUS_TIMEOUT_USE_DEFAULT
582  *
583  * An integer constant representing a request to use the default timeout.
584  * This has numeric value -1.
585  *
586  * For source compatibility with D-Bus versions earlier than 1.4.12, use a
587  * literal -1.
588  */
589 
590 /**
591  * @typedef DBusPendingCall
592  *
593  * Opaque data type representing a message pending.
594  */
595 
596 /**
597  * Increments the reference count on a pending call.
598  *
599  * @param pending the pending call object
600  * @returns the pending call object
601  */
602 DBusPendingCall *
dbus_pending_call_ref(DBusPendingCall * pending)603 dbus_pending_call_ref (DBusPendingCall *pending)
604 {
605   dbus_int32_t old_refcount;
606 
607   _dbus_return_val_if_fail (pending != NULL, NULL);
608 
609   old_refcount = _dbus_atomic_inc (&pending->refcount);
610   _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
611       "ref");
612 
613   return pending;
614 }
615 
616 /**
617  * Decrements the reference count on a pending call,
618  * freeing it if the count reaches 0.
619  *
620  * @param pending the pending call object
621  */
622 void
dbus_pending_call_unref(DBusPendingCall * pending)623 dbus_pending_call_unref (DBusPendingCall *pending)
624 {
625   dbus_int32_t old_refcount;
626 
627   _dbus_return_if_fail (pending != NULL);
628 
629   old_refcount = _dbus_atomic_dec (&pending->refcount);
630   _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1,
631       "unref");
632 
633   if (old_refcount == 1)
634     _dbus_pending_call_last_unref(pending);
635 }
636 
637 /**
638  * Sets a notification function to be called when the reply is
639  * received or the pending call times out.
640  *
641  * @param pending the pending call
642  * @param function notifier function
643  * @param user_data data to pass to notifier function
644  * @param free_user_data function to free the user data
645  * @returns #FALSE if not enough memory
646  */
647 dbus_bool_t
dbus_pending_call_set_notify(DBusPendingCall * pending,DBusPendingCallNotifyFunction function,void * user_data,DBusFreeFunction free_user_data)648 dbus_pending_call_set_notify (DBusPendingCall              *pending,
649                               DBusPendingCallNotifyFunction function,
650                               void                         *user_data,
651                               DBusFreeFunction              free_user_data)
652 {
653   dbus_bool_t ret = FALSE;
654 
655   _dbus_return_val_if_fail (pending != NULL, FALSE);
656 
657   CONNECTION_LOCK (pending->connection);
658 
659   /* could invoke application code! */
660   if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
661                                              user_data, free_user_data))
662     goto out;
663 
664   pending->function = function;
665   ret = TRUE;
666 
667 out:
668   CONNECTION_UNLOCK (pending->connection);
669 
670   return ret;
671 }
672 
673 /**
674  * Cancels the pending call, such that any reply or error received
675  * will just be ignored.  Drops the dbus library's internal reference
676  * to the #DBusPendingCall so will free the call if nobody else is
677  * holding a reference. However you usually get a reference from
678  * dbus_connection_send_with_reply() so probably your app owns a ref
679  * also.
680  *
681  * Note that canceling a pending call will <em>not</em> simulate a
682  * timed-out call; if a call times out, then a timeout error reply is
683  * received. If you cancel the call, no reply is received unless the
684  * the reply was already received before you canceled.
685  *
686  * @param pending the pending call
687  */
688 void
dbus_pending_call_cancel(DBusPendingCall * pending)689 dbus_pending_call_cancel (DBusPendingCall *pending)
690 {
691   _dbus_return_if_fail (pending != NULL);
692 
693   _dbus_connection_remove_pending_call (pending->connection,
694                                         pending);
695 }
696 
697 /**
698  * Checks whether the pending call has received a reply
699  * yet, or not.
700  *
701  * @param pending the pending call
702  * @returns #TRUE if a reply has been received
703  */
704 dbus_bool_t
dbus_pending_call_get_completed(DBusPendingCall * pending)705 dbus_pending_call_get_completed (DBusPendingCall *pending)
706 {
707   dbus_bool_t completed;
708 
709   _dbus_return_val_if_fail (pending != NULL, FALSE);
710 
711   CONNECTION_LOCK (pending->connection);
712   completed = pending->completed;
713   CONNECTION_UNLOCK (pending->connection);
714 
715   return completed;
716 }
717 
718 /**
719  * Gets the reply, or returns #NULL if none has been received
720  * yet. Ownership of the reply message passes to the caller. This
721  * function can only be called once per pending call, since the reply
722  * message is tranferred to the caller.
723  *
724  * @param pending the pending call
725  * @returns the reply message or #NULL.
726  */
727 DBusMessage*
dbus_pending_call_steal_reply(DBusPendingCall * pending)728 dbus_pending_call_steal_reply (DBusPendingCall *pending)
729 {
730   DBusMessage *message;
731 
732   _dbus_return_val_if_fail (pending != NULL, NULL);
733   _dbus_return_val_if_fail (pending->completed, NULL);
734   _dbus_return_val_if_fail (pending->reply != NULL, NULL);
735 
736   CONNECTION_LOCK (pending->connection);
737 
738   message = pending->reply;
739   pending->reply = NULL;
740 
741   CONNECTION_UNLOCK (pending->connection);
742 
743   _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply");
744   return message;
745 }
746 
747 /**
748  * Block until the pending call is completed.  The blocking is as with
749  * dbus_connection_send_with_reply_and_block(); it does not enter the
750  * main loop or process other messages, it simply waits for the reply
751  * in question.
752  *
753  * If the pending call is already completed, this function returns
754  * immediately.
755  *
756  * @todo when you start blocking, the timeout is reset, but it should
757  * really only use time remaining since the pending call was created.
758  * This requires storing timestamps instead of intervals in the timeout
759  *
760  * @param pending the pending call
761  */
762 void
dbus_pending_call_block(DBusPendingCall * pending)763 dbus_pending_call_block (DBusPendingCall *pending)
764 {
765   _dbus_return_if_fail (pending != NULL);
766 
767   _dbus_connection_block_pending_call (pending);
768 }
769 
770 /**
771  * Allocates an integer ID to be used for storing application-specific
772  * data on any DBusPendingCall. The allocated ID may then be used
773  * with dbus_pending_call_set_data() and dbus_pending_call_get_data().
774  * The passed-in slot must be initialized to -1, and is filled in
775  * with the slot ID. If the passed-in slot is not -1, it's assumed
776  * to be already allocated, and its refcount is incremented.
777  *
778  * The allocated slot is global, i.e. all DBusPendingCall objects will
779  * have a slot with the given integer ID reserved.
780  *
781  * @param slot_p address of a global variable storing the slot
782  * @returns #FALSE on failure (no memory)
783  */
784 dbus_bool_t
dbus_pending_call_allocate_data_slot(dbus_int32_t * slot_p)785 dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
786 {
787   _dbus_return_val_if_fail (slot_p != NULL, FALSE);
788 
789   return _dbus_data_slot_allocator_alloc (&slot_allocator,
790                                           slot_p);
791 }
792 
793 /**
794  * Deallocates a global ID for #DBusPendingCall data slots.
795  * dbus_pending_call_get_data() and dbus_pending_call_set_data() may
796  * no longer be used with this slot.  Existing data stored on existing
797  * DBusPendingCall objects will be freed when the #DBusPendingCall is
798  * finalized, but may not be retrieved (and may only be replaced if
799  * someone else reallocates the slot).  When the refcount on the
800  * passed-in slot reaches 0, it is set to -1.
801  *
802  * @param slot_p address storing the slot to deallocate
803  */
804 void
dbus_pending_call_free_data_slot(dbus_int32_t * slot_p)805 dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
806 {
807   _dbus_return_if_fail (slot_p != NULL);
808   _dbus_return_if_fail (*slot_p >= 0);
809 
810   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
811 }
812 
813 /**
814  * Stores a pointer on a #DBusPendingCall, along
815  * with an optional function to be used for freeing
816  * the data when the data is set again, or when
817  * the pending call is finalized. The slot number
818  * must have been allocated with dbus_pending_call_allocate_data_slot().
819  *
820  * @param pending the pending_call
821  * @param slot the slot number
822  * @param data the data to store
823  * @param free_data_func finalizer function for the data
824  * @returns #TRUE if there was enough memory to store the data
825  */
826 dbus_bool_t
dbus_pending_call_set_data(DBusPendingCall * pending,dbus_int32_t slot,void * data,DBusFreeFunction free_data_func)827 dbus_pending_call_set_data (DBusPendingCall  *pending,
828                             dbus_int32_t      slot,
829                             void             *data,
830                             DBusFreeFunction  free_data_func)
831 {
832   dbus_bool_t retval;
833 
834   _dbus_return_val_if_fail (pending != NULL, FALSE);
835   _dbus_return_val_if_fail (slot >= 0, FALSE);
836 
837 
838   CONNECTION_LOCK (pending->connection);
839   retval = _dbus_pending_call_set_data_unlocked (pending, slot, data, free_data_func);
840   CONNECTION_UNLOCK (pending->connection);
841   return retval;
842 }
843 
844 /**
845  * Retrieves data previously set with dbus_pending_call_set_data().
846  * The slot must still be allocated (must not have been freed).
847  *
848  * @param pending the pending_call
849  * @param slot the slot to get data from
850  * @returns the data, or #NULL if not found
851  */
852 void*
dbus_pending_call_get_data(DBusPendingCall * pending,dbus_int32_t slot)853 dbus_pending_call_get_data (DBusPendingCall   *pending,
854                             dbus_int32_t       slot)
855 {
856   void *res;
857 
858   _dbus_return_val_if_fail (pending != NULL, NULL);
859 
860   CONNECTION_LOCK (pending->connection);
861   res = _dbus_data_slot_list_get (&slot_allocator,
862                                   &pending->slot_list,
863                                   slot);
864   CONNECTION_UNLOCK (pending->connection);
865 
866   return res;
867 }
868 
869 /** @} */
870