dbus-server-unix.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-server-unix.c Server implementation for Unix network protocols.
00003  *
00004  * Copyright (C) 2002, 2003, 2004  Red Hat Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include "dbus-internals.h"
00025 #include "dbus-server-unix.h"
00026 #include "dbus-transport-unix.h"
00027 #include "dbus-connection-internal.h"
00028 #include "dbus-string.h"
00029 #include <sys/types.h>
00030 #include <unistd.h>
00031 
00043 typedef struct DBusServerUnix DBusServerUnix;
00044 
00049 struct DBusServerUnix
00050 {
00051   DBusServer base;   
00052   int fd;            
00053   DBusWatch *watch;  
00054   char *socket_name; 
00055 };
00056 
00057 static void
00058 unix_finalize (DBusServer *server)
00059 {
00060   DBusServerUnix *unix_server = (DBusServerUnix*) server;
00061   
00062   _dbus_server_finalize_base (server);
00063 
00064   if (unix_server->watch)
00065     {
00066       _dbus_watch_unref (unix_server->watch);
00067       unix_server->watch = NULL;
00068     }
00069   
00070   dbus_free (unix_server->socket_name);
00071   dbus_free (server);
00072 }
00073 
00082 /* Return value is just for memory, not other failures. */
00083 static dbus_bool_t
00084 handle_new_client_fd_and_unlock (DBusServer *server,
00085                                  int         client_fd)
00086 {
00087   DBusConnection *connection;
00088   DBusTransport *transport;
00089   DBusNewConnectionFunction new_connection_function;
00090   void *new_connection_data;
00091   
00092   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
00093 
00094   HAVE_LOCK_CHECK (server);
00095   
00096   if (!_dbus_set_fd_nonblocking (client_fd, NULL))
00097     {
00098       SERVER_UNLOCK (server);
00099       return TRUE;
00100     }
00101   
00102   transport = _dbus_transport_new_for_fd (client_fd, &server->guid_hex, NULL);
00103   if (transport == NULL)
00104     {
00105       _dbus_close (client_fd, NULL);
00106       SERVER_UNLOCK (server);
00107       return FALSE;
00108     }
00109 
00110   if (!_dbus_transport_set_auth_mechanisms (transport,
00111                                             (const char **) server->auth_mechanisms))
00112     {
00113       _dbus_transport_unref (transport);
00114       SERVER_UNLOCK (server);
00115       return FALSE;
00116     }
00117   
00118   /* note that client_fd is now owned by the transport, and will be
00119    * closed on transport disconnection/finalization
00120    */
00121   
00122   connection = _dbus_connection_new_for_transport (transport);
00123   _dbus_transport_unref (transport);
00124   transport = NULL; /* now under the connection lock */
00125   
00126   if (connection == NULL)
00127     {
00128       SERVER_UNLOCK (server);
00129       return FALSE;
00130     }
00131   
00132   /* See if someone wants to handle this new connection, self-referencing
00133    * for paranoia.
00134    */
00135   new_connection_function = server->new_connection_function;
00136   new_connection_data = server->new_connection_data;
00137 
00138   _dbus_server_ref_unlocked (server);
00139   SERVER_UNLOCK (server);
00140   
00141   if (new_connection_function)
00142     {
00143       (* new_connection_function) (server, connection,
00144                                    new_connection_data);
00145       dbus_server_unref (server);
00146     }
00147   
00148   /* If no one grabbed a reference, the connection will die. */
00149   dbus_connection_unref (connection);
00150 
00151   return TRUE;
00152 }
00153 
00154 static dbus_bool_t
00155 unix_handle_watch (DBusWatch    *watch,
00156                    unsigned int  flags,
00157                    void         *data)
00158 {
00159   DBusServer *server = data;
00160   DBusServerUnix *unix_server = data;
00161 
00162   SERVER_LOCK (server);
00163   
00164   _dbus_assert (watch == unix_server->watch);
00165 
00166   _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
00167   
00168   if (flags & DBUS_WATCH_READABLE)
00169     {
00170       int client_fd;
00171       int listen_fd;
00172       
00173       listen_fd = dbus_watch_get_fd (watch);
00174 
00175       client_fd = _dbus_accept (listen_fd);
00176       
00177       if (client_fd < 0)
00178         {
00179           /* EINTR handled for us */
00180           
00181           if (errno == EAGAIN || errno == EWOULDBLOCK)
00182             _dbus_verbose ("No client available to accept after all\n");
00183           else
00184             _dbus_verbose ("Failed to accept a client connection: %s\n",
00185                            _dbus_strerror (errno));
00186 
00187           SERVER_UNLOCK (server);
00188         }
00189       else
00190         {
00191           _dbus_fd_set_close_on_exec (client_fd);         
00192 
00193           if (!handle_new_client_fd_and_unlock (server, client_fd))
00194             _dbus_verbose ("Rejected client connection due to lack of memory\n");
00195         }
00196     }
00197 
00198   if (flags & DBUS_WATCH_ERROR)
00199     _dbus_verbose ("Error on server listening socket\n");
00200 
00201   if (flags & DBUS_WATCH_HANGUP)
00202     _dbus_verbose ("Hangup on server listening socket\n");
00203 
00204   return TRUE;
00205 }
00206   
00207 static void
00208 unix_disconnect (DBusServer *server)
00209 {
00210   DBusServerUnix *unix_server = (DBusServerUnix*) server;
00211 
00212   HAVE_LOCK_CHECK (server);
00213   
00214   if (unix_server->watch)
00215     {
00216       _dbus_server_remove_watch (server,
00217                                  unix_server->watch);
00218       _dbus_watch_unref (unix_server->watch);
00219       unix_server->watch = NULL;
00220     }
00221   
00222   _dbus_close (unix_server->fd, NULL);
00223   unix_server->fd = -1;
00224 
00225   if (unix_server->socket_name != NULL)
00226     {
00227       DBusString tmp;
00228       _dbus_string_init_const (&tmp, unix_server->socket_name);
00229       _dbus_delete_file (&tmp, NULL);
00230     }
00231 
00232   HAVE_LOCK_CHECK (server);
00233 }
00234 
00235 static const DBusServerVTable unix_vtable = {
00236   unix_finalize,
00237   unix_disconnect
00238 };
00239 
00253 DBusServer*
00254 _dbus_server_new_for_fd (int               fd,
00255                          const DBusString *address)
00256 {
00257   DBusServerUnix *unix_server;
00258   DBusServer *server;
00259   DBusWatch *watch;
00260   
00261   unix_server = dbus_new0 (DBusServerUnix, 1);
00262   if (unix_server == NULL)
00263     return NULL;
00264   
00265   watch = _dbus_watch_new (fd,
00266                            DBUS_WATCH_READABLE,
00267                            TRUE,
00268                            unix_handle_watch, unix_server,
00269                            NULL);
00270   if (watch == NULL)
00271     {
00272       dbus_free (unix_server);
00273       return NULL;
00274     }
00275   
00276   if (!_dbus_server_init_base (&unix_server->base,
00277                                &unix_vtable, address))
00278     {
00279       _dbus_watch_unref (watch);
00280       dbus_free (unix_server);
00281       return NULL;
00282     }
00283 
00284   server = (DBusServer*) unix_server;
00285 
00286   SERVER_LOCK (server);
00287   
00288   if (!_dbus_server_add_watch (&unix_server->base,
00289                                watch))
00290     {
00291       SERVER_UNLOCK (server);
00292       _dbus_server_finalize_base (&unix_server->base);
00293       _dbus_watch_unref (watch);
00294       dbus_free (unix_server);
00295       return NULL;
00296     }
00297   
00298   unix_server->fd = fd;
00299   unix_server->watch = watch;
00300 
00301   SERVER_UNLOCK (server);
00302   
00303   return (DBusServer*) unix_server;
00304 }
00305 
00314 DBusServer*
00315 _dbus_server_new_for_domain_socket (const char     *path,
00316                                     dbus_bool_t     abstract,
00317                                     DBusError      *error)
00318 {
00319   DBusServer *server;
00320   DBusServerUnix *unix_server;
00321   int listen_fd;
00322   DBusString address;
00323   char *path_copy;
00324   DBusString path_str;
00325   
00326   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00327 
00328   if (!_dbus_string_init (&address))
00329     {
00330       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00331       return NULL;
00332     }
00333 
00334   _dbus_string_init_const (&path_str, path);
00335   if ((abstract &&
00336        !_dbus_string_append (&address, "unix:abstract=")) ||
00337       (!abstract &&
00338        !_dbus_string_append (&address, "unix:path=")) ||
00339       !_dbus_address_append_escaped (&address, &path_str))
00340     {
00341       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00342       goto failed_0;
00343     }
00344 
00345   path_copy = _dbus_strdup (path);
00346   if (path_copy == NULL)
00347     {
00348       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00349       goto failed_0;
00350     }
00351   
00352   listen_fd = _dbus_listen_unix_socket (path, abstract, error);
00353   _dbus_fd_set_close_on_exec (listen_fd);
00354   
00355   if (listen_fd < 0)
00356     {
00357       _DBUS_ASSERT_ERROR_IS_SET (error);
00358       goto failed_1;
00359     }
00360   
00361   server = _dbus_server_new_for_fd (listen_fd, &address);
00362   if (server == NULL)
00363     {
00364       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00365       goto failed_2;
00366     }
00367 
00368   unix_server = (DBusServerUnix*) server;
00369   unix_server->socket_name = path_copy;
00370   
00371   _dbus_string_free (&address);
00372   
00373   return server;
00374 
00375  failed_2:
00376   _dbus_close (listen_fd, NULL);
00377  failed_1:
00378   dbus_free (path_copy);
00379  failed_0:
00380   _dbus_string_free (&address);
00381 
00382   return NULL;
00383 }
00384 
00394 DBusServer*
00395 _dbus_server_new_for_tcp_socket (const char     *host,
00396                                  dbus_uint32_t   port,
00397                                  DBusError      *error)
00398 {
00399   DBusServer *server;
00400   int listen_fd;
00401   DBusString address;
00402   DBusString host_str;
00403   
00404   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00405 
00406   if (!_dbus_string_init (&address))
00407     {
00408       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00409       return NULL;
00410     }
00411 
00412   if (host == NULL)
00413     host = "localhost";
00414 
00415   _dbus_string_init_const (&host_str, host);
00416   if (!_dbus_string_append (&address, "tcp:host=") ||
00417       !_dbus_address_append_escaped (&address, &host_str) ||
00418       !_dbus_string_append (&address, ",port=") ||
00419       !_dbus_string_append_int (&address, port))
00420     {
00421       _dbus_string_free (&address);
00422       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00423       return NULL;
00424     }
00425   
00426   listen_fd = _dbus_listen_tcp_socket (host, port, error);
00427   _dbus_fd_set_close_on_exec (listen_fd);
00428   
00429   if (listen_fd < 0)
00430     {
00431       _dbus_string_free (&address);
00432       return NULL;
00433     }
00434   
00435   server = _dbus_server_new_for_fd (listen_fd, &address);
00436   if (server == NULL)
00437     {
00438       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00439       _dbus_close (listen_fd, NULL);
00440       _dbus_string_free (&address);
00441       return NULL;
00442     }
00443 
00444   _dbus_string_free (&address);
00445   
00446   return server;
00447 
00448 
00449 }
00450 

Generated on Wed Jan 3 04:58:28 2007 for D-Bus by  doxygen 1.4.7