guint16 my_dbus_server_get_port (DBusServer* server) { DBusAddressEntry**entries; DBusError error; guint16 port = 0; char * address = dbus_server_get_address (server); int n_entries; int i; dbus_error_init (&error); if (!dbus_parse_address (address, &entries, &n_entries, &error)) { g_warning ("error parsing server address: %s", error.message); dbus_error_free (&error); free (address); exit (1); return 0; } for (i = 0; i < n_entries; i++) { if (!strcmp ("tcp", dbus_address_entry_get_method (entries[i]))) { port = atoi (dbus_address_entry_get_value (entries[i], "port")); break; } } dbus_address_entries_free (entries); free (address); return port; }
static DBusTransportOpenResult _dbus_transport_open_autolaunch (DBusAddressEntry *entry, DBusTransport **transport_p, DBusError *error) { const char *method; method = dbus_address_entry_get_method (entry); _dbus_assert (method != NULL); if (strcmp (method, "autolaunch") == 0) { *transport_p = _dbus_transport_new_for_autolaunch (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 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 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, "nonce-tcp") == 0) { const char *host; const char *port; const char *bind; const char *family; host = dbus_address_entry_get_value (entry, "host"); bind = dbus_address_entry_get_value (entry, "bind"); port = dbus_address_entry_get_value (entry, "port"); family = dbus_address_entry_get_value (entry, "family"); *server_p = _dbus_server_new_for_tcp_socket (host, bind, port, family, error, TRUE); 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; } }
/** * 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; } }
/** * Listens for new connections on the given address. If there are * multiple semicolon-separated address entries in the address, tries * each one and listens on the first one that works. * * Returns #NULL and sets error if listening fails for any reason. * Otherwise returns a new #DBusServer. * dbus_server_set_new_connection_function(), * dbus_server_set_watch_functions(), and * dbus_server_set_timeout_functions() should be called immediately to * render the server fully functional. * * To free the server, applications must call first * dbus_server_disconnect() and then dbus_server_unref(). * * @param address the address of this server. * @param error location to store reason for failure. * @returns a new #DBusServer, or #NULL on failure. * */ DBusServer* dbus_server_listen (const char *address, DBusError *error) { DBusServer *server; DBusAddressEntry **entries; int len, i; DBusError first_connect_error = DBUS_ERROR_INIT; dbus_bool_t handled_once; _dbus_return_val_if_fail (address != NULL, NULL); _dbus_return_val_if_error_is_set (error, NULL); if (!dbus_parse_address (address, &entries, &len, error)) return NULL; server = NULL; handled_once = FALSE; for (i = 0; i < len; i++) { int j; for (j = 0; j < (int) _DBUS_N_ELEMENTS (listen_funcs); ++j) { DBusServerListenResult result; DBusError tmp_error = DBUS_ERROR_INIT; result = (* listen_funcs[j].func) (entries[i], &server, &tmp_error); if (result == DBUS_SERVER_LISTEN_OK) { _dbus_assert (server != NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED) { _dbus_assert (server == NULL); dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, "Address '%s' already used", dbus_address_entry_get_method (entries[0])); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); dbus_move_error (&tmp_error, error); handled_once = TRUE; goto out; } else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); /* keep trying addresses */ } else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT) { _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_SET (&tmp_error); if (!dbus_error_is_set (&first_connect_error)) dbus_move_error (&tmp_error, &first_connect_error); else dbus_error_free (&tmp_error); handled_once = TRUE; /* keep trying addresses */ } } _dbus_assert (server == NULL); _DBUS_ASSERT_ERROR_IS_CLEAR (error); } out: if (!handled_once) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (len > 0) dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Unknown address type '%s'", dbus_address_entry_get_method (entries[0])); else dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Empty address '%s'", address); } dbus_address_entries_free (entries); if (server == NULL) { _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error) || dbus_error_is_set (error)); if (error && dbus_error_is_set (error)) { /* already set the error */ } else { /* didn't set the error but either error should be * NULL or first_connect_error should be set. */ _dbus_assert (error == NULL || dbus_error_is_set (&first_connect_error)); dbus_move_error (&first_connect_error, error); } _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */ _DBUS_ASSERT_ERROR_IS_SET (error); return NULL; } else { _DBUS_ASSERT_ERROR_IS_CLEAR (error); return server; } }
/** * 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 *address_problem_type; const char *address_problem_field; const char *address_problem_other; const char *method; const char *expected_guid_orig; char *expected_guid; _DBUS_ASSERT_ERROR_IS_CLEAR (error); transport = NULL; address_problem_type = NULL; address_problem_field = NULL; address_problem_other = 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; } 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) { address_problem_other = "cannot use the \"tmpdir\" option for an address to connect to, only in an address to listen on"; goto bad_address; } if (path == NULL && abstract == NULL) { address_problem_type = "unix"; address_problem_field = "path or abstract"; goto bad_address; } if (path != NULL && abstract != NULL) { address_problem_other = "can't specify both \"path\" and \"abstract\" options in an address"; goto bad_address; } if (path) transport = _dbus_transport_new_for_domain_socket (path, FALSE, error); else transport = _dbus_transport_new_for_domain_socket (abstract, TRUE, error); } else if (strcmp (method, "tcp") == 0) { const char *host = dbus_address_entry_get_value (entry, "host"); const char *port = dbus_address_entry_get_value (entry, "port"); DBusString str; long lport; dbus_bool_t sresult; if (port == NULL) { address_problem_type = "tcp"; address_problem_field = "port"; goto bad_address; } _dbus_string_init_const (&str, port); sresult = _dbus_string_parse_int (&str, 0, &lport, NULL); _dbus_string_free (&str); if (sresult == FALSE || lport <= 0 || lport > 65535) { address_problem_other = "Port is not an integer between 0 and 65535"; goto bad_address; } transport = _dbus_transport_new_for_tcp_socket (host, lport, error); } #ifdef DBUS_BUILD_TESTS else if (strcmp (method, "debug-pipe") == 0) { const char *name = dbus_address_entry_get_value (entry, "name"); if (name == NULL) { address_problem_type = "debug-pipe"; address_problem_field = "name"; goto bad_address; } transport = _dbus_transport_debug_pipe_new (name, error); } #endif else { address_problem_other = "Unknown address type (examples of valid types are \"unix\" and \"tcp\")"; goto bad_address; } if (transport == NULL) { _DBUS_ASSERT_ERROR_IS_SET (error); dbus_free (expected_guid); } else { transport->expected_guid = expected_guid; } return transport; bad_address: dbus_free (expected_guid); if (address_problem_type != NULL) dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address of type %s was missing argument %s", address_problem_type, address_problem_field); else dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Could not parse address: %s", address_problem_other); return NULL; }