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