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>
34 * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
35 * @ingroup DBusInternals
36 * @brief Implementation details of DBusTransport on UNIX
42 * Opaque object representing a Unix file descriptor transport.
44 typedef struct DBusTransportUnix DBusTransportUnix;
47 * Implementation details of DBusTransportUnix. All members are private.
49 struct DBusTransportUnix
51 DBusTransport base; /**< Parent instance */
52 int fd; /**< File descriptor. */
53 DBusWatch *watch; /**< Watch for readability. */
54 DBusWatch *write_watch; /**< Watch for writability. */
56 int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
57 int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
59 int message_bytes_written; /**< Number of bytes of current
60 * outgoing message that have
66 unix_finalize (DBusTransport *transport)
68 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
70 _dbus_transport_finalize_base (transport);
72 if (unix_transport->watch)
74 _dbus_watch_invalidate (unix_transport->watch);
75 _dbus_watch_unref (unix_transport->watch);
78 dbus_free (transport);
82 do_io_error (DBusTransport *transport)
84 _dbus_transport_disconnect (transport);
85 _dbus_connection_transport_error (transport->connection,
86 DBUS_RESULT_DISCONNECTED);
90 do_writing (DBusTransport *transport)
93 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
97 while (_dbus_connection_have_messages_to_send (transport->connection))
100 DBusMessage *message;
101 const DBusString *header;
102 const DBusString *body;
103 int header_len, body_len;
105 if (total > unix_transport->max_bytes_written_per_iteration)
107 _dbus_verbose ("%d bytes exceeds %d bytes written per iteration, returning\n",
108 total, unix_transport->max_bytes_written_per_iteration);
112 message = _dbus_connection_get_message_to_send (transport->connection);
113 _dbus_assert (message != NULL);
114 _dbus_message_lock (message);
116 _dbus_message_get_network_data (message,
119 header_len = _dbus_string_get_length (header);
120 body_len = _dbus_string_get_length (body);
122 if (unix_transport->message_bytes_written < header_len)
125 _dbus_write_two (unix_transport->fd,
127 unix_transport->message_bytes_written,
128 header_len - unix_transport->message_bytes_written,
135 _dbus_write (unix_transport->fd,
137 (unix_transport->message_bytes_written - header_len),
139 (unix_transport->message_bytes_written - header_len));
142 if (bytes_written < 0)
144 /* EINTR already handled for us */
146 if (errno == EAGAIN ||
147 errno == EWOULDBLOCK)
151 _dbus_verbose ("Error writing to message bus: %s\n",
152 _dbus_strerror (errno));
153 do_io_error (transport);
159 _dbus_verbose (" wrote %d bytes\n", bytes_written);
161 total += bytes_written;
162 unix_transport->message_bytes_written += bytes_written;
164 _dbus_assert (unix_transport->message_bytes_written <=
165 (header_len + body_len));
167 if (unix_transport->message_bytes_written == (header_len + body_len))
169 _dbus_connection_message_sent (transport->connection,
171 unix_transport->message_bytes_written = 0;
177 return; /* I think some C compilers require a statement after a label */
181 do_reading (DBusTransport *transport)
183 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
193 if (total > unix_transport->max_bytes_read_per_iteration)
195 _dbus_verbose ("%d bytes exceeds %d bytes read per iteration, returning\n",
196 total, unix_transport->max_bytes_read_per_iteration);
200 _dbus_message_loader_get_buffer (transport->loader,
203 buffer_len = _dbus_string_get_length (buffer);
205 bytes_read = _dbus_read (unix_transport->fd,
206 buffer, unix_transport->max_bytes_read_per_iteration);
208 _dbus_message_loader_return_buffer (transport->loader,
210 bytes_read < 0 ? 0 : bytes_read);
214 /* EINTR already handled for us */
216 if (errno == EAGAIN ||
217 errno == EWOULDBLOCK)
221 _dbus_verbose ("Error reading from message bus: %s\n",
222 _dbus_strerror (errno));
223 do_io_error (transport);
227 else if (bytes_read == 0)
229 _dbus_verbose ("Disconnected from message bus\n");
230 do_io_error (transport);
235 DBusMessage *message;
237 _dbus_verbose (" read %d bytes\n", bytes_read);
241 /* Queue any messages */
242 while ((message = _dbus_message_loader_pop_message (transport->loader)))
244 _dbus_verbose ("queueing received message %p\n", message);
246 _dbus_connection_queue_received_message (transport->connection,
248 dbus_message_unref (message);
251 /* Try reading more data until we get EAGAIN and return, or
252 * exceed max bytes per iteration. If in blocking mode of
253 * course we'll block instead of returning.
259 return; /* I think some C compilers require a statement after a label */
263 unix_handle_watch (DBusTransport *transport,
267 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
269 _dbus_assert (watch == unix_transport->watch ||
270 watch == unix_transport->write_watch);
272 if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
274 _dbus_transport_disconnect (transport);
275 _dbus_connection_transport_error (transport->connection,
276 DBUS_RESULT_DISCONNECTED);
280 if (watch == unix_transport->watch &&
281 (flags & DBUS_WATCH_READABLE))
282 do_reading (transport);
283 else if (watch == unix_transport->write_watch &&
284 (flags & DBUS_WATCH_WRITABLE))
285 do_writing (transport);
289 unix_disconnect (DBusTransport *transport)
291 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
293 if (unix_transport->watch)
295 _dbus_connection_remove_watch (transport->connection,
296 unix_transport->watch);
297 _dbus_watch_invalidate (unix_transport->watch);
298 _dbus_watch_unref (unix_transport->watch);
299 unix_transport->watch = NULL;
302 close (unix_transport->fd);
303 unix_transport->fd = -1;
307 unix_connection_set (DBusTransport *transport)
309 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
312 _dbus_assert (unix_transport->watch == NULL);
314 watch = _dbus_watch_new (unix_transport->fd,
315 DBUS_WATCH_READABLE);
319 _dbus_transport_disconnect (transport);
323 if (!_dbus_connection_add_watch (transport->connection,
326 _dbus_transport_disconnect (transport);
330 unix_transport->watch = watch;
334 unix_messages_pending (DBusTransport *transport,
335 int messages_pending)
337 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
339 if (messages_pending > 0 &&
340 unix_transport->write_watch == NULL)
342 unix_transport->write_watch =
343 _dbus_watch_new (unix_transport->fd,
344 DBUS_WATCH_WRITABLE);
346 /* we can maybe add it some other time, just silently bomb */
347 if (unix_transport->write_watch == NULL)
350 if (!_dbus_connection_add_watch (transport->connection,
351 unix_transport->write_watch))
353 _dbus_watch_invalidate (unix_transport->write_watch);
354 _dbus_watch_unref (unix_transport->write_watch);
355 unix_transport->write_watch = NULL;
358 else if (messages_pending == 0 &&
359 unix_transport->write_watch != NULL)
361 _dbus_connection_remove_watch (transport->connection,
362 unix_transport->write_watch);
363 _dbus_watch_invalidate (unix_transport->write_watch);
364 _dbus_watch_unref (unix_transport->write_watch);
365 unix_transport->write_watch = NULL;
370 unix_do_iteration (DBusTransport *transport,
372 int timeout_milliseconds)
374 DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
377 dbus_bool_t do_select;
382 if (flags & DBUS_ITERATION_DO_READING)
384 FD_SET (unix_transport->fd, &read_set);
388 FD_ZERO (&write_set);
389 if (flags & DBUS_ITERATION_DO_WRITING)
391 FD_SET (unix_transport->fd, &write_set);
398 struct timeval timeout;
399 dbus_bool_t use_timeout;
404 FD_SET (unix_transport->fd, &err_set);
406 if (flags & DBUS_ITERATION_BLOCK)
408 if (timeout_milliseconds >= 0)
410 timeout.tv_sec = timeout_milliseconds / 1000;
411 timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
413 /* Always use timeout if one is passed in. */
418 use_timeout = FALSE; /* NULL timeout to block forever */
423 /* 0 timeout to not block */
429 if (select (unix_transport->fd + 1, &read_set, &write_set, &err_set,
430 use_timeout ? &timeout : NULL) >= 0)
432 if (FD_ISSET (unix_transport->fd, &err_set))
433 do_io_error (transport);
436 if (FD_ISSET (unix_transport->fd, &read_set))
437 do_reading (transport);
438 if (FD_ISSET (unix_transport->fd, &write_set))
439 do_writing (transport);
442 else if (errno == EINTR)
446 _dbus_verbose ("Error from select(): %s\n",
447 _dbus_strerror (errno));
452 static DBusTransportVTable unix_vtable = {
457 unix_messages_pending,
462 * Creates a new transport for the given file descriptor. The file
463 * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
464 * make it so). This function is shared by various transports that
465 * boil down to a full duplex file descriptor.
467 * @param fd the file descriptor.
468 * @returns the new transport, or #NULL if no memory.
471 _dbus_transport_new_for_fd (int fd)
473 DBusTransportUnix *unix_transport;
475 unix_transport = dbus_new0 (DBusTransportUnix, 1);
476 if (unix_transport == NULL)
479 if (!_dbus_transport_init_base (&unix_transport->base,
482 dbus_free (unix_transport);
486 unix_transport->fd = fd;
487 unix_transport->message_bytes_written = 0;
489 /* These values should probably be tunable or something. */
490 unix_transport->max_bytes_read_per_iteration = 2048;
491 unix_transport->max_bytes_written_per_iteration = 2048;
493 return (DBusTransport*) unix_transport;
497 * Creates a new transport for the given Unix domain socket
500 * @param path the path to the domain socket.
501 * @param result location to store reason for failure.
502 * @returns a new transport, or #NULL on failure.
505 _dbus_transport_new_for_domain_socket (const char *path,
506 DBusResultCode *result)
509 DBusTransport *transport;
511 fd = _dbus_connect_unix_socket (path, result);
515 transport = _dbus_transport_new_for_fd (fd);
516 if (transport == NULL)
518 dbus_set_result (result, DBUS_RESULT_NO_MEMORY);