~ubuntu-branches/ubuntu/oneiric/dbus/oneiric-201107131641

« back to all changes in this revision

Viewing changes to dbus/dbus-server-socket.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2006-11-07 22:16:14 UTC
  • mto: (1.2.2 lenny)
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20061107221614-h1f47bhe3i0w5t3b
Tags: upstream-0.95
Import upstream version 0.95

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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