2003-02-16 Anders Carlsson <andersca@codefactory.se>
[platform/upstream/dbus.git] / dbus / dbus-transport-debug.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport-debug.c In-proc debug subclass of DBusTransport
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-connection-internal.h"
26 #include "dbus-transport-protected.h"
27 #include "dbus-transport-debug.h"
28 #include "dbus-server-debug.h"
29 #include "dbus-list.h"
30
31 #ifdef DBUS_BUILD_TESTS
32
33 /**
34  * @defgroup DBusTransportDebug DBusTransportDebug
35  * @ingroup  DBusInternals
36  * @brief In-process debug transport used in unit tests.
37  *
38  * Types and functions related to DBusTransportDebug.
39  * This is used for unit testing.
40  *
41  * @{
42  */
43
44 /**
45  * Default timeout interval when reading or writing.
46  */
47 #define DEFAULT_INTERVAL 10
48
49 /**
50  * Opaque object representing a debug transport.
51  *
52  */
53 typedef struct DBusTransportDebug DBusTransportDebug;
54
55 /**
56  * Implementation details of DBusTransportDebug. All members are private.
57  */
58 struct DBusTransportDebug
59 {
60   DBusTransport base;                   /**< Parent instance */
61
62   DBusTimeout *write_timeout;           /**< Timeout for reading. */
63   DBusTimeout *read_timeout;            /**< Timeout for writing. */
64   
65   DBusTransport *other_end;             /**< The transport that this transport is connected to. */
66 };
67
68 static void
69 debug_finalize (DBusTransport *transport)
70 {
71   _dbus_transport_finalize_base (transport);  
72
73   dbus_free (transport);
74 }
75
76 static void
77 do_reading (DBusTransport *transport)
78 {
79   DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
80   
81   if (transport->disconnected)
82     return;
83
84   /* Now dispatch the messages */
85   if (dbus_connection_dispatch_message (transport->connection))
86     {
87       debug_transport->read_timeout =
88         _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_reading,
89                            transport, NULL);
90       if (!_dbus_connection_add_timeout (transport->connection,
91                                          debug_transport->read_timeout))
92         {
93           _dbus_timeout_unref (debug_transport->read_timeout);
94           debug_transport->read_timeout = NULL;
95         }
96     }
97 }
98
99 static void
100 check_read_timeout (DBusTransport *transport)
101 {
102   DBusTransportDebug *debug_transport = (DBusTransportDebug*) transport;
103   dbus_bool_t need_read_timeout;
104
105   if (transport->connection == NULL)
106     return;
107
108   _dbus_transport_ref (transport);
109   
110   need_read_timeout = dbus_connection_get_n_messages (transport->connection) > 0;
111   
112   if (transport->disconnected)
113     need_read_timeout = FALSE;
114   
115   if (need_read_timeout &&
116       debug_transport->read_timeout == NULL)
117     {
118       debug_transport->read_timeout =
119         _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_reading,
120                            transport, NULL);
121
122       if (debug_transport->read_timeout == NULL)
123         goto out;
124
125       if (!_dbus_connection_add_timeout (transport->connection,
126                                          debug_transport->read_timeout))
127         {
128           _dbus_timeout_unref (debug_transport->read_timeout);
129           debug_transport->read_timeout = NULL;
130
131           goto out;
132         }
133     }
134   else if (!need_read_timeout &&
135            debug_transport->read_timeout != NULL)
136     {
137       _dbus_connection_remove_timeout (transport->connection,
138                                        debug_transport->read_timeout);
139       _dbus_timeout_unref (debug_transport->read_timeout);
140       debug_transport->read_timeout = NULL;
141     }
142
143  out:
144   _dbus_transport_unref (transport);      
145 }
146
147 static void
148 do_writing (DBusTransport *transport)
149 {
150   if (transport->disconnected)
151     return;
152
153   while (!transport->disconnected &&
154          _dbus_connection_have_messages_to_send (transport->connection))
155     {
156       DBusMessage *message, *copy;
157       
158       message = _dbus_connection_get_message_to_send (transport->connection);
159       _dbus_message_lock (message);
160       
161       copy = dbus_message_new_from_message (message);
162       
163       _dbus_connection_message_sent (transport->connection,
164                                      message);
165       
166       _dbus_connection_queue_received_message (((DBusTransportDebug *)transport)->other_end->connection,
167                                                copy);
168       dbus_message_unref (copy);
169     }
170
171   check_read_timeout (((DBusTransportDebug *)transport)->other_end);
172 }
173
174 static void
175 check_write_timeout (DBusTransport *transport)
176 {
177   DBusTransportDebug *debug_transport = (DBusTransportDebug *)transport;
178   dbus_bool_t need_write_timeout;
179   
180   if (transport->connection == NULL)
181     return;
182
183   _dbus_transport_ref (transport);
184
185   need_write_timeout = transport->messages_need_sending;
186   
187   if (transport->disconnected)
188     need_write_timeout = FALSE;
189
190   if (need_write_timeout &&
191       debug_transport->write_timeout == NULL)
192     {
193       debug_transport->write_timeout =
194         _dbus_timeout_new (DEFAULT_INTERVAL, (DBusTimeoutHandler)do_writing,
195                            transport, NULL);
196
197       if (debug_transport->write_timeout == NULL)
198         goto out;
199
200       if (!_dbus_connection_add_timeout (transport->connection,
201                                          debug_transport->write_timeout))
202         {
203           _dbus_timeout_unref (debug_transport->write_timeout);
204           debug_transport->write_timeout = NULL;
205         }
206     }
207   else if (!need_write_timeout &&
208            debug_transport->write_timeout != NULL)
209     {
210       _dbus_connection_remove_timeout (transport->connection,
211                                        debug_transport->write_timeout);
212       _dbus_timeout_unref (debug_transport->write_timeout);
213       debug_transport->write_timeout = NULL;
214     }
215
216  out:
217   _dbus_transport_unref (transport);
218 }
219
220 static void
221 debug_handle_watch (DBusTransport *transport,
222                     DBusWatch     *watch,
223                     unsigned int   flags)
224 {
225 }
226
227 static void
228 debug_disconnect (DBusTransport *transport)
229 {
230 }
231
232 static void
233 debug_connection_set (DBusTransport *transport)
234 {
235 }
236
237 static void
238 debug_messages_pending (DBusTransport *transport,
239                         int            messages_pending)
240 {
241   check_write_timeout (transport);
242 }
243
244 static void
245 debug_do_iteration (DBusTransport *transport,
246                     unsigned int   flags,
247                     int            timeout_milliseconds)
248 {
249 }
250
251 static void
252 debug_live_messages_changed (DBusTransport *transport)
253 {
254 }
255
256 static DBusTransportVTable debug_vtable = {
257   debug_finalize,
258   debug_handle_watch,
259   debug_disconnect,
260   debug_connection_set,
261   debug_messages_pending,
262   debug_do_iteration,
263   debug_live_messages_changed
264 };
265
266 /**
267  * Creates a new debug server transport.
268  *
269  * @param client the client transport that the server transport
270  * should use.
271  * @returns a new debug transport
272  */
273 DBusTransport*
274 _dbus_transport_debug_server_new (DBusTransport *client)
275 {
276   DBusTransportDebug *debug_transport;
277
278   debug_transport = dbus_new0 (DBusTransportDebug, 1);
279   
280   if (debug_transport == NULL)
281     return NULL;
282
283   if (!_dbus_transport_init_base (&debug_transport->base,
284                                   &debug_vtable,
285                                   TRUE))
286     {
287       dbus_free (debug_transport);
288       return NULL;
289     }
290
291   debug_transport->base.authenticated = TRUE;
292
293   /* Connect the two transports */
294   debug_transport->other_end = client;
295   ((DBusTransportDebug *)client)->other_end = (DBusTransport *)debug_transport;
296   
297   return (DBusTransport *)debug_transport;
298 }
299
300 /**
301  * Creates a new debug client transport.
302  *
303  * @param server_name name of the server transport that
304  * the client should try to connect to.
305  * @param result address where a result code can be returned.
306  * @returns a new transport, or #NULL on failure. 
307  */
308 DBusTransport*
309 _dbus_transport_debug_client_new (const char     *server_name,
310                                   DBusResultCode *result)
311 {
312   DBusServer *debug_server;
313   DBusTransportDebug *debug_transport;
314   
315   debug_server = _dbus_server_debug_lookup (server_name);
316
317   if (!debug_server)
318     {
319       dbus_set_result (result, DBUS_RESULT_NO_SERVER);
320       return NULL;
321     }
322
323   debug_transport = dbus_new0 (DBusTransportDebug, 1);
324   if (debug_transport == NULL)
325     {
326       dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
327       return NULL;
328     }
329
330   if (!_dbus_transport_init_base (&debug_transport->base,
331                                   &debug_vtable,
332                                   FALSE))
333     {
334       dbus_free (debug_transport);
335       dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
336       return NULL;
337     }
338
339   if (!_dbus_server_debug_accept_transport (debug_server, (DBusTransport *)debug_transport))
340     {
341       _dbus_transport_finalize_base (&debug_transport->base);
342
343       dbus_free (debug_transport);      
344       dbus_set_result (result, DBUS_RESULT_IO_ERROR);
345       return NULL;
346       
347     }
348
349   /* FIXME: Prolly wrong to do this. */
350   debug_transport->base.authenticated = TRUE;
351   
352   return (DBusTransport *)debug_transport;
353 }
354
355 /** @} */
356
357 #endif /* DBUS_BUILD_TESTS */