diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/agent.c | 323 | 
1 files changed, 185 insertions, 138 deletions
| diff --git a/src/agent.c b/src/agent.c index 3cae00a5..f0a6a44d 100644 --- a/src/agent.c +++ b/src/agent.c @@ -75,6 +75,7 @@ struct agent {  struct agent_request {  	agent_request_type_t type;  	struct agent *agent; +	DBusMessage *msg;  	DBusPendingCall *call;  	void *cb;  	void *user_data; @@ -82,6 +83,9 @@ struct agent_request {  static DBusConnection *connection = NULL; +static int request_fallback(struct agent_request *req, +				DBusPendingCallNotifyFunction function); +  static void agent_release(struct agent *agent)  {  	DBusMessage *message; @@ -127,6 +131,8 @@ static int send_cancel_request(struct agent_request *req)  static void agent_request_free(struct agent_request *req)  { +	if (req->msg) +		dbus_message_unref(req->msg);  	if (req->call)  		dbus_pending_call_unref(req->call);  	if (req->agent && req->agent->request) @@ -251,36 +257,6 @@ int agent_cancel(struct agent *agent)  	return 0;  } -static DBusPendingCall *agent_call_authorize(struct agent *agent, -						const char *device_path, -						const char *uuid) -{ -	DBusMessage *message; -	DBusPendingCall *call; - -	message = dbus_message_new_method_call(agent->name, agent->path, -				"org.bluez.Agent", "Authorize"); -	if (!message) { -		error("Couldn't allocate D-Bus message"); -		return NULL; -	} - -	dbus_message_append_args(message, -				DBUS_TYPE_OBJECT_PATH, &device_path, -				DBUS_TYPE_STRING, &uuid, -				DBUS_TYPE_INVALID); - -	if (dbus_connection_send_with_reply(connection, message, -					&call, REQUEST_TIMEOUT) == FALSE) { -		error("D-Bus send failed"); -		dbus_message_unref(message); -		return NULL; -	} - -	dbus_message_unref(message); -	return call; -} -  static void simple_agent_reply(DBusPendingCall *call, void *user_data)  {  	struct agent_request *req = user_data; @@ -295,6 +271,12 @@ static void simple_agent_reply(DBusPendingCall *call, void *user_data)  	dbus_error_init(&err);  	if (dbus_set_error_from_message(&err, message)) { +		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || +				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && +				request_fallback(req, simple_agent_reply) == 0) { +			dbus_error_free(&err); +			return; +		}  		error("Agent replied with an error: %s, %s",  				err.name, err.message); @@ -320,6 +302,34 @@ done:  	agent_request_free(req);  } +static int agent_call_authorize(struct agent_request *req, +				const char *device_path, +				const char *uuid) +{ +	struct agent *agent = req->agent; + +	req->msg = dbus_message_new_method_call(agent->name, agent->path, +				"org.bluez.Agent", "Authorize"); +	if (!req->msg) { +		error("Couldn't allocate D-Bus message"); +		return -ENOMEM; +	} + +	dbus_message_append_args(req->msg, +				DBUS_TYPE_OBJECT_PATH, &device_path, +				DBUS_TYPE_STRING, &uuid, +				DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(connection, req->msg, +					&req->call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		return -EIO; +	} + +	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); +	return 0; +} +  int agent_authorize(struct agent *agent,  			const char *path,  			const char *uuid, @@ -327,19 +337,19 @@ int agent_authorize(struct agent *agent,  			void *user_data)  {  	struct agent_request *req; +	int err;  	if (agent->request)  		return -EBUSY;  	req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, user_data); -	req->call = agent_call_authorize(agent, path, uuid); -	if (!req->call) { +	err = agent_call_authorize(req, path, uuid); +	if (err < 0) {  		agent_request_free(req);  		return DBUS_HANDLER_RESULT_NEED_MEMORY;  	} -	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);  	agent->request = req;  	debug("authorize request was sent for %s", path); @@ -347,34 +357,6 @@ int agent_authorize(struct agent *agent,  	return 0;  } -static DBusPendingCall *pincode_request_new(struct agent *agent, -						const char *device_path, -						dbus_bool_t numeric) -{ -	DBusMessage *message; -	DBusPendingCall *call; - -	message = dbus_message_new_method_call(agent->name, agent->path, -					"org.bluez.Agent", "RequestPinCode"); -	if (message == NULL) { -		error("Couldn't allocate D-Bus message"); -		return NULL; -	} - -	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path, -					DBUS_TYPE_INVALID); - -	if (dbus_connection_send_with_reply(connection, message, -					&call, REQUEST_TIMEOUT) == FALSE) { -		error("D-Bus send failed"); -		dbus_message_unref(message); -		return NULL; -	} - -	dbus_message_unref(message); -	return call; -} -  static void pincode_reply(DBusPendingCall *call, void *user_data)  {  	struct agent_request *req = user_data; @@ -394,6 +376,13 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)  	dbus_error_init(&err);  	if (dbus_set_error_from_message(&err, message)) { +		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || +				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && +				request_fallback(req, pincode_reply) == 0) { +			dbus_error_free(&err); +			return; +		} +  		error("Agent replied with an error: %s, %s",  				err.name, err.message); @@ -435,68 +424,91 @@ done:  		dbus_message_unref(message);  	dbus_pending_call_cancel(req->call); +	agent->request = NULL;  	agent_request_free(req);  } +static int pincode_request_new(struct agent_request *req, const char *device_path, +				dbus_bool_t numeric) +{ +	struct agent *agent = req->agent; + +	req->msg = dbus_message_new_method_call(agent->name, agent->path, +					"org.bluez.Agent", "RequestPinCode"); +	if (req->msg == NULL) { +		error("Couldn't allocate D-Bus message"); +		return -ENOMEM; +	} + +	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, +					DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(connection, req->msg, +					&req->call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		return -EIO; +	} + +	dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); +	return 0; +} +  int agent_request_pincode(struct agent *agent, struct btd_device *device,  				agent_pincode_cb cb, void *user_data)  {  	struct agent_request *req;  	const gchar *dev_path = device_get_path(device); +	int err;  	if (agent->request)  		return -EBUSY;  	req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, user_data); -	req->call = pincode_request_new(agent, dev_path, FALSE); -	if (!req->call) +	err = pincode_request_new(req, dev_path, FALSE); +	if (err < 0)  		goto failed; -	dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); -  	agent->request = req;  	return 0;  failed:  	g_free(req); -	return -1; +	return err;  } -static DBusPendingCall *confirm_mode_change_request_new(struct agent *agent, -							const char *mode) +static int confirm_mode_change_request_new(struct agent_request *req, +						const char *mode)  { -	DBusMessage *message; -	DBusPendingCall *call; +	struct agent *agent = req->agent; -	message = dbus_message_new_method_call(agent->name, agent->path, +	req->msg = dbus_message_new_method_call(agent->name, agent->path,  				"org.bluez.Agent", "ConfirmModeChange"); -	if (message == NULL) { +	if (req->msg == NULL) {  		error("Couldn't allocate D-Bus message"); -		return NULL; +		return -ENOMEM;  	} -	dbus_message_append_args(message, +	dbus_message_append_args(req->msg,  				DBUS_TYPE_STRING, &mode,  				DBUS_TYPE_INVALID); -	if (dbus_connection_send_with_reply(connection, message, -					&call, REQUEST_TIMEOUT) == FALSE) { +	if (dbus_connection_send_with_reply(connection, req->msg, +					&req->call, REQUEST_TIMEOUT) == FALSE) {  		error("D-Bus send failed"); -		dbus_message_unref(message); -		return NULL; +		return -EIO;  	} -	dbus_message_unref(message); - -	return call; +	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); +	return 0;  }  int agent_confirm_mode_change(struct agent *agent, const char *new_mode,  				agent_cb cb, void *user_data)  {  	struct agent_request *req; +	int err;  	if (agent->request)  		return -EBUSY; @@ -507,46 +519,17 @@ int agent_confirm_mode_change(struct agent *agent, const char *new_mode,  	req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,  				cb, user_data); -	req->call = confirm_mode_change_request_new(agent, new_mode); -	if (!req->call) +	err = confirm_mode_change_request_new(req, new_mode); +	if (err < 0)  		goto failed; -	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); -  	agent->request = req;  	return 0;  failed:  	agent_request_free(req); -	return -1; -} - -static DBusPendingCall *passkey_request_new(struct agent *agent, -						const char *device_path) -{ -	DBusMessage *message; -	DBusPendingCall *call; - -	message = dbus_message_new_method_call(agent->name, agent->path, -					"org.bluez.Agent", "RequestPasskey"); -	if (message == NULL) { -		error("Couldn't allocate D-Bus message"); -		return NULL; -	} - -	dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device_path, -					DBUS_TYPE_INVALID); - -	if (dbus_connection_send_with_reply(connection, message, -					&call, REQUEST_TIMEOUT) == FALSE) { -		error("D-Bus send failed"); -		dbus_message_unref(message); -		return NULL; -	} - -	dbus_message_unref(message); -	return call; +	return err;  }  static void passkey_reply(DBusPendingCall *call, void *user_data) @@ -564,6 +547,13 @@ static void passkey_reply(DBusPendingCall *call, void *user_data)  	dbus_error_init(&err);  	if (dbus_set_error_from_message(&err, message)) { +		if ((g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) || +				g_str_equal(DBUS_ERROR_NO_REPLY, err.name)) && +				request_fallback(req, passkey_reply) == 0) { +			dbus_error_free(&err); +			return; +		} +  		error("Agent replied with an error: %s, %s",  				err.name, err.message);  		cb(agent, &err, 0, req->user_data); @@ -588,14 +578,41 @@ done:  		dbus_message_unref(message);  	dbus_pending_call_cancel(req->call); +	agent->request = NULL;  	agent_request_free(req);  } +static int passkey_request_new(struct agent_request *req, +				const char *device_path) +{ +	struct agent *agent = req->agent; + +	req->msg = dbus_message_new_method_call(agent->name, agent->path, +					"org.bluez.Agent", "RequestPasskey"); +	if (req->msg == NULL) { +		error("Couldn't allocate D-Bus message"); +		return -ENOMEM; +	} + +	dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, +					DBUS_TYPE_INVALID); + +	if (dbus_connection_send_with_reply(connection, req->msg, +					&req->call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		return -EIO; +	} + +	dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); +	return 0; +} +  int agent_request_passkey(struct agent *agent, struct btd_device *device,  				agent_passkey_cb cb, void *user_data)  {  	struct agent_request *req;  	const gchar *dev_path = device_get_path(device); +	int err;  	if (agent->request)  		return -EBUSY; @@ -605,50 +622,46 @@ int agent_request_passkey(struct agent *agent, struct btd_device *device,  	req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, user_data); -	req->call = passkey_request_new(agent, dev_path); -	if (!req->call) +	err = passkey_request_new(req, dev_path); +	if (err < 0)  		goto failed; -	dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); -  	agent->request = req;  	return 0;  failed:  	agent_request_free(req); -	return -1; +	return err;  } -static DBusPendingCall *confirmation_request_new(struct agent *agent, -						const char *device_path, -						uint32_t passkey) +static int confirmation_request_new(struct agent_request *req, +					const char *device_path, +					uint32_t passkey)  { -	DBusMessage *message; -	DBusPendingCall *call; +	struct agent *agent = req->agent; -	message = dbus_message_new_method_call(agent->name, agent->path, +	req->msg = dbus_message_new_method_call(agent->name, agent->path,  				"org.bluez.Agent", "RequestConfirmation"); -	if (message == NULL) { +	if (req->msg == NULL) {  		error("Couldn't allocate D-Bus message"); -		return NULL; +		return -ENOMEM;  	} -	dbus_message_append_args(message, +	dbus_message_append_args(req->msg,  				DBUS_TYPE_OBJECT_PATH, &device_path,  				DBUS_TYPE_UINT32, &passkey,  				DBUS_TYPE_INVALID); -	if (dbus_connection_send_with_reply(connection, message, -					&call, REQUEST_TIMEOUT) == FALSE) { +	if (dbus_connection_send_with_reply(connection, req->msg, +				&req->call, REQUEST_TIMEOUT) == FALSE) {  		error("D-Bus send failed"); -		dbus_message_unref(message); -		return NULL; +		return -EIO;  	} -	dbus_message_unref(message); +	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); -	return call; +	return 0;  }  int agent_request_confirmation(struct agent *agent, struct btd_device *device, @@ -657,6 +670,7 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,  {  	struct agent_request *req;  	const gchar *dev_path = device_get_path(device); +	int err;  	if (agent->request)  		return -EBUSY; @@ -667,19 +681,52 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,  	req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,  				user_data); -	req->call = confirmation_request_new(agent, dev_path, passkey); -	if (!req->call) +	err = confirmation_request_new(req, dev_path, passkey); +	if (err < 0)  		goto failed; -	dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); -  	agent->request = req;  	return 0;  failed:  	agent_request_free(req); -	return -1; +	return err; +} + +static int request_fallback(struct agent_request *req, +				DBusPendingCallNotifyFunction function) +{ +	struct adapter *adapter = req->agent->adapter; +	DBusMessage *msg; + +	if (req->agent == adapter->agent || adapter->agent == NULL) +		return -EINVAL; + +	dbus_pending_call_cancel(req->call); + +	msg = dbus_message_copy(req->msg); + +	dbus_message_set_destination(msg, adapter->agent->name); +	dbus_message_set_path(msg, adapter->agent->path); + +	if (dbus_connection_send_with_reply(connection, msg, +					&req->call, REQUEST_TIMEOUT) == FALSE) { +		error("D-Bus send failed"); +		dbus_message_unref(msg); +		return -EIO; +	} + +	req->agent->request = NULL; +	req->agent = adapter->agent; +	req->agent->request = req; + +	dbus_message_unref(req->msg); +	req->msg = msg; + +	dbus_pending_call_set_notify(req->call, function, req, NULL); + +	return 0;  }  int agent_display_passkey(struct agent *agent, struct btd_device *device, | 
