2006-09-30 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-server.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-server.c DBusServer object
3  *
4  * Copyright (C) 2002, 2003, 2004, 2005 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */ 
23
24 #include "dbus-server.h"
25 #include "dbus-server-unix.h"
26 #include "dbus-server-socket.h"
27 #include "dbus-string.h"
28 #ifdef DBUS_BUILD_TESTS
29 #include "dbus-server-debug-pipe.h"
30 #endif
31 #include "dbus-address.h"
32 #include "dbus-protocol.h"
33
34 /**
35  * @defgroup DBusServer DBusServer
36  * @ingroup  DBus
37  * @brief Server that listens for new connections.
38  *
39  * Types and functions related to DBusServer.
40  * A DBusServer represents a server that other applications
41  * can connect to. Each connection from another application
42  * is represented by a DBusConnection.
43  *
44  * @todo Thread safety hasn't been looked at for #DBusServer
45  * @todo Need notification to apps of disconnection, may matter for some transports
46  */
47
48 /**
49  * @defgroup DBusServerInternals DBusServer implementation details
50  * @ingroup  DBusInternals
51  * @brief Implementation details of DBusServer
52  *
53  * @{
54  */
55
56 /* this is a little fragile since it assumes the address doesn't
57  * already have a guid, but it shouldn't
58  */
59 static char*
60 copy_address_with_guid_appended (const DBusString *address,
61                                  const DBusString *guid_hex)
62 {
63   DBusString with_guid;
64   char *retval;
65   
66   if (!_dbus_string_init (&with_guid))
67     return NULL;
68
69   if (!_dbus_string_copy (address, 0, &with_guid,
70                           _dbus_string_get_length (&with_guid)) ||
71       !_dbus_string_append (&with_guid, ",guid=") ||
72       !_dbus_string_copy (guid_hex, 0,
73                           &with_guid, _dbus_string_get_length (&with_guid)))
74     {
75       _dbus_string_free (&with_guid);
76       return NULL;
77     }
78
79   retval = NULL;
80   _dbus_string_steal_data (&with_guid, &retval);
81
82   _dbus_string_free (&with_guid);
83       
84   return retval; /* may be NULL if steal_data failed */
85 }
86
87 /**
88  * Initializes the members of the DBusServer base class.
89  * Chained up to by subclass constructors.
90  *
91  * @param server the server.
92  * @param vtable the vtable for the subclass.
93  * @param address the server's address
94  * @returns #TRUE on success.
95  */
96 dbus_bool_t
97 _dbus_server_init_base (DBusServer             *server,
98                         const DBusServerVTable *vtable,
99                         const DBusString       *address)
100 {
101   server->vtable = vtable;
102   server->refcount.value = 1;
103
104   server->address = NULL;
105   server->watches = NULL;
106   server->timeouts = NULL;
107
108   if (!_dbus_string_init (&server->guid_hex))
109     return FALSE;
110
111   _dbus_generate_uuid (&server->guid);
112
113   if (!_dbus_uuid_encode (&server->guid, &server->guid_hex))
114     goto failed;
115   
116   server->address = copy_address_with_guid_appended (address,
117                                                      &server->guid_hex);
118   if (server->address == NULL)
119     goto failed;
120   
121   _dbus_mutex_new_at_location (&server->mutex);
122   if (server->mutex == NULL)
123     goto failed;
124   
125   server->watches = _dbus_watch_list_new ();
126   if (server->watches == NULL)
127     goto failed;
128
129   server->timeouts = _dbus_timeout_list_new ();
130   if (server->timeouts == NULL)
131     goto failed;
132
133   _dbus_data_slot_list_init (&server->slot_list);
134
135   _dbus_verbose ("Initialized server on address %s\n", server->address);
136   
137   return TRUE;
138
139  failed:
140   _dbus_mutex_free_at_location (&server->mutex);
141   server->mutex = NULL;
142   if (server->watches)
143     {
144       _dbus_watch_list_free (server->watches);
145       server->watches = NULL;
146     }
147   if (server->timeouts)
148     {
149       _dbus_timeout_list_free (server->timeouts);
150       server->timeouts = NULL;
151     }
152   if (server->address)
153     {
154       dbus_free (server->address);
155       server->address = NULL;
156     }
157   _dbus_string_free (&server->guid_hex);
158   
159   return FALSE;
160 }
161
162 /**
163  * Finalizes the members of the DBusServer base class.
164  * Chained up to by subclass finalizers.
165  *
166  * @param server the server.
167  */
168 void
169 _dbus_server_finalize_base (DBusServer *server)
170 {
171   /* We don't have the lock, but nobody should be accessing
172    * concurrently since they don't have a ref
173    */
174 #ifndef DBUS_DISABLE_CHECKS
175   _dbus_assert (!server->have_server_lock);
176 #endif
177   _dbus_assert (server->disconnected);
178   
179   /* calls out to application code... */
180   _dbus_data_slot_list_free (&server->slot_list);
181
182   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
183
184   _dbus_watch_list_free (server->watches);
185   _dbus_timeout_list_free (server->timeouts);
186
187   _dbus_mutex_free_at_location (&server->mutex);
188   
189   dbus_free (server->address);
190
191   dbus_free_string_array (server->auth_mechanisms);
192
193   _dbus_string_free (&server->guid_hex);
194 }
195
196
197 typedef dbus_bool_t (* DBusWatchAddFunction)     (DBusWatchList *list,
198                                                   DBusWatch     *watch);
199 typedef void        (* DBusWatchRemoveFunction)  (DBusWatchList *list,
200                                                   DBusWatch     *watch);
201 typedef void        (* DBusWatchToggleFunction)  (DBusWatchList *list,
202                                                   DBusWatch     *watch,
203                                                   dbus_bool_t    enabled);
204
205 static dbus_bool_t
206 protected_change_watch (DBusServer             *server,
207                         DBusWatch              *watch,
208                         DBusWatchAddFunction    add_function,
209                         DBusWatchRemoveFunction remove_function,
210                         DBusWatchToggleFunction toggle_function,
211                         dbus_bool_t             enabled)
212 {
213   DBusWatchList *watches;
214   dbus_bool_t retval;
215   
216   HAVE_LOCK_CHECK (server);
217
218   /* This isn't really safe or reasonable; a better pattern is the "do
219    * everything, then drop lock and call out" one; but it has to be
220    * propagated up through all callers
221    */
222   
223   watches = server->watches;
224   if (watches)
225     {
226       server->watches = NULL;
227       _dbus_server_ref_unlocked (server);
228       SERVER_UNLOCK (server);
229
230       if (add_function)
231         retval = (* add_function) (watches, watch);
232       else if (remove_function)
233         {
234           retval = TRUE;
235           (* remove_function) (watches, watch);
236         }
237       else
238         {
239           retval = TRUE;
240           (* toggle_function) (watches, watch, enabled);
241         }
242       
243       SERVER_LOCK (server);
244       server->watches = watches;
245       _dbus_server_unref_unlocked (server);
246
247       return retval;
248     }
249   else
250     return FALSE;
251 }
252
253 /**
254  * Adds a watch for this server, chaining out to application-provided
255  * watch handlers.
256  *
257  * @param server the server.
258  * @param watch the watch to add.
259  */
260 dbus_bool_t
261 _dbus_server_add_watch (DBusServer *server,
262                         DBusWatch  *watch)
263 {
264   HAVE_LOCK_CHECK (server);
265   return protected_change_watch (server, watch,
266                                  _dbus_watch_list_add_watch,
267                                  NULL, NULL, FALSE);
268 }
269
270 /**
271  * Removes a watch previously added with _dbus_server_remove_watch().
272  *
273  * @param server the server.
274  * @param watch the watch to remove.
275  */
276 void
277 _dbus_server_remove_watch  (DBusServer *server,
278                             DBusWatch  *watch)
279 {
280   HAVE_LOCK_CHECK (server);
281   protected_change_watch (server, watch,
282                           NULL,
283                           _dbus_watch_list_remove_watch,
284                           NULL, FALSE);
285 }
286
287 /**
288  * Toggles a watch and notifies app via server's
289  * DBusWatchToggledFunction if available. It's an error to call this
290  * function on a watch that was not previously added.
291  *
292  * @param server the server.
293  * @param watch the watch to toggle.
294  * @param enabled whether to enable or disable
295  */
296 void
297 _dbus_server_toggle_watch (DBusServer  *server,
298                            DBusWatch   *watch,
299                            dbus_bool_t  enabled)
300 {
301   _dbus_assert (watch != NULL);
302
303   HAVE_LOCK_CHECK (server);
304   protected_change_watch (server, watch,
305                           NULL, NULL,
306                           _dbus_watch_list_toggle_watch,
307                           enabled);
308 }
309
310
311 typedef dbus_bool_t (* DBusTimeoutAddFunction)    (DBusTimeoutList *list,
312                                                    DBusTimeout     *timeout);
313 typedef void        (* DBusTimeoutRemoveFunction) (DBusTimeoutList *list,
314                                                    DBusTimeout     *timeout);
315 typedef void        (* DBusTimeoutToggleFunction) (DBusTimeoutList *list,
316                                                    DBusTimeout     *timeout,
317                                                    dbus_bool_t      enabled);
318
319
320 static dbus_bool_t
321 protected_change_timeout (DBusServer               *server,
322                           DBusTimeout              *timeout,
323                           DBusTimeoutAddFunction    add_function,
324                           DBusTimeoutRemoveFunction remove_function,
325                           DBusTimeoutToggleFunction toggle_function,
326                           dbus_bool_t               enabled)
327 {
328   DBusTimeoutList *timeouts;
329   dbus_bool_t retval;
330   
331   HAVE_LOCK_CHECK (server);
332
333   /* This isn't really safe or reasonable; a better pattern is the "do everything, then
334    * drop lock and call out" one; but it has to be propagated up through all callers
335    */
336   
337   timeouts = server->timeouts;
338   if (timeouts)
339     {
340       server->timeouts = NULL;
341       _dbus_server_ref_unlocked (server);
342       SERVER_UNLOCK (server);
343
344       if (add_function)
345         retval = (* add_function) (timeouts, timeout);
346       else if (remove_function)
347         {
348           retval = TRUE;
349           (* remove_function) (timeouts, timeout);
350         }
351       else
352         {
353           retval = TRUE;
354           (* toggle_function) (timeouts, timeout, enabled);
355         }
356       
357       SERVER_LOCK (server);
358       server->timeouts = timeouts;
359       _dbus_server_unref_unlocked (server);
360
361       return retval;
362     }
363   else
364     return FALSE;
365 }
366
367 /**
368  * Adds a timeout for this server, chaining out to
369  * application-provided timeout handlers. The timeout should be
370  * repeatedly handled with dbus_timeout_handle() at its given interval
371  * until it is removed.
372  *
373  * @param server the server.
374  * @param timeout the timeout to add.
375  */
376 dbus_bool_t
377 _dbus_server_add_timeout (DBusServer  *server,
378                           DBusTimeout *timeout)
379 {
380   return protected_change_timeout (server, timeout,
381                                    _dbus_timeout_list_add_timeout,
382                                    NULL, NULL, FALSE);
383 }
384
385 /**
386  * Removes a timeout previously added with _dbus_server_add_timeout().
387  *
388  * @param server the server.
389  * @param timeout the timeout to remove.
390  */
391 void
392 _dbus_server_remove_timeout (DBusServer  *server,
393                              DBusTimeout *timeout)
394 {
395   protected_change_timeout (server, timeout,
396                             NULL,
397                             _dbus_timeout_list_remove_timeout,
398                             NULL, FALSE);
399 }
400
401 /**
402  * Toggles a timeout and notifies app via server's
403  * DBusTimeoutToggledFunction if available. It's an error to call this
404  * function on a timeout that was not previously added.
405  *
406  * @param server the server.
407  * @param timeout the timeout to toggle.
408  * @param enabled whether to enable or disable
409  */
410 void
411 _dbus_server_toggle_timeout (DBusServer  *server,
412                              DBusTimeout *timeout,
413                              dbus_bool_t  enabled)
414 {
415   protected_change_timeout (server, timeout,
416                             NULL, NULL,
417                             _dbus_timeout_list_toggle_timeout,
418                             enabled);
419 }
420
421 /** @} */
422
423 /**
424  * @addtogroup DBusServer
425  *
426  * @{
427  */
428
429
430 /**
431  * @typedef DBusServer
432  *
433  * An opaque object representing a server that listens for
434  * connections from other applications. Each time a connection
435  * is made, a new DBusConnection is created and made available
436  * via an application-provided DBusNewConnectionFunction.
437  * The DBusNewConnectionFunction is provided with
438  * dbus_server_set_new_connection_function().
439  * 
440  */
441
442 static const struct {
443   DBusServerListenResult (* func) (DBusAddressEntry *entry,
444                                    DBusServer      **server_p,
445                                    DBusError        *error);
446 } listen_funcs[] = {
447   { _dbus_server_listen_socket },
448   { _dbus_server_listen_platform_specific }
449 #ifdef DBUS_BUILD_TESTS
450   , { _dbus_server_listen_debug_pipe }
451 #endif
452 };
453
454 /**
455  * Listens for new connections on the given address.
456  * If there are multiple address entries in the address,
457  * tries each one and listens on the first one that
458  * works.
459  * 
460  * Returns #NULL and sets error if listening fails for any reason.
461  * Otherwise returns a new #DBusServer.
462  * dbus_server_set_new_connection_function() and
463  * dbus_server_set_watch_functions() should be called
464  * immediately to render the server fully functional.
465  * 
466  * @param address the address of this server.
467  * @param error location to store rationale for failure.
468  * @returns a new DBusServer, or #NULL on failure.
469  * 
470  */
471 DBusServer*
472 dbus_server_listen (const char     *address,
473                     DBusError      *error)
474 {
475   DBusServer *server;
476   DBusAddressEntry **entries;
477   int len, i;
478   DBusError first_connect_error;
479   dbus_bool_t handled_once;
480   
481   _dbus_return_val_if_fail (address != NULL, NULL);
482   _dbus_return_val_if_error_is_set (error, NULL);
483   
484   if (!dbus_parse_address (address, &entries, &len, error))
485     return NULL;
486
487   server = NULL;
488   dbus_error_init (&first_connect_error);
489   handled_once = FALSE;
490   
491   for (i = 0; i < len; i++)
492     {
493       int j;
494
495       for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j)
496         {
497           DBusServerListenResult result;
498           DBusError tmp_error;
499       
500           dbus_error_init (&tmp_error);
501           result = (* listen_funcs[j].func) (entries[i],
502                                              &server,
503                                              &tmp_error);
504
505           if (result == DBUS_SERVER_LISTEN_OK)
506             {
507               _dbus_assert (server != NULL);
508               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
509               handled_once = TRUE;
510               goto out;
511             }
512           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
513             {
514               _dbus_assert (server == NULL);
515               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
516               dbus_move_error (&tmp_error, error);
517               handled_once = TRUE;
518               goto out;
519             }
520           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
521             {
522               _dbus_assert (server == NULL);
523               _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
524
525               /* keep trying addresses */
526             }
527           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
528             {
529               _dbus_assert (server == NULL);
530               _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
531               if (!dbus_error_is_set (&first_connect_error))
532                 dbus_move_error (&tmp_error, &first_connect_error);
533               else
534                 dbus_error_free (&tmp_error);
535
536               handled_once = TRUE;
537               
538               /* keep trying addresses */
539             }
540         }
541
542       _dbus_assert (server == NULL);
543       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
544     }
545
546  out:
547
548   if (!handled_once)
549     {
550       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
551       if (len > 0)
552         dbus_set_error (error,
553                        DBUS_ERROR_BAD_ADDRESS,
554                        "Unknown address type '%s'",
555                        dbus_address_entry_get_method (entries[0]));
556       else
557         dbus_set_error (error,
558                         DBUS_ERROR_BAD_ADDRESS,
559                         "Empty address '%s'",
560                         address);
561     }
562   
563   dbus_address_entries_free (entries);
564
565   if (server == NULL)
566     {
567       _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) ||
568                    dbus_error_is_set (error));
569       
570       if (error && dbus_error_is_set (error))
571         {
572           /* already set the error */
573         }
574       else
575         {
576           /* didn't set the error but either error should be
577            * NULL or first_connect_error should be set.
578            */
579           _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error));
580           dbus_move_error (&first_connect_error, error);
581         }
582
583       _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
584       _DBUS_ASSERT_ERROR_IS_SET (error);
585
586       return NULL;
587     }
588   else
589     {
590       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
591       return server;
592     }
593 }
594
595 /**
596  * Increments the reference count of a DBusServer.
597  *
598  * @param server the server.
599  * @returns the server
600  */
601 DBusServer *
602 dbus_server_ref (DBusServer *server)
603 {
604   _dbus_return_val_if_fail (server != NULL, NULL);
605   _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
606
607 #ifdef DBUS_HAVE_ATOMIC_INT
608   _dbus_atomic_inc (&server->refcount);
609 #else
610   SERVER_LOCK (server);
611   _dbus_assert (server->refcount.value > 0);
612
613   server->refcount.value += 1;
614   SERVER_UNLOCK (server);
615 #endif
616
617   return server;
618 }
619
620 /**
621  * Decrements the reference count of a DBusServer.  Finalizes the
622  * server if the reference count reaches zero.
623  *
624  * The server must be disconnected before the refcount reaches zero.
625  *
626  * @param server the server.
627  */
628 void
629 dbus_server_unref (DBusServer *server)
630 {
631   dbus_bool_t last_unref;
632   
633   _dbus_return_if_fail (server != NULL);
634   _dbus_return_if_fail (server->refcount.value > 0);
635
636 #ifdef DBUS_HAVE_ATOMIC_INT
637   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
638 #else
639   SERVER_LOCK (server);
640   
641   _dbus_assert (server->refcount.value > 0);
642
643   server->refcount.value -= 1;
644   last_unref = (server->refcount.value == 0);
645   
646   SERVER_UNLOCK (server);
647 #endif
648   
649   if (last_unref)
650     {
651       /* lock not held! */
652       _dbus_assert (server->disconnected);
653       
654       _dbus_assert (server->vtable->finalize != NULL);
655       
656       (* server->vtable->finalize) (server);
657     }
658 }
659
660 /**
661  * Like dbus_server_ref() but does not acquire the lock (must already be held)
662  *
663  * @param server the server.
664  */
665 void
666 _dbus_server_ref_unlocked (DBusServer *server)
667 {
668   _dbus_assert (server != NULL);
669   _dbus_assert (server->refcount.value > 0);
670   
671   HAVE_LOCK_CHECK (server);
672
673 #ifdef DBUS_HAVE_ATOMIC_INT
674   _dbus_atomic_inc (&server->refcount);
675 #else
676   _dbus_assert (server->refcount.value > 0);
677
678   server->refcount.value += 1;
679 #endif
680 }
681
682 /**
683  * Like dbus_server_unref() but does not acquire the lock (must already be held)
684  *
685  * @param server the server.
686  */
687 void
688 _dbus_server_unref_unlocked (DBusServer *server)
689 {
690   dbus_bool_t last_unref;
691   
692   _dbus_assert (server != NULL);
693   _dbus_assert (server->refcount.value > 0);
694
695   HAVE_LOCK_CHECK (server);
696   
697 #ifdef DBUS_HAVE_ATOMIC_INT
698   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
699 #else
700   _dbus_assert (server->refcount.value > 0);
701
702   server->refcount.value -= 1;
703   last_unref = (server->refcount.value == 0);
704 #endif
705   
706   if (last_unref)
707     {
708       _dbus_assert (server->disconnected);
709       
710       SERVER_UNLOCK (server);
711       
712       _dbus_assert (server->vtable->finalize != NULL);
713       
714       (* server->vtable->finalize) (server);
715     }
716 }
717
718 /**
719  * Releases the server's address and stops listening for
720  * new clients. If called more than once, only the first
721  * call has an effect. Does not modify the server's
722  * reference count.
723  * 
724  * @param server the server.
725  */
726 void
727 dbus_server_disconnect (DBusServer *server)
728 {
729   _dbus_return_if_fail (server != NULL);
730   _dbus_return_if_fail (server->refcount.value > 0);
731
732   SERVER_LOCK (server);
733   _dbus_server_ref_unlocked (server);
734   
735   _dbus_assert (server->vtable->disconnect != NULL);
736
737   if (!server->disconnected)
738     {
739       /* this has to be first so recursive calls to disconnect don't happen */
740       server->disconnected = TRUE;
741       
742       (* server->vtable->disconnect) (server);
743     }
744
745   SERVER_UNLOCK (server);
746   dbus_server_unref (server);
747 }
748
749 /**
750  * Returns #TRUE if the server is still listening for new connections.
751  *
752  * @param server the server.
753  */
754 dbus_bool_t
755 dbus_server_get_is_connected (DBusServer *server)
756 {
757   dbus_bool_t retval;
758   
759   _dbus_return_val_if_fail (server != NULL, FALSE);
760
761   SERVER_LOCK (server);
762   retval = !server->disconnected;
763   SERVER_UNLOCK (server);
764
765   return retval;
766 }
767
768 /**
769  * Returns the address of the server, as a newly-allocated
770  * string which must be freed by the caller.
771  *
772  * @param server the server
773  * @returns the address or #NULL if no memory
774  */
775 char*
776 dbus_server_get_address (DBusServer *server)
777 {
778   char *retval;
779   
780   _dbus_return_val_if_fail (server != NULL, NULL);
781
782   SERVER_LOCK (server);
783   retval = _dbus_strdup (server->address);
784   SERVER_UNLOCK (server);
785
786   return retval;
787 }
788
789 /**
790  * Sets a function to be used for handling new connections.  The given
791  * function is passed each new connection as the connection is
792  * created. If the new connection function increments the connection's
793  * reference count, the connection will stay alive. Otherwise, the
794  * connection will be unreferenced and closed.
795  *
796  * @param server the server.
797  * @param function a function to handle new connections.
798  * @param data data to pass to the new connection handler.
799  * @param free_data_function function to free the data.
800  */
801 void
802 dbus_server_set_new_connection_function (DBusServer                *server,
803                                          DBusNewConnectionFunction  function,
804                                          void                      *data,
805                                          DBusFreeFunction           free_data_function)
806 {
807   DBusFreeFunction old_free_function;
808   void *old_data;
809   
810   _dbus_return_if_fail (server != NULL);
811
812   SERVER_LOCK (server);
813   old_free_function = server->new_connection_free_data_function;
814   old_data = server->new_connection_data;
815   
816   server->new_connection_function = function;
817   server->new_connection_data = data;
818   server->new_connection_free_data_function = free_data_function;
819   SERVER_UNLOCK (server);
820     
821   if (old_free_function != NULL)
822     (* old_free_function) (old_data);
823 }
824
825 /**
826  * Sets the watch functions for the connection. These functions are
827  * responsible for making the application's main loop aware of file
828  * descriptors that need to be monitored for events.
829  *
830  * This function behaves exactly like dbus_connection_set_watch_functions();
831  * see the documentation for that routine.
832  *
833  * @param server the server.
834  * @param add_function function to begin monitoring a new descriptor.
835  * @param remove_function function to stop monitoring a descriptor.
836  * @param toggled_function function to notify when the watch is enabled/disabled
837  * @param data data to pass to add_function and remove_function.
838  * @param free_data_function function to be called to free the data.
839  * @returns #FALSE on failure (no memory)
840  */
841 dbus_bool_t
842 dbus_server_set_watch_functions (DBusServer              *server,
843                                  DBusAddWatchFunction     add_function,
844                                  DBusRemoveWatchFunction  remove_function,
845                                  DBusWatchToggledFunction toggled_function,
846                                  void                    *data,
847                                  DBusFreeFunction         free_data_function)
848 {
849   dbus_bool_t result;
850   DBusWatchList *watches;
851   
852   _dbus_return_val_if_fail (server != NULL, FALSE);
853
854   SERVER_LOCK (server);
855   watches = server->watches;
856   server->watches = NULL;
857   if (watches)
858     {
859       SERVER_UNLOCK (server);
860       result = _dbus_watch_list_set_functions (watches,
861                                                add_function,
862                                                remove_function,
863                                                toggled_function,
864                                                data,
865                                                free_data_function);
866       SERVER_LOCK (server);
867     }
868   else
869     {
870       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
871       result = FALSE;
872     }
873   server->watches = watches;
874   SERVER_UNLOCK (server);
875   
876   return result;
877 }
878
879 /**
880  * Sets the timeout functions for the connection. These functions are
881  * responsible for making the application's main loop aware of timeouts.
882  *
883  * This function behaves exactly like dbus_connection_set_timeout_functions();
884  * see the documentation for that routine.
885  *
886  * @param server the server.
887  * @param add_function function to add a timeout.
888  * @param remove_function function to remove a timeout.
889  * @param toggled_function function to notify when the timeout is enabled/disabled
890  * @param data data to pass to add_function and remove_function.
891  * @param free_data_function function to be called to free the data.
892  * @returns #FALSE on failure (no memory)
893  */
894 dbus_bool_t
895 dbus_server_set_timeout_functions (DBusServer                *server,
896                                    DBusAddTimeoutFunction     add_function,
897                                    DBusRemoveTimeoutFunction  remove_function,
898                                    DBusTimeoutToggledFunction toggled_function,
899                                    void                      *data,
900                                    DBusFreeFunction           free_data_function)
901 {
902   dbus_bool_t result;
903   DBusTimeoutList *timeouts;
904   
905   _dbus_return_val_if_fail (server != NULL, FALSE);
906
907   SERVER_LOCK (server);
908   timeouts = server->timeouts;
909   server->timeouts = NULL;
910   if (timeouts)
911     {
912       SERVER_UNLOCK (server);
913       result = _dbus_timeout_list_set_functions (timeouts,
914                                                  add_function,
915                                                  remove_function,
916                                                  toggled_function,
917                                                  data,
918                                                  free_data_function);
919       SERVER_LOCK (server);
920     }
921   else
922     {
923       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
924       result = FALSE;
925     }
926   server->timeouts = timeouts;
927   SERVER_UNLOCK (server);
928   
929   return result;
930 }
931
932 /**
933  * Sets the authentication mechanisms that this server offers
934  * to clients, as a list of SASL mechanisms. This function
935  * only affects connections created *after* it is called.
936  * Pass #NULL instead of an array to use all available mechanisms.
937  *
938  * @param server the server
939  * @param mechanisms #NULL-terminated array of mechanisms
940  * @returns #FALSE if no memory
941  */
942 dbus_bool_t
943 dbus_server_set_auth_mechanisms (DBusServer  *server,
944                                  const char **mechanisms)
945 {
946   char **copy;
947
948   _dbus_return_val_if_fail (server != NULL, FALSE);
949
950   SERVER_LOCK (server);
951   
952   if (mechanisms != NULL)
953     {
954       copy = _dbus_dup_string_array (mechanisms);
955       if (copy == NULL)
956         return FALSE;
957     }
958   else
959     copy = NULL;
960
961   dbus_free_string_array (server->auth_mechanisms);
962   server->auth_mechanisms = copy;
963
964   SERVER_UNLOCK (server);
965   
966   return TRUE;
967 }
968
969
970 static DBusDataSlotAllocator slot_allocator;
971 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
972
973 /**
974  * Allocates an integer ID to be used for storing application-specific
975  * data on any DBusServer. The allocated ID may then be used
976  * with dbus_server_set_data() and dbus_server_get_data().
977  * The slot must be initialized with -1. If a nonnegative
978  * slot is passed in, the refcount is incremented on that
979  * slot, rather than creating a new slot.
980  *  
981  * The allocated slot is global, i.e. all DBusServer objects will have
982  * a slot with the given integer ID reserved.
983  *
984  * @param slot_p address of global variable storing the slot ID
985  * @returns #FALSE on no memory
986  */
987 dbus_bool_t
988 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
989 {
990   return _dbus_data_slot_allocator_alloc (&slot_allocator,
991                                           (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
992                                           slot_p);
993 }
994
995 /**
996  * Deallocates a global ID for server data slots.
997  * dbus_server_get_data() and dbus_server_set_data()
998  * may no longer be used with this slot.
999  * Existing data stored on existing DBusServer objects
1000  * will be freed when the server is finalized,
1001  * but may not be retrieved (and may only be replaced
1002  * if someone else reallocates the slot).
1003  *
1004  * @param slot_p address of the slot to deallocate
1005  */
1006 void
1007 dbus_server_free_data_slot (dbus_int32_t *slot_p)
1008 {
1009   _dbus_return_if_fail (*slot_p >= 0);
1010   
1011   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
1012 }
1013
1014 /**
1015  * Stores a pointer on a DBusServer, along
1016  * with an optional function to be used for freeing
1017  * the data when the data is set again, or when
1018  * the server is finalized. The slot number
1019  * must have been allocated with dbus_server_allocate_data_slot().
1020  *
1021  * @param server the server
1022  * @param slot the slot number
1023  * @param data the data to store
1024  * @param free_data_func finalizer function for the data
1025  * @returns #TRUE if there was enough memory to store the data
1026  */
1027 dbus_bool_t
1028 dbus_server_set_data (DBusServer       *server,
1029                       int               slot,
1030                       void             *data,
1031                       DBusFreeFunction  free_data_func)
1032 {
1033   DBusFreeFunction old_free_func;
1034   void *old_data;
1035   dbus_bool_t retval;
1036
1037   _dbus_return_val_if_fail (server != NULL, FALSE);
1038
1039   SERVER_LOCK (server);
1040   
1041   retval = _dbus_data_slot_list_set (&slot_allocator,
1042                                      &server->slot_list,
1043                                      slot, data, free_data_func,
1044                                      &old_free_func, &old_data);
1045
1046
1047   SERVER_UNLOCK (server);
1048   
1049   if (retval)
1050     {
1051       /* Do the actual free outside the server lock */
1052       if (old_free_func)
1053         (* old_free_func) (old_data);
1054     }
1055
1056   return retval;
1057 }
1058
1059 /**
1060  * Retrieves data previously set with dbus_server_set_data().
1061  * The slot must still be allocated (must not have been freed).
1062  *
1063  * @param server the server
1064  * @param slot the slot to get data from
1065  * @returns the data, or #NULL if not found
1066  */
1067 void*
1068 dbus_server_get_data (DBusServer   *server,
1069                       int           slot)
1070 {
1071   void *res;
1072
1073   _dbus_return_val_if_fail (server != NULL, NULL);
1074   
1075   SERVER_LOCK (server);
1076   
1077   res = _dbus_data_slot_list_get (&slot_allocator,
1078                                   &server->slot_list,
1079                                   slot);
1080
1081   SERVER_UNLOCK (server);
1082   
1083   return res;
1084 }
1085
1086 /** @} */
1087
1088 #ifdef DBUS_BUILD_TESTS
1089 #include "dbus-test.h"
1090
1091 dbus_bool_t
1092 _dbus_server_test (void)
1093 {
1094   const char *valid_addresses[] = {
1095     "tcp:port=1234",
1096     "unix:path=./boogie",
1097     "tcp:host=localhost,port=1234",
1098     "tcp:host=localhost,port=1234;tcp:port=5678",
1099     "tcp:port=1234;unix:path=./boogie",
1100   };
1101
1102   DBusServer *server;
1103   int i;
1104   
1105   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
1106     {
1107       DBusError error;
1108
1109       /* FIXME um, how are the two tests here different? */
1110       
1111       dbus_error_init (&error);
1112       server = dbus_server_listen (valid_addresses[i], &error);
1113       if (server == NULL)
1114         {
1115           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
1116           dbus_error_free (&error);
1117           _dbus_assert_not_reached ("Failed to listen for valid address.");
1118         }
1119
1120       dbus_server_disconnect (server);
1121       dbus_server_unref (server);
1122
1123       /* Try disconnecting before unreffing */
1124       server = dbus_server_listen (valid_addresses[i], &error);
1125       if (server == NULL)
1126         {
1127           _dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
1128           dbus_error_free (&error);          
1129           _dbus_assert_not_reached ("Failed to listen for valid address.");
1130         }
1131
1132       dbus_server_disconnect (server);
1133       dbus_server_unref (server);
1134     }
1135
1136   return TRUE;
1137 }
1138
1139 #endif /* DBUS_BUILD_TESTS */