static dbus_bool_t do_check_nonce (int fd, const DBusString *nonce, DBusError *error) { DBusString buffer; DBusString p; size_t nleft; dbus_bool_t result; int n; _DBUS_ASSERT_ERROR_IS_CLEAR (error); nleft = 16; if ( !_dbus_string_init (&buffer) || !_dbus_string_init (&p) ) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } while (nleft) { n = _dbus_read_socket (fd, &p, nleft); if (n == -1 && _dbus_get_is_errno_eintr()) ; else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock()) _dbus_sleep_milliseconds (100); else if (n==-1) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd ); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } else if (!n) { _dbus_string_free (&p); _dbus_string_free (&buffer); dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%d)", fd ); return FALSE; } else { _dbus_string_append_len(&buffer, _dbus_string_get_const_data (&p), n); nleft -= n; } } result = _dbus_string_equal_len (&buffer, nonce, 16); if (!result) dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%d)", fd ); _dbus_string_free (&p); _dbus_string_free (&buffer); return result; }
/** * @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 * we're not currently serving. Otherwise a call that just reads * could block a write call forever (if there are no incoming * messages). */ static void socket_do_iteration (DBusTransport *transport, unsigned int flags, int timeout_milliseconds) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; DBusPollFD poll_fd; int poll_res; int poll_timeout; _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %" DBUS_SOCKET_FORMAT "\n", flags & DBUS_ITERATION_DO_READING ? "read" : "", flags & DBUS_ITERATION_DO_WRITING ? "write" : "", timeout_milliseconds, socket_transport->read_watch, socket_transport->write_watch, _dbus_socket_printable (socket_transport->fd)); /* 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, * we don't want to read any messages yet if not given DO_READING. */ poll_fd.fd = _dbus_socket_get_pollable (socket_transport->fd); poll_fd.events = 0; if (_dbus_transport_try_to_authenticate (transport)) { /* This is kind of a hack; if we have stuff to write, then try * to avoid the poll. This is probably about a 5% speedup on an * echo client/server. * * If both reading and writing were requested, we want to avoid this * since it could have funky effects: * - both ends spinning waiting for the other one to read * data so they can finish writing * - prioritizing all writing ahead of reading */ if ((flags & DBUS_ITERATION_DO_WRITING) && !(flags & (DBUS_ITERATION_DO_READING | DBUS_ITERATION_BLOCK)) && !transport->disconnected && _dbus_connection_has_messages_to_send_unlocked (transport->connection)) { do_writing (transport); if (transport->disconnected || !_dbus_connection_has_messages_to_send_unlocked (transport->connection)) goto out; } /* If we get here, we decided to do the poll() after all */ _dbus_assert (socket_transport->read_watch); if (flags & DBUS_ITERATION_DO_READING) poll_fd.events |= _DBUS_POLLIN; _dbus_assert (socket_transport->write_watch); if (flags & DBUS_ITERATION_DO_WRITING) poll_fd.events |= _DBUS_POLLOUT; } else { DBusAuthState auth_state; auth_state = _dbus_auth_do_work (transport->auth); if (transport->receive_credentials_pending || auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT) poll_fd.events |= _DBUS_POLLIN; if (transport->send_credentials_pending || auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND) poll_fd.events |= _DBUS_POLLOUT; } if (poll_fd.events) { int saved_errno; if (flags & DBUS_ITERATION_BLOCK) poll_timeout = timeout_milliseconds; else poll_timeout = 0; /* For blocking selects we drop the connection lock here * to avoid blocking out connection access during a potentially * indefinite blocking call. The io path is still protected * by the io_path_cond condvar, so we won't reenter this. */ if (flags & DBUS_ITERATION_BLOCK) { _dbus_verbose ("unlock pre poll\n"); _dbus_connection_unlock (transport->connection); } again: poll_res = _dbus_poll (&poll_fd, 1, poll_timeout); saved_errno = _dbus_save_socket_errno (); if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno)) goto again; if (flags & DBUS_ITERATION_BLOCK) { _dbus_verbose ("lock post poll\n"); _dbus_connection_lock (transport->connection); } if (poll_res >= 0) { if (poll_res == 0) poll_fd.revents = 0; /* some concern that posix does not guarantee this; * valgrind flags it as an error. though it probably * is guaranteed on linux at least. */ if (poll_fd.revents & _DBUS_POLLERR) do_io_error (transport); else { dbus_bool_t need_read = (poll_fd.revents & _DBUS_POLLIN) > 0; dbus_bool_t need_write = (poll_fd.revents & _DBUS_POLLOUT) > 0; dbus_bool_t authentication_completed; _dbus_verbose ("in iteration, need_read=%d need_write=%d\n", need_read, need_write); do_authentication (transport, need_read, need_write, &authentication_completed); /* See comment in socket_handle_watch. */ if (authentication_completed) goto out; if (need_read && (flags & DBUS_ITERATION_DO_READING)) do_reading (transport); if (need_write && (flags & DBUS_ITERATION_DO_WRITING)) do_writing (transport); } } else { _dbus_verbose ("Error from _dbus_poll(): %s\n", _dbus_strerror (saved_errno)); } } out: /* We need to install the write watch only if we did not * successfully write everything. Note we need to be careful that we * don't call check_write_watch *before* do_writing, since it's * inefficient to add the write watch, and we can avoid it most of * the time since we can write immediately. * * However, we MUST always call check_write_watch(); DBusConnection code * relies on the fact that running an iteration will notice that * messages are pending. */ check_write_watch (transport); _dbus_verbose (" ... leaving do_iteration()\n"); }
static dbus_bool_t do_check_nonce (DBusSocket fd, const DBusString *nonce, DBusError *error) { DBusString buffer; DBusString p; size_t nleft; dbus_bool_t result; int n; _DBUS_ASSERT_ERROR_IS_CLEAR (error); nleft = 16; /* This is a trick to make it safe to call _dbus_string_free on these * strings during error unwinding, even if allocating memory for them * fails. A constant DBusString is considered to be valid to "free", * even though there is nothing to free (of course the free operation * is trivial, because it does not own its own buffer); but * unlike a mutable DBusString, initializing a constant DBusString * cannot fail. * * We must successfully re-initialize the strings to be mutable before * writing to them, of course. */ _dbus_string_init_const (&buffer, ""); _dbus_string_init_const (&p, ""); if ( !_dbus_string_init (&buffer) || !_dbus_string_init (&p) ) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } while (nleft) { int saved_errno; n = _dbus_read_socket (fd, &p, nleft); saved_errno = _dbus_save_socket_errno (); if (n == -1 && _dbus_get_is_errno_eintr (saved_errno)) ; else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno)) _dbus_sleep_milliseconds (100); else if (n==-1) { dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd)); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } else if (!n) { _dbus_string_free (&p); _dbus_string_free (&buffer); dbus_set_error (error, DBUS_ERROR_IO_ERROR, "Could not read nonce from socket (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd)); return FALSE; } else { if (!_dbus_string_append_len (&buffer, _dbus_string_get_const_data (&p), n)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_string_free (&p); _dbus_string_free (&buffer); return FALSE; } nleft -= n; } } result = _dbus_string_equal_len (&buffer, nonce, 16); if (!result) dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, "Nonces do not match, access denied (fd=%" DBUS_SOCKET_FORMAT ")", _dbus_socket_printable (fd)); _dbus_string_free (&p); _dbus_string_free (&buffer); return result; }