static void close_reload_pipe (void) { _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL); reload_pipe[RELOAD_READ_END] = -1; _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL); reload_pipe[RELOAD_WRITE_END] = -1; }
static void close_reload_pipe (DBusWatch **watch) { _dbus_loop_remove_watch (bus_context_get_loop (context), *watch); _dbus_watch_invalidate (*watch); _dbus_watch_unref (*watch); *watch = NULL; _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL); reload_pipe[RELOAD_READ_END] = -1; _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL); reload_pipe[RELOAD_WRITE_END] = -1; }
static void close_error_pipe_from_child (DBusBabysitter *sitter) { _dbus_verbose ("Closing child error\n"); _dbus_close_socket (sitter->error_pipe_from_child, NULL); sitter->error_pipe_from_child = -1; }
static void close_socket_to_babysitter (DBusBabysitter *sitter) { _dbus_verbose ("Closing babysitter\n"); _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter = -1; }
DBusSocket _dbus_accept_with_noncefile (DBusSocket listen_fd, const DBusNonceFile *noncefile) { DBusSocket fd = _dbus_socket_get_invalid (); DBusString nonce; _dbus_assert (noncefile != NULL); /* Make it valid to "free" this even if _dbus_string_init() runs * out of memory: see comment in do_check_nonce() */ _dbus_string_init_const (&nonce, ""); if (!_dbus_string_init (&nonce)) goto out; //PENDING(kdab): set better errors if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE) goto out; fd = _dbus_accept (listen_fd); if (!_dbus_socket_is_valid (fd)) goto out; if (do_check_nonce(fd, &nonce, NULL) != TRUE) { _dbus_verbose ("nonce check failed. Closing socket.\n"); _dbus_close_socket(fd, NULL); _dbus_socket_invalidate (&fd); goto out; } out: _dbus_string_free (&nonce); return fd; }
static void socket_disconnect (DBusServer *server) { DBusServerSocket *socket_server = (DBusServerSocket*) server; int i; HAVE_LOCK_CHECK (server); for (i = 0 ; i < socket_server->n_fds ; i++) { if (socket_server->watch[i]) { _dbus_server_remove_watch (server, socket_server->watch[i]); _dbus_watch_unref (socket_server->watch[i]); socket_server->watch[i] = NULL; } _dbus_close_socket (socket_server->fds[i], NULL); socket_server->fds[i] = -1; } if (socket_server->socket_name != NULL) { DBusString tmp; _dbus_string_init_const (&tmp, socket_server->socket_name); _dbus_delete_file (&tmp, NULL); } if (server->published_address) _dbus_daemon_unpublish_session_bus_address(); HAVE_LOCK_CHECK (server); }
/** * 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; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } fd = -1; if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_string_append (&address, path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } fd = _dbus_connect_unix_socket (path, abstract, error); if (fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_0; } _dbus_verbose ("Successfully connected to unix socket %s\n", path); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_1; } _dbus_string_free (&address); return transport; failed_1: _dbus_close_socket (fd, NULL); failed_0: _dbus_string_free (&address); return NULL; }
/** * Creates a new transport for the given VMWare Communication Interface * CID and port. This creates a client-side of a transport. * * @param cid the virtual machine context ID to connect to * @param port the port to connect to * @param error address where an error can be returned. * @returns a new transport, or #NULL on failure. */ static DBusTransport* _dbus_transport_new_for_vmci (const char *cid, const char *port, DBusError *error) { int fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } fd = -1; if (!_dbus_string_append (&address, "vmci:cid=") || !_dbus_string_append(&address, cid) || !_dbus_string_append(&address, "port=") || !_dbus_string_append(&address, port)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } fd = _dbus_connect_vmci (cid, port, error); if (fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_0; } _dbus_verbose ("Successfully connected to vmci stream socket %s:%s\n", cid, port); transport = _dbus_transport_new_for_socket (fd, NULL, &address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_1; } _dbus_string_free (&address); return transport; failed_1: _dbus_close_socket (fd, NULL); failed_0: _dbus_string_free (&address); return NULL; }
static void socket_disconnect (DBusTransport *transport) { DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport; _dbus_verbose ("\n"); free_watches (transport); _dbus_close_socket (socket_transport->fd, NULL); _dbus_socket_invalidate (&socket_transport->fd); }
/* Avoids a danger in threaded situations (calling close() * on a file descriptor twice, and another thread has * re-opened it since the first close) */ static int close_and_invalidate (int *fd) { int ret; if (*fd < 0) return -1; else { ret = _dbus_close_socket (*fd, NULL); *fd = -1; } return ret; }
static void close_socket_to_babysitter (DBusBabysitter *sitter) { _dbus_verbose ("Closing babysitter\n"); if (sitter->sitter_watch != NULL) { _dbus_assert (sitter->watches != NULL); _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch); _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->socket_to_babysitter.fd >= 0) { _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter.fd = -1; } }
static void close_error_pipe_from_child (DBusBabysitter *sitter) { _dbus_verbose ("Closing child error\n"); if (sitter->error_watch != NULL) { _dbus_assert (sitter->watches != NULL); _dbus_watch_list_remove_watch (sitter->watches, sitter->error_watch); _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; } if (sitter->error_pipe_from_child >= 0) { _dbus_close_socket (sitter->error_pipe_from_child, NULL); sitter->error_pipe_from_child = -1; } }
int _dbus_accept_with_noncefile (int listen_fd, const DBusNonceFile *noncefile) { int fd; DBusString nonce; _dbus_assert (noncefile != NULL); if (!_dbus_string_init (&nonce)) return -1; //PENDING(kdab): set better errors if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE) return -1; fd = _dbus_accept (listen_fd); if (_dbus_socket_is_invalid (fd)) return fd; if (do_check_nonce(fd, &nonce, NULL) != TRUE) { _dbus_verbose ("nonce check failed. Closing socket.\n"); _dbus_close_socket(fd, NULL); return -1; } return fd; }
static dbus_bool_t handle_watch (DBusWatch *watch, unsigned int condition, void *data) { DBusBabysitter *sitter = data; /* On Unix dbus-spawn uses a babysitter *process*, thus it has to * actually send the exit statuses, error codes and whatnot through * sockets and/or pipes. On Win32, the babysitter is jus a thread, * so it can set the status fields directly in the babysitter struct * just fine. The socket pipe is used just so we can watch it with * select(), as soon as anything is written to it we know that the * babysitter thread has recorded the status in the babysitter * struct. */ PING(); _dbus_close_socket (sitter->socket_to_babysitter, NULL); PING(); sitter->socket_to_babysitter = -1; return TRUE; }
/** * Creates a new transport for the given hostname and port. * If host is NULL, it will default to localhost * * @param host the host to connect to * @param port the port to connect to * @param family the address family to connect to * @param noncefile path to nonce file * @param error location to store reason for failure. * @returns a new transport, or #NULL on failure. */ DBusTransport* _dbus_transport_new_for_tcp_socket (const char *host, const char *port, const char *family, const char *noncefile, DBusError *error) { DBusSocket fd; DBusTransport *transport; DBusString address; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (host == NULL) host = "localhost"; if (!_dbus_string_append (&address, noncefile ? "nonce-tcp:" : "tcp:")) goto error; if (!_dbus_string_append (&address, "host=") || !_dbus_string_append (&address, host)) goto error; if (!_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, port)) goto error; if (family != NULL && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) goto error; if (noncefile != NULL && (!_dbus_string_append (&address, ",noncefile=") || !_dbus_string_append (&address, noncefile))) goto error; fd = _dbus_connect_tcp_socket_with_nonce (host, port, family, noncefile, error); if (!_dbus_socket_is_valid (fd)) { _DBUS_ASSERT_ERROR_IS_SET (error); _dbus_string_free (&address); return NULL; } _dbus_verbose ("Successfully connected to tcp socket %s:%s\n", host, port); transport = _dbus_transport_new_for_socket (fd, NULL, &address); _dbus_string_free (&address); if (transport == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); _dbus_close_socket (fd, NULL); _dbus_socket_invalidate (&fd); } return transport; error: _dbus_string_free (&address); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; }
/** * Tries to interpret the address entry in a platform-specific * way, creating a platform-specific server type if appropriate. * Sets error if the result is not OK. * * @param entry an address entry * @param server_p location to store a new DBusServer, or #NULL on failure. * @param error location to store rationale for failure on bad address * @returns the outcome * */ DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "unix") == 0) { const char *path = dbus_address_entry_get_value (entry, "path"); const char *tmpdir = dbus_address_entry_get_value (entry, "tmpdir"); const char *abstract = dbus_address_entry_get_value (entry, "abstract"); if (path == NULL && tmpdir == NULL && abstract == NULL) { _dbus_set_bad_address(error, "unix", "path or tmpdir or abstract", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if ((path && tmpdir) || (path && abstract) || (tmpdir && abstract)) { _dbus_set_bad_address(error, NULL, NULL, "cannot specify two of \"path\" and \"tmpdir\" and \"abstract\" at the same time"); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } if (tmpdir != NULL) { DBusString full_path; DBusString filename; if (!_dbus_string_init (&full_path)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_init (&filename)) { _dbus_string_free (&full_path); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if (!_dbus_string_append (&filename, "dbus-") || !_dbus_generate_random_ascii (&filename, 10) || !_dbus_string_append (&full_path, tmpdir) || !_dbus_concat_dir_and_file (&full_path, &filename)) { _dbus_string_free (&full_path); _dbus_string_free (&filename); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } /* Always use abstract namespace if possible with tmpdir */ *server_p = _dbus_server_new_for_domain_socket (_dbus_string_get_const_data (&full_path), #ifdef HAVE_ABSTRACT_SOCKETS TRUE, #else FALSE, #endif error); _dbus_string_free (&full_path); _dbus_string_free (&filename); } else { if (path) *server_p = _dbus_server_new_for_domain_socket (path, FALSE, error); else *server_p = _dbus_server_new_for_domain_socket (abstract, TRUE, error); } if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } else if (strcmp (method, "systemd") == 0) { int i, n, *fds; DBusString address; n = _dbus_listen_systemd_sockets (&fds, error); if (n < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } if(!_dbus_string_init(&address)) goto oom; for (i = 0; i < n; i++) { if ( i > 0) { if(!_dbus_string_append (&address, ";")) goto oom; } if(!_dbus_append_address_from_socket (fds[i], &address)) goto oom; } *server_p = _dbus_server_new_for_socket (fds, n, &address, NULL); if (*server_p == NULL) goto oom; dbus_free (fds); return DBUS_SERVER_LISTEN_OK; oom: dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); for (i = 0; i < n; i++) { _dbus_close_socket (fds[i], NULL); } dbus_free (fds); _dbus_string_free (&address); dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } #ifdef DBUS_ENABLE_LAUNCHD else if (strcmp (method, "launchd") == 0) { const char *launchd_env_var = dbus_address_entry_get_value (entry, "env"); if (launchd_env_var == NULL) { _dbus_set_bad_address (error, "launchd", "env", NULL); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } *server_p = _dbus_server_new_for_launchd (launchd_env_var, error); if (*server_p != NULL) { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_OK; } else { _DBUS_ASSERT_ERROR_IS_SET(error); return DBUS_SERVER_LISTEN_DID_NOT_CONNECT; } } #endif else { /* If we don't handle the method, we return NULL with the * error unset */ _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } }
/** * Creates a new server listening on the given Unix domain socket. * * @param path the path for the domain socket. * @param abstract #TRUE to use abstract socket namespace * @param error location to store reason for failure. * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_domain_socket (const char *path, dbus_bool_t abstract, DBusError *error) { DBusServer *server; int listen_fd; DBusString address; char *path_copy; DBusString path_str; _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } _dbus_string_init_const (&path_str, path); if ((abstract && !_dbus_string_append (&address, "unix:abstract=")) || (!abstract && !_dbus_string_append (&address, "unix:path=")) || !_dbus_address_append_escaped (&address, &path_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (abstract) { path_copy = NULL; } else { path_copy = _dbus_strdup (path); if (path_copy == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } } listen_fd = _dbus_listen_unix_socket (path, abstract, error); if (listen_fd < 0) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed_1; } server = _dbus_server_new_for_socket (&listen_fd, 1, &address, 0); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (path_copy != NULL) _dbus_server_socket_own_filename(server, path_copy); _dbus_string_free (&address); return server; failed_2: _dbus_close_socket (listen_fd, NULL); failed_1: dbus_free (path_copy); failed_0: _dbus_string_free (&address); return NULL; }
/** * Decrement the reference count on the babysitter object. * * @param sitter the babysitter */ void _dbus_babysitter_unref (DBusBabysitter *sitter) { int i; PING(); _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount -= 1; if (sitter->refcount == 0) { if (sitter->socket_to_babysitter != -1) { _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter = -1; } if (sitter->socket_to_main != -1) { _dbus_close_socket (sitter->socket_to_main, NULL); sitter->socket_to_main = -1; } PING(); if (sitter->argv != NULL) { for (i = 0; i < sitter->argc; i++) if (sitter->argv[i] != NULL) { dbus_free (sitter->argv[i]); sitter->argv[i] = NULL; } dbus_free (sitter->argv); sitter->argv = NULL; } if (sitter->envp != NULL) { char **e = sitter->envp; while (*e) dbus_free (*e++); dbus_free (sitter->envp); sitter->envp = NULL; } if (sitter->child_handle != NULL) { CloseHandle (sitter->child_handle); sitter->child_handle = NULL; } if (sitter->sitter_watch) { _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->watches) _dbus_watch_list_free (sitter->watches); if (sitter->start_sync_event != NULL) { PING(); CloseHandle (sitter->start_sync_event); sitter->start_sync_event = NULL; } #ifdef DBUS_BUILD_TESTS if (sitter->end_sync_event != NULL) { CloseHandle (sitter->end_sync_event); sitter->end_sync_event = NULL; } #endif dbus_free (sitter->executable); dbus_free (sitter); } }
/* 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; }
/** * Decrement the reference count on the babysitter object. * When the reference count of the babysitter object reaches * zero, the babysitter is killed and the child that was being * babysat gets emancipated. * * @param sitter the babysitter */ void _dbus_babysitter_unref (DBusBabysitter *sitter) { _dbus_assert (sitter != NULL); _dbus_assert (sitter->refcount > 0); sitter->refcount -= 1; if (sitter->refcount == 0) { if (sitter->socket_to_babysitter >= 0) { /* If we haven't forked other babysitters * since this babysitter and socket were * created then this close will cause the * babysitter to wake up from poll with * a hangup and then the babysitter will * quit itself. */ _dbus_close_socket (sitter->socket_to_babysitter, NULL); sitter->socket_to_babysitter = -1; } if (sitter->error_pipe_from_child >= 0) { _dbus_close_socket (sitter->error_pipe_from_child, NULL); sitter->error_pipe_from_child = -1; } if (sitter->sitter_pid > 0) { int status; int ret; /* It's possible the babysitter died on its own above * from the close, or was killed randomly * by some other process, so first try to reap it */ ret = waitpid (sitter->sitter_pid, &status, WNOHANG); /* If we couldn't reap the child then kill it, and * try again */ if (ret == 0) kill (sitter->sitter_pid, SIGKILL); again: if (ret == 0) ret = waitpid (sitter->sitter_pid, &status, 0); if (ret < 0) { if (errno == EINTR) goto again; else if (errno == ECHILD) _dbus_warn ("Babysitter process not available to be reaped; should not happen\n"); else _dbus_warn ("Unexpected error %d in waitpid() for babysitter: %s\n", errno, _dbus_strerror (errno)); } else { _dbus_verbose ("Reaped %ld, waiting for babysitter %ld\n", (long) ret, (long) sitter->sitter_pid); if (WIFEXITED (sitter->status)) _dbus_verbose ("Babysitter exited with status %d\n", WEXITSTATUS (sitter->status)); else if (WIFSIGNALED (sitter->status)) _dbus_verbose ("Babysitter received signal %d\n", WTERMSIG (sitter->status)); else _dbus_verbose ("Babysitter exited abnormally\n"); } sitter->sitter_pid = -1; } if (sitter->error_watch) { _dbus_watch_invalidate (sitter->error_watch); _dbus_watch_unref (sitter->error_watch); sitter->error_watch = NULL; } if (sitter->sitter_watch) { _dbus_watch_invalidate (sitter->sitter_watch); _dbus_watch_unref (sitter->sitter_watch); sitter->sitter_watch = NULL; } if (sitter->watches) _dbus_watch_list_free (sitter->watches); dbus_free (sitter->executable); dbus_free (sitter); } }
/** * 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; }
/** * Creates a new server listening on TCP. * If host is NULL, it will default to localhost. * If bind is NULL, it will default to the value for the host * parameter, and if that is NULL, then localhost * If bind is a hostname, it will be resolved and will listen * on all returned addresses. * If family is NULL, hostname resolution will try all address * families, otherwise it can be ipv4 or ipv6 to restrict the * addresses considered. * * @param host the hostname to report for the listen address * @param bind the hostname to listen on * @param port the port to listen on or 0 to let the OS choose * @param family * @param error location to store reason for failure. * @param use_nonce whether to use a nonce for low-level authentication (nonce-tcp transport) or not (tcp transport) * @returns the new server, or #NULL on failure. */ DBusServer* _dbus_server_new_for_tcp_socket (const char *host, const char *bind, const char *port, const char *family, DBusError *error, dbus_bool_t use_nonce) { DBusServer *server; int *listen_fds = NULL; int nlisten_fds = 0, i; DBusString address; DBusString host_str; DBusString port_str; DBusNonceFile *noncefile; _DBUS_ASSERT_ERROR_IS_CLEAR (error); noncefile = NULL; if (!_dbus_string_init (&address)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); return NULL; } if (!_dbus_string_init (&port_str)) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_0; } if (host == NULL) host = "localhost"; if (port == NULL) port = "0"; if (bind == NULL) bind = host; else if (strcmp (bind, "*") == 0) bind = NULL; nlisten_fds =_dbus_listen_tcp_socket (bind, port, family, &port_str, &listen_fds, error); if (nlisten_fds <= 0) { _DBUS_ASSERT_ERROR_IS_SET(error); goto failed_1; } _dbus_string_init_const (&host_str, host); if (!_dbus_string_append (&address, use_nonce ? "nonce-tcp:host=" : "tcp:host=") || !_dbus_address_append_escaped (&address, &host_str) || !_dbus_string_append (&address, ",port=") || !_dbus_string_append (&address, _dbus_string_get_const_data(&port_str))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (family && (!_dbus_string_append (&address, ",family=") || !_dbus_string_append (&address, family))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (use_nonce) { noncefile = dbus_new0 (DBusNonceFile, 1); if (noncefile == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_2; } if (!_dbus_noncefile_create (noncefile, error)) goto failed_3; if (!_dbus_string_append (&address, ",noncefile=") || !_dbus_address_append_escaped (&address, _dbus_noncefile_get_path (noncefile))) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_4; } } server = _dbus_server_new_for_socket (listen_fds, nlisten_fds, &address, noncefile); if (server == NULL) { dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed_4; } _dbus_string_free (&port_str); _dbus_string_free (&address); dbus_free(listen_fds); return server; failed_4: _dbus_noncefile_delete (noncefile, NULL); failed_3: dbus_free (noncefile); failed_2: for (i = 0 ; i < nlisten_fds ; i++) _dbus_close_socket (listen_fds[i], NULL); dbus_free(listen_fds); failed_1: _dbus_string_free (&port_str); failed_0: _dbus_string_free (&address); return NULL; }