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