1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport
4 * Copyright (C) 2002 Red Hat Inc.
6 * Licensed under the Academic Free License version 1.2
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.
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.
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
24 #include "dbus-internals.h"
25 #include "dbus-connection-internal.h"
26 #include "dbus-transport-unix.h"
27 #include "dbus-transport-protected.h"
28 #include "dbus-watch.h"
29 #include <sys/types.h>
35 * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
36 * @ingroup DBusInternals
37 * @brief Implementation details of DBusTransport on UNIX
43 * Opaque object representing a Unix file descriptor transport.
45 typedef struct DBusTransportUnix DBusTransportUnix;
48 * Implementation details of DBusTransportUnix. All members are private.
50 struct DBusTransportUnix
52 DBusTransport base; /**< Parent instance */
53 int fd; /**< File descriptor. */
54 DBusWatch *watch; /**< Watch for readability. */
55 DBusWatch *write_watch; /**< Watch for writability. */
57 int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
58 int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
60 int message_bytes_written; /**< Number of bytes of current
61 * outgoing message that have
67 unix_finalize (DBusTransport *transport)
69 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
71 _dbus_transport_finalize_base (transport);
73 if (unix_transport->watch)
75 _dbus_watch_invalidate (unix_transport->watch);
76 _dbus_watch_unref (unix_transport->watch);
79 dbus_free (transport);
83 do_io_error (DBusTransport *transport)
85 _dbus_transport_disconnect (transport);
86 _dbus_connection_transport_error (transport->connection,
87 DBUS_RESULT_DISCONNECTED);
91 do_writing (DBusTransport *transport)
94 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
98 while (_dbus_connection_have_messages_to_send (transport->connection))
101 DBusMessage *message;
102 const DBusString *header;
103 const DBusString *body;
104 int header_len, body_len;
106 if (total > unix_transport->max_bytes_written_per_iteration)
108 _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
109 total, unix_transport->max_bytes_written_per_iteration);
113 message = _dbus_connection_get_message_to_send (transport->connection);
114 _dbus_assert (message != NULL);
115 _dbus_message_lock (message);
117 _dbus_message_get_network_data (message,
120 header_len = _dbus_string_get_length (header);
121 body_len = _dbus_string_get_length (body);
123 if (unix_transport->message_bytes_written < header_len)
126 _dbus_write_two (unix_transport->fd,
128 unix_transport->message_bytes_written,
129 header_len - unix_transport->message_bytes_written,
136 _dbus_write (unix_transport->fd,
138 (unix_transport->message_bytes_written - header_len),
140 (unix_transport->message_bytes_written - header_len));
143 if (bytes_written < 0)
145 /* EINTR already handled for us */
147 if (errno == EAGAIN ||
148 errno == EWOULDBLOCK)
152 _dbus_verbose ("Error writing to message bus: %s\n",
153 _dbus_strerror (errno));
154 do_io_error (transport);
160 _dbus_verbose (" wrote %d bytes\n", bytes_written);
162 total += bytes_written;
163 unix_transport->message_bytes_written += bytes_written;
165 _dbus_assert (unix_transport->message_bytes_written <=
166 (header_len + body_len));
168 if (unix_transport->message_bytes_written == (header_len + body_len))
170 _dbus_connection_message_sent (transport->connection,
172 unix_transport->message_bytes_written = 0;
178 return; /* I think some C compilers require a statement after a label */
182 do_reading (DBusTransport *transport)
184 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
194 if (total > unix_transport->max_bytes_read_per_iteration)
196 _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
197 total, unix_transport->max_bytes_read_per_iteration);
201 _dbus_message_loader_get_buffer (transport->loader,
204 buffer_len = _dbus_string_get_length (buffer);
206 bytes_read = _dbus_read (unix_transport->fd,
207 buffer, unix_transport->max_bytes_read_per_iteration);
209 _dbus_message_loader_return_buffer (transport->loader,
211 bytes_read < 0 ? 0 : bytes_read);
215 /* EINTR already handled for us */
217 if (errno == EAGAIN ||
218 errno == EWOULDBLOCK)
222 _dbus_verbose ("Error reading from message bus: %s\n",
223 _dbus_strerror (errno));
224 do_io_error (transport);
228 else if (bytes_read == 0)
230 _dbus_verbose ("Disconnected from message bus\n");
231 do_io_error (transport);
236 DBusMessage *message;
238 _dbus_verbose (" read %d bytes\n", bytes_read);
242 /* Queue any messages */
243 while ((message = _dbus_message_loader_pop_message (transport->loader)))
245 _dbus_verbose ("queueing received message %p\n", message);
247 _dbus_connection_queue_received_message (transport->connection,
249 dbus_message_unref (message);
252 /* Try reading more data until we get EAGAIN and return, or
253 * exceed max bytes per iteration. If in blocking mode of
254 * course we'll block instead of returning.
260 return; /* I think some C compilers require a statement after a label */
264 unix_handle_watch (DBusTransport *transport,
268 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
270 _dbus_assert (watch == unix_transport->watch ||
271 watch == unix_transport->write_watch);
273 if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
275 _dbus_transport_disconnect (transport);
276 _dbus_connection_transport_error (transport->connection,
277 DBUS_RESULT_DISCONNECTED);
281 if (watch == unix_transport->watch &&
282 (flags & DBUS_WATCH_READABLE))
283 do_reading (transport);
284 else if (watch == unix_transport->write_watch &&
285 (flags & DBUS_WATCH_WRITABLE))
286 do_writing (transport);
290 unix_disconnect (DBusTransport *transport)
292 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
294 if (unix_transport->watch)
296 _dbus_connection_remove_watch (transport->connection,
297 unix_transport->watch);
298 _dbus_watch_invalidate (unix_transport->watch);
299 _dbus_watch_unref (unix_transport->watch);
300 unix_transport->watch = NULL;
303 close (unix_transport->fd);
304 unix_transport->fd = -1;
308 unix_connection_set (DBusTransport *transport)
310 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
313 _dbus_assert (unix_transport->watch == NULL);
315 watch = _dbus_watch_new (unix_transport->fd,
316 DBUS_WATCH_READABLE);
320 _dbus_transport_disconnect (transport);
324 if (!_dbus_connection_add_watch (transport->connection,
327 _dbus_transport_disconnect (transport);
331 unix_transport->watch = watch;
335 unix_messages_pending (DBusTransport *transport,
336 int messages_pending)
338 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
340 if (messages_pending > 0 &&
341 unix_transport->write_watch == NULL)
343 unix_transport->write_watch =
344 _dbus_watch_new (unix_transport->fd,
345 DBUS_WATCH_WRITABLE);
347 /* we can maybe add it some other time, just silently bomb */
348 if (unix_transport->write_watch == NULL)
351 if (!_dbus_connection_add_watch (transport->connection,
352 unix_transport->write_watch))
354 _dbus_watch_invalidate (unix_transport->write_watch);
355 _dbus_watch_unref (unix_transport->write_watch);
356 unix_transport->write_watch = NULL;
359 else if (messages_pending == 0 &&
360 unix_transport->write_watch != NULL)
362 _dbus_connection_remove_watch (transport->connection,
363 unix_transport->write_watch);
364 _dbus_watch_invalidate (unix_transport->write_watch);
365 _dbus_watch_unref (unix_transport->write_watch);
366 unix_transport->write_watch = NULL;
371 unix_do_iteration (DBusTransport *transport,
373 int timeout_milliseconds)
375 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
378 dbus_bool_t do_select;
383 if (flags & DBUS_ITERATION_DO_READING)
385 FD_SET (unix_transport->fd, &read_set);
389 FD_ZERO (&write_set);
390 if (flags & DBUS_ITERATION_DO_WRITING)
392 FD_SET (unix_transport->fd, &write_set);
399 struct timeval timeout;
400 dbus_bool_t use_timeout;
405 FD_SET (unix_transport->fd, &err_set);
407 if (flags & DBUS_ITERATION_BLOCK)
409 if (timeout_milliseconds >= 0)
411 timeout.tv_sec = timeout_milliseconds / 1000;
412 timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
414 /* Always use timeout if one is passed in. */
419 use_timeout = FALSE; /* NULL timeout to block forever */
424 /* 0 timeout to not block */
430 if (select (unix_transport->fd + 1, &read_set, &write_set, &err_set,
431 use_timeout ? &timeout : NULL) >= 0)
433 if (FD_ISSET (unix_transport->fd, &err_set))
434 do_io_error (transport);
437 if (FD_ISSET (unix_transport->fd, &read_set))
438 do_reading (transport);
439 if (FD_ISSET (unix_transport->fd, &write_set))
440 do_writing (transport);
443 else if (errno == EINTR)
447 _dbus_verbose ("Error from select(): %s\n",
448 _dbus_strerror (errno));
453 static DBusTransportVTable unix_vtable = {
458 unix_messages_pending,
463 * Creates a new transport for the given file descriptor. The file
464 * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
465 * make it so). This function is shared by various transports that
466 * boil down to a full duplex file descriptor.
468 * @param fd the file descriptor.
469 * @returns the new transport, or #NULL if no memory.
472 _dbus_transport_new_for_fd (int fd)
474 DBusTransportUnix *unix_transport;
476 unix_transport = dbus_new0 (DBusTransportUnix, 1);
477 if (unix_transport == NULL)
480 if (!_dbus_transport_init_base (&unix_transport->base,
483 dbus_free (unix_transport);
487 unix_transport->fd = fd;
488 unix_transport->message_bytes_written = 0;
490 /* These values should probably be tunable or something. */
491 unix_transport->max_bytes_read_per_iteration = 2048;
492 unix_transport->max_bytes_written_per_iteration = 2048;
494 return (DBusTransport*) unix_transport;
498 * Creates a new transport for the given Unix domain socket
501 * @param path the path to the domain socket.
502 * @param result location to store reason for failure.
503 * @returns a new transport, or #NULL on failure.
506 _dbus_transport_new_for_domain_socket (const char *path,
507 DBusResultCode *result)
510 DBusTransport *transport;
512 fd = _dbus_connect_unix_socket (path, result);
516 transport = _dbus_transport_new_for_fd (fd);
517 if (transport == NULL)
519 dbus_set_result (result, DBUS_RESULT_NO_MEMORY);