Home | History | Annotate | Download | only in dbus
      1 /* -*- mode: C; c-file-style: "gnu" -*- */
      2 /* dbus-server-socket.c Server implementation for sockets
      3  *
      4  * Copyright (C) 2002, 2003, 2004, 2006  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-internals.h"
     25 #include "dbus-server-socket.h"
     26 #include "dbus-transport-socket.h"
     27 #include "dbus-connection-internal.h"
     28 #include "dbus-string.h"
     29 
     30 /**
     31  * @defgroup DBusServerSocket DBusServer implementations for SOCKET
     32  * @ingroup  DBusInternals
     33  * @brief Implementation details of DBusServer on SOCKET
     34  *
     35  * @{
     36  */
     37 /**
     38  *
     39  * Opaque object representing a Socket server implementation.
     40  */
     41 typedef struct DBusServerSocket DBusServerSocket;
     42 
     43 /**
     44  * Implementation details of DBusServerSocket. All members
     45  * are private.
     46  */
     47 struct DBusServerSocket
     48 {
     49   DBusServer base;   /**< Parent class members. */
     50   int fd;            /**< File descriptor or -1 if disconnected. */
     51   DBusWatch *watch;  /**< File descriptor watch. */
     52   char *socket_name; /**< Name of domain socket, to unlink if appropriate */
     53 };
     54 
     55 static void
     56 socket_finalize (DBusServer *server)
     57 {
     58   DBusServerSocket *socket_server = (DBusServerSocket*) server;
     59 
     60   _dbus_server_finalize_base (server);
     61 
     62   if (socket_server->watch)
     63     {
     64       _dbus_watch_unref (socket_server->watch);
     65       socket_server->watch = NULL;
     66     }
     67 
     68   dbus_free (socket_server->socket_name);
     69   dbus_free (server);
     70 }
     71 
     72 /* Return value is just for memory, not other failures. */
     73 static dbus_bool_t
     74 handle_new_client_fd_and_unlock (DBusServer *server,
     75                                  int         client_fd)
     76 {
     77   DBusConnection *connection;
     78   DBusTransport *transport;
     79   DBusNewConnectionFunction new_connection_function;
     80   void *new_connection_data;
     81 
     82   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
     83 
     84   HAVE_LOCK_CHECK (server);
     85 
     86   if (!_dbus_set_fd_nonblocking (client_fd, NULL))
     87     {
     88       SERVER_UNLOCK (server);
     89       return TRUE;
     90     }
     91 
     92   transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL);
     93   if (transport == NULL)
     94     {
     95       _dbus_close_socket (client_fd, NULL);
     96       SERVER_UNLOCK (server);
     97       return FALSE;
     98     }
     99 
    100   if (!_dbus_transport_set_auth_mechanisms (transport,
    101                                             (const char **) server->auth_mechanisms))
    102     {
    103       _dbus_transport_unref (transport);
    104       SERVER_UNLOCK (server);
    105       return FALSE;
    106     }
    107 
    108   /* note that client_fd is now owned by the transport, and will be
    109    * closed on transport disconnection/finalization
    110    */
    111 
    112   connection = _dbus_connection_new_for_transport (transport);
    113   _dbus_transport_unref (transport);
    114   transport = NULL; /* now under the connection lock */
    115 
    116   if (connection == NULL)
    117     {
    118       SERVER_UNLOCK (server);
    119       return FALSE;
    120     }
    121 
    122   /* See if someone wants to handle this new connection, self-referencing
    123    * for paranoia.
    124    */
    125   new_connection_function = server->new_connection_function;
    126   new_connection_data = server->new_connection_data;
    127 
    128   _dbus_server_ref_unlocked (server);
    129   SERVER_UNLOCK (server);
    130 
    131   if (new_connection_function)
    132     {
    133       (* new_connection_function) (server, connection,
    134                                    new_connection_data);
    135     }
    136   dbus_server_unref (server);
    137 
    138   /* If no one grabbed a reference, the connection will die. */
    139   _dbus_connection_close_if_only_one_ref (connection);
    140   dbus_connection_unref (connection);
    141 
    142   return TRUE;
    143 }
    144 
    145 static dbus_bool_t
    146 socket_handle_watch (DBusWatch    *watch,
    147                    unsigned int  flags,
    148                    void         *data)
    149 {
    150   DBusServer *server = data;
    151   DBusServerSocket *socket_server = data;
    152 
    153   SERVER_LOCK (server);
    154 
    155   _dbus_assert (watch == socket_server->watch);
    156 
    157   _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
    158 
    159   if (flags & DBUS_WATCH_READABLE)
    160     {
    161       int client_fd;
    162       int listen_fd;
    163 
    164       listen_fd = dbus_watch_get_fd (watch);
    165 
    166       client_fd = _dbus_accept (listen_fd);
    167 
    168       if (client_fd < 0)
    169         {
    170           /* EINTR handled for us */
    171 
    172           if (errno == EAGAIN || errno == EWOULDBLOCK)
    173             _dbus_verbose ("No client available to accept after all\n");
    174           else
    175             _dbus_verbose ("Failed to accept a client connection: %s\n",
    176                            _dbus_strerror (errno));
    177 
    178           SERVER_UNLOCK (server);
    179         }
    180       else
    181         {
    182 	  _dbus_fd_set_close_on_exec (client_fd);
    183 
    184           if (!handle_new_client_fd_and_unlock (server, client_fd))
    185             _dbus_verbose ("Rejected client connection due to lack of memory\n");
    186         }
    187     }
    188 
    189   if (flags & DBUS_WATCH_ERROR)
    190     _dbus_verbose ("Error on server listening socket\n");
    191 
    192   if (flags & DBUS_WATCH_HANGUP)
    193     _dbus_verbose ("Hangup on server listening socket\n");
    194 
    195   return TRUE;
    196 }
    197 
    198 static void
    199 socket_disconnect (DBusServer *server)
    200 {
    201   DBusServerSocket *socket_server = (DBusServerSocket*) server;
    202 
    203   HAVE_LOCK_CHECK (server);
    204 
    205   if (socket_server->watch)
    206     {
    207       _dbus_server_remove_watch (server,
    208                                  socket_server->watch);
    209       _dbus_watch_unref (socket_server->watch);
    210       socket_server->watch = NULL;
    211     }
    212 
    213   _dbus_close_socket (socket_server->fd, NULL);
    214   socket_server->fd = -1;
    215 
    216   if (socket_server->socket_name != NULL)
    217     {
    218       DBusString tmp;
    219       _dbus_string_init_const (&tmp, socket_server->socket_name);
    220       _dbus_delete_file (&tmp, NULL);
    221     }
    222 
    223   HAVE_LOCK_CHECK (server);
    224 }
    225 
    226 static const DBusServerVTable socket_vtable = {
    227   socket_finalize,
    228   socket_disconnect
    229 };
    230 
    231 /**
    232  * Creates a new server listening on the given file descriptor.  The
    233  * file descriptor should be nonblocking (use
    234  * _dbus_set_fd_nonblocking() to make it so). The file descriptor
    235  * should be listening for connections, that is, listen() should have
    236  * been successfully invoked on it. The server will use accept() to
    237  * accept new client connections.
    238  *
    239  * @param fd the file descriptor.
    240  * @param address the server's address
    241  * @returns the new server, or #NULL if no memory.
    242  *
    243  */
    244 DBusServer*
    245 _dbus_server_new_for_socket (int               fd,
    246                              const DBusString *address)
    247 {
    248   DBusServerSocket *socket_server;
    249   DBusServer *server;
    250   DBusWatch *watch;
    251 
    252   socket_server = dbus_new0 (DBusServerSocket, 1);
    253   if (socket_server == NULL)
    254     return NULL;
    255 
    256   watch = _dbus_watch_new (fd,
    257                            DBUS_WATCH_READABLE,
    258                            TRUE,
    259                            socket_handle_watch, socket_server,
    260                            NULL);
    261   if (watch == NULL)
    262     {
    263       dbus_free (socket_server);
    264       return NULL;
    265     }
    266 
    267   if (!_dbus_server_init_base (&socket_server->base,
    268                                &socket_vtable, address))
    269     {
    270       _dbus_watch_unref (watch);
    271       dbus_free (socket_server);
    272       return NULL;
    273     }
    274 
    275   server = (DBusServer*) socket_server;
    276 
    277   SERVER_LOCK (server);
    278 
    279   if (!_dbus_server_add_watch (&socket_server->base,
    280                                watch))
    281     {
    282       SERVER_UNLOCK (server);
    283       _dbus_server_finalize_base (&socket_server->base);
    284       _dbus_watch_unref (watch);
    285       dbus_free (socket_server);
    286       return NULL;
    287     }
    288 
    289   socket_server->fd = fd;
    290   socket_server->watch = watch;
    291 
    292   SERVER_UNLOCK (server);
    293 
    294   return (DBusServer*) socket_server;
    295 }
    296 
    297 /**
    298  * Creates a new server listening on the given hostname and port.
    299  * If the hostname is NULL, listens on localhost.
    300  *
    301  * @param host the hostname to listen on.
    302  * @param port the port to listen on.
    303  * @param error location to store reason for failure.
    304  * @returns the new server, or #NULL on failure.
    305  */
    306 DBusServer*
    307 _dbus_server_new_for_tcp_socket (const char     *host,
    308                                  dbus_uint32_t   port,
    309                                  DBusError      *error)
    310 {
    311   DBusServer *server;
    312   int listen_fd;
    313   DBusString address;
    314   DBusString host_str;
    315 
    316   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
    317 
    318   if (!_dbus_string_init (&address))
    319     {
    320       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    321       return NULL;
    322     }
    323 
    324   if (host == NULL)
    325     host = "localhost";
    326 
    327   _dbus_string_init_const (&host_str, host);
    328   if (!_dbus_string_append (&address, "tcp:host=") ||
    329       !_dbus_address_append_escaped (&address, &host_str) ||
    330       !_dbus_string_append (&address, ",port=") ||
    331       !_dbus_string_append_int (&address, port))
    332     {
    333       _dbus_string_free (&address);
    334       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    335       return NULL;
    336     }
    337 
    338   listen_fd = _dbus_listen_tcp_socket (host, port, error);
    339   _dbus_fd_set_close_on_exec (listen_fd);
    340 
    341   if (listen_fd < 0)
    342     {
    343       _dbus_string_free (&address);
    344       return NULL;
    345     }
    346 
    347   server = _dbus_server_new_for_socket (listen_fd, &address);
    348   if (server == NULL)
    349     {
    350       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    351       _dbus_close_socket (listen_fd, NULL);
    352       _dbus_string_free (&address);
    353       return NULL;
    354     }
    355 
    356   _dbus_string_free (&address);
    357 
    358   return server;
    359 
    360 
    361 }
    362 
    363 /**
    364  * Tries to interpret the address entry for various socket-related
    365  * addresses (well, currently only tcp).
    366  *
    367  * Sets error if the result is not OK.
    368  *
    369  * @param entry an address entry
    370  * @param server_p a new DBusServer, or #NULL on failure.
    371  * @param error location to store rationale for failure on bad address
    372  * @returns the outcome
    373  *
    374  */
    375 DBusServerListenResult
    376 _dbus_server_listen_socket (DBusAddressEntry *entry,
    377                             DBusServer      **server_p,
    378                             DBusError        *error)
    379 {
    380   const char *method;
    381 
    382   *server_p = NULL;
    383 
    384   method = dbus_address_entry_get_method (entry);
    385 
    386   if (strcmp (method, "tcp") == 0)
    387     {
    388       const char *host = dbus_address_entry_get_value (entry, "host");
    389       const char *port = dbus_address_entry_get_value (entry, "port");
    390       DBusString  str;
    391       long lport;
    392       dbus_bool_t sresult;
    393 
    394       if (port == NULL)
    395         {
    396           _dbus_set_bad_address(error, "tcp", "port", NULL);
    397           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
    398         }
    399 
    400       _dbus_string_init_const (&str, port);
    401       sresult = _dbus_string_parse_int (&str, 0, &lport, NULL);
    402       _dbus_string_free (&str);
    403 
    404       if (sresult == FALSE || lport <= 0 || lport > 65535)
    405         {
    406           _dbus_set_bad_address(error, NULL, NULL,
    407                                 "Port is not an integer between 0 and 65535");
    408           return DBUS_SERVER_LISTEN_BAD_ADDRESS;
    409         }
    410 
    411       *server_p = _dbus_server_new_for_tcp_socket (host, lport, error);
    412 
    413       if (*server_p)
    414         {
    415           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
    416           return DBUS_SERVER_LISTEN_OK;
    417         }
    418       else
    419         {
    420           _DBUS_ASSERT_ERROR_IS_SET(error);
    421           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
    422         }
    423     }
    424   else
    425     {
    426       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
    427       return DBUS_SERVER_LISTEN_NOT_HANDLED;
    428     }
    429 }
    430 
    431 /**
    432  * This is a bad hack since it's really unix domain socket
    433  * specific. Also, the function weirdly adopts ownership
    434  * of the passed-in string.
    435  *
    436  * @param server a socket server
    437  * @param filename socket filename to report/delete
    438  *
    439  */
    440 void
    441 _dbus_server_socket_own_filename (DBusServer *server,
    442                                   char       *filename)
    443 {
    444   DBusServerSocket *socket_server = (DBusServerSocket*) server;
    445 
    446   socket_server->socket_name = filename;
    447 }
    448 
    449 
    450 /** @} */
    451 
    452