daemon fix and development
[platform/upstream/dbus.git] / dbus / dbus-transport.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-Bus implementation)
3  *
4  * Copyright (C) 2002, 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <../config.h>
25 #include "dbus-transport-protected.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-transport-socket.h"
28 #include "dbus-connection-internal.h"
29 #include "dbus-watch.h"
30 #include "dbus-auth.h"
31 #include "dbus-address.h"
32 #include "dbus-credentials.h"
33 #include "dbus-mainloop.h"
34 #include "dbus-message.h"
35 #include "dbus-transport-kdbus.h"
36 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
37 #include "dbus-server-debug-pipe.h"
38 #endif
39
40 /**
41  * @defgroup DBusTransport DBusTransport object
42  * @ingroup  DBusInternals
43  * @brief "Backend" for a DBusConnection.
44  *
45  * Types and functions related to DBusTransport.  A transport is an
46  * abstraction that can send and receive data via various kinds of
47  * network connections or other IPC mechanisms.
48  * 
49  * @{
50  */
51
52 /**
53  * @typedef DBusTransport
54  *
55  * Opaque object representing a way message stream.
56  * DBusTransport abstracts various kinds of actual
57  * transport mechanism, such as different network protocols,
58  * or encryption schemes.
59  */
60
61 static void
62 live_messages_notify (DBusCounter *counter,
63                            void        *user_data)
64 {
65   DBusTransport *transport = user_data;
66
67   _dbus_transport_ref (transport);
68
69 #if 0
70   _dbus_verbose ("Size counter value is now %d\n",
71                  (int) _dbus_counter_get_size_value (counter));
72   _dbus_verbose ("Unix FD counter value is now %d\n",
73                  (int) _dbus_counter_get_unix_fd_value (counter));
74 #endif
75
76   /* disable or re-enable the read watch for the transport if
77    * required.
78    */
79   if (transport->vtable->live_messages_changed)
80     {
81       _dbus_connection_lock (transport->connection);
82       (* transport->vtable->live_messages_changed) (transport);
83       _dbus_connection_unlock (transport->connection);
84     }
85
86   _dbus_transport_unref (transport);
87 }
88
89 /**
90  * Initializes the base class members of DBusTransport.  Chained up to
91  * by subclasses in their constructor.  The server GUID is the
92  * globally unique ID for the server creating this connection
93  * and will be #NULL for the client side of a connection. The GUID
94  * is in hex format.
95  *
96  * @param transport the transport being created.
97  * @param vtable the subclass vtable.
98  * @param server_guid non-#NULL if this transport is on the server side of a connection
99  * @param address the address of the transport
100  * @returns #TRUE on success.
101  */
102 dbus_bool_t
103 _dbus_transport_init_base (DBusTransport             *transport,
104                            const DBusTransportVTable *vtable,
105                            const DBusString          *server_guid,
106                            const DBusString          *address)
107 {
108   DBusMessageLoader *loader;
109   DBusAuth *auth;
110   DBusCounter *counter;
111   char *address_copy;
112   DBusCredentials *creds;
113   
114   loader = _dbus_message_loader_new ();
115   if (loader == NULL)
116     return FALSE;
117   
118   if (server_guid)
119     auth = _dbus_auth_server_new (server_guid);
120   else
121   {
122           _dbus_assert (address != NULL);
123           if (!_dbus_string_copy_data (address, &address_copy))
124         {
125           _dbus_message_loader_unref (loader);
126           return FALSE;
127         }
128       if(address_copy == strstr(address_copy, "kdbus:path="))
129           auth = _dbus_auth_client_new_kdbus();
130           else
131                   auth = _dbus_auth_client_new ();
132   }
133
134   if (auth == NULL)
135     {
136       _dbus_message_loader_unref (loader);
137       return FALSE;
138     }
139
140   counter = _dbus_counter_new ();
141   if (counter == NULL)
142     {
143       _dbus_auth_unref (auth);
144       _dbus_message_loader_unref (loader);
145       return FALSE;
146     }  
147
148   creds = _dbus_credentials_new ();
149   if (creds == NULL)
150     {
151       _dbus_counter_unref (counter);
152       _dbus_auth_unref (auth);
153       _dbus_message_loader_unref (loader);
154       return FALSE;
155     }
156   
157   if (server_guid)
158     {
159       _dbus_assert (address == NULL);
160       address_copy = NULL;
161     }
162   
163   transport->refcount = 1;
164   transport->vtable = vtable;
165   transport->loader = loader;
166   transport->auth = auth;
167   transport->live_messages = counter;
168   transport->authenticated = FALSE;
169   transport->disconnected = FALSE;
170   transport->is_server = (server_guid != NULL);
171   transport->send_credentials_pending = !transport->is_server;
172   transport->receive_credentials_pending = transport->is_server;
173   transport->address = address_copy;
174   
175   transport->unix_user_function = NULL;
176   transport->unix_user_data = NULL;
177   transport->free_unix_user_data = NULL;
178
179   transport->windows_user_function = NULL;
180   transport->windows_user_data = NULL;
181   transport->free_windows_user_data = NULL;
182   
183   transport->expected_guid = NULL;
184   
185   /* Try to default to something that won't totally hose the system,
186    * but doesn't impose too much of a limitation.
187    */
188   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
189
190   /* On Linux RLIMIT_NOFILE defaults to 1024, so allowing 4096 fds live
191      should be more than enough */
192   transport->max_live_messages_unix_fds = 4096;
193
194   /* credentials read from socket if any */
195   transport->credentials = creds;
196
197   _dbus_counter_set_notify (transport->live_messages,
198                             transport->max_live_messages_size,
199                             transport->max_live_messages_unix_fds,
200                             live_messages_notify,
201                             transport);
202
203   if (transport->address)
204     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
205
206   return TRUE;
207 }
208
209 /**
210  * Finalizes base class members of DBusTransport.
211  * Chained up to from subclass finalizers.
212  *
213  * @param transport the transport.
214  */
215 void
216 _dbus_transport_finalize_base (DBusTransport *transport)
217 {
218   if (!transport->disconnected)
219     _dbus_transport_disconnect (transport);
220
221   if (transport->free_unix_user_data != NULL)
222     (* transport->free_unix_user_data) (transport->unix_user_data);
223
224   if (transport->free_windows_user_data != NULL)
225     (* transport->free_windows_user_data) (transport->windows_user_data);
226   
227   _dbus_message_loader_unref (transport->loader);
228   _dbus_auth_unref (transport->auth);
229   _dbus_counter_set_notify (transport->live_messages,
230                             0, 0, NULL, NULL);
231   _dbus_counter_unref (transport->live_messages);
232   dbus_free (transport->address);
233   dbus_free (transport->expected_guid);
234   if (transport->credentials)
235     _dbus_credentials_unref (transport->credentials);
236 }
237
238
239 /**
240  * Verifies if a given D-Bus address is a valid address
241  * by attempting to connect to it. If it is, returns the
242  * opened DBusTransport object. If it isn't, returns #NULL
243  * and sets @p error.
244  *
245  * @param address the address to be checked.
246  * @param error address where an error can be returned.
247  * @returns a new transport, or #NULL on failure.
248  */
249 static DBusTransport*
250 check_address (const char *address, DBusError *error)
251 {
252   DBusAddressEntry **entries;
253   DBusTransport *transport = NULL;
254   int len, i;
255
256   _dbus_assert (address != NULL);
257
258   if (!dbus_parse_address (address, &entries, &len, error))
259     return NULL;              /* not a valid address */
260
261   for (i = 0; i < len; i++)
262     {
263       transport = _dbus_transport_open (entries[i], error);
264       if (transport != NULL)
265         break;
266     }
267
268   dbus_address_entries_free (entries);
269   return transport;
270 }
271
272 /**
273  * Creates a new transport for the "autostart" method.
274  * This creates a client-side of a transport.
275  *
276  * @param scope scope of autolaunch (Windows only)
277  * @param error address where an error can be returned.
278  * @returns a new transport, or #NULL on failure.
279  */
280 static DBusTransport*
281 _dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
282 {
283   DBusString address;
284   DBusTransport *result = NULL;
285
286   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
287
288   if (!_dbus_string_init (&address))
289     {
290       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
291       return NULL;
292     }
293
294   if (!_dbus_get_autolaunch_address (scope, &address, error))
295     {
296       _DBUS_ASSERT_ERROR_IS_SET (error);
297       goto out;
298     }
299
300   result = check_address (_dbus_string_get_const_data (&address), error);
301   if (result == NULL)
302     _DBUS_ASSERT_ERROR_IS_SET (error);
303   else
304     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
305
306  out:
307   _dbus_string_free (&address);
308   return result;
309 }
310
311 static DBusTransportOpenResult
312 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
313                                  DBusTransport    **transport_p,
314                                  DBusError         *error)
315 {
316   const char *method;
317   
318   method = dbus_address_entry_get_method (entry);
319   _dbus_assert (method != NULL);
320
321   if (strcmp (method, "autolaunch") == 0)
322     {
323       const char *scope = dbus_address_entry_get_value (entry, "scope");
324
325       *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
326
327       if (*transport_p == NULL)
328         {
329           _DBUS_ASSERT_ERROR_IS_SET (error);
330           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
331         }
332       else
333         {
334           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
335           return DBUS_TRANSPORT_OPEN_OK;
336         }      
337     }
338   else
339     {
340       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
341       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
342     }
343 }
344
345 static const struct {
346   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
347                                     DBusTransport   **transport_p,
348                                     DBusError        *error);
349 } open_funcs[] = {
350   { _dbus_transport_open_socket },
351   { _dbus_transport_open_platform_specific },
352   { _dbus_transport_open_kdbus },
353   { _dbus_transport_open_autolaunch }
354 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
355   , { _dbus_transport_open_debug_pipe }
356 #endif
357 };
358
359 /**
360  * Try to open a new transport for the given address entry.  (This
361  * opens a client-side-of-the-connection transport.)
362  * 
363  * @param entry the address entry
364  * @param error location to store reason for failure.
365  * @returns new transport of #NULL on failure.
366  */
367 DBusTransport*
368 _dbus_transport_open (DBusAddressEntry *entry,
369                       DBusError        *error)
370 {
371   DBusTransport *transport;
372   const char *expected_guid_orig;
373   char *expected_guid;
374   int i;
375   DBusError tmp_error = DBUS_ERROR_INIT;
376
377   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
378   
379   transport = NULL;
380   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
381   expected_guid = _dbus_strdup (expected_guid_orig);
382
383   if (expected_guid_orig != NULL && expected_guid == NULL)
384     {
385       _DBUS_SET_OOM (error);
386       return NULL;
387     }
388
389   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
390     {
391       DBusTransportOpenResult result;
392
393       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
394       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
395
396       switch (result)
397         {
398         case DBUS_TRANSPORT_OPEN_OK:
399           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
400           goto out;
401           break;
402         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
403           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
404           /* keep going through the loop of open funcs */
405           break;
406         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
407           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
408           goto out;
409           break;
410         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
411           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
412           goto out;
413           break;
414         }
415     }
416
417  out:
418   
419   if (transport == NULL)
420     {
421       if (!dbus_error_is_set (&tmp_error))
422         _dbus_set_bad_address (&tmp_error,
423                                NULL, NULL,
424                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
425       
426       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
427       dbus_move_error(&tmp_error, error);
428       dbus_free (expected_guid);
429     }
430   else
431     {
432       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
433
434       /* In the case of autostart the initial guid is NULL
435        * and the autostart transport recursively calls
436        * _dbus_open_transport wich returns a transport
437        * with a guid.  That guid is the definitive one.
438        *
439        * FIXME: if more transports are added they may have
440        * an effect on the expected_guid semantics (i.e. 
441        * expected_guid and transport->expected_guid may
442        * both have values).  This is very unlikely though
443        * we should either throw asserts here for those 
444        * corner cases or refactor the code so it is 
445        * clearer on what is expected and what is not
446        */
447       if(expected_guid)
448         transport->expected_guid = expected_guid;
449     }
450
451   return transport;
452 }
453
454 /**
455  * Increments the reference count for the transport.
456  *
457  * @param transport the transport.
458  * @returns the transport.
459  */
460 DBusTransport *
461 _dbus_transport_ref (DBusTransport *transport)
462 {
463   _dbus_assert (transport->refcount > 0);
464   
465   transport->refcount += 1;
466
467   return transport;
468 }
469
470 /**
471  * Decrements the reference count for the transport.
472  * Disconnects and finalizes the transport if
473  * the reference count reaches zero.
474  *
475  * @param transport the transport.
476  */
477 void
478 _dbus_transport_unref (DBusTransport *transport)
479 {
480   _dbus_assert (transport != NULL);
481   _dbus_assert (transport->refcount > 0);
482   
483   transport->refcount -= 1;
484   if (transport->refcount == 0)
485     {
486       _dbus_verbose ("finalizing\n");
487       
488       _dbus_assert (transport->vtable->finalize != NULL);
489       
490       (* transport->vtable->finalize) (transport);
491     }
492 }
493
494 /**
495  * Closes our end of the connection to a remote application. Further
496  * attempts to use this transport will fail. Only the first call to
497  * _dbus_transport_disconnect() will have an effect.
498  *
499  * @param transport the transport.
500  * 
501  */
502 void
503 _dbus_transport_disconnect (DBusTransport *transport)
504 {
505   _dbus_verbose ("start\n");
506   
507   _dbus_assert (transport->vtable->disconnect != NULL);
508   
509   if (transport->disconnected)
510     return;
511
512   (* transport->vtable->disconnect) (transport);
513   
514   transport->disconnected = TRUE;
515
516   _dbus_verbose ("end\n");
517 }
518
519 /**
520  * Returns #TRUE if the transport has not been disconnected.
521  * Disconnection can result from _dbus_transport_disconnect()
522  * or because the server drops its end of the connection.
523  *
524  * @param transport the transport.
525  * @returns whether we're connected
526  */
527 dbus_bool_t
528 _dbus_transport_get_is_connected (DBusTransport *transport)
529 {
530   return !transport->disconnected;
531 }
532
533 static dbus_bool_t
534 auth_via_unix_user_function (DBusTransport *transport)
535 {
536   DBusCredentials *auth_identity;
537   dbus_bool_t allow;
538   DBusConnection *connection;
539   DBusAllowUnixUserFunction unix_user_function;
540   void *unix_user_data;
541   dbus_uid_t uid;
542
543   /* Dropping the lock here probably isn't that safe. */
544   
545   auth_identity = _dbus_auth_get_identity (transport->auth);
546   _dbus_assert (auth_identity != NULL);
547
548   connection = transport->connection;
549   unix_user_function = transport->unix_user_function;
550   unix_user_data = transport->unix_user_data;
551   uid = _dbus_credentials_get_unix_uid (auth_identity);
552               
553   _dbus_verbose ("unlock\n");
554   _dbus_connection_unlock (connection);
555
556   allow = (* unix_user_function) (connection,
557                                   uid,
558                                   unix_user_data);
559               
560   _dbus_verbose ("lock post unix user function\n");
561   _dbus_connection_lock (connection);
562
563   if (allow)
564     {
565       _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", uid);
566     }
567   else
568     {
569       _dbus_verbose ("Client UID "DBUS_UID_FORMAT
570                      " was rejected, disconnecting\n",
571                      _dbus_credentials_get_unix_uid (auth_identity));
572       _dbus_transport_disconnect (transport);
573     }
574
575   return allow;
576 }
577
578 static dbus_bool_t
579 auth_via_windows_user_function (DBusTransport *transport)
580 {
581   DBusCredentials *auth_identity;  
582   dbus_bool_t allow;
583   DBusConnection *connection;
584   DBusAllowWindowsUserFunction windows_user_function;
585   void *windows_user_data;
586   char *windows_sid;
587
588   /* Dropping the lock here probably isn't that safe. */
589   
590   auth_identity = _dbus_auth_get_identity (transport->auth);
591   _dbus_assert (auth_identity != NULL);
592
593   connection = transport->connection;
594   windows_user_function = transport->windows_user_function;
595   windows_user_data = transport->unix_user_data;
596   windows_sid = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
597
598   if (windows_sid == NULL)
599     {
600       /* OOM */
601       return FALSE;
602     }
603                 
604   _dbus_verbose ("unlock\n");
605   _dbus_connection_unlock (connection);
606
607   allow = (* windows_user_function) (connection,
608                                      windows_sid,
609                                      windows_user_data);
610               
611   _dbus_verbose ("lock post windows user function\n");
612   _dbus_connection_lock (connection);
613
614   if (allow)
615     {
616       _dbus_verbose ("Client SID '%s' authorized\n", windows_sid);
617     }
618   else
619     {
620       _dbus_verbose ("Client SID '%s' was rejected, disconnecting\n",
621                      _dbus_credentials_get_windows_sid (auth_identity));
622       _dbus_transport_disconnect (transport);
623     }
624
625   return allow;
626 }
627
628 static dbus_bool_t
629 auth_via_default_rules (DBusTransport *transport)
630 {
631   DBusCredentials *auth_identity;
632   DBusCredentials *our_identity;
633   dbus_bool_t allow;
634   
635   auth_identity = _dbus_auth_get_identity (transport->auth);
636   _dbus_assert (auth_identity != NULL);
637
638   /* By default, connection is allowed if the client is 1) root or 2)
639    * has the same UID as us or 3) anonymous is allowed.
640    */
641   
642   our_identity = _dbus_credentials_new_from_current_process ();
643   if (our_identity == NULL)
644     {
645       /* OOM */
646       return FALSE;
647     }
648               
649   if (transport->allow_anonymous ||
650       _dbus_credentials_get_unix_uid (auth_identity) == 0 ||
651       _dbus_credentials_same_user (our_identity,
652                                    auth_identity))
653     {
654       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
655           _dbus_verbose ("Client authorized as SID '%s'"
656                          "matching our SID '%s'\n",
657                          _dbus_credentials_get_windows_sid(auth_identity),
658                          _dbus_credentials_get_windows_sid(our_identity));
659       else
660           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
661                          " matching our UID "DBUS_UID_FORMAT"\n",
662                          _dbus_credentials_get_unix_uid(auth_identity),
663                          _dbus_credentials_get_unix_uid(our_identity));
664       /* We have authenticated! */
665       allow = TRUE;
666     }
667   else
668     {
669       if (_dbus_credentials_include(our_identity,DBUS_CREDENTIAL_WINDOWS_SID))
670           _dbus_verbose ("Client authorized as SID '%s'"
671                          " but our SID is '%s', disconnecting\n",
672                          (_dbus_credentials_get_windows_sid(auth_identity) ?
673                           _dbus_credentials_get_windows_sid(auth_identity) : "<null>"),
674                          (_dbus_credentials_get_windows_sid(our_identity) ?
675                           _dbus_credentials_get_windows_sid(our_identity) : "<null>"));
676       else
677           _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
678                          " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
679                          _dbus_credentials_get_unix_uid(auth_identity),
680                          _dbus_credentials_get_unix_uid(our_identity));
681       _dbus_transport_disconnect (transport);
682       allow = FALSE;
683     }  
684
685   _dbus_credentials_unref (our_identity);
686   
687   return allow;
688 }
689
690 /**
691  * Returns #TRUE if we have been authenticated. It will return #TRUE even if
692  * the transport is now disconnected, but was ever authenticated before
693  * disconnecting.
694  *
695  * This replaces the older _dbus_transport_get_is_authenticated() which
696  * had side-effects.
697  *
698  * @param transport the transport
699  * @returns whether we're authenticated
700  */
701 dbus_bool_t
702 _dbus_transport_peek_is_authenticated (DBusTransport *transport)
703 {
704   return transport->authenticated;
705 }
706
707 /**
708  * Returns #TRUE if we have been authenticated. It will return #TRUE even if
709  * the transport is now disconnected, but was ever authenticated before
710  * disconnecting.
711  *
712  * If we have not finished authenticating, but we have enough buffered input
713  * to finish the job, then this function will do so before it returns.
714  *
715  * This used to be called _dbus_transport_get_is_authenticated(), but that
716  * name seems inappropriate for a function with side-effects.
717  *
718  * @todo we drop connection->mutex when calling the unix_user_function,
719  * and windows_user_function, which may not be safe really.
720  *
721  * @param transport the transport
722  * @returns whether we're authenticated
723  */
724 dbus_bool_t
725 _dbus_transport_try_to_authenticate (DBusTransport *transport)
726 {  
727   if (transport->authenticated)
728     return TRUE;
729   else
730     {
731       dbus_bool_t maybe_authenticated;
732       
733       if (transport->disconnected)
734         return FALSE;
735
736       /* paranoia ref since we call user callbacks sometimes */
737       _dbus_connection_ref_unlocked (transport->connection);
738       
739       maybe_authenticated =
740         (!(transport->send_credentials_pending ||
741            transport->receive_credentials_pending));
742
743       if (maybe_authenticated)
744         {
745           switch (_dbus_auth_do_work (transport->auth))
746             {
747             case DBUS_AUTH_STATE_AUTHENTICATED:
748               /* leave as maybe_authenticated */
749               break;
750             default:
751               maybe_authenticated = FALSE;
752             }
753         }
754
755       /* If we're the client, verify the GUID
756        */
757       if (maybe_authenticated && !transport->is_server)
758         {
759           const char *server_guid;
760
761           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
762           _dbus_assert (server_guid != NULL);
763
764           if (transport->expected_guid &&
765               strcmp (transport->expected_guid, server_guid) != 0)
766             {
767               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
768                              transport->expected_guid, server_guid);
769               _dbus_transport_disconnect (transport);
770               _dbus_connection_unref_unlocked (transport->connection);
771               return FALSE;
772             }
773         }
774
775       /* If we're the server, see if we want to allow this identity to proceed.
776        */
777       if (maybe_authenticated && transport->is_server)
778         {
779           dbus_bool_t allow;
780           DBusCredentials *auth_identity;
781           
782           auth_identity = _dbus_auth_get_identity (transport->auth);
783           _dbus_assert (auth_identity != NULL);
784           
785           /* If we have an auth'd user and a user function, delegate
786            * deciding whether auth credentials are good enough to the
787            * app; otherwise, use our default decision process.
788            */
789           if (transport->unix_user_function != NULL &&
790               _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_UNIX_USER_ID))
791             {
792               allow = auth_via_unix_user_function (transport);
793             }
794           else if (transport->windows_user_function != NULL &&
795                    _dbus_credentials_include (auth_identity, DBUS_CREDENTIAL_WINDOWS_SID))
796             {
797               allow = auth_via_windows_user_function (transport);
798             }      
799           else
800             {
801               allow = auth_via_default_rules (transport);
802             }
803           
804           if (!allow)
805             maybe_authenticated = FALSE;
806         }
807
808       transport->authenticated = maybe_authenticated;
809
810       _dbus_connection_unref_unlocked (transport->connection);
811       return maybe_authenticated;
812     }
813 }
814
815 /**
816  * See dbus_connection_get_is_anonymous().
817  *
818  * @param transport the transport
819  * @returns #TRUE if not authenticated or authenticated as anonymous
820  */
821 dbus_bool_t
822 _dbus_transport_get_is_anonymous (DBusTransport *transport)
823 {
824   DBusCredentials *auth_identity;
825   
826   if (!transport->authenticated)
827     return TRUE;
828   
829   auth_identity = _dbus_auth_get_identity (transport->auth);
830
831   if (_dbus_credentials_are_anonymous (auth_identity))
832     return TRUE;
833   else
834     return FALSE;
835 }
836
837 /**
838  * Returns TRUE if the transport supports sending unix fds.
839  *
840  * @param transport the transport
841  * @returns #TRUE if TRUE it is possible to send unix fds across the transport.
842  */
843 dbus_bool_t
844 _dbus_transport_can_pass_unix_fd(DBusTransport *transport)
845 {
846   return DBUS_TRANSPORT_CAN_SEND_UNIX_FD(transport);
847 }
848
849 /**
850  * Gets the address of a transport. It will be
851  * #NULL for a server-side transport.
852  *
853  * @param transport the transport
854  * @returns transport's address
855  */
856 const char*
857 _dbus_transport_get_address (DBusTransport *transport)
858 {
859   return transport->address;
860 }
861
862 /**
863  * Gets the id of the server we are connected to (see
864  * dbus_server_get_id()). Only works on client side.
865  *
866  * @param transport the transport
867  * @returns transport's server's id or #NULL if we are the server side
868  */
869 const char*
870 _dbus_transport_get_server_id (DBusTransport *transport)
871 {
872   if (transport->is_server)
873     return NULL;
874   else if (transport->authenticated)
875     return _dbus_auth_get_guid_from_server (transport->auth);
876   else
877     return transport->expected_guid;
878 }
879
880 /**
881  * Handles a watch by reading data, writing data, or disconnecting
882  * the transport, as appropriate for the given condition.
883  *
884  * @param transport the transport.
885  * @param watch the watch.
886  * @param condition the current state of the watched file descriptor.
887  * @returns #FALSE if not enough memory to fully handle the watch
888  */
889 dbus_bool_t
890 _dbus_transport_handle_watch (DBusTransport           *transport,
891                               DBusWatch               *watch,
892                               unsigned int             condition)
893 {
894   dbus_bool_t retval;
895   
896   _dbus_assert (transport->vtable->handle_watch != NULL);
897
898   if (transport->disconnected)
899     return TRUE;
900
901   if (dbus_watch_get_socket (watch) < 0)
902     {
903       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
904       return TRUE;
905     }
906   
907   _dbus_watch_sanitize_condition (watch, &condition);
908
909   _dbus_transport_ref (transport);
910   _dbus_watch_ref (watch);
911   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
912   _dbus_watch_unref (watch);
913   _dbus_transport_unref (transport);
914
915   return retval;
916 }
917
918 /**
919  * Sets the connection using this transport. Allows the transport
920  * to add watches to the connection, queue incoming messages,
921  * and pull outgoing messages.
922  *
923  * @param transport the transport.
924  * @param connection the connection.
925  * @returns #FALSE if not enough memory
926  */
927 dbus_bool_t
928 _dbus_transport_set_connection (DBusTransport  *transport,
929                                 DBusConnection *connection)
930 {
931   _dbus_assert (transport->vtable->connection_set != NULL);
932   _dbus_assert (transport->connection == NULL);
933   
934   transport->connection = connection;
935
936   _dbus_transport_ref (transport);
937   if (!(* transport->vtable->connection_set) (transport))
938     transport->connection = NULL;
939   _dbus_transport_unref (transport);
940
941   return transport->connection != NULL;
942 }
943
944 /**
945  * Get the socket file descriptor, if any.
946  *
947  * @param transport the transport
948  * @param fd_p pointer to fill in with the descriptor
949  * @returns #TRUE if a descriptor was available
950  */
951 dbus_bool_t
952 _dbus_transport_get_socket_fd (DBusTransport *transport,
953                                int           *fd_p)
954 {
955   dbus_bool_t retval;
956   
957   if (transport->vtable->get_socket_fd == NULL)
958     return FALSE;
959
960   if (transport->disconnected)
961     return FALSE;
962
963   _dbus_transport_ref (transport);
964
965   retval = (* transport->vtable->get_socket_fd) (transport,
966                                                  fd_p);
967   
968   _dbus_transport_unref (transport);
969
970   return retval;
971 }
972
973 /**
974  * Performs a single poll()/select() on the transport's file
975  * descriptors and then reads/writes data as appropriate,
976  * queueing incoming messages and sending outgoing messages.
977  * This is the backend for _dbus_connection_do_iteration().
978  * See _dbus_connection_do_iteration() for full details.
979  *
980  * @param transport the transport.
981  * @param flags indicates whether to read or write, and whether to block.
982  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
983  */
984 void
985 _dbus_transport_do_iteration (DBusTransport  *transport,
986                               unsigned int    flags,
987                               int             timeout_milliseconds)
988 {
989   _dbus_assert (transport->vtable->do_iteration != NULL);
990
991   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
992                  flags, timeout_milliseconds, !transport->disconnected);
993   
994   if ((flags & (DBUS_ITERATION_DO_WRITING |
995                 DBUS_ITERATION_DO_READING)) == 0)
996     return; /* Nothing to do */
997
998   if (transport->disconnected)
999     return;
1000
1001   _dbus_transport_ref (transport);
1002   (* transport->vtable->do_iteration) (transport, flags,
1003                                        timeout_milliseconds);
1004   _dbus_transport_unref (transport);
1005
1006   _dbus_verbose ("end\n");
1007 }
1008
1009 static dbus_bool_t
1010 recover_unused_bytes (DBusTransport *transport)
1011 {
1012   if (_dbus_auth_needs_decoding (transport->auth))
1013     {
1014       DBusString plaintext;
1015       const DBusString *encoded;
1016       DBusString *buffer;
1017       int orig_len;
1018
1019       if (!_dbus_string_init (&plaintext))
1020         goto nomem;
1021       
1022       _dbus_auth_get_unused_bytes (transport->auth,
1023                                    &encoded);
1024
1025       if (!_dbus_auth_decode_data (transport->auth,
1026                                    encoded, &plaintext))
1027         {
1028           _dbus_string_free (&plaintext);
1029           goto nomem;
1030         }
1031
1032       _dbus_message_loader_get_buffer (transport->loader,
1033                                        &buffer);
1034       
1035       orig_len = _dbus_string_get_length (buffer);
1036
1037       if (!_dbus_string_move (&plaintext, 0, buffer,
1038                               orig_len))
1039         {
1040           _dbus_string_free (&plaintext);
1041           goto nomem;
1042         }
1043       
1044       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1045                      _dbus_string_get_length (buffer) -
1046                      orig_len);
1047       
1048       _dbus_message_loader_return_buffer (transport->loader,
1049                                           buffer,
1050                                           _dbus_string_get_length (buffer) -
1051                                           orig_len);
1052
1053       _dbus_auth_delete_unused_bytes (transport->auth);
1054       
1055       _dbus_string_free (&plaintext);
1056     }
1057   else
1058     {
1059       const DBusString *bytes;
1060       DBusString *buffer;
1061       int orig_len;
1062       dbus_bool_t succeeded;
1063
1064       _dbus_message_loader_get_buffer (transport->loader,
1065                                        &buffer);
1066                 
1067       orig_len = _dbus_string_get_length (buffer);
1068
1069       _dbus_auth_get_unused_bytes (transport->auth,
1070                                    &bytes);
1071
1072       succeeded = TRUE;
1073       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
1074         succeeded = FALSE;
1075       
1076       _dbus_verbose (" %d unused bytes sent to message loader\n", 
1077                      _dbus_string_get_length (buffer) -
1078                      orig_len);
1079       
1080       _dbus_message_loader_return_buffer (transport->loader,
1081                                           buffer,
1082                                           _dbus_string_get_length (buffer) -
1083                                           orig_len);
1084
1085       if (succeeded)
1086         _dbus_auth_delete_unused_bytes (transport->auth);
1087       else
1088         goto nomem;
1089     }
1090
1091   return TRUE;
1092
1093  nomem:
1094   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
1095   return FALSE;
1096 }
1097
1098 /**
1099  * Reports our current dispatch status (whether there's buffered
1100  * data to be queued as messages, or not, or we need memory).
1101  *
1102  * @param transport the transport
1103  * @returns current status
1104  */
1105 DBusDispatchStatus
1106 _dbus_transport_get_dispatch_status (DBusTransport *transport)
1107 {
1108   if (_dbus_counter_get_size_value (transport->live_messages) >= transport->max_live_messages_size ||
1109       _dbus_counter_get_unix_fd_value (transport->live_messages) >= transport->max_live_messages_unix_fds)
1110     return DBUS_DISPATCH_COMPLETE; /* complete for now */
1111
1112   if (!_dbus_transport_try_to_authenticate (transport))
1113     {
1114       if (_dbus_auth_do_work (transport->auth) ==
1115           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
1116         return DBUS_DISPATCH_NEED_MEMORY;
1117       else if (!_dbus_transport_try_to_authenticate (transport))
1118         return DBUS_DISPATCH_COMPLETE;
1119     }
1120
1121   if (!transport->unused_bytes_recovered &&
1122       !recover_unused_bytes (transport))
1123     return DBUS_DISPATCH_NEED_MEMORY;
1124
1125   transport->unused_bytes_recovered = TRUE;
1126   
1127   if (!_dbus_message_loader_queue_messages (transport->loader))
1128     return DBUS_DISPATCH_NEED_MEMORY;
1129
1130   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
1131     return DBUS_DISPATCH_DATA_REMAINS;
1132   else
1133     return DBUS_DISPATCH_COMPLETE;
1134 }
1135
1136 /**
1137  * Processes data we've read while handling a watch, potentially
1138  * converting some of it to messages and queueing those messages on
1139  * the connection.
1140  *
1141  * @param transport the transport
1142  * @returns #TRUE if we had enough memory to queue all messages
1143  */
1144 dbus_bool_t
1145 _dbus_transport_queue_messages (DBusTransport *transport)
1146 {
1147   DBusDispatchStatus status;
1148
1149 #if 0
1150   _dbus_verbose ("_dbus_transport_queue_messages()\n");
1151 #endif
1152   
1153   /* Queue any messages */
1154   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
1155     {
1156       DBusMessage *message;
1157       DBusList *link;
1158
1159       link = _dbus_message_loader_pop_message_link (transport->loader);
1160       _dbus_assert (link != NULL);
1161       
1162       message = link->data;
1163       
1164       _dbus_verbose ("queueing received message %p\n", message);
1165
1166       if (!_dbus_message_add_counter (message, transport->live_messages))
1167         {
1168           _dbus_message_loader_putback_message_link (transport->loader,
1169                                                      link);
1170           status = DBUS_DISPATCH_NEED_MEMORY;
1171           break;
1172         }
1173       else
1174         {
1175           /* We didn't call the notify function when we added the counter, so
1176            * catch up now. Since we have the connection's lock, it's desirable
1177            * that we bypass the notify function and call this virtual method
1178            * directly. */
1179           if (transport->vtable->live_messages_changed)
1180             (* transport->vtable->live_messages_changed) (transport);
1181
1182           /* pass ownership of link and message ref to connection */
1183           _dbus_connection_queue_received_message_link (transport->connection,
1184                                                         link);
1185         }
1186     }
1187
1188   if (_dbus_message_loader_get_is_corrupted (transport->loader))
1189     {
1190       _dbus_verbose ("Corrupted message stream, disconnecting\n");
1191       _dbus_transport_disconnect (transport);
1192     }
1193
1194   return status != DBUS_DISPATCH_NEED_MEMORY;
1195 }
1196
1197 /**
1198  * See dbus_connection_set_max_message_size().
1199  *
1200  * @param transport the transport
1201  * @param size the max size of a single message
1202  */
1203 void
1204 _dbus_transport_set_max_message_size (DBusTransport  *transport,
1205                                       long            size)
1206 {
1207   _dbus_message_loader_set_max_message_size (transport->loader, size);
1208 }
1209
1210 /**
1211  * See dbus_connection_set_max_message_unix_fds().
1212  *
1213  * @param transport the transport
1214  * @param n the max number of unix fds of a single message
1215  */
1216 void
1217 _dbus_transport_set_max_message_unix_fds (DBusTransport  *transport,
1218                                           long            n)
1219 {
1220   _dbus_message_loader_set_max_message_unix_fds (transport->loader, n);
1221 }
1222
1223 /**
1224  * See dbus_connection_get_max_message_size().
1225  *
1226  * @param transport the transport
1227  * @returns max message size
1228  */
1229 long
1230 _dbus_transport_get_max_message_size (DBusTransport  *transport)
1231 {
1232   return _dbus_message_loader_get_max_message_size (transport->loader);
1233 }
1234
1235 /**
1236  * See dbus_connection_get_max_message_unix_fds().
1237  *
1238  * @param transport the transport
1239  * @returns max message unix fds
1240  */
1241 long
1242 _dbus_transport_get_max_message_unix_fds (DBusTransport  *transport)
1243 {
1244   return _dbus_message_loader_get_max_message_unix_fds (transport->loader);
1245 }
1246
1247 /**
1248  * See dbus_connection_set_max_received_size().
1249  *
1250  * @param transport the transport
1251  * @param size the max size of all incoming messages
1252  */
1253 void
1254 _dbus_transport_set_max_received_size (DBusTransport  *transport,
1255                                        long            size)
1256 {
1257   transport->max_live_messages_size = size;
1258   _dbus_counter_set_notify (transport->live_messages,
1259                             transport->max_live_messages_size,
1260                             transport->max_live_messages_unix_fds,
1261                             live_messages_notify,
1262                             transport);
1263 }
1264
1265 /**
1266  * See dbus_connection_set_max_received_unix_fds().
1267  *
1268  * @param transport the transport
1269  * @param n the max unix fds of all incoming messages
1270  */
1271 void
1272 _dbus_transport_set_max_received_unix_fds (DBusTransport  *transport,
1273                                            long            n)
1274 {
1275   transport->max_live_messages_unix_fds = n;
1276   _dbus_counter_set_notify (transport->live_messages,
1277                             transport->max_live_messages_size,
1278                             transport->max_live_messages_unix_fds,
1279                             live_messages_notify,
1280                             transport);
1281 }
1282
1283 /**
1284  * See dbus_connection_get_max_received_size().
1285  *
1286  * @param transport the transport
1287  * @returns max bytes for all live messages
1288  */
1289 long
1290 _dbus_transport_get_max_received_size (DBusTransport  *transport)
1291 {
1292   return transport->max_live_messages_size;
1293 }
1294
1295 /**
1296  * See dbus_connection_set_max_received_unix_fds().
1297  *
1298  * @param transport the transport
1299  * @returns max unix fds for all live messages
1300  */
1301 long
1302 _dbus_transport_get_max_received_unix_fds (DBusTransport  *transport)
1303 {
1304   return transport->max_live_messages_unix_fds;
1305 }
1306
1307 /**
1308  * See dbus_connection_get_unix_user().
1309  *
1310  * @param transport the transport
1311  * @param uid return location for the user ID
1312  * @returns #TRUE if uid is filled in with a valid user ID
1313  */
1314 dbus_bool_t
1315 _dbus_transport_get_unix_user (DBusTransport *transport,
1316                                unsigned long *uid)
1317 {
1318   DBusCredentials *auth_identity;
1319
1320   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
1321                            * case of bugs in the caller. Caller should
1322                            * never use this value on purpose, however.
1323                            */
1324   
1325   if (!transport->authenticated)
1326     return FALSE;
1327   
1328   auth_identity = _dbus_auth_get_identity (transport->auth);
1329
1330   if (_dbus_credentials_include (auth_identity,
1331                                  DBUS_CREDENTIAL_UNIX_USER_ID))
1332     {
1333       *uid = _dbus_credentials_get_unix_uid (auth_identity);
1334       return TRUE;
1335     }
1336   else
1337     return FALSE;
1338 }
1339
1340 /**
1341  * See dbus_connection_get_unix_process_id().
1342  *
1343  * @param transport the transport
1344  * @param pid return location for the process ID
1345  * @returns #TRUE if uid is filled in with a valid process ID
1346  */
1347 dbus_bool_t
1348 _dbus_transport_get_unix_process_id (DBusTransport *transport,
1349                                      unsigned long *pid)
1350 {
1351   DBusCredentials *auth_identity;
1352
1353   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
1354                           * but we set it to a safe number, INT_MAX,
1355                           * just to root out possible bugs in bad callers.
1356                           */
1357   
1358   if (!transport->authenticated)
1359     return FALSE;
1360   
1361   auth_identity = _dbus_auth_get_identity (transport->auth);
1362
1363   if (_dbus_credentials_include (auth_identity,
1364                                  DBUS_CREDENTIAL_UNIX_PROCESS_ID))
1365     {
1366       *pid = _dbus_credentials_get_pid (auth_identity);
1367       return TRUE;
1368     }
1369   else
1370     return FALSE;
1371 }
1372
1373 /**
1374  * See dbus_connection_get_adt_audit_session_data().
1375  *
1376  * @param transport the transport
1377  * @param data return location for the ADT audit data 
1378  * @param data_size return length of audit data
1379  * @returns #TRUE if audit data is filled in with a valid ucred
1380  */
1381 dbus_bool_t
1382 _dbus_transport_get_adt_audit_session_data (DBusTransport      *transport,
1383                                             void              **data,
1384                                             int                *data_size)
1385 {
1386   DBusCredentials *auth_identity;
1387
1388   *data = NULL;
1389   *data_size = 0;
1390   
1391   if (!transport->authenticated)
1392     return FALSE;
1393   
1394   auth_identity = _dbus_auth_get_identity (transport->auth);
1395
1396   if (_dbus_credentials_include (auth_identity,
1397                                  DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID))
1398     {
1399       *data = (void *) _dbus_credentials_get_adt_audit_data (auth_identity);
1400       *data_size = _dbus_credentials_get_adt_audit_data_size (auth_identity);
1401       return TRUE;
1402     }
1403   else
1404     return FALSE;
1405 }
1406
1407 /**
1408  * See dbus_connection_set_unix_user_function().
1409  *
1410  * @param transport the transport
1411  * @param function the predicate
1412  * @param data data to pass to the predicate
1413  * @param free_data_function function to free the data
1414  * @param old_data the old user data to be freed
1415  * @param old_free_data_function old free data function to free it with
1416  */
1417 void
1418 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
1419                                         DBusAllowUnixUserFunction  function,
1420                                         void                      *data,
1421                                         DBusFreeFunction           free_data_function,
1422                                         void                     **old_data,
1423                                         DBusFreeFunction          *old_free_data_function)
1424 {  
1425   *old_data = transport->unix_user_data;
1426   *old_free_data_function = transport->free_unix_user_data;
1427
1428   transport->unix_user_function = function;
1429   transport->unix_user_data = data;
1430   transport->free_unix_user_data = free_data_function;
1431 }
1432
1433 /**
1434  * See dbus_connection_get_windows_user().
1435  *
1436  * @param transport the transport
1437  * @param windows_sid_p return location for the user ID
1438  * @returns #TRUE if user is available; the returned value may still be #NULL if no memory to copy it
1439  */
1440 dbus_bool_t
1441 _dbus_transport_get_windows_user (DBusTransport              *transport,
1442                                   char                      **windows_sid_p)
1443 {
1444   DBusCredentials *auth_identity;
1445
1446   *windows_sid_p = NULL;
1447   
1448   if (!transport->authenticated)
1449     return FALSE;
1450   
1451   auth_identity = _dbus_auth_get_identity (transport->auth);
1452
1453   if (_dbus_credentials_include (auth_identity,
1454                                  DBUS_CREDENTIAL_WINDOWS_SID))
1455     {
1456       /* If no memory, we are supposed to return TRUE and set NULL */
1457       *windows_sid_p = _dbus_strdup (_dbus_credentials_get_windows_sid (auth_identity));
1458
1459       return TRUE;
1460     }
1461   else
1462     return FALSE;
1463 }
1464
1465 /**
1466  * See dbus_connection_set_windows_user_function().
1467  *
1468  * @param transport the transport
1469  * @param function the predicate
1470  * @param data data to pass to the predicate
1471  * @param free_data_function function to free the data
1472  * @param old_data the old user data to be freed
1473  * @param old_free_data_function old free data function to free it with
1474  */
1475
1476 void
1477 _dbus_transport_set_windows_user_function (DBusTransport              *transport,
1478                                            DBusAllowWindowsUserFunction   function,
1479                                            void                       *data,
1480                                            DBusFreeFunction            free_data_function,
1481                                            void                      **old_data,
1482                                            DBusFreeFunction           *old_free_data_function)
1483 {
1484   *old_data = transport->windows_user_data;
1485   *old_free_data_function = transport->free_windows_user_data;
1486
1487   transport->windows_user_function = function;
1488   transport->windows_user_data = data;
1489   transport->free_windows_user_data = free_data_function;
1490 }
1491
1492 /**
1493  * Sets the SASL authentication mechanisms supported by this transport.
1494  *
1495  * @param transport the transport
1496  * @param mechanisms the #NULL-terminated array of mechanisms
1497  *
1498  * @returns #FALSE if no memory
1499  */
1500 dbus_bool_t
1501 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
1502                                      const char    **mechanisms)
1503 {
1504   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
1505 }
1506
1507 /**
1508  * See dbus_connection_set_allow_anonymous()
1509  *
1510  * @param transport the transport
1511  * @param value #TRUE to allow anonymous connection
1512  */
1513 void
1514 _dbus_transport_set_allow_anonymous (DBusTransport              *transport,
1515                                      dbus_bool_t                 value)
1516 {
1517   transport->allow_anonymous = value != FALSE;
1518 }
1519
1520 #ifdef DBUS_ENABLE_STATS
1521 void
1522 _dbus_transport_get_stats (DBusTransport  *transport,
1523                            dbus_uint32_t  *queue_bytes,
1524                            dbus_uint32_t  *queue_fds,
1525                            dbus_uint32_t  *peak_queue_bytes,
1526                            dbus_uint32_t  *peak_queue_fds)
1527 {
1528   if (queue_bytes != NULL)
1529     *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
1530
1531   if (queue_fds != NULL)
1532     *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
1533
1534   if (peak_queue_bytes != NULL)
1535     *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
1536
1537   if (peak_queue_fds != NULL)
1538     *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
1539 }
1540 #endif /* DBUS_ENABLE_STATS */
1541
1542 /** @} */