LCOV - code coverage report
Current view: top level - sbus - sssd_dbus_connection.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 245 0.0 %
Date: 2012-11-29 Functions: 0 22 0.0 %
Branches: 0 412 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :     Authors:
       3                 :            :         Simo Sorce <ssorce@redhat.com>
       4                 :            :         Stephen Gallagher <sgallagh@redhat.com>
       5                 :            : 
       6                 :            :     Copyright (C) 2009 Red Hat
       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 3 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, see <http://www.gnu.org/licenses/>.
      20                 :            : */
      21                 :            : 
      22                 :            : #include <sys/time.h>
      23                 :            : #include "util/util.h"
      24                 :            : #include "dbus/dbus.h"
      25                 :            : #include "sbus/sssd_dbus.h"
      26                 :            : #include "sbus/sssd_dbus_private.h"
      27                 :            : 
      28                 :            : /* Types */
      29                 :            : struct dbus_ctx_list;
      30                 :            : 
      31                 :            : struct sbus_interface_p {
      32                 :            :     struct sbus_interface_p *prev, *next;
      33                 :            :     struct sbus_connection *conn;
      34                 :            :     struct sbus_interface *intf;
      35                 :            : };
      36                 :            : 
      37                 :            : static bool path_in_interface_list(struct sbus_interface_p *list,
      38                 :            :                                    const char *path);
      39                 :            : static void sbus_unreg_object_paths(struct sbus_connection *conn);
      40                 :            : 
      41                 :            : static int sbus_auto_reconnect(struct sbus_connection *conn);
      42                 :            : 
      43                 :          0 : static void sbus_dispatch(struct tevent_context *ev,
      44                 :            :                           struct tevent_timer *te,
      45                 :            :                           struct timeval tv, void *data)
      46                 :            : {
      47                 :            :     struct tevent_timer *new_event;
      48                 :            :     struct sbus_connection *conn;
      49                 :            :     DBusConnection *dbus_conn;
      50                 :            :     int ret;
      51                 :            : 
      52         [ #  # ]:          0 :     if (data == NULL) return;
      53                 :            : 
      54                 :          0 :     conn = talloc_get_type(data, struct sbus_connection);
      55                 :            : 
      56                 :          0 :     dbus_conn = conn->dbus.conn;
      57 [ #  # ][ #  # ]:          0 :     DEBUG(9, ("dbus conn: %lX\n", dbus_conn));
         [ #  # ][ #  # ]
                 [ #  # ]
      58                 :            : 
      59         [ #  # ]:          0 :     if (conn->retries > 0) {
      60 [ #  # ][ #  # ]:          0 :         DEBUG(6, ("SBUS is reconnecting. Deferring.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      61                 :            :         /* Currently trying to reconnect, defer dispatch for 30ms */
      62                 :          0 :         tv = tevent_timeval_current_ofs(0, 30);
      63                 :          0 :         new_event = tevent_add_timer(ev, conn, tv, sbus_dispatch, conn);
      64         [ #  # ]:          0 :         if (new_event == NULL) {
      65 [ #  # ][ #  # ]:          0 :             DEBUG(0,("Could not defer dispatch!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      66                 :            :         }
      67                 :            :         return;
      68                 :            :     }
      69                 :            : 
      70 [ #  # ][ #  # ]:          0 :     if ((!dbus_connection_get_is_connected(dbus_conn)) &&
      71                 :          0 :         (conn->max_retries != 0)) {
      72                 :            :         /* Attempt to reconnect automatically */
      73                 :          0 :         ret = sbus_auto_reconnect(conn);
      74         [ #  # ]:          0 :         if (ret == EOK) {
      75 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("Performing auto-reconnect\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      76                 :            :             return;
      77                 :            :         }
      78                 :            : 
      79 [ #  # ][ #  # ]:          0 :         DEBUG(0, ("Cannot start auto-reconnection.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      80                 :          0 :         conn->reconnect_callback(conn,
      81                 :            :                                  SBUS_RECONNECT_ERROR,
      82                 :            :                                  conn->reconnect_pvt);
      83                 :          0 :         return;
      84                 :            :     }
      85                 :            : 
      86   [ #  #  #  # ]:          0 :     if ((conn->disconnect) ||
      87                 :          0 :         (!dbus_connection_get_is_connected(dbus_conn))) {
      88 [ #  # ][ #  # ]:          0 :         DEBUG(3,("Connection is not open for dispatching.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
      89                 :            :         /*
      90                 :            :          * Free the connection object.
      91                 :            :          * This will invoke the destructor for the connection
      92                 :            :          */
      93                 :          0 :         talloc_free(conn);
      94                 :          0 :         conn = NULL;
      95                 :          0 :         return;
      96                 :            :     }
      97                 :            : 
      98                 :            :     /* Dispatch only once each time through the mainloop to avoid
      99                 :            :      * starving other features
     100                 :            :      */
     101                 :          0 :     ret = dbus_connection_get_dispatch_status(dbus_conn);
     102         [ #  # ]:          0 :     if (ret != DBUS_DISPATCH_COMPLETE) {
     103 [ #  # ][ #  # ]:          0 :         DEBUG(9,("Dispatching.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     104                 :          0 :         dbus_connection_dispatch(dbus_conn);
     105                 :            :     }
     106                 :            : 
     107                 :            :     /* If other dispatches are waiting, queue up the dispatch function
     108                 :            :      * for the next loop.
     109                 :            :      */
     110                 :          0 :     ret = dbus_connection_get_dispatch_status(dbus_conn);
     111         [ #  # ]:          0 :     if (ret != DBUS_DISPATCH_COMPLETE) {
     112                 :          0 :         new_event = tevent_add_timer(ev, conn, tv, sbus_dispatch, conn);
     113         [ #  # ]:          0 :         if (new_event == NULL) {
     114 [ #  # ][ #  # ]:          0 :             DEBUG(2,("Could not add dispatch event!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     115                 :            : 
     116                 :            :             /* TODO: Calling exit here is bad */
     117                 :          0 :             exit(1);
     118                 :            :         }
     119                 :            :     }
     120                 :            : }
     121                 :            : 
     122                 :            : /* dbus_connection_wakeup_main
     123                 :            :  * D-BUS makes a callback to the wakeup_main function when
     124                 :            :  * it has data available for dispatching.
     125                 :            :  * In order to avoid blocking, this function will create a now()
     126                 :            :  * timed event to perform the dispatch during the next iteration
     127                 :            :  * through the mainloop
     128                 :            :  */
     129                 :          0 : static void sbus_conn_wakeup_main(void *data)
     130                 :            : {
     131                 :            :     struct sbus_connection *conn;
     132                 :            :     struct timeval tv;
     133                 :            :     struct tevent_timer *te;
     134                 :            : 
     135                 :          0 :     conn = talloc_get_type(data, struct sbus_connection);
     136                 :            : 
     137                 :          0 :     tv = tevent_timeval_current();
     138                 :            : 
     139                 :            :     /* D-BUS calls this function when it is time to do a dispatch */
     140                 :          0 :     te = tevent_add_timer(conn->ev, conn, tv, sbus_dispatch, conn);
     141         [ #  # ]:          0 :     if (te == NULL) {
     142 [ #  # ][ #  # ]:          0 :         DEBUG(2,("Could not add dispatch event!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     143                 :            :         /* TODO: Calling exit here is bad */
     144                 :          0 :         exit(1);
     145                 :            :     }
     146                 :          0 : }
     147                 :            : 
     148                 :            : static int sbus_conn_set_fns(struct sbus_connection *conn);
     149                 :            : 
     150                 :            : /*
     151                 :            :  * integrate_connection_with_event_loop
     152                 :            :  * Set up a D-BUS connection to use the libevents mainloop
     153                 :            :  * for handling file descriptor and timed events
     154                 :            :  */
     155                 :          0 : int sbus_init_connection(TALLOC_CTX *ctx,
     156                 :            :                          struct tevent_context *ev,
     157                 :            :                          DBusConnection *dbus_conn,
     158                 :            :                          struct sbus_interface *intf,
     159                 :            :                          int connection_type,
     160                 :            :                          struct sbus_connection **_conn)
     161                 :            : {
     162                 :            :     struct sbus_connection *conn;
     163                 :            :     int ret;
     164                 :            : 
     165 [ #  # ][ #  # ]:          0 :     DEBUG(5,("Adding connection %lX\n", dbus_conn));
         [ #  # ][ #  # ]
                 [ #  # ]
     166                 :          0 :     conn = talloc_zero(ctx, struct sbus_connection);
     167                 :            : 
     168                 :          0 :     conn->ev = ev;
     169                 :          0 :     conn->type = SBUS_CONNECTION;
     170                 :          0 :     conn->dbus.conn = dbus_conn;
     171                 :          0 :     conn->connection_type = connection_type;
     172                 :            : 
     173                 :          0 :     ret = sbus_conn_add_interface(conn, intf);
     174         [ #  # ]:          0 :     if (ret != EOK) {
     175                 :          0 :         talloc_free(conn);
     176                 :          0 :         return ret;
     177                 :            :     }
     178                 :            : 
     179                 :          0 :     ret = sbus_conn_set_fns(conn);
     180         [ #  # ]:          0 :     if (ret != EOK) {
     181                 :          0 :         talloc_free(conn);
     182                 :          0 :         return ret;
     183                 :            :     }
     184                 :            : 
     185                 :          0 :     *_conn = conn;
     186                 :          0 :     return ret;
     187                 :            : }
     188                 :            : 
     189                 :          0 : static int sbus_conn_set_fns(struct sbus_connection *conn)
     190                 :            : {
     191                 :            :     dbus_bool_t dbret;
     192                 :            : 
     193                 :            :     /*
     194                 :            :      * Set the default destructor
     195                 :            :      * Connections can override this with
     196                 :            :      * sbus_conn_set_destructor
     197                 :            :      */
     198                 :          0 :     sbus_conn_set_destructor(conn, NULL);
     199                 :            : 
     200                 :            :     /* Set up DBusWatch functions */
     201                 :          0 :     dbret = dbus_connection_set_watch_functions(conn->dbus.conn,
     202                 :            :                                                 sbus_add_watch,
     203                 :            :                                                 sbus_remove_watch,
     204                 :            :                                                 sbus_toggle_watch,
     205                 :            :                                                 conn, NULL);
     206         [ #  # ]:          0 :     if (!dbret) {
     207 [ #  # ][ #  # ]:          0 :         DEBUG(2,("Error setting up D-BUS connection watch functions\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     208                 :            :         return EIO;
     209                 :            :     }
     210                 :            : 
     211                 :            :     /* Set up DBusTimeout functions */
     212                 :          0 :     dbret = dbus_connection_set_timeout_functions(conn->dbus.conn,
     213                 :            :                                                   sbus_add_timeout,
     214                 :            :                                                   sbus_remove_timeout,
     215                 :            :                                                   sbus_toggle_timeout,
     216                 :            :                                                   conn, NULL);
     217         [ #  # ]:          0 :     if (!dbret) {
     218 [ #  # ][ #  # ]:          0 :         DEBUG(2,("Error setting up D-BUS server timeout functions\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     219                 :            :         /* FIXME: free resources ? */
     220                 :            :         return EIO;
     221                 :            :     }
     222                 :            : 
     223                 :            :     /* Set up dispatch handler */
     224                 :          0 :     dbus_connection_set_wakeup_main_function(conn->dbus.conn,
     225                 :            :                                              sbus_conn_wakeup_main,
     226                 :            :                                              conn, NULL);
     227                 :            : 
     228                 :            :     /* Set up any method_contexts passed in */
     229                 :            : 
     230                 :            :     /* Attempt to dispatch immediately in case of opportunistic
     231                 :            :      * services connecting before the handlers were all up.
     232                 :            :      * If there are no messages to be dispatched, this will do
     233                 :            :      * nothing.
     234                 :            :      */
     235                 :          0 :     sbus_conn_wakeup_main(conn);
     236                 :            : 
     237                 :          0 :     return EOK;
     238                 :            : }
     239                 :            : 
     240                 :          0 : int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev,
     241                 :            :                         const char *address, struct sbus_interface *intf,
     242                 :            :                         struct sbus_connection **_conn)
     243                 :            : {
     244                 :            :     struct sbus_connection *conn;
     245                 :            :     DBusConnection *dbus_conn;
     246                 :            :     DBusError dbus_error;
     247                 :            :     int ret;
     248                 :            : 
     249                 :          0 :     dbus_error_init(&dbus_error);
     250                 :            : 
     251                 :            :     /* Open a shared D-BUS connection to the address */
     252                 :          0 :     dbus_conn = dbus_connection_open(address, &dbus_error);
     253         [ #  # ]:          0 :     if (!dbus_conn) {
     254 [ #  # ][ #  # ]:          0 :         DEBUG(1, ("Failed to open connection: name=%s, message=%s\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     255                 :            :                 dbus_error.name, dbus_error.message));
     256         [ #  # ]:          0 :         if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
     257                 :            :         return EIO;
     258                 :            :     }
     259                 :            : 
     260                 :          0 :     ret = sbus_init_connection(ctx, ev, dbus_conn, intf,
     261                 :            :                                SBUS_CONN_TYPE_SHARED, &conn);
     262                 :            :     if (ret != EOK) {
     263                 :            :         /* FIXME: release resources */
     264                 :            :     }
     265                 :            : 
     266                 :            :     /* Store the address for later reconnection */
     267                 :          0 :     conn->address = talloc_strdup(conn, address);
     268                 :            : 
     269                 :          0 :     dbus_connection_set_exit_on_disconnect(conn->dbus.conn, FALSE);
     270                 :            : 
     271                 :          0 :     *_conn = conn;
     272                 :            :     return ret;
     273                 :            : }
     274                 :            : 
     275                 :            : /*
     276                 :            :  * sbus_conn_set_destructor
     277                 :            :  * Configures a callback to clean up this connection when it
     278                 :            :  * is finalized.
     279                 :            :  * @param conn The sbus_connection created
     280                 :            :  * when this connection was established
     281                 :            :  * @param destructor The destructor function that should be
     282                 :            :  * called when the connection is finalized. If passed NULL,
     283                 :            :  * this will reset the connection to the default destructor.
     284                 :            :  */
     285                 :          0 : void sbus_conn_set_destructor(struct sbus_connection *conn,
     286                 :            :                               sbus_conn_destructor_fn destructor)
     287                 :            : {
     288         [ #  # ]:          0 :     if (!conn) return;
     289                 :            : 
     290                 :          0 :     conn->destructor = destructor;
     291                 :            :     /* TODO: Should we try to handle the talloc_destructor too? */
     292                 :            : }
     293                 :            : 
     294                 :          0 : int sbus_default_connection_destructor(void *ctx)
     295                 :            : {
     296                 :            :     struct sbus_connection *conn;
     297                 :          0 :     conn = talloc_get_type(ctx, struct sbus_connection);
     298                 :            : 
     299 [ #  # ][ #  # ]:          0 :     DEBUG(5, ("Invoking default destructor on connection %lX\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     300                 :            :               conn->dbus.conn));
     301         [ #  # ]:          0 :     if (conn->connection_type == SBUS_CONN_TYPE_PRIVATE) {
     302                 :            :         /* Private connections must be closed explicitly */
     303                 :          0 :         dbus_connection_close(conn->dbus.conn);
     304                 :            :     }
     305         [ #  # ]:          0 :     else if (conn->connection_type == SBUS_CONN_TYPE_SHARED) {
     306                 :            :         /* Shared connections are destroyed when their last reference is removed */
     307                 :            :     }
     308                 :            :     else {
     309                 :            :         /* Critical Error! */
     310 [ #  # ][ #  # ]:          0 :         DEBUG(1,("Critical Error, connection_type is neither shared nor private!\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     311                 :            :         return -1;
     312                 :            :     }
     313                 :            : 
     314                 :            :     /* Remove object path */
     315                 :            :     /* TODO: Remove object paths */
     316                 :            : 
     317                 :          0 :     dbus_connection_unref(conn->dbus.conn);
     318                 :          0 :     return 0;
     319                 :            : }
     320                 :            : 
     321                 :            : /*
     322                 :            :  * sbus_get_connection
     323                 :            :  * Utility function to retreive the DBusConnection object
     324                 :            :  * from a sbus_connection
     325                 :            :  */
     326                 :          0 : DBusConnection *sbus_get_connection(struct sbus_connection *conn)
     327                 :            : {
     328                 :          0 :     return conn->dbus.conn;
     329                 :            : }
     330                 :            : 
     331                 :          0 : void sbus_disconnect (struct sbus_connection *conn)
     332                 :            : {
     333         [ #  # ]:          0 :     if (conn == NULL) {
     334                 :          0 :         return;
     335                 :            :     }
     336                 :            : 
     337 [ #  # ][ #  # ]:          0 :     DEBUG(5,("Disconnecting %lX\n", conn->dbus.conn));
         [ #  # ][ #  # ]
                 [ #  # ]
     338                 :            : 
     339                 :            :     /*******************************
     340                 :            :      *  Referencing conn->dbus.conn */
     341                 :          0 :     dbus_connection_ref(conn->dbus.conn);
     342                 :            : 
     343                 :          0 :     conn->disconnect = 1;
     344                 :            : 
     345                 :            :     /* Invoke the custom destructor, if it exists */
     346         [ #  # ]:          0 :     if (conn->destructor) {
     347                 :          0 :         conn->destructor(conn);
     348                 :            :     }
     349                 :            : 
     350                 :            :     /* Unregister object paths */
     351                 :          0 :     sbus_unreg_object_paths(conn);
     352                 :            : 
     353                 :            :     /* Disable watch functions */
     354                 :          0 :     dbus_connection_set_watch_functions(conn->dbus.conn,
     355                 :            :                                         NULL, NULL, NULL,
     356                 :            :                                         NULL, NULL);
     357                 :            :     /* Disable timeout functions */
     358                 :          0 :     dbus_connection_set_timeout_functions(conn->dbus.conn,
     359                 :            :                                           NULL, NULL, NULL,
     360                 :            :                                           NULL, NULL);
     361                 :            : 
     362                 :            :     /* Disable dispatch status function */
     363                 :          0 :     dbus_connection_set_dispatch_status_function(conn->dbus.conn,
     364                 :            :                                                  NULL, NULL, NULL);
     365                 :            : 
     366                 :            :     /* Disable wakeup main function */
     367                 :          0 :     dbus_connection_set_wakeup_main_function(conn->dbus.conn,
     368                 :            :                                              NULL, NULL, NULL);
     369                 :            : 
     370                 :            :     /* Finalize the connection */
     371                 :          0 :     sbus_default_connection_destructor(conn);
     372                 :            : 
     373                 :          0 :     dbus_connection_unref(conn->dbus.conn);
     374                 :            :     /* Unreferenced conn->dbus_conn *
     375                 :            :      ******************************/
     376                 :            : 
     377 [ #  # ][ #  # ]:          0 :     DEBUG(5,("Disconnected %lX\n", conn->dbus.conn));
         [ #  # ][ #  # ]
                 [ #  # ]
     378                 :            : }
     379                 :            : 
     380                 :          0 : static int sbus_reply_internal_error(DBusMessage *message,
     381                 :            :                                      struct sbus_connection *conn) {
     382                 :          0 :     DBusMessage *reply = dbus_message_new_error(message, DBUS_ERROR_IO_ERROR,
     383                 :            :                                                 "Internal Error");
     384         [ #  # ]:          0 :     if (reply) {
     385                 :          0 :         sbus_conn_send_reply(conn, reply);
     386                 :          0 :         dbus_message_unref(reply);
     387                 :          0 :         return DBUS_HANDLER_RESULT_HANDLED;
     388                 :            :     }
     389                 :            :     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     390                 :            : }
     391                 :            : 
     392                 :            : /* messsage_handler
     393                 :            :  * Receive messages and process them
     394                 :            :  */
     395                 :          0 : DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
     396                 :            :                                          DBusMessage *message,
     397                 :            :                                          void *user_data)
     398                 :            : {
     399                 :            :     struct sbus_interface_p *intf_p;
     400                 :            :     const char *method;
     401                 :            :     const char *path;
     402                 :            :     const char *msg_interface;
     403                 :          0 :     DBusMessage *reply = NULL;
     404                 :            :     int i, ret;
     405                 :            :     int found;
     406                 :            : 
     407         [ #  # ]:          0 :     if (!user_data) {
     408                 :            :         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     409                 :            :     }
     410                 :          0 :     intf_p = talloc_get_type(user_data, struct sbus_interface_p);
     411                 :            : 
     412                 :          0 :     method = dbus_message_get_member(message);
     413 [ #  # ][ #  # ]:          0 :     DEBUG(9, ("Received SBUS method [%s]\n", method));
         [ #  # ][ #  # ]
                 [ #  # ]
     414                 :          0 :     path = dbus_message_get_path(message);
     415                 :          0 :     msg_interface = dbus_message_get_interface(message);
     416                 :            : 
     417 [ #  # ][ #  # ]:          0 :     if (!method || !path || !msg_interface)
     418                 :            :         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     419                 :            : 
     420                 :            :     /* Validate the D-BUS path */
     421         [ #  # ]:          0 :     if (strcmp(path, intf_p->intf->path) != 0)
     422                 :            :         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     423                 :            : 
     424                 :            :     /* Validate the method interface */
     425         [ #  # ]:          0 :     if (strcmp(msg_interface, intf_p->intf->interface) == 0) {
     426                 :            :         found = 0;
     427         [ #  # ]:          0 :         for (i = 0; intf_p->intf->methods[i].method != NULL; i++) {
     428         [ #  # ]:          0 :             if (strcmp(method, intf_p->intf->methods[i].method) == 0) {
     429                 :          0 :                 found = 1;
     430                 :          0 :                 ret = intf_p->intf->methods[i].fn(message, intf_p->conn);
     431         [ #  # ]:          0 :                 if (ret != EOK) {
     432                 :          0 :                     return sbus_reply_internal_error(message, intf_p->conn);
     433                 :            :                 }
     434                 :            :                 break;
     435                 :            :             }
     436                 :            :         }
     437                 :            : 
     438         [ #  # ]:          0 :         if (!found) {
     439                 :            :             /* Reply DBUS_ERROR_UNKNOWN_METHOD */
     440 [ #  # ][ #  # ]:          0 :             DEBUG(1, ("No matching method found for %s.\n", method));
         [ #  # ][ #  # ]
                 [ #  # ]
     441                 :          0 :             reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
     442                 :          0 :             sbus_conn_send_reply(intf_p->conn, reply);
     443                 :          0 :             dbus_message_unref(reply);
     444                 :            :         }
     445                 :            :     }
     446                 :            :     else {
     447                 :            :         /* Special case: check for Introspection request
     448                 :            :          * This is usually only useful for system bus connections
     449                 :            :          */
     450 [ #  # ][ #  # ]:          0 :         if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
     451                 :          0 :             strcmp(method, DBUS_INTROSPECT_METHOD) == 0)
     452                 :            :         {
     453         [ #  # ]:          0 :             if (intf_p->intf->introspect_fn) {
     454                 :            :                 /* If we have been asked for introspection data and we have
     455                 :            :                  * an introspection function registered, user that.
     456                 :            :                  */
     457                 :          0 :                 ret = intf_p->intf->introspect_fn(message, intf_p->conn);
     458         [ #  # ]:          0 :                 if (ret != EOK) {
     459                 :          0 :                     return sbus_reply_internal_error(message, intf_p->conn);
     460                 :            :                 }
     461                 :            :             }
     462                 :            :         }
     463                 :            :         else
     464                 :            :             return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     465                 :            :     }
     466                 :            : 
     467                 :            :     return DBUS_HANDLER_RESULT_HANDLED;
     468                 :            : }
     469                 :            : 
     470                 :            : /* Adds a new D-BUS path message handler to the connection
     471                 :            :  * Note: this must be a unique path.
     472                 :            :  */
     473                 :          0 : int sbus_conn_add_interface(struct sbus_connection *conn,
     474                 :            :                              struct sbus_interface *intf)
     475                 :            : {
     476                 :            :     struct sbus_interface_p *intf_p;
     477                 :            :     dbus_bool_t dbret;
     478                 :            :     const char *path;
     479                 :            : 
     480 [ #  # ][ #  # ]:          0 :     if (!conn || !intf || !intf->vtable.message_function) {
     481                 :            :         return EINVAL;
     482                 :            :     }
     483                 :            : 
     484                 :          0 :     path = intf->path;
     485                 :            : 
     486         [ #  # ]:          0 :     if (path_in_interface_list(conn->intf_list, path)) {
     487 [ #  # ][ #  # ]:          0 :         DEBUG(0, ("Cannot add method context with identical path.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     488                 :            :         return EINVAL;
     489                 :            :     }
     490                 :            : 
     491                 :          0 :     intf_p = talloc_zero(conn, struct sbus_interface_p);
     492         [ #  # ]:          0 :     if (!intf_p) {
     493                 :            :         return ENOMEM;
     494                 :            :     }
     495                 :          0 :     intf_p->conn = conn;
     496                 :          0 :     intf_p->intf = intf;
     497                 :            : 
     498         [ #  # ]:          0 :     DLIST_ADD(conn->intf_list, intf_p);
     499                 :            : 
     500                 :          0 :     dbret = dbus_connection_register_object_path(conn->dbus.conn,
     501                 :          0 :                                                  path, &intf->vtable, intf_p);
     502         [ #  # ]:          0 :     if (!dbret) {
     503 [ #  # ][ #  # ]:          0 :         DEBUG(0, ("Could not register object path to the connection.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     504                 :            :         return ENOMEM;
     505                 :            :     }
     506                 :            : 
     507                 :            :     return EOK;
     508                 :            : }
     509                 :            : 
     510                 :          0 : static bool path_in_interface_list(struct sbus_interface_p *list,
     511                 :            :                                    const char *path)
     512                 :            : {
     513                 :            :     struct sbus_interface_p *iter;
     514                 :            : 
     515         [ #  # ]:          0 :     if (!list || !path) {
     516                 :            :         return false;
     517                 :            :     }
     518                 :            : 
     519                 :            :     iter = list;
     520         [ #  # ]:          0 :     while (iter != NULL) {
     521         [ #  # ]:          0 :         if (strcmp(iter->intf->path, path) == 0) {
     522                 :            :             return true;
     523                 :            :         }
     524                 :          0 :         iter = iter->next;
     525                 :            :     }
     526                 :            : 
     527                 :            :     return false;
     528                 :            : }
     529                 :            : 
     530                 :          0 : static void sbus_unreg_object_paths(struct sbus_connection *conn)
     531                 :            : {
     532                 :          0 :     struct sbus_interface_p *iter = conn->intf_list;
     533                 :            : 
     534         [ #  # ]:          0 :     while (iter != NULL) {
     535                 :          0 :         dbus_connection_unregister_object_path(conn->dbus.conn,
     536                 :          0 :                                                iter->intf->path);
     537                 :          0 :         iter = iter->next;
     538                 :            :     }
     539                 :          0 : }
     540                 :            : 
     541                 :          0 : void sbus_conn_set_private_data(struct sbus_connection *conn, void *pvt_data)
     542                 :            : {
     543                 :          0 :     conn->pvt_data = pvt_data;
     544                 :          0 : }
     545                 :            : 
     546                 :          0 : void *sbus_conn_get_private_data(struct sbus_connection *conn)
     547                 :            : {
     548                 :          0 :     return conn->pvt_data;
     549                 :            : }
     550                 :            : 
     551                 :          0 : static void sbus_reconnect(struct tevent_context *ev,
     552                 :            :                            struct tevent_timer *te,
     553                 :            :                            struct timeval tv, void *data)
     554                 :            : {
     555                 :            :     struct sbus_connection *conn;
     556                 :            :     struct sbus_interface_p *iter;
     557                 :            :     DBusError dbus_error;
     558                 :            :     dbus_bool_t dbret;
     559                 :            :     int ret;
     560                 :            : 
     561                 :          0 :     conn = talloc_get_type(data, struct sbus_connection);
     562                 :          0 :     dbus_error_init(&dbus_error);
     563                 :            : 
     564 [ #  # ][ #  # ]:          0 :     DEBUG(3, ("Making reconnection attempt %d to [%s]\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     565                 :            :               conn->retries, conn->address));
     566                 :          0 :     conn->dbus.conn = dbus_connection_open(conn->address, &dbus_error);
     567         [ #  # ]:          0 :     if (conn->dbus.conn) {
     568                 :            :         /* We successfully reconnected. Set up mainloop integration. */
     569 [ #  # ][ #  # ]:          0 :         DEBUG(3, ("Reconnected to [%s]\n", conn->address));
         [ #  # ][ #  # ]
                 [ #  # ]
     570                 :          0 :         ret = sbus_conn_set_fns(conn);
     571         [ #  # ]:          0 :         if (ret != EOK) {
     572                 :          0 :             dbus_connection_unref(conn->dbus.conn);
     573                 :            :             goto failed;
     574                 :            :         }
     575                 :            : 
     576                 :            :         /* Re-register object paths */
     577                 :          0 :         iter = conn->intf_list;
     578         [ #  # ]:          0 :         while (iter) {
     579                 :          0 :             dbret = dbus_connection_register_object_path(conn->dbus.conn,
     580                 :            :                                                          iter->intf->path,
     581                 :          0 :                                                          &iter->intf->vtable,
     582                 :            :                                                          iter);
     583         [ #  # ]:          0 :             if (!dbret) {
     584 [ #  # ][ #  # ]:          0 :                 DEBUG(0, ("Could not register object path.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     585                 :          0 :                 dbus_connection_unref(conn->dbus.conn);
     586                 :            :                 goto failed;
     587                 :            :             }
     588                 :          0 :             iter = iter->next;
     589                 :            :         }
     590                 :            : 
     591                 :            :         /* Reset retries to 0 to resume dispatch processing */
     592                 :          0 :         conn->retries = 0;
     593                 :            : 
     594                 :            :         /* Notify the owner of this connection that the
     595                 :            :          * reconnection was successful
     596                 :            :          */
     597                 :          0 :         conn->reconnect_callback(conn,
     598                 :            :                                  SBUS_RECONNECT_SUCCESS,
     599                 :            :                                  conn->reconnect_pvt);
     600                 :          0 :         return;
     601                 :            :     }
     602                 :            : 
     603                 :            : failed:
     604                 :            :     /* Reconnection failed, try again in a few seconds */
     605 [ #  # ][ #  # ]:          0 :     DEBUG(1, ("Failed to open connection: name=%s, message=%s\n",
         [ #  # ][ #  # ]
                 [ #  # ]
     606                 :            :                 dbus_error.name, dbus_error.message));
     607         [ #  # ]:          0 :     if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
     608                 :            : 
     609                 :          0 :     conn->retries++;
     610                 :            : 
     611                 :            :     /* Check if we've passed our last chance or if we've lost track of
     612                 :            :      * our retry count somehow
     613                 :            :      */
     614 [ #  # ][ #  # ]:          0 :     if ((conn->retries > conn->max_retries) || (conn->retries <= 0)) {
     615                 :          0 :         conn->reconnect_callback(conn,
     616                 :            :                                  SBUS_RECONNECT_EXCEEDED_RETRIES,
     617                 :            :                                  conn->reconnect_pvt);
     618                 :            :     }
     619                 :            : 
     620         [ #  # ]:          0 :     if (conn->retries == 2) {
     621                 :            :         /* Wait 3 seconds before the second reconnect attempt */
     622                 :          0 :         tv.tv_sec += 3;
     623                 :            :     }
     624         [ #  # ]:          0 :     else if (conn->retries == 3) {
     625                 :            :         /* Wait 10 seconds before the third reconnect attempt */
     626                 :          0 :         tv.tv_sec += 10;
     627                 :            :     }
     628                 :            :     else {
     629                 :            :         /* Wait 30 seconds before all subsequent reconnect attempts */
     630                 :          0 :         tv.tv_sec += 30;
     631                 :            :     }
     632                 :            : 
     633                 :          0 :     te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn);
     634         [ #  # ]:          0 :     if (!te) {
     635                 :          0 :         conn->reconnect_callback(conn,
     636                 :            :                                  SBUS_RECONNECT_ERROR,
     637                 :            :                                  conn->reconnect_pvt);
     638                 :            :     }
     639                 :            : }
     640                 :            : 
     641                 :            : /* This function will free and recreate the sbus_connection,
     642                 :            :  * calling functions need to be aware of this (and whether
     643                 :            :  * they have attached a talloc destructor to the
     644                 :            :  * sbus_connection.
     645                 :            :  */
     646                 :          0 : static int sbus_auto_reconnect(struct sbus_connection *conn)
     647                 :            : {
     648                 :          0 :     struct tevent_timer *te = NULL;
     649                 :            :     struct timeval tv;
     650                 :            : 
     651                 :          0 :     conn->retries++;
     652         [ #  # ]:          0 :     if (conn->retries >= conn->max_retries) {
     653                 :            :         /* Return EIO (to tell the calling process it
     654                 :            :          * needs to create a new connection from scratch
     655                 :            :          */
     656                 :            :         return EIO;
     657                 :            :     }
     658                 :            : 
     659                 :          0 :     gettimeofday(&tv, NULL);
     660                 :          0 :     tv.tv_sec += 1; /* Wait 1 second before the first reconnect attempt */
     661                 :          0 :     te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn);
     662         [ #  # ]:          0 :     if (!te) {
     663                 :            :         return EIO;
     664                 :            :     }
     665                 :            : 
     666                 :            :     return EOK;
     667                 :            : }
     668                 :            : 
     669                 :            : /* Max retries */
     670                 :          0 : void sbus_reconnect_init(struct sbus_connection *conn,
     671                 :            :                          int max_retries,
     672                 :            :                          sbus_conn_reconn_callback_fn callback,
     673                 :            :                          void *pvt)
     674                 :            : {
     675         [ #  # ]:          0 :     if (max_retries < 0 || callback == NULL) return;
     676                 :            : 
     677                 :          0 :     conn->retries = 0;
     678                 :          0 :     conn->max_retries = max_retries;
     679                 :          0 :     conn->reconnect_callback = callback;
     680                 :          0 :     conn->reconnect_pvt = pvt;
     681                 :            : }
     682                 :            : 
     683                 :          0 : bool sbus_conn_disconnecting(struct sbus_connection *conn)
     684                 :            : {
     685         [ #  # ]:          0 :     if (conn->disconnect == 1) return true;
     686                 :          0 :     return false;
     687                 :            : }
     688                 :            : 
     689                 :            : /*
     690                 :            :  * Send a message across the SBUS
     691                 :            :  * If requested, the DBusPendingCall object will
     692                 :            :  * be returned to the caller.
     693                 :            :  *
     694                 :            :  * This function will return EAGAIN in the event
     695                 :            :  * that the connection is not open for
     696                 :            :  * communication.
     697                 :            :  */
     698                 :          0 : int sbus_conn_send(struct sbus_connection *conn,
     699                 :            :                    DBusMessage *msg,
     700                 :            :                    int timeout_ms,
     701                 :            :                    DBusPendingCallNotifyFunction reply_handler,
     702                 :            :                    void *pvt,
     703                 :            :                    DBusPendingCall **pending)
     704                 :            : {
     705                 :            :     DBusPendingCall *pending_reply;
     706                 :            :     DBusConnection *dbus_conn;
     707                 :            :     dbus_bool_t dbret;
     708                 :            : 
     709                 :          0 :     dbus_conn = sbus_get_connection(conn);
     710         [ #  # ]:          0 :     if (!dbus_conn) {
     711 [ #  # ][ #  # ]:          0 :         DEBUG(SSSDBG_CRIT_FAILURE, ("D-BUS not connected\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     712                 :            :         return ENOTCONN;
     713                 :            :     }
     714                 :            : 
     715                 :          0 :     dbret = dbus_connection_send_with_reply(dbus_conn, msg,
     716                 :            :                                             &pending_reply,
     717                 :            :                                             timeout_ms);
     718         [ #  # ]:          0 :     if (!dbret) {
     719                 :            :         /*
     720                 :            :          * Critical Failure
     721                 :            :          * Insufficient memory to send message
     722                 :            :          */
     723 [ #  # ][ #  # ]:          0 :         DEBUG(0, ("D-BUS send failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     724                 :            :         return ENOMEM;
     725                 :            :     }
     726                 :            : 
     727         [ #  # ]:          0 :     if (pending_reply) {
     728                 :            :         /* Set up the reply handler */
     729                 :          0 :         dbret = dbus_pending_call_set_notify(pending_reply, reply_handler,
     730                 :            :                                              pvt, NULL);
     731         [ #  # ]:          0 :         if (!dbret) {
     732                 :            :             /*
     733                 :            :              * Critical Failure
     734                 :            :              * Insufficient memory to create pending call notify
     735                 :            :              */
     736 [ #  # ][ #  # ]:          0 :             DEBUG(0, ("D-BUS send failed.\n"));
         [ #  # ][ #  # ]
                 [ #  # ]
     737                 :          0 :             dbus_pending_call_cancel(pending_reply);
     738                 :          0 :             dbus_pending_call_unref(pending_reply);
     739                 :            :             return ENOMEM;
     740                 :            :         }
     741                 :            : 
     742         [ #  # ]:          0 :         if(pending) {
     743                 :          0 :             *pending = pending_reply;
     744                 :            :         }
     745                 :            :         return EOK;
     746                 :            :     }
     747                 :            : 
     748                 :            :     /* If pending_reply is NULL, the connection was not
     749                 :            :      * open for sending.
     750                 :            :      */
     751                 :            : 
     752                 :            :     /* TODO: Create a callback into the reconnection logic so this
     753                 :            :      * request is invoked when the connection is re-established
     754                 :            :      */
     755                 :            :     return EAGAIN;
     756                 :            : }
     757                 :            : 
     758                 :          0 : void sbus_conn_send_reply(struct sbus_connection *conn, DBusMessage *reply)
     759                 :            : {
     760                 :          0 :     dbus_connection_send(conn->dbus.conn, reply, NULL);
     761                 :          0 : }
     762                 :            : 

Generated by: LCOV version 1.9