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