2003-04-01 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-server-unix.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-server-unix.c Server implementation for Unix network protocols.
3  *
4  * Copyright (C) 2002  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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-unix.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-connection-internal.h"
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 /**
32  * @defgroup DBusServerUnix DBusServer implementations for UNIX
33  * @ingroup  DBusInternals
34  * @brief Implementation details of DBusServer on UNIX
35  *
36  * @{
37  */
38 /**
39  * 
40  * Opaque object representing a Unix server implementation.
41  */
42 typedef struct DBusServerUnix DBusServerUnix;
43
44 /**
45  * Implementation details of DBusServerUnix. All members
46  * are private.
47  */
48 struct DBusServerUnix
49 {
50   DBusServer base;  /**< Parent class members. */
51   int fd;           /**< File descriptor or -1 if disconnected. */
52   DBusWatch *watch; /**< File descriptor watch. */
53 };
54
55 static void
56 unix_finalize (DBusServer *server)
57 {
58   DBusServerUnix *unix_server = (DBusServerUnix*) server;
59   
60   _dbus_server_finalize_base (server);
61
62   if (unix_server->watch)
63     _dbus_watch_unref (unix_server->watch);
64   
65   dbus_free (server);
66 }
67
68 /**
69  * @todo unreffing the connection at the end may cause
70  * us to drop the last ref to the connection before
71  * disconnecting it. That is invalid.
72  */
73 /* Return value is just for memory, not other failures. */
74 static dbus_bool_t
75 handle_new_client_fd (DBusServer *server,
76                       int         client_fd)
77 {
78   DBusConnection *connection;
79   DBusTransport *transport;
80   
81   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
82           
83   if (!_dbus_set_fd_nonblocking (client_fd, NULL))
84     return TRUE;
85   
86   transport = _dbus_transport_new_for_fd (client_fd, TRUE, NULL);
87   if (transport == NULL)
88     {
89       close (client_fd);
90       return FALSE;
91     }
92
93   if (!_dbus_transport_set_auth_mechanisms (transport,
94                                             (const char **) server->auth_mechanisms))
95     {
96       _dbus_transport_unref (transport);
97       return FALSE;
98     }
99   
100   /* note that client_fd is now owned by the transport, and will be
101    * closed on transport disconnection/finalization
102    */
103   
104   connection = _dbus_connection_new_for_transport (transport);
105   _dbus_transport_unref (transport);
106   
107   if (connection == NULL)
108     return FALSE;
109
110   _dbus_connection_set_connection_counter (connection,
111                                            server->connection_counter);
112   
113   /* See if someone wants to handle this new connection,
114    * self-referencing for paranoia
115    */
116   if (server->new_connection_function)
117     {
118       dbus_server_ref (server);
119       
120       (* server->new_connection_function) (server, connection,
121                                            server->new_connection_data);
122       dbus_server_unref (server);
123     }
124   
125   /* If no one grabbed a reference, the connection will die. */
126   dbus_connection_unref (connection);
127
128   return TRUE;
129 }
130
131 static dbus_bool_t
132 unix_handle_watch (DBusServer  *server,
133                    DBusWatch   *watch,
134                    unsigned int flags)
135 {
136   DBusServerUnix *unix_server = (DBusServerUnix*) server;
137
138   _dbus_assert (watch == unix_server->watch);
139
140   _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
141   
142   if (flags & DBUS_WATCH_READABLE)
143     {
144       int client_fd;
145       int listen_fd;
146       
147       listen_fd = dbus_watch_get_fd (watch);
148
149       client_fd = _dbus_accept (listen_fd);
150       
151       if (client_fd < 0)
152         {
153           /* EINTR handled for us */
154           
155           if (errno == EAGAIN || errno == EWOULDBLOCK)
156             _dbus_verbose ("No client available to accept after all\n");
157           else
158             _dbus_verbose ("Failed to accept a client connection: %s\n",
159                            _dbus_strerror (errno));
160         }
161       else
162         {
163           _dbus_fd_set_close_on_exec (client_fd);         
164
165           if (!handle_new_client_fd (server, client_fd))
166             _dbus_verbose ("Rejected client connection due to lack of memory\n");
167         }
168     }
169
170   if (flags & DBUS_WATCH_ERROR)
171     _dbus_verbose ("Error on server listening socket\n");
172
173   if (flags & DBUS_WATCH_HANGUP)
174     _dbus_verbose ("Hangup on server listening socket\n");
175
176   return TRUE;
177 }
178   
179 static void
180 unix_disconnect (DBusServer *server)
181 {
182   DBusServerUnix *unix_server = (DBusServerUnix*) server;
183
184   if (unix_server->watch)
185     {
186       _dbus_server_remove_watch (server,
187                                  unix_server->watch);
188       _dbus_watch_unref (unix_server->watch);
189       unix_server->watch = NULL;
190     }
191   
192   close (unix_server->fd);
193   unix_server->fd = -1;
194 }
195
196 static DBusServerVTable unix_vtable = {
197   unix_finalize,
198   unix_handle_watch,
199   unix_disconnect
200 };
201
202 /**
203  * Creates a new server listening on the given file descriptor.  The
204  * file descriptor should be nonblocking (use
205  * _dbus_set_fd_nonblocking() to make it so). The file descriptor
206  * should be listening for connections, that is, listen() should have
207  * been successfully invoked on it. The server will use accept() to
208  * accept new client connections.
209  *
210  * @param fd the file descriptor.
211  * @param address the server's address
212  * @returns the new server, or #NULL if no memory.
213  * 
214  */
215 DBusServer*
216 _dbus_server_new_for_fd (int               fd,
217                          const DBusString *address)
218 {
219   DBusServerUnix *unix_server;
220   DBusWatch *watch;
221
222   watch = _dbus_watch_new (fd,
223                            DBUS_WATCH_READABLE,
224                            TRUE);
225   if (watch == NULL)
226     return NULL;
227   
228   unix_server = dbus_new0 (DBusServerUnix, 1);
229   if (unix_server == NULL)
230     {
231       _dbus_watch_unref (watch);
232       return NULL;
233     }
234   
235   if (!_dbus_server_init_base (&unix_server->base,
236                                &unix_vtable, address))
237     {
238       _dbus_watch_unref (watch);
239       dbus_free (unix_server);
240       return NULL;
241     }
242
243   if (!_dbus_server_add_watch (&unix_server->base,
244                                watch))
245     {
246       _dbus_server_finalize_base (&unix_server->base);
247       _dbus_watch_unref (watch);
248       dbus_free (unix_server);
249       return NULL;
250     }
251   
252   unix_server->fd = fd;
253   unix_server->watch = watch;
254
255   return (DBusServer*) unix_server;
256 }
257
258 /**
259  * Creates a new server listening on the given Unix domain socket.
260  *
261  * @param path the path for the domain socket.
262  * @param error location to store reason for failure.
263  * @returns the new server, or #NULL on failure.
264  */
265 DBusServer*
266 _dbus_server_new_for_domain_socket (const char     *path,
267                                     DBusError      *error)
268 {
269   DBusServer *server;
270   int listen_fd;
271   DBusString address;
272   
273   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
274
275   if (!_dbus_string_init (&address))
276     {
277       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
278       return NULL;
279     }
280
281   if (!_dbus_string_append (&address, "unix:path=") ||
282       !_dbus_string_append (&address, path))
283     {
284       _dbus_string_free (&address);
285       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
286       return NULL;
287     }
288   
289   listen_fd = _dbus_listen_unix_socket (path, error);
290   _dbus_fd_set_close_on_exec (listen_fd);
291   
292   if (listen_fd < 0)
293     {
294       _dbus_string_free (&address);
295       return NULL;
296     }
297   
298   server = _dbus_server_new_for_fd (listen_fd, &address);
299   if (server == NULL)
300     {
301       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
302       close (listen_fd);
303       _dbus_string_free (&address);
304       return NULL;
305     }
306
307   _dbus_string_free (&address);
308   
309   return server;
310 }
311
312 /**
313  * Creates a new server listening on the given hostname and port.
314  * If the hostname is NULL, listens on localhost.
315  *
316  * @param host the hostname to listen on.
317  * @param port the port to listen on.
318  * @param error location to store reason for failure.
319  * @returns the new server, or #NULL on failure.
320  */
321 DBusServer*
322 _dbus_server_new_for_tcp_socket (const char     *host,
323                                  dbus_uint32_t   port,
324                                  DBusError      *error)
325 {
326   DBusServer *server;
327   int listen_fd;
328   DBusString address;
329   
330   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
331
332   if (!_dbus_string_init (&address))
333     {
334       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
335       return NULL;
336     }
337
338   if (!_dbus_string_append (&address, "tcp:host=") ||
339       !_dbus_string_append (&address, host) ||
340       !_dbus_string_append (&address, ",port=") ||
341       !_dbus_string_append_int (&address, port))
342     {
343       _dbus_string_free (&address);
344       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
345       return NULL;
346     }
347   
348   listen_fd = _dbus_listen_tcp_socket (host, port, error);
349   _dbus_fd_set_close_on_exec (listen_fd);
350   
351   if (listen_fd < 0)
352     {
353       _dbus_string_free (&address);
354       return NULL;
355     }
356   
357   server = _dbus_server_new_for_fd (listen_fd, &address);
358   if (server == NULL)
359     {
360       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
361       close (listen_fd);
362       _dbus_string_free (&address);
363       return NULL;
364     }
365
366   _dbus_string_free (&address);
367   
368   return server;
369
370
371 }
372
373 /** @} */
374