/** * Opens a TCP socket transport. * * @param entry the address entry to try opening as a tcp transport. * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_socket(DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; dbus_bool_t isTcp; dbus_bool_t isNonceTcp; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); isTcp = strcmp (method, "tcp") == 0; isNonceTcp = strcmp (method, "nonce-tcp") == 0; if (isTcp || isNonceTcp) { const char *host = dbus_address_entry_get_value (entry, "host"); const char *port = dbus_address_entry_get_value (entry, "port"); const char *family = dbus_address_entry_get_value (entry, "family"); const char *noncefile = dbus_address_entry_get_value (entry, "noncefile"); if ((isNonceTcp == TRUE) != (noncefile != NULL)) { _dbus_set_bad_address (error, method, "noncefile", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (port == NULL) { _dbus_set_bad_address (error, method, "port", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } }
/** * Tries to interpret the address entry as a debug pipe entry. * * 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_debug_pipe (DBusAddressEntry *entry, DBusServer **server_p, DBusError *error) { const char *method; *server_p = NULL; method = dbus_address_entry_get_method (entry); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address(error, "debug-pipe", "name", NULL); return DBUS_SERVER_LISTEN_BAD_ADDRESS; } *server_p = _dbus_server_debug_pipe_new (name, error); if (*server_p) { _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 { _DBUS_ASSERT_ERROR_IS_CLEAR(error); return DBUS_SERVER_LISTEN_NOT_HANDLED; } }
/** * Opens a debug pipe transport, used in the test suite. * * @param entry the address entry to try opening as debug-pipe * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_debug_pipe (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { _dbus_set_bad_address (error, "debug-pipe", "name", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_debug_pipe_new (name, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } }
/** * Opens a VMCI stream socket transport. * * @param entry the address entry to try opening as a tcp transport. * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_vmci(DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; const char *cid; const char *port; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "vmci") != 0) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } cid = dbus_address_entry_get_value (entry, "cid"); port = dbus_address_entry_get_value (entry, "port"); if (0 || port == NULL) { _dbus_set_bad_address (error, method, "port", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } *transport_p = _dbus_transport_new_for_vmci (cid, port, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } }
/** * 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; } }
/** * Opens platform specific transport types. * * @param entry the address entry to try opening * @param transport_p return location for the opened transport * @param error error to be set * @returns result of the attempt */ DBusTransportOpenResult _dbus_transport_open_platform_specific (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); 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 (tmpdir != NULL) { _dbus_set_bad_address (error, NULL, NULL, "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path == NULL && abstract == NULL) { _dbus_set_bad_address (error, "unix", "path or abstract", NULL); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path != NULL && abstract != NULL) { _dbus_set_bad_address (error, NULL, NULL, "can't specify both \"path\" and \"abstract\" options in an address"); return DBUS_TRANSPORT_OPEN_BAD_ADDRESS; } if (path) *transport_p = _dbus_transport_new_for_domain_socket (path, FALSE, error); else *transport_p = _dbus_transport_new_for_domain_socket (abstract, TRUE, error); if (*transport_p == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_OK; } } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return DBUS_TRANSPORT_OPEN_NOT_HANDLED; } }
/** * Try to open a new transport for the given address entry. (This * opens a client-side-of-the-connection transport.) * * @param entry the address entry * @param error location to store reason for failure. * @returns new transport of #NULL on failure. */ DBusTransport* _dbus_transport_open (DBusAddressEntry *entry, DBusError *error) { DBusTransport *transport; const char *expected_guid_orig; char *expected_guid; int i; DBusError tmp_error = DBUS_ERROR_INIT; _DBUS_ASSERT_ERROR_IS_CLEAR (error); transport = NULL; expected_guid_orig = dbus_address_entry_get_value (entry, "guid"); expected_guid = _dbus_strdup (expected_guid_orig); if (expected_guid_orig != NULL && expected_guid == NULL) { _DBUS_SET_OOM (error); return NULL; } for (i = 0; i < (int) _DBUS_N_ELEMENTS (open_funcs); ++i) { DBusTransportOpenResult result; _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); result = (* open_funcs[i].func) (entry, &transport, &tmp_error); switch (result) { case DBUS_TRANSPORT_OPEN_OK: _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); goto out; break; case DBUS_TRANSPORT_OPEN_NOT_HANDLED: _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* keep going through the loop of open funcs */ break; case DBUS_TRANSPORT_OPEN_BAD_ADDRESS: _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); goto out; break; case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT: _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); goto out; break; } } out: if (transport == NULL) { if (!dbus_error_is_set (&tmp_error)) _dbus_set_bad_address (&tmp_error, NULL, NULL, "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")"); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); dbus_move_error(&tmp_error, error); dbus_free (expected_guid); } else { _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* In the case of autostart the initial guid is NULL * and the autostart transport recursively calls * _dbus_open_transport wich returns a transport * with a guid. That guid is the definitive one. * * FIXME: if more transports are added they may have * an effect on the expected_guid semantics (i.e. * expected_guid and transport->expected_guid may * both have values). This is very unlikely though * we should either throw asserts here for those * corner cases or refactor the code so it is * clearer on what is expected and what is not */ if(expected_guid) transport->expected_guid = expected_guid; } return transport; }