2002-12-11 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-transport.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport.c DBusTransport object (internal to D-BUS implementation)
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-transport-protected.h"
25 #include "dbus-transport-unix.h"
26 #include "dbus-connection-internal.h"
27 #include "dbus-watch.h"
28
29 /**
30  * @defgroup DBusTransport DBusTransport object
31  * @ingroup  DBusInternals
32  * @brief "Backend" for a DBusConnection.
33  *
34  * Types and functions related to DBusTransport.  A transport is an
35  * abstraction that can send and receive data via various kinds of
36  * network connections or other IPC mechanisms.
37  * 
38  * @{
39  */
40
41 /**
42  * @typedef DBusTransport
43  *
44  * Opaque object representing a way message stream.
45  * DBusTransport abstracts various kinds of actual
46  * transport mechanism, such as different network protocols,
47  * or encryption schemes.
48  */
49
50 /**
51  * Initializes the base class members of DBusTransport.
52  * Chained up to by subclasses in their constructor.
53  *
54  * @param transport the transport being created.
55  * @param vtable the subclass vtable.
56  * @returns #TRUE on success.
57  */
58 dbus_bool_t
59 _dbus_transport_init_base (DBusTransport             *transport,
60                            const DBusTransportVTable *vtable)
61 {
62   DBusMessageLoader *loader;
63
64   loader = _dbus_message_loader_new ();
65   if (loader == NULL)
66     return FALSE;
67   
68   transport->refcount = 1;
69   transport->vtable = vtable;
70   transport->loader = loader;
71   
72   return TRUE;
73 }
74
75 /**
76  * Finalizes base class members of DBusTransport.
77  * Chained up to from subclass finalizers.
78  *
79  * @param transport the transport.
80  */
81 void
82 _dbus_transport_finalize_base (DBusTransport *transport)
83 {
84   if (!transport->disconnected)
85     _dbus_transport_disconnect (transport);
86
87   _dbus_message_loader_unref (transport->loader);
88 }
89
90 /**
91  * Opens a new transport for the given address.
92  *
93  * @todo right now the address is just a Unix domain socket path.
94  * 
95  * @param address the address.
96  * @param result location to store reason for failure.
97  * @returns new transport of #NULL on failure.
98  */
99 DBusTransport*
100 _dbus_transport_open (const char     *address,
101                       DBusResultCode *result)
102 {
103   DBusTransport *transport;
104   
105   /* FIXME parse the address - whatever format
106    * we decide addresses are in - and find the
107    * appropriate transport.
108    */
109
110   /* Pretend it's just a unix domain socket name for now */
111   transport = _dbus_transport_new_for_domain_socket (address, result);
112   
113   return transport;
114 }
115
116 /**
117  * Increments the reference count for the transport.
118  *
119  * @param transport the transport.
120  */
121 void
122 _dbus_transport_ref (DBusTransport *transport)
123 {
124   transport->refcount += 1;
125 }
126
127 /**
128  * Decrements the reference count for the transport.
129  * Disconnects and finalizes the transport if
130  * the reference count reaches zero.
131  *
132  * @param transport the transport.
133  */
134 void
135 _dbus_transport_unref (DBusTransport *transport)
136 {
137   _dbus_assert (transport != NULL);
138   _dbus_assert (transport->refcount > 0);
139
140   transport->refcount -= 1;
141   if (transport->refcount == 0)
142     {
143       _dbus_assert (transport->vtable->finalize != NULL);
144       
145       (* transport->vtable->finalize) (transport);
146     }
147 }
148
149 /**
150  * Closes our end of the connection to a remote application. Further
151  * attempts to use this transport will fail. Only the first call to
152  * _dbus_transport_disconnect() will have an effect.
153  *
154  * @param transport the transport.
155  * 
156  */
157 void
158 _dbus_transport_disconnect (DBusTransport *transport)
159 {
160   _dbus_assert (transport->vtable->disconnect != NULL);
161
162   if (transport->disconnected)
163     return;
164   
165   (* transport->vtable->disconnect) (transport);
166
167   transport->disconnected = TRUE;
168 }
169
170 /**
171  * Returns #TRUE if the transport has not been disconnected.
172  * Disconnection can result from _dbus_transport_disconnect()
173  * or because the server drops its end of the connection.
174  *
175  * @param transport the transport.
176  */
177 dbus_bool_t
178 _dbus_transport_get_is_connected (DBusTransport *transport)
179 {
180   return !transport->disconnected;
181 }
182
183 /**
184  * Handles a watch by reading data, writing data, or disconnecting
185  * the transport, as appropriate for the given condition.
186  *
187  * @param transport the transport.
188  * @param watch the watch.
189  * @param condition the current state of the watched file descriptor.
190  */
191 void
192 _dbus_transport_handle_watch (DBusTransport           *transport,
193                               DBusWatch               *watch,
194                               unsigned int             condition)
195 {
196   _dbus_assert (transport->vtable->handle_watch != NULL);
197
198   if (transport->disconnected)
199     {
200       _dbus_connection_transport_error (transport->connection,
201                                         DBUS_RESULT_DISCONNECTED);
202       return;
203     }
204
205   _dbus_watch_sanitize_condition (watch, &condition);
206   
207   (* transport->vtable->handle_watch) (transport, watch, condition);
208 }
209
210 /**
211  * Sets the connection using this transport. Allows the transport
212  * to add watches to the connection, queue incoming messages,
213  * and pull outgoing messages.
214  *
215  * @param transport the transport.
216  * @param connection the connection.
217  */
218 void
219 _dbus_transport_set_connection (DBusTransport  *transport,
220                                 DBusConnection *connection)
221 {
222   _dbus_assert (transport->vtable->connection_set != NULL);
223   _dbus_assert (transport->connection == NULL);
224   
225   transport->connection = connection;
226
227   (* transport->vtable->connection_set) (transport);
228 }
229
230 /**
231  * Notifies the transport when the outgoing message queue goes from
232  * empty to non-empty or vice versa. Typically causes the transport to
233  * add or remove its DBUS_WATCH_WRITABLE watch.
234  *
235  * @param transport the transport.
236  * @param queue_length the length of the outgoing message queue.
237  *
238  */
239 void
240 _dbus_transport_messages_pending (DBusTransport  *transport,
241                                   int             queue_length)
242 {
243   _dbus_assert (transport->vtable->messages_pending != NULL);
244
245   if (transport->disconnected)
246     {
247       _dbus_connection_transport_error (transport->connection,
248                                         DBUS_RESULT_DISCONNECTED);
249       return;
250     }
251   
252   (* transport->vtable->messages_pending) (transport,
253                                            queue_length);
254 }
255
256 /**
257  * Performs a single poll()/select() on the transport's file
258  * descriptors and then reads/writes data as appropriate,
259  * queueing incoming messages and sending outgoing messages.
260  * This is the backend for _dbus_connection_do_iteration().
261  * See _dbus_connection_do_iteration() for full details.
262  *
263  * @param transport the transport.
264  * @param flags indicates whether to read or write, and whether to block.
265  * @param timeout_milliseconds if blocking, timeout or -1 for no timeout.
266  */
267 void
268 _dbus_transport_do_iteration (DBusTransport  *transport,
269                               unsigned int    flags,
270                               int             timeout_milliseconds)
271 {
272   _dbus_assert (transport->vtable->do_iteration != NULL);
273
274   if ((flags & (DBUS_ITERATION_DO_WRITING |
275                 DBUS_ITERATION_DO_READING)) == 0)
276     return; /* Nothing to do */
277
278   if (transport->disconnected)
279     {
280       _dbus_connection_transport_error (transport->connection,
281                                         DBUS_RESULT_DISCONNECTED);
282       return;
283     }
284   
285   (* transport->vtable->do_iteration) (transport, flags,
286                                        timeout_milliseconds);
287 }
288
289 /** @} */