Exemplo n.º 1
0
int tool_cmd_scan(int argc, char *argv[])
{
	int ret = 0;
	int c;
	int timeout = DEFAULT_TIMEOUT_IN_SECONDS * 1000;
	DBusConnection* connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	DBusPendingCall *pending = NULL;
	DBusError error;
	int32_t scan_period = 0;
	uint32_t channel_mask = 0;

	dbus_error_init(&error);

	while (1) {
		static struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"timeout", required_argument, 0, 't'},
			{"channel", required_argument, 0, 'c'},
			{0, 0, 0, 0}
		};

		int option_index = 0;
		c = getopt_long(argc, argv, "hc:t:", long_options,
				&option_index);

		if (c == -1)
			break;

		switch (c) {
		case 'h':
			print_arg_list_help(scan_option_list, argv[0],
					    scan_cmd_syntax);
			ret = ERRORCODE_HELP;
			goto bail;

		case 't':
			timeout = strtol(optarg, NULL, 0);
			break;

		case 'c':
			channel_mask = strtomask_uint32(optarg);
			break;
		}
	}

	if (optind < argc) {
		if (scan_period == 0) {
			scan_period = strtol(argv[optind], NULL, 0);
			optind++;
		}
	}

	if (optind < argc) {
			fprintf(stderr,
			        "%s: error: Unexpected extra argument: \"%s\"\n",
			argv[0], argv[optind]);
			ret = ERRORCODE_BADARG;
			goto bail;
		}

	if (gInterfaceName[0] == 0) {
		fprintf(stderr,
		        "%s: error: No WPAN interface set (use the `cd` command, or the `-I` argument for `wpanctl`).\n",
		        argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	connection = dbus_bus_get(DBUS_BUS_STARTER, &error);

	if (!connection) {
		dbus_error_free(&error);
		dbus_error_init(&error);
		connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	}

	require_string(connection != NULL, bail, error.message);

	dbus_bus_add_match(connection, gDBusObjectManagerMatchString, &error);

	require_string(error.name == NULL, bail, error.message);

	dbus_connection_add_filter(connection, &dbus_beacon_handler, NULL, NULL);

	{
		char path[DBUS_MAXIMUM_NAME_LENGTH+1];
		char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];
		DBusMessageIter iter;
		ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);

		if (ret != 0) {
			goto bail;
		}

		snprintf(
			path,
			sizeof(path),
			"%s/%s",
			WPANTUND_DBUS_PATH,
			gInterfaceName
		);

		message = dbus_message_new_method_call(
			interface_dbus_name,
			path,
			WPANTUND_DBUS_APIv1_INTERFACE,
			WPANTUND_IF_CMD_NET_SCAN_START
		);

		dbus_message_append_args(
			message,
			DBUS_TYPE_UINT32, &channel_mask,
			DBUS_TYPE_INVALID
		);

		print_scan_header();

		gScannedNetworkCount = 0;

		if(!dbus_connection_send_with_reply(
		    connection,
		    message,
			&pending,
		    timeout
	    )) {
			fprintf(stderr, "%s: error: IPC failure\n", argv[0]);
			ret = ERRORCODE_UNKNOWN;
			goto bail;
		}

		while ((dbus_connection_get_dispatch_status(connection) == DBUS_DISPATCH_DATA_REMAINS)
			|| dbus_connection_has_messages_to_send(connection)
			|| !dbus_pending_call_get_completed(pending)
		) {
			dbus_connection_read_write_dispatch(connection, 5000 /*ms*/);
		}

		reply = dbus_pending_call_steal_reply(pending);

		require(reply!=NULL, bail);


		dbus_message_iter_init(reply, &iter);

		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
			fprintf(stderr, "%s: error: Server returned a bad response ('%c')\n",
			        argv[0], dbus_message_iter_get_arg_type(&iter));
			ret = ERRORCODE_UNKNOWN;
			goto bail;
		}

		// Get return code
		dbus_message_iter_get_basic(&iter, &ret);

		if (ret) {
			fprintf(stderr, "%s failed with error %d. %s\n", argv[0], ret, wpantund_status_to_cstr(ret));
			print_error_diagnosis(ret);
			goto bail;
		}
	}


bail:

	if (reply) {
		dbus_message_unref(reply);
	}

	if (pending != NULL) {
		dbus_pending_call_unref(pending);
	}

	if (message) {
		dbus_message_unref(message);
	}

	if (connection) {
		dbus_bus_remove_match(connection, gDBusObjectManagerMatchString, NULL);
		dbus_connection_remove_filter(connection,&dbus_beacon_handler,NULL);
		dbus_connection_unref(connection);
	}

	dbus_error_free(&error);

	return ret;
}
Exemplo n.º 2
0
int tool_cmd_peek(int argc, char* argv[])
{
	int ret = 0;
	int c;
	int timeout = DEFAULT_TIMEOUT_IN_SECONDS * 1000;
	DBusConnection* connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	DBusError error;
	uint32_t address = 0;
	uint16_t count = 32;
	bool simple_data_format = false;

	dbus_error_init(&error);

	while (1) {
		static struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"timeout", required_argument, 0, 't'},
			{"count", required_argument, 0, 'c'},
			{"data", no_argument, 0, 'd'},
			{0, 0, 0, 0}
		};

		int option_index = 0;
		c = getopt_long(argc, argv, "ht:c:d", long_options,	&option_index);

		if (c == -1) {
			break;
		}

		switch (c) {
		case 'h':
			print_arg_list_help(peek_option_list, argv[0], peek_cmd_syntax);
			ret = ERRORCODE_HELP;
			goto bail;

		case 't':
			timeout = strtol(optarg, NULL, 0);
			break;

		case 'c':
			count = strtol(optarg, NULL, 0);
			break;

		case 'd':
			simple_data_format = true;
			break;
		}
	}

	if (optind < argc) {
		address = strtol(argv[optind], NULL, 0);
		optind++;
	} else {
		fprintf(stderr,	"%s: error: Missing required address parameter\n", argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (optind < argc) {
		fprintf(stderr,	"%s: error: Unexpected extra argument: \"%s\"\n", argv[0], argv[optind]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (gInterfaceName[0] == 0) {
		fprintf(
			stderr,
			"%s: error: No WPAN interface set (use the `cd` command, or the `-I` argument for `wpanctl`).\n",
			argv[0]
		);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);

	require_string(connection != NULL, bail, error.message);

	{
		char path[DBUS_MAXIMUM_NAME_LENGTH+1];
		char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];
		bool did_succeed;
		uint8_t *data_ptr = NULL;
		int data_len = 0;
		uint16_t i;

		ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);
		if (ret != 0) {
			print_error_diagnosis(ret);
			goto bail;
		}
		snprintf(path,
				 sizeof(path),
				 "%s/%s",
				 WPANTUND_DBUS_PATH,
				 gInterfaceName);

		message = dbus_message_new_method_call(
			interface_dbus_name,
			path,
			WPANTUND_DBUS_APIv1_INTERFACE,
			WPANTUND_IF_CMD_PEEK
		);

		fprintf(stdout, "Peeking at address 0x%x (%d) for %d bytes\n", address, address, count);

		dbus_message_append_args(
			message,
			DBUS_TYPE_UINT32, &address,
			DBUS_TYPE_UINT16, &count,
			DBUS_TYPE_INVALID
		);

		reply = dbus_connection_send_with_reply_and_block(
			connection,
			message,
			timeout,
			&error
		);

		if (!reply) {
			fprintf(stderr, "%s: error: %s\n", argv[0], error.message);
			ret = ERRORCODE_TIMEOUT;
			goto bail;
		}

		did_succeed = dbus_message_get_args(reply, &error,
			DBUS_TYPE_INT32, &ret,
			DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &data_ptr, &data_len,
			DBUS_TYPE_INVALID
		);

		if (!did_succeed)
		{
			did_succeed = dbus_message_get_args(reply, NULL,
				DBUS_TYPE_INT32, &ret,
				DBUS_TYPE_INVALID
			);
		}

		if (!did_succeed || ret != 0) {
			fprintf(stderr, "%s failed with error %d. %s\n", argv[0], ret, wpantund_status_to_cstr(ret));
			print_error_diagnosis(ret);
			goto bail;
		}

		if (simple_data_format) {
			for (i = 0; i < data_len; i++) {
				fprintf(stdout, "%02X ", *data_ptr++);
				if (i % 32 == 31) {
					fprintf(stdout, "\n");
				}
			}
			fprintf(stdout, "\n");
		} else {
			dump_data(data_ptr, data_len);
		}
	}

bail:

	if (connection) {
		dbus_connection_unref(connection);
	}

	if (message) {
		dbus_message_unref(message);
	}

	if (reply) {
		dbus_message_unref(reply);
	}

	dbus_error_free(&error);

	return ret;
}
Exemplo n.º 3
0
int tool_cmd_reset(int argc, char *argv[])
{
	int ret = 0;
	int c;
	int timeout = 10 * 1000;
	DBusConnection* connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	DBusError error;

	dbus_error_init(&error);

	while (1) {
		static struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"timeout", required_argument, 0, 't'},
			{0, 0, 0, 0}
		};

		int option_index = 0;
		c = getopt_long(argc, argv, "ht:", long_options, &option_index);

		if (c == -1)
			break;

		switch (c) {
		case 'h':
			print_arg_list_help(reset_option_list, argv[0],
					    reset_cmd_syntax);
			ret = ERRORCODE_HELP;
			goto bail;

		case 't':
			timeout = strtol(optarg, NULL, 0);
			break;
		}
	}

	if (optind < argc) {
		fprintf(stderr,
		        "%s: error: Unexpected extra argument: \"%s\"\n",
			argv[0], argv[optind]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (gInterfaceName[0] == 0) {
		fprintf(stderr,
		        "%s: error: No WPAN interface set (use the `cd` command, or the `-I` argument for `wpanctl`).\n",
		        argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	connection = dbus_bus_get(DBUS_BUS_STARTER, &error);

	if (!connection) {
		dbus_error_free(&error);
		dbus_error_init(&error);
		connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	}

	require_string(connection != NULL, bail, error.message);

	{
		DBusMessageIter iter;
		DBusMessageIter list_iter;
		char path[DBUS_MAXIMUM_NAME_LENGTH+1];
		char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];
		ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);
		if (ret != 0) {
			goto bail;
		}
		snprintf(path,
		         sizeof(path),
		         "%s/%s",
		         WPANTUND_DBUS_PATH,
		         gInterfaceName);

		message = dbus_message_new_method_call(
		    interface_dbus_name,
		    path,
		    WPANTUND_DBUS_APIv1_INTERFACE,
		    WPANTUND_IF_CMD_RESET
		    );

		fprintf(stderr, "Resetting NCP. . .\n");

		reply = dbus_connection_send_with_reply_and_block(
		    connection,
		    message,
		    timeout,
		    &error
		    );

		if (!reply) {
			fprintf(stderr, "%s: error: %s\n", argv[0], error.message);
			ret = ERRORCODE_TIMEOUT;
			goto bail;
		}

		dbus_message_get_args(reply, &error,
		                      DBUS_TYPE_INT32, &ret,
		                      DBUS_TYPE_INVALID
		                      );

		if (ret == 6)
			ret = 0;
	}

bail:

	if (connection)
		dbus_connection_unref(connection);

	if (message)
		dbus_message_unref(message);

	if (reply)
		dbus_message_unref(reply);

	dbus_error_free(&error);

	return ret;
}
Exemplo n.º 4
0
int tool_cmd_begin_net_wake(int argc, char *argv[])
{
	int ret = 0;
	int c;
	int timeout = DEFAULT_TIMEOUT_IN_SECONDS * 1000;
	DBusConnection* connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	DBusError error;

	bool has_net_wake_data = false;
	uint8_t net_wake_data = 0;
	uint32_t net_wake_flags = -1;

	dbus_error_init(&error);

	while (1) {
		static struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"timeout", required_argument, 0, 't'},
			{0, 0, 0, 0}
		};

		int option_index = 0;
		c = getopt_long(argc, argv, "ht:", long_options, &option_index);

		if (c == -1)
			break;

		switch (c) {
		case 'h':
			print_arg_list_help(begin_net_wake_option_list,
					    argv[0], begin_net_wake_cmd_syntax);
			ret = ERRORCODE_HELP;
			goto bail;

		case 't':
			timeout = strtol(optarg, NULL, 0);
			break;
		}
	}

	if (optind < argc) {
		if (!has_net_wake_data) {
			net_wake_data = strtol(argv[optind], NULL, 0);
			has_net_wake_data = true;
			optind++;
		}
	}

	if (optind < argc) {
		fprintf(stderr,
		        "%s: error: Unexpected extra argument: \"%s\"\n",
		        argv[0], argv[optind]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (gInterfaceName[0] == 0) {
		fprintf(stderr,
		        "%s: error: No WPAN interface set (use the `cd` command, or the `-I` argument for `wpanctl`).\n",
		        argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	connection = dbus_bus_get(DBUS_BUS_STARTER, &error);

	if (!connection) {
		dbus_error_free(&error);
		dbus_error_init(&error);
		connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	}

	require_string(connection != NULL, bail, error.message);

	{
		DBusMessageIter iter;
		DBusMessageIter list_iter;
		char path[DBUS_MAXIMUM_NAME_LENGTH+1];
		char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];
		ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);
		if (ret != 0) {
			goto bail;
		}
		snprintf(path,
		         sizeof(path),
		         "%s/%s",
		         WPAN_TUNNEL_DBUS_PATH,
		         gInterfaceName);

		message = dbus_message_new_method_call(
		    interface_dbus_name,
		    path,
		    WPAN_TUNNEL_DBUS_INTERFACE,
		    WPAN_IFACE_CMD_BEGIN_NET_WAKE
		    );

		dbus_message_append_args(
		    message,
		    DBUS_TYPE_BYTE, &net_wake_data,
		    DBUS_TYPE_UINT32, &net_wake_flags,
		    DBUS_TYPE_INVALID
		    );

		fprintf(stderr,
				"Begin Net Wake, data = 0x%02X\n",
				net_wake_data);

		reply = dbus_connection_send_with_reply_and_block(
		    connection,
		    message,
		    timeout,
		    &error
		    );

		if (!reply) {
			fprintf(stderr, "%s: error: %s\n", argv[0], error.message);
			ret = ERRORCODE_TIMEOUT;
			goto bail;
		}

		dbus_message_get_args(reply, &error,
		                      DBUS_TYPE_INT32, &ret,
		                      DBUS_TYPE_INVALID
		                      );

		if (ret) {
			fprintf(stderr, "%s failed with error %d. %s\n", argv[0], ret, (ret<0)?strerror(-ret):"");
			print_error_diagnosis(ret);
		}
	}

bail:

	if (connection)
		dbus_connection_unref(connection);

	if (message)
		dbus_message_unref(message);

	if (reply)
		dbus_message_unref(reply);

	dbus_error_free(&error);

	return ret;
}
Exemplo n.º 5
0
int tool_cmd_form(int argc, char* argv[])
{
	int ret = 0;
	int c;
	int timeout = DEFAULT_TIMEOUT_IN_SECONDS * 1000;
	DBusConnection* connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	DBusError error;
	const char* network_name = NULL;
	const char* ula_prefix = NULL;
	uint16_t node_type = WPAN_IFACE_ROLE_ROUTER; // Default to router for form
	uint32_t channel_mask = 0;

	dbus_error_init(&error);

	while (1) {
		static struct option long_options[] = {
			{"help", no_argument, 0, 'h'},
			{"timeout", required_argument, 0, 't'},
			{"channel", required_argument, 0, 'c'},
			{"ula-prefix", required_argument, 0, 'u'},
			{"mesh-local-prefix", required_argument, 0, 'M'},
			{"legacy-prefix", required_argument, 0, 'L'},
			{"type", required_argument, 0, 'T'},
			{0, 0, 0, 0}
		};

		int option_index = 0;
		c = getopt_long(argc, argv, "hc:t:T:u:", long_options,
				&option_index);

		if (c == -1)
			break;

		switch (c) {
		case 'h':
			print_arg_list_help(form_option_list, argv[0],
					    form_cmd_syntax);
			ret = ERRORCODE_HELP;
			goto bail;

		case 't':
			timeout = strtol(optarg, NULL, 0);
			break;

		case 'c':
			channel_mask = (1 << strtol(optarg, NULL, 0));
			break;

		case 'M':
			fprintf(stderr,
					"%s: error: Setting the mesh local address at the command line isn't yet implemented. Set it as a property instead.\n",
					argv[0]);
			ret = ERRORCODE_BADARG;
			goto bail;
			break;

		case 'L':
		case 'u':
			ula_prefix = optarg;
			break;

		case 'T':
			node_type = node_type_str2int(optarg);
			break;
		}
	}

	if (optind < argc) {
		if (!network_name) {
			network_name = argv[optind];
			optind++;
		}
	}

	if (optind < argc) {
		fprintf(stderr,
			"%s: error: Unexpected extra argument: \"%s\"\n",
			argv[0], argv[optind]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (!network_name) {
		fprintf(stderr, "%s: error: Missing network name.\n", argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	if (gInterfaceName[0] == 0) {
		fprintf(stderr,
		        "%s: error: No WPAN interface set (use the `cd` command, or the `-I` argument for `wpanctl`).\n",
		        argv[0]);
		ret = ERRORCODE_BADARG;
		goto bail;
	}

	connection = dbus_bus_get(DBUS_BUS_STARTER, &error);

	if (!connection) {
		dbus_error_free(&error);
		dbus_error_init(&error);
		connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
	}

	require_string(connection != NULL, bail, error.message);

	{
		DBusMessageIter iter;
		DBusMessageIter list_iter;
		char path[DBUS_MAXIMUM_NAME_LENGTH+1];
		char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];
		ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);
		if (ret != 0) {
			goto bail;
		}
		snprintf(path,
		         sizeof(path),
		         "%s/%s",
		         WPAN_TUNNEL_DBUS_PATH,
		         gInterfaceName);

		message = dbus_message_new_method_call(
		    interface_dbus_name,
		    path,
		    WPAN_TUNNEL_DBUS_INTERFACE,
		    WPAN_IFACE_CMD_FORM
		    );

		dbus_message_append_args(
		    message,
		    DBUS_TYPE_STRING, &network_name,
		    DBUS_TYPE_INT16, &node_type,
		    DBUS_TYPE_UINT32, &channel_mask,
		    DBUS_TYPE_INVALID
		    );

		if(ula_prefix) {
			uint8_t ula_bytes[16] = {};

			// So the ULA prefix could either be
			// specified like an IPv6 address, or
			// specified as a bunch of hex numbers.
			// We use the presence of a colon (':')
			// to differentiate.
			if(strstr(ula_prefix,":")) {

				// Address-style
				int bits = inet_pton(AF_INET6,ula_prefix,ula_bytes);
				if(bits<0) {
					fprintf(stderr,
					        "Bad ULA \"%s\", errno=%d (%s)\n",
					        ula_prefix,
					        errno,
					        strerror(errno));
					goto bail;
				} else if(!bits) {
					fprintf(stderr, "Bad ULA \"%s\"\n", ula_prefix);
					goto bail;
				}
			} else {
				// DATA-style
				int length = parse_string_into_data(ula_bytes,
				                                    8,
				                                    ula_prefix);
				if(length<=0) {
					fprintf(stderr, "Bad ULA \"%s\"\n", ula_prefix);
					goto bail;
				}
			}

			fprintf(stderr, "Using ULA prefix \"%s\"\n", ula_prefix);

			uint8_t *addr = ula_bytes;
			dbus_message_append_args(
			    message,
			    DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &addr, 8,
			    DBUS_TYPE_INVALID
			    );
		}

		fprintf(stderr,
		        "Forming WPAN \"%s\" as node type %d\n",
		        network_name,
		        node_type);

		reply = dbus_connection_send_with_reply_and_block(
		    connection,
		    message,
		    timeout,
		    &error
		    );

		if (!reply) {
			fprintf(stderr, "%s: error: %s\n", argv[0], error.message);
			ret = ERRORCODE_TIMEOUT;
			goto bail;
		}

		dbus_message_get_args(reply, &error,
		                      DBUS_TYPE_INT32, &ret,
		                      DBUS_TYPE_INVALID
		                      );

		if (!ret) {
			fprintf(stderr, "Successfully formed!\n");
		} else {
			fprintf(stderr, "%s failed with error %d. %s\n", argv[0], ret, wpantund_status_to_cstr(ret));
			print_error_diagnosis(ret);
		}
	}

bail:

	if (connection)
		dbus_connection_unref(connection);

	if (message)
		dbus_message_unref(message);

	if (reply)
		dbus_message_unref(reply);

	dbus_error_free(&error);

	return ret;
}
Exemplo n.º 6
0
static int
do_pcap_to_fd(int fd, int timeout, DBusError *error)
{
	int ret = ERRORCODE_UNKNOWN;
	DBusConnection *connection = NULL;
	DBusMessage *message = NULL;
	DBusMessage *reply = NULL;
	char path[DBUS_MAXIMUM_NAME_LENGTH+1];
	char interface_dbus_name[DBUS_MAXIMUM_NAME_LENGTH+1];

	connection = dbus_bus_get(DBUS_BUS_STARTER, error);

	if (connection == NULL) {
		if (error != NULL) {
			dbus_error_free(error);
			dbus_error_init(error);
		}
		connection = dbus_bus_get(DBUS_BUS_SYSTEM, error);
	}

	require(connection != NULL, bail);

	ret = lookup_dbus_name_from_interface(interface_dbus_name, gInterfaceName);

	require_noerr(ret, bail);

	snprintf(
		path,
		sizeof(path),
		"%s/%s",
		WPANTUND_DBUS_PATH,
		gInterfaceName
	);

	message = dbus_message_new_method_call(
		interface_dbus_name,
		path,
		WPANTUND_DBUS_APIv1_INTERFACE,
		WPANTUND_IF_CMD_PCAP_TO_FD
	);

	dbus_message_append_args(
		message,
		DBUS_TYPE_UNIX_FD, &fd,
		DBUS_TYPE_INVALID
	);

	ret = ERRORCODE_TIMEOUT;

	reply = dbus_connection_send_with_reply_and_block(
		connection,
		message,
		timeout,
		error
	);

	require(reply != NULL, bail);

	dbus_message_get_args(
		reply,
		error,
		DBUS_TYPE_INT32, &ret,
		DBUS_TYPE_INVALID
	);

bail:

	if (connection) {
		dbus_connection_unref(connection);
	}

	if (message) {
		dbus_message_unref(message);
	}

	if (reply) {
		dbus_message_unref(reply);
	}

	return ret;
}