Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     21  *
     22  */
     23 
     24 #include "dbus-transport-protected.h"
     25 #include "dbus-transport-unix.h"
     26 #include "dbus-transport-socket.h"
     27 #include "dbus-connection-internal.h"
     28 #include "dbus-watch.h"
     29 #include "dbus-auth.h"
     30 #include "dbus-address.h"
     31 #ifdef DBUS_BUILD_TESTS
     32 #include "dbus-server-debug-pipe.h"
     33 #endif
     34 
     35 /**
     36  * @defgroup DBusTransport DBusTransport object
     37  * @ingroup  DBusInternals
     38  * @brief "Backend" for a DBusConnection.
     39  *
     40  * Types and functions related to DBusTransport.  A transport is an
     41  * abstraction that can send and receive data via various kinds of
     42  * network connections or other IPC mechanisms.
     43  *
     44  * @{
     45  */
     46 
     47 /**
     48  * @typedef DBusTransport
     49  *
     50  * Opaque object representing a way message stream.
     51  * DBusTransport abstracts various kinds of actual
     52  * transport mechanism, such as different network protocols,
     53  * or encryption schemes.
     54  */
     55 
     56 static void
     57 live_messages_size_notify (DBusCounter *counter,
     58                            void        *user_data)
     59 {
     60   DBusTransport *transport = user_data;
     61 
     62   _dbus_transport_ref (transport);
     63 
     64 #if 0
     65   _dbus_verbose ("Counter value is now %d\n",
     66                  (int) _dbus_counter_get_value (counter));
     67 #endif
     68 
     69   /* disable or re-enable the read watch for the transport if
     70    * required.
     71    */
     72   if (transport->vtable->live_messages_changed)
     73     (* transport->vtable->live_messages_changed) (transport);
     74 
     75   _dbus_transport_unref (transport);
     76 }
     77 
     78 /**
     79  * Initializes the base class members of DBusTransport.  Chained up to
     80  * by subclasses in their constructor.  The server GUID is the
     81  * globally unique ID for the server creating this connection
     82  * and will be #NULL for the client side of a connection. The GUID
     83  * is in hex format.
     84  *
     85  * @param transport the transport being created.
     86  * @param vtable the subclass vtable.
     87  * @param server_guid non-#NULL if this transport is on the server side of a connection
     88  * @param address the address of the transport
     89  * @returns #TRUE on success.
     90  */
     91 dbus_bool_t
     92 _dbus_transport_init_base (DBusTransport             *transport,
     93                            const DBusTransportVTable *vtable,
     94                            const DBusString          *server_guid,
     95                            const DBusString          *address)
     96 {
     97   DBusMessageLoader *loader;
     98   DBusAuth *auth;
     99   DBusCounter *counter;
    100   char *address_copy;
    101 
    102   loader = _dbus_message_loader_new ();
    103   if (loader == NULL)
    104     return FALSE;
    105 
    106   if (server_guid)
    107     auth = _dbus_auth_server_new (server_guid);
    108   else
    109     auth = _dbus_auth_client_new ();
    110   if (auth == NULL)
    111     {
    112       _dbus_message_loader_unref (loader);
    113       return FALSE;
    114     }
    115 
    116   counter = _dbus_counter_new ();
    117   if (counter == NULL)
    118     {
    119       _dbus_auth_unref (auth);
    120       _dbus_message_loader_unref (loader);
    121       return FALSE;
    122     }
    123 
    124   if (server_guid)
    125     {
    126       _dbus_assert (address == NULL);
    127       address_copy = NULL;
    128     }
    129   else
    130     {
    131       _dbus_assert (address != NULL);
    132 
    133       if (!_dbus_string_copy_data (address, &address_copy))
    134         {
    135           _dbus_counter_unref (counter);
    136           _dbus_auth_unref (auth);
    137           _dbus_message_loader_unref (loader);
    138           return FALSE;
    139         }
    140     }
    141 
    142   transport->refcount = 1;
    143   transport->vtable = vtable;
    144   transport->loader = loader;
    145   transport->auth = auth;
    146   transport->live_messages_size = counter;
    147   transport->authenticated = FALSE;
    148   transport->disconnected = FALSE;
    149   transport->is_server = (server_guid != NULL);
    150   transport->send_credentials_pending = !transport->is_server;
    151   transport->receive_credentials_pending = transport->is_server;
    152   transport->address = address_copy;
    153 
    154   transport->unix_user_function = NULL;
    155   transport->unix_user_data = NULL;
    156   transport->free_unix_user_data = NULL;
    157 
    158   transport->expected_guid = NULL;
    159 
    160   /* Try to default to something that won't totally hose the system,
    161    * but doesn't impose too much of a limitation.
    162    */
    163   transport->max_live_messages_size = _DBUS_ONE_MEGABYTE * 63;
    164 
    165   transport->credentials.pid = -1;
    166   transport->credentials.uid = -1;
    167   transport->credentials.gid = -1;
    168 
    169   _dbus_counter_set_notify (transport->live_messages_size,
    170                             transport->max_live_messages_size,
    171                             live_messages_size_notify,
    172                             transport);
    173 
    174   if (transport->address)
    175     _dbus_verbose ("Initialized transport on address %s\n", transport->address);
    176 
    177   return TRUE;
    178 }
    179 
    180 /**
    181  * Finalizes base class members of DBusTransport.
    182  * Chained up to from subclass finalizers.
    183  *
    184  * @param transport the transport.
    185  */
    186 void
    187 _dbus_transport_finalize_base (DBusTransport *transport)
    188 {
    189   if (!transport->disconnected)
    190     _dbus_transport_disconnect (transport);
    191 
    192   if (transport->free_unix_user_data != NULL)
    193     (* transport->free_unix_user_data) (transport->unix_user_data);
    194 
    195   _dbus_message_loader_unref (transport->loader);
    196   _dbus_auth_unref (transport->auth);
    197   _dbus_counter_set_notify (transport->live_messages_size,
    198                             0, NULL, NULL);
    199   _dbus_counter_unref (transport->live_messages_size);
    200   dbus_free (transport->address);
    201   dbus_free (transport->expected_guid);
    202 }
    203 
    204 
    205 /**
    206  * Verifies if a given D-Bus address is a valid address
    207  * by attempting to connect to it. If it is, returns the
    208  * opened DBusTransport object. If it isn't, returns #NULL
    209  * and sets @p error.
    210  *
    211  * @param error address where an error can be returned.
    212  * @returns a new transport, or #NULL on failure.
    213  */
    214 static DBusTransport*
    215 check_address (const char *address, DBusError *error)
    216 {
    217   DBusAddressEntry **entries;
    218   DBusTransport *transport = NULL;
    219   int len, i;
    220 
    221   _dbus_assert (address != NULL);
    222   _dbus_assert (*address != '\0');
    223 
    224   if (!dbus_parse_address (address, &entries, &len, error))
    225     return FALSE;              /* not a valid address */
    226 
    227   for (i = 0; i < len; i++)
    228     {
    229       transport = _dbus_transport_open (entries[i], error);
    230       if (transport != NULL)
    231         break;
    232     }
    233 
    234   dbus_address_entries_free (entries);
    235   return transport;
    236 }
    237 
    238 /**
    239  * Creates a new transport for the "autostart" method.
    240  * This creates a client-side of a transport.
    241  *
    242  * @param error address where an error can be returned.
    243  * @returns a new transport, or #NULL on failure.
    244  */
    245 static DBusTransport*
    246 _dbus_transport_new_for_autolaunch (DBusError      *error)
    247 {
    248   DBusString address;
    249   DBusTransport *result = NULL;
    250 
    251   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    252 
    253   if (!_dbus_string_init (&address))
    254     {
    255       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    256       return NULL;
    257     }
    258 
    259   if (!_dbus_get_autolaunch_address (&address, error))
    260     {
    261       _DBUS_ASSERT_ERROR_IS_SET (error);
    262       goto out;
    263     }
    264 
    265   result = check_address (_dbus_string_get_const_data (&address), error);
    266   if (result == NULL)
    267     _DBUS_ASSERT_ERROR_IS_SET (error);
    268   else
    269     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    270 
    271  out:
    272   _dbus_string_free (&address);
    273   return result;
    274 }
    275 
    276 static DBusTransportOpenResult
    277 _dbus_transport_open_autolaunch (DBusAddressEntry  *entry,
    278                                  DBusTransport    **transport_p,
    279                                  DBusError         *error)
    280 {
    281   const char *method;
    282 
    283   method = dbus_address_entry_get_method (entry);
    284   _dbus_assert (method != NULL);
    285 
    286   if (strcmp (method, "autolaunch") == 0)
    287     {
    288       *transport_p = _dbus_transport_new_for_autolaunch (error);
    289 
    290       if (*transport_p == NULL)
    291         {
    292           _DBUS_ASSERT_ERROR_IS_SET (error);
    293           return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
    294         }
    295       else
    296         {
    297           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    298           return DBUS_TRANSPORT_OPEN_OK;
    299         }
    300     }
    301   else
    302     {
    303       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    304       return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
    305     }
    306 }
    307 
    308 static const struct {
    309   DBusTransportOpenResult (* func) (DBusAddressEntry *entry,
    310                                     DBusTransport   **transport_p,
    311                                     DBusError        *error);
    312 } open_funcs[] = {
    313   { _dbus_transport_open_socket },
    314   { _dbus_transport_open_platform_specific },
    315   { _dbus_transport_open_autolaunch }
    316 #ifdef DBUS_BUILD_TESTS
    317   , { _dbus_transport_open_debug_pipe }
    318 #endif
    319 };
    320 
    321 /**
    322  * Try to open a new transport for the given address entry.  (This
    323  * opens a client-side-of-the-connection transport.)
    324  *
    325  * @param entry the address entry
    326  * @param error location to store reason for failure.
    327  * @returns new transport of #NULL on failure.
    328  */
    329 DBusTransport*
    330 _dbus_transport_open (DBusAddressEntry *entry,
    331                       DBusError        *error)
    332 {
    333   DBusTransport *transport;
    334   const char *expected_guid_orig;
    335   char *expected_guid;
    336   int i;
    337   DBusError tmp_error;
    338 
    339   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    340 
    341   transport = NULL;
    342   expected_guid_orig = dbus_address_entry_get_value (entry, "guid");
    343   expected_guid = _dbus_strdup (expected_guid_orig);
    344 
    345   if (expected_guid_orig != NULL && expected_guid == NULL)
    346     {
    347       _DBUS_SET_OOM (error);
    348       return NULL;
    349     }
    350 
    351   dbus_error_init (&tmp_error);
    352   for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i)
    353     {
    354       DBusTransportOpenResult result;
    355 
    356       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
    357       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
    358 
    359       switch (result)
    360         {
    361         case DBUS_TRANSPORT_OPEN_OK:
    362           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
    363           goto out;
    364           break;
    365         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
    366           _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
    367           /* keep going through the loop of open funcs */
    368           break;
    369         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
    370           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
    371           goto out;
    372           break;
    373         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
    374           _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
    375           goto out;
    376           break;
    377         }
    378     }
    379 
    380  out:
    381 
    382   if (transport == NULL)
    383     {
    384       if (!dbus_error_is_set (&tmp_error))
    385         _dbus_set_bad_address (&tmp_error,
    386                                NULL, NULL,
    387                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
    388 
    389       _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
    390       dbus_move_error(&tmp_error, error);
    391       dbus_free (expected_guid);
    392     }
    393   else
    394     {
    395       _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
    396       transport->expected_guid = expected_guid;
    397     }
    398 
    399   return transport;
    400 }
    401 
    402 /**
    403  * Increments the reference count for the transport.
    404  *
    405  * @param transport the transport.
    406  * @returns the transport.
    407  */
    408 DBusTransport *
    409 _dbus_transport_ref (DBusTransport *transport)
    410 {
    411   _dbus_assert (transport->refcount > 0);
    412 
    413   transport->refcount += 1;
    414 
    415   return transport;
    416 }
    417 
    418 /**
    419  * Decrements the reference count for the transport.
    420  * Disconnects and finalizes the transport if
    421  * the reference count reaches zero.
    422  *
    423  * @param transport the transport.
    424  */
    425 void
    426 _dbus_transport_unref (DBusTransport *transport)
    427 {
    428   _dbus_assert (transport != NULL);
    429   _dbus_assert (transport->refcount > 0);
    430 
    431   transport->refcount -= 1;
    432   if (transport->refcount == 0)
    433     {
    434       _dbus_verbose ("%s: finalizing\n", _DBUS_FUNCTION_NAME);
    435 
    436       _dbus_assert (transport->vtable->finalize != NULL);
    437 
    438       (* transport->vtable->finalize) (transport);
    439     }
    440 }
    441 
    442 /**
    443  * Closes our end of the connection to a remote application. Further
    444  * attempts to use this transport will fail. Only the first call to
    445  * _dbus_transport_disconnect() will have an effect.
    446  *
    447  * @param transport the transport.
    448  *
    449  */
    450 void
    451 _dbus_transport_disconnect (DBusTransport *transport)
    452 {
    453   _dbus_verbose ("%s start\n", _DBUS_FUNCTION_NAME);
    454 
    455   _dbus_assert (transport->vtable->disconnect != NULL);
    456 
    457   if (transport->disconnected)
    458     return;
    459 
    460   (* transport->vtable->disconnect) (transport);
    461 
    462   transport->disconnected = TRUE;
    463 
    464   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
    465 }
    466 
    467 /**
    468  * Returns #TRUE if the transport has not been disconnected.
    469  * Disconnection can result from _dbus_transport_disconnect()
    470  * or because the server drops its end of the connection.
    471  *
    472  * @param transport the transport.
    473  * @returns whether we're connected
    474  */
    475 dbus_bool_t
    476 _dbus_transport_get_is_connected (DBusTransport *transport)
    477 {
    478   return !transport->disconnected;
    479 }
    480 
    481 /**
    482  * Returns #TRUE if we have been authenticated.  Will return #TRUE
    483  * even if the transport is disconnected.
    484  *
    485  * @todo we drop connection->mutex when calling the unix_user_function,
    486  * which may not be safe really.
    487  *
    488  * @param transport the transport
    489  * @returns whether we're authenticated
    490  */
    491 dbus_bool_t
    492 _dbus_transport_get_is_authenticated (DBusTransport *transport)
    493 {
    494   /* We don't want to run unix_user_function on Windows, but it
    495    * can exist, which allows application code to just unconditionally
    496    * set it and have it only be invoked when appropriate.
    497    */
    498   dbus_bool_t on_windows = FALSE;
    499 #ifdef DBUS_WIN
    500   on_windows = TRUE;
    501 #endif
    502 
    503   if (transport->authenticated)
    504     return TRUE;
    505   else
    506     {
    507       dbus_bool_t maybe_authenticated;
    508 
    509       if (transport->disconnected)
    510         return FALSE;
    511 
    512       /* paranoia ref since we call user callbacks sometimes */
    513       _dbus_connection_ref_unlocked (transport->connection);
    514 
    515       maybe_authenticated =
    516         (!(transport->send_credentials_pending ||
    517            transport->receive_credentials_pending));
    518 
    519       if (maybe_authenticated)
    520         {
    521           switch (_dbus_auth_do_work (transport->auth))
    522             {
    523             case DBUS_AUTH_STATE_AUTHENTICATED:
    524               /* leave as maybe_authenticated */
    525               break;
    526             default:
    527               maybe_authenticated = FALSE;
    528             }
    529         }
    530 
    531       if (maybe_authenticated && !transport->is_server)
    532         {
    533           const char *server_guid;
    534 
    535           server_guid = _dbus_auth_get_guid_from_server (transport->auth);
    536           _dbus_assert (server_guid != NULL);
    537 
    538           if (transport->expected_guid &&
    539               strcmp (transport->expected_guid, server_guid) != 0)
    540             {
    541               _dbus_verbose ("Client expected GUID '%s' and we got '%s' from the server\n",
    542                              transport->expected_guid, server_guid);
    543               _dbus_transport_disconnect (transport);
    544               _dbus_connection_unref_unlocked (transport->connection);
    545               return FALSE;
    546             }
    547 
    548           if (transport->expected_guid == NULL)
    549             {
    550               transport->expected_guid = _dbus_strdup (server_guid);
    551 
    552               if (transport->expected_guid == NULL)
    553                 {
    554                   _dbus_verbose ("No memory to complete auth in %s\n", _DBUS_FUNCTION_NAME);
    555                   return FALSE;
    556                 }
    557             }
    558         }
    559 
    560       /* If we've authenticated as some identity, check that the auth
    561        * identity is the same as our own identity.  In the future, we
    562        * may have API allowing applications to specify how this is
    563        * done, for example they may allow connection as any identity,
    564        * but then impose restrictions on certain identities.
    565        * Or they may give certain identities extra privileges.
    566        */
    567 
    568       if (maybe_authenticated && transport->is_server)
    569         {
    570           DBusCredentials auth_identity;
    571 
    572           _dbus_auth_get_identity (transport->auth, &auth_identity);
    573 
    574           if (transport->unix_user_function != NULL && !on_windows)
    575             {
    576               dbus_bool_t allow;
    577               DBusConnection *connection;
    578               DBusAllowUnixUserFunction unix_user_function;
    579               void *unix_user_data;
    580 
    581               /* Dropping the lock here probably isn't that safe. */
    582 
    583               connection = transport->connection;
    584               unix_user_function = transport->unix_user_function;
    585               unix_user_data = transport->unix_user_data;
    586 
    587               _dbus_verbose ("unlock %s\n", _DBUS_FUNCTION_NAME);
    588               _dbus_connection_unlock (connection);
    589 
    590               allow = (* unix_user_function) (connection,
    591                                               auth_identity.uid,
    592                                               unix_user_data);
    593 
    594               _dbus_verbose ("lock %s post unix user function\n", _DBUS_FUNCTION_NAME);
    595               _dbus_connection_lock (connection);
    596 
    597               if (allow)
    598                 {
    599                   _dbus_verbose ("Client UID "DBUS_UID_FORMAT" authorized\n", auth_identity.uid);
    600                 }
    601               else
    602                 {
    603                   _dbus_verbose ("Client UID "DBUS_UID_FORMAT
    604                                  " was rejected, disconnecting\n",
    605                                  auth_identity.uid);
    606                   _dbus_transport_disconnect (transport);
    607                   _dbus_connection_unref_unlocked (connection);
    608                   return FALSE;
    609                 }
    610             }
    611           else
    612             {
    613               DBusCredentials our_identity;
    614 
    615               _dbus_credentials_from_current_process (&our_identity);
    616 
    617               if (!_dbus_credentials_match (&our_identity,
    618                                             &auth_identity))
    619                 {
    620                   _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
    621                                  " but our UID is "DBUS_UID_FORMAT", disconnecting\n",
    622                                  auth_identity.uid, our_identity.uid);
    623                   _dbus_transport_disconnect (transport);
    624                   _dbus_connection_unref_unlocked (transport->connection);
    625                   return FALSE;
    626                 }
    627               else
    628                 {
    629                   _dbus_verbose ("Client authorized as UID "DBUS_UID_FORMAT
    630                                  " matching our UID "DBUS_UID_FORMAT"\n",
    631                                  auth_identity.uid, our_identity.uid);
    632                 }
    633             }
    634         }
    635 
    636       transport->authenticated = maybe_authenticated;
    637 
    638       _dbus_connection_unref_unlocked (transport->connection);
    639       return maybe_authenticated;
    640     }
    641 }
    642 
    643 /**
    644  * Gets the address of a transport. It will be
    645  * #NULL for a server-side transport.
    646  *
    647  * @param transport the transport
    648  * @returns transport's address
    649  */
    650 const char*
    651 _dbus_transport_get_address (DBusTransport *transport)
    652 {
    653   return transport->address;
    654 }
    655 
    656 /**
    657  * Handles a watch by reading data, writing data, or disconnecting
    658  * the transport, as appropriate for the given condition.
    659  *
    660  * @param transport the transport.
    661  * @param watch the watch.
    662  * @param condition the current state of the watched file descriptor.
    663  * @returns #FALSE if not enough memory to fully handle the watch
    664  */
    665 dbus_bool_t
    666 _dbus_transport_handle_watch (DBusTransport           *transport,
    667                               DBusWatch               *watch,
    668                               unsigned int             condition)
    669 {
    670   dbus_bool_t retval;
    671 
    672   _dbus_assert (transport->vtable->handle_watch != NULL);
    673 
    674   if (transport->disconnected)
    675     return TRUE;
    676 
    677   if (dbus_watch_get_fd (watch) < 0)
    678     {
    679       _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n");
    680       return TRUE;
    681     }
    682 
    683   _dbus_watch_sanitize_condition (watch, &condition);
    684 
    685   _dbus_transport_ref (transport);
    686   _dbus_watch_ref (watch);
    687   retval = (* transport->vtable->handle_watch) (transport, watch, condition);
    688   _dbus_watch_unref (watch);
    689   _dbus_transport_unref (transport);
    690 
    691   return retval;
    692 }
    693 
    694 /**
    695  * Sets the connection using this transport. Allows the transport
    696  * to add watches to the connection, queue incoming messages,
    697  * and pull outgoing messages.
    698  *
    699  * @param transport the transport.
    700  * @param connection the connection.
    701  * @returns #FALSE if not enough memory
    702  */
    703 dbus_bool_t
    704 _dbus_transport_set_connection (DBusTransport  *transport,
    705                                 DBusConnection *connection)
    706 {
    707   _dbus_assert (transport->vtable->connection_set != NULL);
    708   _dbus_assert (transport->connection == NULL);
    709 
    710   transport->connection = connection;
    711 
    712   _dbus_transport_ref (transport);
    713   if (!(* transport->vtable->connection_set) (transport))
    714     transport->connection = NULL;
    715   _dbus_transport_unref (transport);
    716 
    717   return transport->connection != NULL;
    718 }
    719 
    720 /**
    721  * Get the socket file descriptor, if any.
    722  *
    723  * @param transport the transport
    724  * @param fd_p pointer to fill in with the descriptor
    725  * @returns #TRUE if a descriptor was available
    726  */
    727 dbus_bool_t
    728 _dbus_transport_get_socket_fd (DBusTransport *transport,
    729                                int           *fd_p)
    730 {
    731   dbus_bool_t retval;
    732 
    733   if (transport->vtable->get_socket_fd == NULL)
    734     return FALSE;
    735 
    736   if (transport->disconnected)
    737     return FALSE;
    738 
    739   _dbus_transport_ref (transport);
    740 
    741   retval = (* transport->vtable->get_socket_fd) (transport,
    742                                                  fd_p);
    743 
    744   _dbus_transport_unref (transport);
    745 
    746   return retval;
    747 }
    748 
    749 /**
    750  * Performs a single poll()/select() on the transport's file
    751  * descriptors and then reads/writes data as appropriate,
    752  * queueing incoming messages and sending outgoing messages.
    753  * This is the backend for _dbus_connection_do_iteration().
    754  * See _dbus_connection_do_iteration() for full details.
    755  *
    756  * @param transport the transport.
    757  * @param flags indicates whether to read or write, and whether to block.
    758  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
    759  */
    760 void
    761 _dbus_transport_do_iteration (DBusTransport  *transport,
    762                               unsigned int    flags,
    763                               int             timeout_milliseconds)
    764 {
    765   _dbus_assert (transport->vtable->do_iteration != NULL);
    766 
    767   _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n",
    768                  flags, timeout_milliseconds, !transport->disconnected);
    769 
    770   if ((flags & (DBUS_ITERATION_DO_WRITING |
    771                 DBUS_ITERATION_DO_READING)) == 0)
    772     return; /* Nothing to do */
    773 
    774   if (transport->disconnected)
    775     return;
    776 
    777   _dbus_transport_ref (transport);
    778   (* transport->vtable->do_iteration) (transport, flags,
    779                                        timeout_milliseconds);
    780   _dbus_transport_unref (transport);
    781 
    782   _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME);
    783 }
    784 
    785 static dbus_bool_t
    786 recover_unused_bytes (DBusTransport *transport)
    787 {
    788   if (_dbus_auth_needs_decoding (transport->auth))
    789     {
    790       DBusString plaintext;
    791       const DBusString *encoded;
    792       DBusString *buffer;
    793       int orig_len;
    794 
    795       if (!_dbus_string_init (&plaintext))
    796         goto nomem;
    797 
    798       _dbus_auth_get_unused_bytes (transport->auth,
    799                                    &encoded);
    800 
    801       if (!_dbus_auth_decode_data (transport->auth,
    802                                    encoded, &plaintext))
    803         {
    804           _dbus_string_free (&plaintext);
    805           goto nomem;
    806         }
    807 
    808       _dbus_message_loader_get_buffer (transport->loader,
    809                                        &buffer);
    810 
    811       orig_len = _dbus_string_get_length (buffer);
    812 
    813       if (!_dbus_string_move (&plaintext, 0, buffer,
    814                               orig_len))
    815         {
    816           _dbus_string_free (&plaintext);
    817           goto nomem;
    818         }
    819 
    820       _dbus_verbose (" %d unused bytes sent to message loader\n",
    821                      _dbus_string_get_length (buffer) -
    822                      orig_len);
    823 
    824       _dbus_message_loader_return_buffer (transport->loader,
    825                                           buffer,
    826                                           _dbus_string_get_length (buffer) -
    827                                           orig_len);
    828 
    829       _dbus_auth_delete_unused_bytes (transport->auth);
    830 
    831       _dbus_string_free (&plaintext);
    832     }
    833   else
    834     {
    835       const DBusString *bytes;
    836       DBusString *buffer;
    837       int orig_len;
    838       dbus_bool_t succeeded;
    839 
    840       _dbus_message_loader_get_buffer (transport->loader,
    841                                        &buffer);
    842 
    843       orig_len = _dbus_string_get_length (buffer);
    844 
    845       _dbus_auth_get_unused_bytes (transport->auth,
    846                                    &bytes);
    847 
    848       succeeded = TRUE;
    849       if (!_dbus_string_copy (bytes, 0, buffer, _dbus_string_get_length (buffer)))
    850         succeeded = FALSE;
    851 
    852       _dbus_verbose (" %d unused bytes sent to message loader\n",
    853                      _dbus_string_get_length (buffer) -
    854                      orig_len);
    855 
    856       _dbus_message_loader_return_buffer (transport->loader,
    857                                           buffer,
    858                                           _dbus_string_get_length (buffer) -
    859                                           orig_len);
    860 
    861       if (succeeded)
    862         _dbus_auth_delete_unused_bytes (transport->auth);
    863       else
    864         goto nomem;
    865     }
    866 
    867   return TRUE;
    868 
    869  nomem:
    870   _dbus_verbose ("Not enough memory to transfer unused bytes from auth conversation\n");
    871   return FALSE;
    872 }
    873 
    874 /**
    875  * Reports our current dispatch status (whether there's buffered
    876  * data to be queued as messages, or not, or we need memory).
    877  *
    878  * @param transport the transport
    879  * @returns current status
    880  */
    881 DBusDispatchStatus
    882 _dbus_transport_get_dispatch_status (DBusTransport *transport)
    883 {
    884   if (_dbus_counter_get_value (transport->live_messages_size) >= transport->max_live_messages_size)
    885     return DBUS_DISPATCH_COMPLETE; /* complete for now */
    886 
    887   if (!_dbus_transport_get_is_authenticated (transport))
    888     {
    889       if (_dbus_auth_do_work (transport->auth) ==
    890           DBUS_AUTH_STATE_WAITING_FOR_MEMORY)
    891         return DBUS_DISPATCH_NEED_MEMORY;
    892       else if (!_dbus_transport_get_is_authenticated (transport))
    893         return DBUS_DISPATCH_COMPLETE;
    894     }
    895 
    896   if (!transport->unused_bytes_recovered &&
    897       !recover_unused_bytes (transport))
    898     return DBUS_DISPATCH_NEED_MEMORY;
    899 
    900   transport->unused_bytes_recovered = TRUE;
    901 
    902   if (!_dbus_message_loader_queue_messages (transport->loader))
    903     return DBUS_DISPATCH_NEED_MEMORY;
    904 
    905   if (_dbus_message_loader_peek_message (transport->loader) != NULL)
    906     return DBUS_DISPATCH_DATA_REMAINS;
    907   else
    908     return DBUS_DISPATCH_COMPLETE;
    909 }
    910 
    911 /**
    912  * Processes data we've read while handling a watch, potentially
    913  * converting some of it to messages and queueing those messages on
    914  * the connection.
    915  *
    916  * @param transport the transport
    917  * @returns #TRUE if we had enough memory to queue all messages
    918  */
    919 dbus_bool_t
    920 _dbus_transport_queue_messages (DBusTransport *transport)
    921 {
    922   DBusDispatchStatus status;
    923 
    924 #if 0
    925   _dbus_verbose ("_dbus_transport_queue_messages()\n");
    926 #endif
    927 
    928   /* Queue any messages */
    929   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)
    930     {
    931       DBusMessage *message;
    932       DBusList *link;
    933 
    934       link = _dbus_message_loader_pop_message_link (transport->loader);
    935       _dbus_assert (link != NULL);
    936 
    937       message = link->data;
    938 
    939       _dbus_verbose ("queueing received message %p\n", message);
    940 
    941       if (!_dbus_message_add_size_counter (message, transport->live_messages_size))
    942         {
    943           _dbus_message_loader_putback_message_link (transport->loader,
    944                                                      link);
    945           status = DBUS_DISPATCH_NEED_MEMORY;
    946           break;
    947         }
    948       else
    949         {
    950           /* pass ownership of link and message ref to connection */
    951           _dbus_connection_queue_received_message_link (transport->connection,
    952                                                         link);
    953         }
    954     }
    955 
    956   if (_dbus_message_loader_get_is_corrupted (transport->loader))
    957     {
    958       _dbus_verbose ("Corrupted message stream, disconnecting\n");
    959       _dbus_transport_disconnect (transport);
    960     }
    961 
    962   return status != DBUS_DISPATCH_NEED_MEMORY;
    963 }
    964 
    965 /**
    966  * See dbus_connection_set_max_message_size().
    967  *
    968  * @param transport the transport
    969  * @param size the max size of a single message
    970  */
    971 void
    972 _dbus_transport_set_max_message_size (DBusTransport  *transport,
    973                                       long            size)
    974 {
    975   _dbus_message_loader_set_max_message_size (transport->loader, size);
    976 }
    977 
    978 /**
    979  * See dbus_connection_get_max_message_size().
    980  *
    981  * @param transport the transport
    982  * @returns max message size
    983  */
    984 long
    985 _dbus_transport_get_max_message_size (DBusTransport  *transport)
    986 {
    987   return _dbus_message_loader_get_max_message_size (transport->loader);
    988 }
    989 
    990 /**
    991  * See dbus_connection_set_max_received_size().
    992  *
    993  * @param transport the transport
    994  * @param size the max size of all incoming messages
    995  */
    996 void
    997 _dbus_transport_set_max_received_size (DBusTransport  *transport,
    998                                        long            size)
    999 {
   1000   transport->max_live_messages_size = size;
   1001   _dbus_counter_set_notify (transport->live_messages_size,
   1002                             transport->max_live_messages_size,
   1003                             live_messages_size_notify,
   1004                             transport);
   1005 }
   1006 
   1007 
   1008 /**
   1009  * See dbus_connection_get_max_received_size().
   1010  *
   1011  * @param transport the transport
   1012  * @returns max bytes for all live messages
   1013  */
   1014 long
   1015 _dbus_transport_get_max_received_size (DBusTransport  *transport)
   1016 {
   1017   return transport->max_live_messages_size;
   1018 }
   1019 
   1020 /**
   1021  * See dbus_connection_get_unix_user().
   1022  *
   1023  * @param transport the transport
   1024  * @param uid return location for the user ID
   1025  * @returns #TRUE if uid is filled in with a valid user ID
   1026  */
   1027 dbus_bool_t
   1028 _dbus_transport_get_unix_user (DBusTransport *transport,
   1029                                unsigned long *uid)
   1030 {
   1031   DBusCredentials auth_identity;
   1032 
   1033   *uid = _DBUS_INT32_MAX; /* better than some root or system user in
   1034                            * case of bugs in the caller. Caller should
   1035                            * never use this value on purpose, however.
   1036                            */
   1037 
   1038   if (!transport->authenticated)
   1039     return FALSE;
   1040 
   1041   _dbus_auth_get_identity (transport->auth, &auth_identity);
   1042 
   1043   if (auth_identity.uid != DBUS_UID_UNSET)
   1044     {
   1045       *uid = auth_identity.uid;
   1046       return TRUE;
   1047     }
   1048   else
   1049     return FALSE;
   1050 }
   1051 
   1052 /**
   1053  * See dbus_connection_get_unix_process_id().
   1054  *
   1055  * @param transport the transport
   1056  * @param pid return location for the process ID
   1057  * @returns #TRUE if uid is filled in with a valid process ID
   1058  */
   1059 dbus_bool_t
   1060 _dbus_transport_get_unix_process_id (DBusTransport *transport,
   1061 				     unsigned long *pid)
   1062 {
   1063   DBusCredentials auth_identity;
   1064 
   1065   *pid = DBUS_PID_UNSET; /* Caller should never use this value on purpose,
   1066 			  * but we set it to a safe number, INT_MAX,
   1067 			  * just to root out possible bugs in bad callers.
   1068 			  */
   1069 
   1070   if (!transport->authenticated)
   1071     return FALSE;
   1072 
   1073   _dbus_auth_get_identity (transport->auth, &auth_identity);
   1074 
   1075   if (auth_identity.pid != DBUS_PID_UNSET)
   1076     {
   1077       *pid = auth_identity.pid;
   1078       return TRUE;
   1079     }
   1080   else
   1081     return FALSE;
   1082 }
   1083 
   1084 /**
   1085  * See dbus_connection_set_unix_user_function().
   1086  *
   1087  * @param transport the transport
   1088  * @param function the predicate
   1089  * @param data data to pass to the predicate
   1090  * @param free_data_function function to free the data
   1091  * @param old_data the old user data to be freed
   1092  * @param old_free_data_function old free data function to free it with
   1093  */
   1094 void
   1095 _dbus_transport_set_unix_user_function (DBusTransport             *transport,
   1096                                         DBusAllowUnixUserFunction  function,
   1097                                         void                      *data,
   1098                                         DBusFreeFunction           free_data_function,
   1099                                         void                     **old_data,
   1100                                         DBusFreeFunction          *old_free_data_function)
   1101 {
   1102   *old_data = transport->unix_user_data;
   1103   *old_free_data_function = transport->free_unix_user_data;
   1104 
   1105   transport->unix_user_function = function;
   1106   transport->unix_user_data = data;
   1107   transport->free_unix_user_data = free_data_function;
   1108 }
   1109 
   1110 /**
   1111  * Sets the SASL authentication mechanisms supported by this transport.
   1112  *
   1113  * @param transport the transport
   1114  * @param mechanisms the #NULL-terminated array of mechanisms
   1115  *
   1116  * @returns #FALSE if no memory
   1117  */
   1118 dbus_bool_t
   1119 _dbus_transport_set_auth_mechanisms (DBusTransport  *transport,
   1120                                      const char    **mechanisms)
   1121 {
   1122   return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
   1123 }
   1124 
   1125 
   1126 /** @} */
   1127