2005-02-13 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 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-string.h"
27 #ifdef DBUS_BUILD_TESTS
28 #include "dbus-server-debug-pipe.h"
29 #endif
30 #include "dbus-address.h"
31 #include "dbus-protocol.h"
32
33 /**
34  * @defgroup DBusServer DBusServer
35  * @ingroup  DBus
36  * @brief Server that listens for new connections.
37  *
38  * Types and functions related to DBusServer.
39  * A DBusServer represents a server that other applications
40  * can connect to. Each connection from another application
41  * is represented by a DBusConnection.
42  *
43  * @todo Thread safety hasn't been looked at for #DBusServer
44  * @todo Need notification to apps of disconnection, may matter for some transports
45  */
46
47 /**
48  * @defgroup DBusServerInternals DBusServer implementation details
49  * @ingroup  DBusInternals
50  * @brief Implementation details of DBusServer
51  *
52  * @{
53  */
54
55 /**
56  * Initializes the members of the DBusServer base class.
57  * Chained up to by subclass constructors.
58  *
59  * @param server the server.
60  * @param vtable the vtable for the subclass.
61  * @param address the server's address
62  * @returns #TRUE on success.
63  */
64 dbus_bool_t
65 _dbus_server_init_base (DBusServer             *server,
66                         const DBusServerVTable *vtable,
67                         const DBusString       *address)
68 {
69   server->vtable = vtable;
70   server->refcount.value = 1;
71
72   server->address = NULL;
73   server->watches = NULL;
74   server->timeouts = NULL;
75   
76   if (!_dbus_string_copy_data (address, &server->address))
77     goto failed;
78
79   server->mutex = dbus_mutex_new ();
80   if (server->mutex == NULL)
81     goto failed;
82   
83   server->watches = _dbus_watch_list_new ();
84   if (server->watches == NULL)
85     goto failed;
86
87   server->timeouts = _dbus_timeout_list_new ();
88   if (server->timeouts == NULL)
89     goto failed;
90
91   _dbus_data_slot_list_init (&server->slot_list);
92
93   _dbus_verbose ("Initialized server on address %s\n", server->address);
94   
95   return TRUE;
96
97  failed:
98   if (server->mutex)
99     {
100       dbus_mutex_free (server->mutex);
101       server->mutex = NULL;
102     }
103   if (server->watches)
104     {
105       _dbus_watch_list_free (server->watches);
106       server->watches = NULL;
107     }
108   if (server->timeouts)
109     {
110       _dbus_timeout_list_free (server->timeouts);
111       server->timeouts = NULL;
112     }
113   if (server->address)
114     {
115       dbus_free (server->address);
116       server->address = NULL;
117     }
118   
119   return FALSE;
120 }
121
122 /**
123  * Finalizes the members of the DBusServer base class.
124  * Chained up to by subclass finalizers.
125  *
126  * @param server the server.
127  */
128 void
129 _dbus_server_finalize_base (DBusServer *server)
130 {  
131   /* calls out to application code... */
132   _dbus_data_slot_list_free (&server->slot_list);
133
134   dbus_server_set_new_connection_function (server, NULL, NULL, NULL);
135
136   if (!server->disconnected)
137     dbus_server_disconnect (server);
138
139   _dbus_watch_list_free (server->watches);
140   _dbus_timeout_list_free (server->timeouts);
141
142   dbus_mutex_free (server->mutex);
143   
144   dbus_free (server->address);
145
146   dbus_free_string_array (server->auth_mechanisms);
147 }
148
149 /**
150  * Adds a watch for this server, chaining out to application-provided
151  * watch handlers.
152  *
153  * @param server the server.
154  * @param watch the watch to add.
155  */
156 dbus_bool_t
157 _dbus_server_add_watch (DBusServer *server,
158                         DBusWatch  *watch)
159 {
160   HAVE_LOCK_CHECK (server);
161   return _dbus_watch_list_add_watch (server->watches, watch);
162 }
163
164 /**
165  * Removes a watch previously added with _dbus_server_remove_watch().
166  *
167  * @param server the server.
168  * @param watch the watch to remove.
169  */
170 void
171 _dbus_server_remove_watch  (DBusServer *server,
172                             DBusWatch  *watch)
173 {
174   HAVE_LOCK_CHECK (server);
175   _dbus_watch_list_remove_watch (server->watches, watch);
176 }
177
178 /**
179  * Toggles a watch and notifies app via server's
180  * DBusWatchToggledFunction if available. It's an error to call this
181  * function on a watch that was not previously added.
182  *
183  * @param server the server.
184  * @param watch the watch to toggle.
185  * @param enabled whether to enable or disable
186  */
187 void
188 _dbus_server_toggle_watch (DBusServer  *server,
189                            DBusWatch   *watch,
190                            dbus_bool_t  enabled)
191 {
192   HAVE_LOCK_CHECK (server);
193   
194   if (server->watches) /* null during finalize */
195     _dbus_watch_list_toggle_watch (server->watches,
196                                    watch, enabled);
197 }
198
199 /**
200  * Adds a timeout for this server, chaining out to
201  * application-provided timeout handlers. The timeout should be
202  * repeatedly handled with dbus_timeout_handle() at its given interval
203  * until it is removed.
204  *
205  * @param server the server.
206  * @param timeout the timeout to add.
207  */
208 dbus_bool_t
209 _dbus_server_add_timeout (DBusServer  *server,
210                           DBusTimeout *timeout)
211 {
212   HAVE_LOCK_CHECK (server);
213   
214   return _dbus_timeout_list_add_timeout (server->timeouts, timeout);
215 }
216
217 /**
218  * Removes a timeout previously added with _dbus_server_add_timeout().
219  *
220  * @param server the server.
221  * @param timeout the timeout to remove.
222  */
223 void
224 _dbus_server_remove_timeout (DBusServer  *server,
225                              DBusTimeout *timeout)
226 {
227   HAVE_LOCK_CHECK (server);
228   
229   _dbus_timeout_list_remove_timeout (server->timeouts, timeout);  
230 }
231
232 /**
233  * Toggles a timeout and notifies app via server's
234  * DBusTimeoutToggledFunction if available. It's an error to call this
235  * function on a timeout that was not previously added.
236  *
237  * @param server the server.
238  * @param timeout the timeout to toggle.
239  * @param enabled whether to enable or disable
240  */
241 void
242 _dbus_server_toggle_timeout (DBusServer  *server,
243                              DBusTimeout *timeout,
244                              dbus_bool_t  enabled)
245 {
246   HAVE_LOCK_CHECK (server);
247   
248   if (server->timeouts) /* null during finalize */
249     _dbus_timeout_list_toggle_timeout (server->timeouts,
250                                        timeout, enabled);
251 }
252
253
254 /** @} */
255
256 /**
257  * @addtogroup DBusServer
258  *
259  * @{
260  */
261
262
263 /**
264  * @typedef DBusServer
265  *
266  * An opaque object representing a server that listens for
267  * connections from other applications. Each time a connection
268  * is made, a new DBusConnection is created and made available
269  * via an application-provided DBusNewConnectionFunction.
270  * The DBusNewConnectionFunction is provided with
271  * dbus_server_set_new_connection_function().
272  * 
273  */
274
275 /**
276  * Listens for new connections on the given address.
277  * Returns #NULL if listening fails for any reason.
278  * Otherwise returns a new #DBusServer.
279  * dbus_server_set_new_connection_function() and
280  * dbus_server_set_watch_functions() should be called
281  * immediately to render the server fully functional.
282  *
283  * @todo error messages on bad address could really be better.
284  * DBusResultCode is a bit limiting here.
285  *
286  * @param address the address of this server.
287  * @param error location to store rationale for failure.
288  * @returns a new DBusServer, or #NULL on failure.
289  * 
290  */
291 DBusServer*
292 dbus_server_listen (const char     *address,
293                     DBusError      *error)
294 {
295   DBusServer *server;
296   DBusAddressEntry **entries;
297   int len, i;
298   const char *address_problem_type;
299   const char *address_problem_field;
300   const char *address_problem_other;
301
302   _dbus_return_val_if_fail (address != NULL, NULL);
303   _dbus_return_val_if_error_is_set (error, NULL);
304   
305   if (!dbus_parse_address (address, &entries, &len, error))
306     return NULL;
307
308   server = NULL;
309   address_problem_type = NULL;
310   address_problem_field = NULL;
311   address_problem_other = NULL;
312   
313   for (i = 0; i < len; i++)
314     {
315       const char *method = dbus_address_entry_get_method (entries[i]);
316
317       if (strcmp (method, "unix") == 0)
318         {
319           const char *path = dbus_address_entry_get_value (entries[i], "path");
320           const char *tmpdir = dbus_address_entry_get_value (entries[i], "tmpdir");
321           const char *abstract = dbus_address_entry_get_value (entries[i], "abstract");
322           
323           if (path == NULL && tmpdir == NULL && abstract == NULL)
324             {
325               address_problem_type = "unix";
326               address_problem_field = "path or tmpdir or abstract";
327               goto bad_address;
328             }
329
330           if ((path && tmpdir) ||
331               (path && abstract) ||
332               (tmpdir && abstract))
333             {
334               address_problem_other = "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time";
335               goto bad_address;
336             }
337
338           if (tmpdir != NULL)
339             {
340               DBusString full_path;
341               DBusString filename;
342               
343               if (!_dbus_string_init (&full_path))
344                 {
345                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
346                   goto out;
347                 }
348                   
349               if (!_dbus_string_init (&filename))
350                 {
351                   _dbus_string_free (&full_path);
352                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
353                   goto out;
354                 }
355               
356               if (!_dbus_string_append (&filename,
357                                         "dbus-") ||
358                   !_dbus_generate_random_ascii (&filename, 10) ||
359                   !_dbus_string_append (&full_path, tmpdir) ||
360                   !_dbus_concat_dir_and_file (&full_path, &filename))
361                 {
362                   _dbus_string_free (&full_path);
363                   _dbus_string_free (&filename);
364                   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
365                   goto out;
366                 }
367               
368               /* FIXME - we will unconditionally unlink() the path if
369                * we don't support abstract namespace.  unlink() does
370                * not follow symlinks, but would like independent
371                * confirmation this is safe enough. See also
372                * _dbus_listen_unix_socket() and comments therein.
373                */
374
375               /* Always use abstract namespace if possible with tmpdir */
376               
377               server =
378                 _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path),
379 #ifdef HAVE_ABSTRACT_SOCKETS
380                                                     TRUE,
381 #else
382                                                     FALSE,
383 #endif
384                                                     error);
385
386               _dbus_string_free (&full_path);
387               _dbus_string_free (&filename);
388             }
389           else
390             {
391               if (path)
392                 server = _dbus_server_new_for_domain_socket (path, FALSE, error);
393               else
394                 server = _dbus_server_new_for_domain_socket (abstract, TRUE, error);
395             }
396         }
397       else if (strcmp (method, "tcp") == 0)
398         {
399           const char *host = dbus_address_entry_get_value (entries[i], "host");
400           const char *port = dbus_address_entry_get_value (entries[i], "port");
401           DBusString  str;
402           long lport;
403           dbus_bool_t sresult;
404           
405           if (port == NULL)
406             {
407               address_problem_type = "tcp";
408               address_problem_field = "port";
409               goto bad_address;
410             }
411
412           _dbus_string_init_const (&str, port);
413           sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
414           _dbus_string_free (&str);
415           
416           if (sresult == FALSE || lport <= 0 || lport > 65535)
417             {
418               address_problem_other = "Port is not an integer between 0 and 65535";
419               goto bad_address;
420             }
421           
422           server = _dbus_server_new_for_tcp_socket (host, lport, error);
423
424           if (server)
425             break;
426         }
427 #ifdef DBUS_BUILD_TESTS
428       else if (strcmp (method, "debug-pipe") == 0)
429         {
430           const char *name = dbus_address_entry_get_value (entries[i], "name");
431
432           if (name == NULL)
433             {
434               address_problem_type = "debug-pipe";
435               address_problem_field = "name";
436               goto bad_address;
437             }
438
439           server = _dbus_server_debug_pipe_new (name, error);
440         }
441 #endif
442       else
443         {
444           address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")";
445           goto bad_address;
446         }
447       
448       if (server)
449         break;
450     }
451
452  out:
453   
454   dbus_address_entries_free (entries);
455   return server;
456
457  bad_address:
458   dbus_address_entries_free (entries);
459   if (address_problem_type != NULL)
460     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
461                     "Server address of type %s was missing argument %s",
462                     address_problem_type, address_problem_field);
463   else
464     dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
465                     "Could not parse server address: %s",
466                     address_problem_other);
467
468   return NULL;
469 }
470
471 /**
472  * Increments the reference count of a DBusServer.
473  *
474  * @param server the server.
475  * @returns the server
476  */
477 DBusServer *
478 dbus_server_ref (DBusServer *server)
479 {
480   _dbus_return_val_if_fail (server != NULL, NULL);
481
482 #ifdef DBUS_HAVE_ATOMIC_INT
483   _dbus_atomic_inc (&server->refcount);
484 #else
485   SERVER_LOCK (server);
486   _dbus_assert (server->refcount.value > 0);
487
488   server->refcount.value += 1;
489   SERVER_UNLOCK (server);
490 #endif
491
492   return server;
493 }
494
495 /**
496  * Decrements the reference count of a DBusServer.  Finalizes the
497  * server if the reference count reaches zero. The server connection
498  * will be closed as with dbus_server_disconnect() when the server is
499  * finalized.
500  *
501  * @param server the server.
502  */
503 void
504 dbus_server_unref (DBusServer *server)
505 {
506   dbus_bool_t last_unref;
507   
508   _dbus_return_if_fail (server != NULL);
509
510 #ifdef DBUS_HAVE_ATOMIC_INT
511   last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
512 #else
513   SERVER_LOCK (server);
514   
515   _dbus_assert (server->refcount.value > 0);
516
517   server->refcount.value -= 1;
518   last_unref = (server->refcount.value == 0);
519   
520   SERVER_UNLOCK (server);
521 #endif
522   
523   if (last_unref)
524     {
525       _dbus_assert (server->vtable->finalize != NULL);
526       
527       (* server->vtable->finalize) (server);
528     }
529 }
530
531 /**
532  * Like dbus_server_ref() but does not acquire the lock (must already be held)
533  *
534  * @param server the server.
535  */
536 void
537 _dbus_server_ref_unlocked (DBusServer *server)
538 {
539   HAVE_LOCK_CHECK (server);
540
541 #ifdef DBUS_HAVE_ATOMIC_INT
542   _dbus_atomic_inc (&server->refcount);
543 #else
544   _dbus_assert (server->refcount.value > 0);
545
546   server->refcount.value += 1;
547 #endif
548 }
549
550 /**
551  * Releases the server's address and stops listening for
552  * new clients. If called more than once, only the first
553  * call has an effect. Does not modify the server's
554  * reference count.
555  * 
556  * @param server the server.
557  */
558 void
559 dbus_server_disconnect (DBusServer *server)
560 {
561   _dbus_return_if_fail (server != NULL);
562
563   SERVER_LOCK (server);
564   
565   _dbus_assert (server->vtable->disconnect != NULL);
566
567   if (server->disconnected)
568     return;
569   
570   (* server->vtable->disconnect) (server);
571   server->disconnected = TRUE;
572
573   SERVER_UNLOCK (server);
574 }
575
576 /**
577  * Returns #TRUE if the server is still listening for new connections.
578  *
579  * @param server the server.
580  */
581 dbus_bool_t
582 dbus_server_get_is_connected (DBusServer *server)
583 {
584   dbus_bool_t retval;
585   
586   _dbus_return_val_if_fail (server != NULL, FALSE);
587
588   SERVER_LOCK (server);
589   retval = !server->disconnected;
590   SERVER_UNLOCK (server);
591
592   return retval;
593 }
594
595 /**
596  * Returns the address of the server, as a newly-allocated
597  * string which must be freed by the caller.
598  *
599  * @param server the server
600  * @returns the address or #NULL if no memory
601  */
602 char*
603 dbus_server_get_address (DBusServer *server)
604 {
605   char *retval;
606   
607   _dbus_return_val_if_fail (server != NULL, NULL);
608
609   SERVER_LOCK (server);
610   retval = _dbus_strdup (server->address);
611   SERVER_UNLOCK (server);
612
613   return retval;
614 }
615
616 /**
617  * Sets a function to be used for handling new connections.  The given
618  * function is passed each new connection as the connection is
619  * created. If the new connection function increments the connection's
620  * reference count, the connection will stay alive. Otherwise, the
621  * connection will be unreferenced and closed.
622  *
623  * @param server the server.
624  * @param function a function to handle new connections.
625  * @param data data to pass to the new connection handler.
626  * @param free_data_function function to free the data.
627  */
628 void
629 dbus_server_set_new_connection_function (DBusServer                *server,
630                                          DBusNewConnectionFunction  function,
631                                          void                      *data,
632                                          DBusFreeFunction           free_data_function)
633 {
634   DBusFreeFunction old_free_function;
635   void *old_data;
636   
637   _dbus_return_if_fail (server != NULL);
638
639   SERVER_LOCK (server);
640   old_free_function = server->new_connection_free_data_function;
641   old_data = server->new_connection_data;
642   
643   server->new_connection_function = function;
644   server->new_connection_data = data;
645   server->new_connection_free_data_function = free_data_function;
646   SERVER_UNLOCK (server);
647     
648   if (old_free_function != NULL)
649     (* old_free_function) (old_data);
650 }
651
652 /**
653  * Sets the watch functions for the connection. These functions are
654  * responsible for making the application's main loop aware of file
655  * descriptors that need to be monitored for events.
656  *
657  * This function behaves exactly like dbus_connection_set_watch_functions();
658  * see the documentation for that routine.
659  *
660  * @param server the server.
661  * @param add_function function to begin monitoring a new descriptor.
662  * @param remove_function function to stop monitoring a descriptor.
663  * @param toggled_function function to notify when the watch is enabled/disabled
664  * @param data data to pass to add_function and remove_function.
665  * @param free_data_function function to be called to free the data.
666  * @returns #FALSE on failure (no memory)
667  */
668 dbus_bool_t
669 dbus_server_set_watch_functions (DBusServer              *server,
670                                  DBusAddWatchFunction     add_function,
671                                  DBusRemoveWatchFunction  remove_function,
672                                  DBusWatchToggledFunction toggled_function,
673                                  void                    *data,
674                                  DBusFreeFunction         free_data_function)
675 {
676   dbus_bool_t result;
677   DBusWatchList *watches;
678   
679   _dbus_return_val_if_fail (server != NULL, FALSE);
680
681   SERVER_LOCK (server);
682   watches = server->watches;
683   server->watches = NULL;
684   if (watches)
685     {
686       SERVER_UNLOCK (server);
687       result = _dbus_watch_list_set_functions (watches,
688                                                add_function,
689                                                remove_function,
690                                                toggled_function,
691                                                data,
692                                                free_data_function);
693       SERVER_LOCK (server);
694     }
695   else
696     {
697       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
698       result = FALSE;
699     }
700   server->watches = watches;
701   SERVER_UNLOCK (server);
702   
703   return result;
704 }
705
706 /**
707  * Sets the timeout functions for the connection. These functions are
708  * responsible for making the application's main loop aware of timeouts.
709  *
710  * This function behaves exactly like dbus_connection_set_timeout_functions();
711  * see the documentation for that routine.
712  *
713  * @param server the server.
714  * @param add_function function to add a timeout.
715  * @param remove_function function to remove a timeout.
716  * @param toggled_function function to notify when the timeout is enabled/disabled
717  * @param data data to pass to add_function and remove_function.
718  * @param free_data_function function to be called to free the data.
719  * @returns #FALSE on failure (no memory)
720  */
721 dbus_bool_t
722 dbus_server_set_timeout_functions (DBusServer                *server,
723                                    DBusAddTimeoutFunction     add_function,
724                                    DBusRemoveTimeoutFunction  remove_function,
725                                    DBusTimeoutToggledFunction toggled_function,
726                                    void                      *data,
727                                    DBusFreeFunction           free_data_function)
728 {
729   dbus_bool_t result;
730   DBusTimeoutList *timeouts;
731   
732   _dbus_return_val_if_fail (server != NULL, FALSE);
733
734   SERVER_LOCK (server);
735   timeouts = server->timeouts;
736   server->timeouts = NULL;
737   if (timeouts)
738     {
739       SERVER_UNLOCK (server);
740       result = _dbus_timeout_list_set_functions (timeouts,
741                                                  add_function,
742                                                  remove_function,
743                                                  toggled_function,
744                                                  data,
745                                                  free_data_function);
746       SERVER_LOCK (server);
747     }
748   else
749     {
750       _dbus_warn ("Re-entrant call to %s\n", _DBUS_FUNCTION_NAME);
751       result = FALSE;
752     }
753   server->timeouts = timeouts;
754   SERVER_UNLOCK (server);
755   
756   return result;
757 }
758
759 /**
760  * Sets the authentication mechanisms that this server offers
761  * to clients, as a list of SASL mechanisms. This function
762  * only affects connections created *after* it is called.
763  * Pass #NULL instead of an array to use all available mechanisms.
764  *
765  * @param server the server
766  * @param mechanisms #NULL-terminated array of mechanisms
767  * @returns #FALSE if no memory
768  */
769 dbus_bool_t
770 dbus_server_set_auth_mechanisms (DBusServer  *server,
771                                  const char **mechanisms)
772 {
773   char **copy;
774
775   _dbus_return_val_if_fail (server != NULL, FALSE);
776
777   SERVER_LOCK (server);
778   
779   if (mechanisms != NULL)
780     {
781       copy = _dbus_dup_string_array (mechanisms);
782       if (copy == NULL)
783         return FALSE;
784     }
785   else
786     copy = NULL;
787
788   dbus_free_string_array (server->auth_mechanisms);
789   server->auth_mechanisms = copy;
790
791   SERVER_UNLOCK (server);
792   
793   return TRUE;
794 }
795
796
797 static DBusDataSlotAllocator slot_allocator;
798 _DBUS_DEFINE_GLOBAL_LOCK (server_slots);
799
800 /**
801  * Allocates an integer ID to be used for storing application-specific
802  * data on any DBusServer. The allocated ID may then be used
803  * with dbus_server_set_data() and dbus_server_get_data().
804  * The slot must be initialized with -1. If a nonnegative
805  * slot is passed in, the refcount is incremented on that
806  * slot, rather than creating a new slot.
807  *  
808  * The allocated slot is global, i.e. all DBusServer objects will have
809  * a slot with the given integer ID reserved.
810  *
811  * @param slot_p address of global variable storing the slot ID
812  * @returns #FALSE on no memory
813  */
814 dbus_bool_t
815 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
816 {
817   return _dbus_data_slot_allocator_alloc (&slot_allocator,
818                                           _DBUS_LOCK_NAME (server_slots),
819                                           slot_p);
820 }
821
822 /**
823  * Deallocates a global ID for server data slots.
824  * dbus_server_get_data() and dbus_server_set_data()
825  * may no longer be used with this slot.
826  * Existing data stored on existing DBusServer objects
827  * will be freed when the server is finalized,
828  * but may not be retrieved (and may only be replaced
829  * if someone else reallocates the slot).
830  *
831  * @param slot_p address of the slot to deallocate
832  */
833 void
834 dbus_server_free_data_slot (dbus_int32_t *slot_p)
835 {
836   _dbus_return_if_fail (*slot_p >= 0);
837   
838   _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
839 }
840
841 /**
842  * Stores a pointer on a DBusServer, along
843  * with an optional function to be used for freeing
844  * the data when the data is set again, or when
845  * the server is finalized. The slot number
846  * must have been allocated with dbus_server_allocate_data_slot().
847  *
848  * @param server the server
849  * @param slot the slot number
850  * @param data the data to store
851  * @param free_data_func finalizer function for the data
852  * @returns #TRUE if there was enough memory to store the data
853  */
854 dbus_bool_t
855 dbus_server_set_data (DBusServer       *server,
856                       int               slot,
857                       void             *data,
858                       DBusFreeFunction  free_data_func)
859 {
860   DBusFreeFunction old_free_func;
861   void *old_data;
862   dbus_bool_t retval;
863
864   _dbus_return_val_if_fail (server != NULL, FALSE);
865
866   SERVER_LOCK (server);
867   
868   retval = _dbus_data_slot_list_set (&slot_allocator,
869                                      &server->slot_list,
870                                      slot, data, free_data_func,
871                                      &old_free_func, &old_data);
872
873
874   SERVER_UNLOCK (server);
875   
876   if (retval)
877     {
878       /* Do the actual free outside the server lock */
879       if (old_free_func)
880         (* old_free_func) (old_data);
881     }
882
883   return retval;
884 }
885
886 /**
887  * Retrieves data previously set with dbus_server_set_data().
888  * The slot must still be allocated (must not have been freed).
889  *
890  * @param server the server
891  * @param slot the slot to get data from
892  * @returns the data, or #NULL if not found
893  */
894 void*
895 dbus_server_get_data (DBusServer   *server,
896                       int           slot)
897 {
898   void *res;
899
900   _dbus_return_val_if_fail (server != NULL, NULL);
901   
902   SERVER_LOCK (server);
903   
904   res = _dbus_data_slot_list_get (&slot_allocator,
905                                   &server->slot_list,
906                                   slot);
907
908   SERVER_UNLOCK (server);
909   
910   return res;
911 }
912
913 /** @} */
914
915 #ifdef DBUS_BUILD_TESTS
916 #include "dbus-test.h"
917
918 dbus_bool_t
919 _dbus_server_test (void)
920 {
921   const char *valid_addresses[] = {
922     "tcp:port=1234",
923     "unix:path=./boogie",
924     "tcp:host=localhost,port=1234",
925     "tcp:host=localhost,port=1234;tcp:port=5678",
926     "tcp:port=1234;unix:path=./boogie",
927   };
928
929   DBusServer *server;
930   int i;
931   
932   for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
933     {
934       server = dbus_server_listen (valid_addresses[i], NULL);
935       if (server == NULL)
936         _dbus_assert_not_reached ("Failed to listen for valid address.");
937
938       dbus_server_unref (server);
939
940       /* Try disconnecting before unreffing */
941       server = dbus_server_listen (valid_addresses[i], NULL);
942       if (server == NULL)
943         _dbus_assert_not_reached ("Failed to listen for valid address.");
944
945       dbus_server_disconnect (server);
946
947       dbus_server_unref (server);
948     }
949
950   return TRUE;
951 }
952
953 #endif /* DBUS_BUILD_TESTS */