static void do_io_error (DBusTransport *transport) { _dbus_transport_ref (transport); _dbus_transport_disconnect (transport); _dbus_transport_unref (transport); }
/** * Handles a watch by reading data, writing data, or disconnecting * the transport, as appropriate for the given condition. * * @param transport the transport. * @param watch the watch. * @param condition the current state of the watched file descriptor. * @returns #FALSE if not enough memory to fully handle the watch */ dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport, DBusWatch *watch, unsigned int condition) { dbus_bool_t retval; _dbus_assert (transport->vtable->handle_watch != NULL); if (transport->disconnected) return TRUE; if (dbus_watch_get_socket (watch) < 0) { _dbus_warn_check_failed ("Tried to handle an invalidated watch; this watch should have been removed\n"); return TRUE; } _dbus_watch_sanitize_condition (watch, &condition); _dbus_transport_ref (transport); _dbus_watch_ref (watch); retval = (* transport->vtable->handle_watch) (transport, watch, condition); _dbus_watch_unref (watch); _dbus_transport_unref (transport); return retval; }
static void check_read_watch (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; dbus_bool_t need_read_watch; _dbus_verbose ("fd = %" DBUS_SOCKET_FORMAT "\n", _dbus_socket_printable (socket_transport->fd)); if (transport->connection == NULL) return; if (transport->disconnected) { _dbus_assert (socket_transport->read_watch == NULL); return; } _dbus_transport_ref (transport); if (_dbus_transport_try_to_authenticate (transport)) need_read_watch = (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) && (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds); else { if (transport->receive_credentials_pending) need_read_watch = TRUE; else { /* The reason to disable need_read_watch when not WAITING_FOR_INPUT * is to avoid spinning on the file descriptor when we're waiting * to write or for some other part of the auth process */ DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); /* If we need memory we install the read watch just in case, * if there's no need for it, it will get de-installed * next time we try reading. If we're authenticated we * install it since we normally have it installed while * authenticated. */ if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || auth_state == DBUS_AUTH_STATE_AUTHENTICATED) need_read_watch = TRUE; else need_read_watch = FALSE; } } _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch); _dbus_connection_toggle_watch_unlocked (transport->connection, socket_transport->read_watch, need_read_watch); _dbus_transport_unref (transport); }
static void live_messages_notify (DBusCounter *counter, void *user_data) { DBusTransport *transport = user_data; _dbus_transport_ref (transport); #if 0 _dbus_verbose ("Size counter value is now %d\n", (int) _dbus_counter_get_size_value (counter)); _dbus_verbose ("Unix FD counter value is now %d\n", (int) _dbus_counter_get_unix_fd_value (counter)); #endif /* disable or re-enable the read watch for the transport if * required. */ if (transport->vtable->live_messages_changed) { _dbus_connection_lock (transport->connection); (* transport->vtable->live_messages_changed) (transport); _dbus_connection_unlock (transport->connection); } _dbus_transport_unref (transport); }
static void check_write_watch (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; dbus_bool_t needed; if (transport->connection == NULL) return; if (transport->disconnected) { _dbus_assert (socket_transport->write_watch == NULL); return; } _dbus_transport_ref (transport); if (_dbus_transport_try_to_authenticate (transport)) needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection); else { if (transport->send_credentials_pending) needed = TRUE; else { DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); /* If we need memory we install the write watch just in case, * if there's no need for it, it will get de-installed * next time we try reading. */ if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) needed = TRUE; else needed = FALSE; } } _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %" DBUS_SOCKET_FORMAT " outgoing messages exist %d\n", needed, transport->connection, socket_transport->write_watch, _dbus_socket_printable (socket_transport->fd), _dbus_connection_has_messages_to_send_unlocked (transport->connection)); _dbus_connection_toggle_watch_unlocked (transport->connection, socket_transport->write_watch, needed); _dbus_transport_unref (transport); }
/** * Sets the connection using this transport. Allows the transport * to add watches to the connection, queue incoming messages, * and pull outgoing messages. * * @param transport the transport. * @param connection the connection. * @returns #FALSE if not enough memory */ dbus_bool_t _dbus_transport_set_connection (DBusTransport *transport, DBusConnection *connection) { _dbus_assert (transport->vtable->connection_set != NULL); _dbus_assert (transport->connection == NULL); transport->connection = connection; _dbus_transport_ref (transport); if (!(* transport->vtable->connection_set) (transport)) transport->connection = NULL; _dbus_transport_unref (transport); return transport->connection != NULL; }
/** * Get the socket file descriptor, if any. * * @param transport the transport * @param fd_p pointer to fill in with the descriptor * @returns #TRUE if a descriptor was available */ dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport *transport, int *fd_p) { dbus_bool_t retval; if (transport->vtable->get_socket_fd == NULL) return FALSE; if (transport->disconnected) return FALSE; _dbus_transport_ref (transport); retval = (* transport->vtable->get_socket_fd) (transport, fd_p); _dbus_transport_unref (transport); return retval; }
/** * Performs a single poll()/select() on the transport's file * descriptors and then reads/writes data as appropriate, * queueing incoming messages and sending outgoing messages. * This is the backend for _dbus_connection_do_iteration(). * See _dbus_connection_do_iteration() for full details. * * @param transport the transport. * @param flags indicates whether to read or write, and whether to block. * @param timeout_milliseconds if blocking, timeout or -1 for no timeout. */ void _dbus_transport_do_iteration (DBusTransport *transport, unsigned int flags, int timeout_milliseconds) { _dbus_assert (transport->vtable->do_iteration != NULL); _dbus_verbose ("Transport iteration flags 0x%x timeout %d connected = %d\n", flags, timeout_milliseconds, !transport->disconnected); if ((flags & (DBUS_ITERATION_DO_WRITING | DBUS_ITERATION_DO_READING)) == 0) return; /* Nothing to do */ if (transport->disconnected) return; _dbus_transport_ref (transport); (* transport->vtable->do_iteration) (transport, flags, timeout_milliseconds); _dbus_transport_unref (transport); _dbus_verbose ("%s end\n", _DBUS_FUNCTION_NAME); }
static dbus_bool_t do_authentication (DBusTransport *transport, dbus_bool_t do_reading, dbus_bool_t do_writing, dbus_bool_t *auth_completed) { dbus_bool_t oom; dbus_bool_t orig_auth_state; oom = FALSE; orig_auth_state = _dbus_transport_try_to_authenticate (transport); /* This is essential to avoid the check_write_watch() at the end, * we don't want to add a write watch in do_iteration before * we try writing and get EAGAIN */ if (orig_auth_state) { if (auth_completed) *auth_completed = FALSE; return TRUE; } _dbus_transport_ref (transport); while (!_dbus_transport_try_to_authenticate (transport) && _dbus_transport_get_is_connected (transport)) { if (!exchange_credentials (transport, do_reading, do_writing)) { /* OOM */ oom = TRUE; goto out; } if (transport->send_credentials_pending || transport->receive_credentials_pending) { _dbus_verbose ("send_credentials_pending = %d receive_credentials_pending = %d\n", transport->send_credentials_pending, 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 (" %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 (" %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 (" %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 (" %s auth state: need to disconnect\n", TRANSPORT_SIDE (transport)); do_io_error (transport); break; case DBUS_AUTH_STATE_AUTHENTICATED: _dbus_verbose (" %s auth state: authenticated\n", TRANSPORT_SIDE (transport)); break; } } out: if (auth_completed) *auth_completed = (orig_auth_state != _dbus_transport_try_to_authenticate (transport)); check_read_watch (transport); check_write_watch (transport); _dbus_transport_unref (transport); if (oom) return FALSE; else return TRUE; }