*
* Copyright (C) 2002, 2003 Red Hat Inc.
*
- * Licensed under the Academic Free License version 1.2
+ * Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "dbus-transport-unix.h"
#include "dbus-transport-protected.h"
#include "dbus-watch.h"
-#include <sys/types.h>
-#include <sys/time.h>
-#include <unistd.h>
/**
transport->receive_credentials_pending);
goto out;
}
-
+
+#define TRANSPORT_SIDE(t) ((t)->is_server ? "server" : "client")
switch (_dbus_auth_do_work (transport->auth))
{
case DBUS_AUTH_STATE_WAITING_FOR_INPUT:
- _dbus_verbose (" auth state: waiting for input\n");
+ _dbus_verbose (" %s auth state: waiting for input\n",
+ TRANSPORT_SIDE (transport));
if (!do_reading || !read_data_into_auth (transport, &oom))
goto out;
break;
case DBUS_AUTH_STATE_WAITING_FOR_MEMORY:
- _dbus_verbose (" auth state: waiting for memory\n");
+ _dbus_verbose (" %s auth state: waiting for memory\n",
+ TRANSPORT_SIDE (transport));
oom = TRUE;
goto out;
break;
case DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND:
- _dbus_verbose (" auth state: bytes to send\n");
+ _dbus_verbose (" %s auth state: bytes to send\n",
+ TRANSPORT_SIDE (transport));
if (!do_writing || !write_data_from_auth (transport))
goto out;
break;
case DBUS_AUTH_STATE_NEED_DISCONNECT:
- _dbus_verbose (" auth state: need to disconnect\n");
+ _dbus_verbose (" %s auth state: need to disconnect\n",
+ TRANSPORT_SIDE (transport));
do_io_error (transport);
break;
- case DBUS_AUTH_STATE_AUTHENTICATED_WITH_UNUSED_BYTES:
- _dbus_verbose (" auth state: auth with unused bytes\n");
- /* We'll recover the unused bytes in dbus-transport.c */
- goto out;
- break;
-
case DBUS_AUTH_STATE_AUTHENTICATED:
- _dbus_verbose (" auth state: authenticated\n");
+ _dbus_verbose (" %s auth state: authenticated\n",
+ TRANSPORT_SIDE (transport));
break;
}
}
/* No messages without authentication! */
if (!_dbus_transport_get_is_authenticated (transport))
- return TRUE;
+ {
+ _dbus_verbose ("Not authenticated, not writing anything\n");
+ return TRUE;
+ }
if (transport->disconnected)
- return TRUE;
+ {
+ _dbus_verbose ("Not connected, not writing anything\n");
+ return TRUE;
+ }
+#if 0
+ _dbus_verbose ("do_writing(), have_messages = %d\n",
+ _dbus_connection_have_messages_to_send (transport->connection));
+#endif
+
oom = FALSE;
total = 0;
}
}
else
- {
+ {
_dbus_verbose (" wrote %d bytes of %d\n", bytes_written,
total_bytes_to_write);
total = 0;
again:
-
+
/* See if we've exceeded max messages and need to disable reading */
check_read_watch (transport);
- if (!dbus_watch_get_enabled (unix_transport->read_watch))
- return TRUE;
if (total > unix_transport->max_bytes_read_per_iteration)
{
goto out;
}
+ _dbus_assert (unix_transport->read_watch != NULL ||
+ transport->disconnected);
+
if (transport->disconnected)
goto out;
+ if (!dbus_watch_get_enabled (unix_transport->read_watch))
+ return TRUE;
+
if (_dbus_auth_needs_decoding (transport->auth))
{
if (_dbus_string_get_length (&unix_transport->encoded_incoming) > 0)
total += bytes_read;
- if (_dbus_transport_queue_messages (transport) == DBUS_DISPATCH_NEED_MEMORY)
+ if (!_dbus_transport_queue_messages (transport))
{
oom = TRUE;
+ _dbus_verbose (" out of memory when queueing messages we just read in the transport\n");
goto out;
}
_dbus_assert (watch == unix_transport->read_watch ||
watch == unix_transport->write_watch);
- if (flags & (DBUS_WATCH_HANGUP | DBUS_WATCH_ERROR))
+ /* Disconnect in case of an error. In case of hangup do not
+ * disconnect the transport because data can still be in the buffer
+ * and do_reading may need several iteration to read it all (because
+ * of its max_bytes_read_per_iteration limit). The condition where
+ * flags == HANGUP (without READABLE) probably never happen in fact.
+ */
+ if ((flags & DBUS_WATCH_ERROR) ||
+ ((flags & DBUS_WATCH_HANGUP) && !(flags & DBUS_WATCH_READABLE)))
{
+ _dbus_verbose ("Hang up or error on watch\n");
_dbus_transport_disconnect (transport);
return TRUE;
}
(flags & DBUS_WATCH_READABLE))
{
#if 0
- _dbus_verbose ("handling read watch\n");
+ _dbus_verbose ("handling read watch (%x)\n", flags);
#endif
if (!do_authentication (transport, TRUE, FALSE))
return FALSE;
if (!do_reading (transport))
- return FALSE;
+ {
+ _dbus_verbose ("no memory to read\n");
+ return FALSE;
+ }
}
else if (watch == unix_transport->write_watch &&
(flags & DBUS_WATCH_WRITABLE))
{
#if 0
- _dbus_verbose ("handling write watch\n");
+ _dbus_verbose ("handling write watch, messages_need_sending = %d\n",
+ transport->messages_need_sending);
#endif
if (!do_authentication (transport, FALSE, TRUE))
return FALSE;
if (!do_writing (transport))
- return FALSE;
+ {
+ _dbus_verbose ("no memory to write\n");
+ return FALSE;
+ }
+ }
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ else
+ {
+ if (watch == unix_transport->read_watch)
+ _dbus_verbose ("asked to handle read watch with non-read condition 0x%x\n",
+ flags);
+ else if (watch == unix_transport->write_watch)
+ _dbus_verbose ("asked to handle write watch with non-write condition 0x%x\n",
+ flags);
+ else
+ _dbus_verbose ("asked to handle watch %p on fd %d that we don't recognize\n",
+ watch, dbus_watch_get_fd (watch));
}
+#endif /* DBUS_ENABLE_VERBOSE_MODE */
return TRUE;
}
unix_connection_set (DBusTransport *transport)
{
DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
+
+ _dbus_watch_set_handler (unix_transport->write_watch,
+ _dbus_connection_handle_watch,
+ transport->connection, NULL);
+
+ _dbus_watch_set_handler (unix_transport->read_watch,
+ _dbus_connection_handle_watch,
+ transport->connection, NULL);
if (!_dbus_connection_add_watch (transport->connection,
unix_transport->write_watch))
check_write_watch (transport);
}
-/* FIXME use _dbus_poll(), not select() */
/**
* @todo We need to have a way to wake up the select sleep if
* a new iteration request comes in with a flag (read/write) that
int timeout_milliseconds)
{
DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
- fd_set read_set;
- fd_set write_set;
- dbus_bool_t do_select;
- int select_res;
+ DBusPollFD poll_fd;
+ int poll_res;
+ int poll_timeout;
_dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p\n",
flags & DBUS_ITERATION_DO_READING ? "read" : "",
unix_transport->read_watch,
unix_transport->write_watch);
- /* "again" has to be up here because on EINTR the fd sets become
- * undefined
- */
- again:
-
- do_select = FALSE;
-
/* the passed in DO_READING/DO_WRITING flags indicate whether to
* read/write messages, but regardless of those we may need to block
* for reading/writing to do auth. But if we do reading for auth,
* want to read/write so don't.
*/
- FD_ZERO (&read_set);
- FD_ZERO (&write_set);
+ poll_fd.fd = unix_transport->fd;
+ poll_fd.events = 0;
if (_dbus_transport_get_is_authenticated (transport))
{
if (unix_transport->read_watch &&
(flags & DBUS_ITERATION_DO_READING))
- {
- FD_SET (unix_transport->fd, &read_set);
- do_select = TRUE;
- }
+ poll_fd.events |= _DBUS_POLLIN;
if (unix_transport->write_watch &&
(flags & DBUS_ITERATION_DO_WRITING))
- {
- FD_SET (unix_transport->fd, &write_set);
- do_select = TRUE;
- }
+ poll_fd.events |= _DBUS_POLLOUT;
}
else
{
if (transport->receive_credentials_pending ||
auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT)
- {
- FD_SET (unix_transport->fd, &read_set);
- do_select = TRUE;
- }
+ poll_fd.events |= _DBUS_POLLIN;
if (transport->send_credentials_pending ||
auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)
- {
- FD_SET (unix_transport->fd, &write_set);
- do_select = TRUE;
- }
+ poll_fd.events |= _DBUS_POLLOUT;
}
- if (do_select)
+ if (poll_fd.events)
{
- fd_set err_set;
- struct timeval timeout;
- dbus_bool_t use_timeout;
-
- FD_ZERO (&err_set);
- FD_SET (unix_transport->fd, &err_set);
-
if (flags & DBUS_ITERATION_BLOCK)
- {
- if (timeout_milliseconds >= 0)
- {
- timeout.tv_sec = timeout_milliseconds / 1000;
- timeout.tv_usec = (timeout_milliseconds % 1000) * 1000;
-
- /* Always use timeout if one is passed in. */
- use_timeout = TRUE;
- }
- else
- {
- use_timeout = FALSE; /* NULL timeout to block forever */
- }
- }
+ poll_timeout = timeout_milliseconds;
else
- {
- /* 0 timeout to not block */
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- use_timeout = TRUE;
- }
+ poll_timeout = 0;
/* For blocking selects we drop the connection lock here
* to avoid blocking out connection access during a potentially
if (flags & DBUS_ITERATION_BLOCK)
_dbus_connection_unlock (transport->connection);
- select_res = select (unix_transport->fd + 1,
- &read_set, &write_set, &err_set,
- use_timeout ? &timeout : NULL);
+ again:
+ poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
+
+ if (poll_res < 0 && errno == EINTR)
+ goto again;
if (flags & DBUS_ITERATION_BLOCK)
_dbus_connection_lock (transport->connection);
-
- if (select_res >= 0)
+ if (poll_res >= 0)
{
- if (FD_ISSET (unix_transport->fd, &err_set))
+ if (poll_fd.revents & _DBUS_POLLERR)
do_io_error (transport);
else
{
- dbus_bool_t need_read = FD_ISSET (unix_transport->fd, &read_set);
- dbus_bool_t need_write = FD_ISSET (unix_transport->fd, &write_set);
+ dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0;
+ dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0;
_dbus_verbose ("in iteration, need_read=%d need_write=%d\n",
need_read, need_write);
do_writing (transport);
}
}
- else if (errno == EINTR)
- goto again;
else
{
- _dbus_verbose ("Error from select(): %s\n",
+ _dbus_verbose ("Error from _dbus_poll(): %s\n",
_dbus_strerror (errno));
}
}
check_read_watch (transport);
}
+
+static dbus_bool_t
+unix_get_unix_fd (DBusTransport *transport,
+ int *fd_p)
+{
+ DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
+
+ *fd_p = unix_transport->fd;
+
+ return TRUE;
+}
+
static DBusTransportVTable unix_vtable = {
unix_finalize,
unix_handle_watch,
unix_connection_set,
unix_messages_pending,
unix_do_iteration,
- unix_live_messages_changed
+ unix_live_messages_changed,
+ unix_get_unix_fd
};
/**
unix_transport->write_watch = _dbus_watch_new (fd,
DBUS_WATCH_WRITABLE,
- FALSE);
+ FALSE,
+ NULL, NULL, NULL);
if (unix_transport->write_watch == NULL)
goto failed_2;
unix_transport->read_watch = _dbus_watch_new (fd,
DBUS_WATCH_READABLE,
- FALSE);
+ FALSE,
+ NULL, NULL, NULL);
if (unix_transport->read_watch == NULL)
goto failed_3;
* Creates a new transport for the given Unix domain socket
* path. This creates a client-side of a transport.
*
+ * @todo once we add a way to escape paths in a dbus
+ * address, this function needs to do escaping.
+ *
* @param path the path to the domain socket.
+ * @param abstract #TRUE to use abstract socket namespace
* @param error address where an error can be returned.
* @returns a new transport, or #NULL on failure.
*/
DBusTransport*
_dbus_transport_new_for_domain_socket (const char *path,
+ dbus_bool_t abstract,
DBusError *error)
{
int fd;
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
-
- if (!_dbus_string_append (&address, "unix:path=") ||
+
+ fd = -1;
+
+ if ((abstract &&
+ !_dbus_string_append (&address, "unix:abstract=")) ||
+ (!abstract &&
+ !_dbus_string_append (&address, "unix:path=")) ||
!_dbus_string_append (&address, path))
{
- _dbus_string_free (&address);
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
- return NULL;
+ goto failed_0;
}
- fd = _dbus_connect_unix_socket (path, error);
+ fd = _dbus_connect_unix_socket (path, abstract, error);
if (fd < 0)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
- _dbus_string_free (&address);
- return NULL;
+ goto failed_0;
}
_dbus_fd_set_close_on_exec (fd);
if (transport == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
- _dbus_string_free (&address);
- _dbus_close (fd, NULL);
- fd = -1;
+ goto failed_1;
}
-
+
_dbus_string_free (&address);
return transport;
+
+ failed_1:
+ _dbus_close (fd, NULL);
+ failed_0:
+ _dbus_string_free (&address);
+ return NULL;
}
/**