2003-04-24 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-server-debug.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-server-debug.h In-proc debug server implementation 
3  *
4  * Copyright (C) 2003  CodeFactory AB
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-debug.h"
26 #include "dbus-transport-debug.h"
27 #include "dbus-connection-internal.h"
28 #include "dbus-hash.h"
29
30 #ifdef DBUS_BUILD_TESTS
31
32 /**
33  * @defgroup DBusServerDebug DBusServerDebug
34  * @ingroup  DBusInternals
35  * @brief In-process debug server used in unit tests.
36  *
37  * Types and functions related to DBusServerDebug.
38  * This is used for unit testing.
39  *
40  * @{
41  */
42
43 /**
44  * Default timeout interval when reading or writing.
45  */
46 #define DEFAULT_INTERVAL 1
47
48 /**
49  * Opaque object representing a debug server implementation.
50  */
51 typedef struct DBusServerDebug DBusServerDebug;
52
53 /**
54  * Implementation details of DBusServerDebug. All members
55  * are private.
56  */
57 struct DBusServerDebug
58 {
59   DBusServer base;  /**< Parent class members. */
60
61   char *name; /**< Server name. */
62 };
63
64 /* Not thread safe, but OK since we don't use
65  * threads in the bus
66  */
67 static DBusHashTable *server_hash;
68
69 static void
70 debug_finalize (DBusServer *server)
71 {
72 }
73
74 static void
75 debug_disconnect (DBusServer *server)
76 {
77 }
78
79 static DBusServerVTable debug_vtable = {
80   debug_finalize,
81   debug_disconnect
82 };
83
84 /**
85  * Looks up a server by its name.
86  *
87  * @param server_name the server name.
88  * @returns the server, or #NULL if none exists.
89  */
90 DBusServer*
91 _dbus_server_debug_lookup (const char *server_name)
92 {
93   if (!server_hash)
94     return NULL;
95
96   return _dbus_hash_table_lookup_string (server_hash, server_name);
97 }
98
99 /**
100  * Creates a new debug server.
101  *
102  * @param server_name the name of the server.
103  * @param error address where an error can be returned.
104  * @returns a new server, or #NULL on failure.
105  */
106 DBusServer*
107 _dbus_server_debug_new (const char     *server_name,
108                         DBusError      *error)
109 {
110   DBusServerDebug *debug_server;
111   DBusString address;
112   
113   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
114   
115   if (!server_hash)
116     {
117       server_hash = _dbus_hash_table_new (DBUS_HASH_STRING, NULL, NULL);
118
119       if (!server_hash)
120         {
121           dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
122           return NULL;
123         }
124     }
125
126   if (_dbus_hash_table_lookup_string (server_hash, server_name) != NULL)
127     {
128       dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE,
129                       NULL);
130       return NULL;
131     }
132   
133   debug_server = dbus_new0 (DBusServerDebug, 1);
134
135   if (debug_server == NULL)
136     return NULL;
137
138   if (!_dbus_string_init (&address))
139     goto nomem_0;
140
141   if (!_dbus_string_append (&address, "debug:name=") ||
142       !_dbus_string_append (&address, server_name))
143     goto nomem_1;
144   
145   debug_server->name = _dbus_strdup (server_name);
146   if (debug_server->name == NULL)
147     goto nomem_1;
148   
149   if (!_dbus_server_init_base (&debug_server->base,
150                                &debug_vtable,
151                                &address))
152     goto nomem_2;
153
154   if (!_dbus_hash_table_insert_string (server_hash,
155                                        debug_server->name,
156                                        debug_server))
157     goto nomem_3;
158
159   _dbus_string_free (&address);
160   
161   return (DBusServer *)debug_server;
162
163  nomem_3:
164   _dbus_server_finalize_base (&debug_server->base);
165  nomem_2:
166   dbus_free (debug_server->name);
167  nomem_1:
168   _dbus_string_free (&address);
169  nomem_0:
170   dbus_free (debug_server);
171
172   dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
173   
174   return NULL;
175 }
176
177 typedef struct
178 {
179   DBusServer *server;
180   DBusTransport *transport;
181   DBusTimeout *timeout;
182 } ServerAndTransport;
183
184 static dbus_bool_t
185 handle_new_client (void *data)
186 {
187   ServerAndTransport *st = data;
188   DBusTransport *transport;
189   DBusConnection *connection;
190
191   _dbus_verbose ("  new debug client transport %p connecting to server\n",
192                  st->transport);
193   
194   transport = _dbus_transport_debug_server_new (st->transport);
195   if (transport == NULL)
196     return FALSE;
197
198   connection = _dbus_connection_new_for_transport (transport);
199   _dbus_transport_unref (transport);
200
201   if (connection == NULL)
202     return FALSE;
203
204   /* See if someone wants to handle this new connection,
205    * self-referencing for paranoia
206    */
207   if (st->server->new_connection_function)
208     {
209       dbus_server_ref (st->server);
210       
211       (* st->server->new_connection_function) (st->server, connection,
212                                                st->server->new_connection_data);
213       dbus_server_unref (st->server);
214     }
215
216   _dbus_server_remove_timeout (st->server, st->timeout);
217   
218   /* If no one grabbed a reference, the connection will die. */
219   dbus_connection_unref (connection);
220
221   /* killing timeout frees both "st" and "timeout" */
222   _dbus_timeout_unref (st->timeout);
223
224   return TRUE;
225 }
226
227 /**
228  * Tells the server to accept a transport so the transport
229  * can send messages to it.
230  *
231  * @param server the server
232  * @param transport the transport
233  * @returns #TRUE on success.
234  */
235 dbus_bool_t
236 _dbus_server_debug_accept_transport (DBusServer     *server,
237                                      DBusTransport  *transport)
238 {
239   ServerAndTransport *st = NULL;
240
241   st = dbus_new (ServerAndTransport, 1);
242   if (st == NULL)
243     return FALSE;
244
245   st->transport = transport;
246   st->server = server;
247   
248   st->timeout = _dbus_timeout_new (DEFAULT_INTERVAL, handle_new_client, st,
249                                    dbus_free);
250
251   if (st->timeout == NULL)
252     goto failed;
253
254   if (!_dbus_server_add_timeout (server, st->timeout))
255     goto failed;
256   
257   return TRUE;
258
259  failed:
260   if (st->timeout)
261     _dbus_timeout_unref (st->timeout);
262   dbus_free (st);
263   return FALSE;
264 }
265
266 /** @} */
267
268 #endif /* DBUS_BUILD_TESTS */
269