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; }
/* Return value is just for memory, not other failures. */ static dbus_bool_t handle_new_client_fd_and_unlock (DBusServer *server, int client_fd) { DBusConnection *connection; DBusTransport *transport; DBusNewConnectionFunction new_connection_function; DBusServerSocket* socket_server; void *new_connection_data; socket_server = (DBusServerSocket*)server; _dbus_verbose ("Creating new client connection with fd %d\n", client_fd); HAVE_LOCK_CHECK (server); if (!_dbus_set_fd_nonblocking (client_fd, NULL)) { SERVER_UNLOCK (server); return TRUE; } transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, FALSE); if (transport == NULL) { _dbus_close_socket (client_fd, NULL); SERVER_UNLOCK (server); return FALSE; } if (!_dbus_transport_set_auth_mechanisms (transport, (const char **) server->auth_mechanisms)) { _dbus_transport_unref (transport); SERVER_UNLOCK (server); return FALSE; } /* note that client_fd is now owned by the transport, and will be * closed on transport disconnection/finalization */ connection = _dbus_connection_new_for_transport (transport); _dbus_transport_unref (transport); transport = NULL; /* now under the connection lock */ if (connection == NULL) { SERVER_UNLOCK (server); return FALSE; } /* See if someone wants to handle this new connection, self-referencing * for paranoia. */ new_connection_function = server->new_connection_function; new_connection_data = server->new_connection_data; _dbus_server_ref_unlocked (server); SERVER_UNLOCK (server); if (new_connection_function) { (* new_connection_function) (server, connection, new_connection_data); } dbus_server_unref (server); /* If no one grabbed a reference, the connection will die. */ _dbus_connection_close_if_only_one_ref (connection); dbus_connection_unref (connection); return TRUE; }
/** * Creates the client-side transport for * a debug-pipe connection connected to the * given debug-pipe server name. * * @param server_name name of server to connect to * @param error address where an error can be returned. * @returns #NULL on no memory or transport */ DBusTransport* _dbus_transport_debug_pipe_new (const char *server_name, DBusError *error) { DBusTransport *client_transport; DBusTransport *server_transport; DBusConnection *connection; int client_fd, server_fd; DBusServer *server; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (server_pipe_hash == NULL) { dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); return NULL; } server = _dbus_hash_table_lookup_string (server_pipe_hash, server_name); if (server == NULL || ((DBusServerDebugPipe*)server)->disconnected) { dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL); return NULL; } if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_append (&address, "debug-pipe:name=") || !_dbus_string_append (&address, server_name)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&address); return NULL; } if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE, NULL)) { _dbus_verbose ("failed to create full duplex pipe\n"); dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe"); _dbus_string_free (&address); return NULL; } _dbus_fd_set_close_on_exec (client_fd); _dbus_fd_set_close_on_exec (server_fd); client_transport = _dbus_transport_new_for_socket (client_fd, NULL, &address); if (client_transport == NULL) { _dbus_close_socket (client_fd, NULL); _dbus_close_socket (server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&address); return NULL; } _dbus_string_free (&address); client_fd = -1; server_transport = _dbus_transport_new_for_socket (server_fd, &server->guid_hex, NULL); if (server_transport == NULL) { _dbus_transport_unref (client_transport); _dbus_close_socket (server_fd, NULL); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } server_fd = -1; if (!_dbus_transport_set_auth_mechanisms (server_transport, (const char**) server->auth_mechanisms)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_transport_unref (server_transport); _dbus_transport_unref (client_transport); return NULL; } connection = _dbus_connection_new_for_transport (server_transport); _dbus_transport_unref (server_transport); server_transport = NULL; if (connection == NULL) { _dbus_transport_unref (client_transport); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } /* See if someone wants to handle this new connection, * self-referencing for paranoia */ if (server->new_connection_function) { dbus_server_ref (server); (* server->new_connection_function) (server, connection, server->new_connection_data); dbus_server_unref (server); } /* If no one grabbed a reference, the connection will die, * and the client transport will get an immediate disconnect */ _dbus_connection_close_if_only_one_ref (connection); dbus_connection_unref (connection); return client_transport; }