From 2fcb820a84ac4552a5aa8906c69410578dfd4b43 Mon Sep 17 00:00:00 2001 From: Atul Rai Date: Thu, 14 Jul 2016 18:53:16 +0900 Subject: [PATCH] [Adapt] Implement rfcomm socket connect APIs This patch adds bt-service implementation for RFCOMM client socket connect APIs given below: _bt_rfcomm_connect_using_uuid() _bt_rfcomm_connect_using_channel() Change-Id: I70f910a01acf77ea4e8c9a1ff37a56d695691eec Signed-off-by: Atul Rai --- bt-service-adaptation/CMakeLists.txt | 1 + .../services/bt-request-handler.c | 50 ++++++ .../services/bt-service-event-receiver.c | 5 + bt-service-adaptation/services/bt-service-util.c | 29 ++++ .../services/include/bt-request-handler.h | 4 + .../services/include/bt-service-rfcomm.h | 39 +++++ .../services/include/bt-service-socket.h | 9 ++ .../services/include/bt-service-util.h | 8 + .../services/rfcomm/bt-service-rfcomm.c | 172 +++++++++++++++++++++ .../services/socket/bt-service-socket.c | 144 +++++++++++++++++ 10 files changed, 461 insertions(+) create mode 100644 bt-service-adaptation/services/include/bt-service-rfcomm.h create mode 100644 bt-service-adaptation/services/rfcomm/bt-service-rfcomm.c diff --git a/bt-service-adaptation/CMakeLists.txt b/bt-service-adaptation/CMakeLists.txt index 661ccfb..462991a 100644 --- a/bt-service-adaptation/CMakeLists.txt +++ b/bt-service-adaptation/CMakeLists.txt @@ -16,6 +16,7 @@ marshal.c ./services/bt-service-agent-util.c ./services/hid/bt-service-hidhost.c ./services/socket/bt-service-socket.c +./services/rfcomm/bt-service-rfcomm.c ) IF("${CMAKE_BUILD_TYPE}" STREQUAL "") diff --git a/bt-service-adaptation/services/bt-request-handler.c b/bt-service-adaptation/services/bt-request-handler.c index 022ae2f..8319541 100644 --- a/bt-service-adaptation/services/bt-request-handler.c +++ b/bt-service-adaptation/services/bt-request-handler.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include "bt-service-dpm.h" #endif #include "bt-service-hidhost.h" +#include "bt-service-rfcomm.h" /* For maintaining Application Sync API call requests */ GSList *invocation_list = NULL; @@ -950,6 +952,41 @@ int __bt_bluez_request(int function_name, break; } #endif + case BT_RFCOMM_CLIENT_CONNECT: { + bluetooth_device_address_t address = { {0} }; + char *input_string; + int connect_type; + + __bt_service_get_parameters(in_param1, + &address, sizeof(bluetooth_device_address_t)); + input_string = (char *)g_variant_get_data(in_param2); + __bt_service_get_parameters(in_param3, &connect_type, sizeof(int)); + + if (connect_type == BT_RFCOMM_UUID) + result = _bt_rfcomm_connect_using_uuid(&address, input_string); + else + result = _bt_rfcomm_connect_using_channel(&address, input_string); + + if (result != BLUETOOTH_ERROR_NONE) { + bluetooth_rfcomm_connection_t conn_info; + + BT_ERR("BT_RFCOMM_CLIENT_CONNECT failed, send error"); + memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t)); + if (connect_type == BT_RFCOMM_UUID) + g_strlcpy(conn_info.uuid, input_string, BLUETOOTH_UUID_STRING_MAX); + else + g_strlcpy(conn_info.uuid, "not_used", BLUETOOTH_UUID_STRING_MAX); + + conn_info.device_role = RFCOMM_ROLE_CLIENT; + conn_info.socket_fd = -1; + g_array_append_vals(*out_param1, &conn_info, + sizeof(bluetooth_rfcomm_connection_t)); + } else { + sender = (char*)g_dbus_method_invocation_get_sender(context); + _bt_save_invocation_context(context, result, sender, function_name, NULL); + } + break; + } default: BT_INFO("UnSupported function [%d]", function_name); result = BLUETOOTH_ERROR_NOT_SUPPORT; @@ -1489,3 +1526,16 @@ void _bt_service_method_return(GDBusMethodInvocation *invocation, g_variant_new("(iv)", result, out_var)); BT_DBG("-"); } + +void _bt_service_method_return_with_unix_fd_list(GDBusMethodInvocation *invocation, + GArray *out_param, int result, GUnixFDList *fd_list) +{ + GVariant *out_var; + BT_DBG("+"); + out_var = g_variant_new_from_data((const GVariantType *)"ay", + out_param->data, out_param->len, TRUE, NULL, NULL); + + g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, + g_variant_new("(iv)", result, out_var), fd_list); + BT_DBG("-"); +} diff --git a/bt-service-adaptation/services/bt-service-event-receiver.c b/bt-service-adaptation/services/bt-service-event-receiver.c index 912c3a6..a832bea 100644 --- a/bt-service-adaptation/services/bt-service-event-receiver.c +++ b/bt-service-adaptation/services/bt-service-event-receiver.c @@ -137,6 +137,11 @@ void _bt_service_oal_event_receiver(int event_type, gpointer event_data, gsize l if (hid_cb) hid_cb(event_type, event_data); break; + case OAL_EVENT_SOCKET_OUTGOING_CONNECTED: + case OAL_EVENT_SOCKET_DISCONNECTED: + if (socket_cb) + socket_cb(event_type, event_data); + break; default: BT_ERR("Unhandled Event: %d", event_type); break; diff --git a/bt-service-adaptation/services/bt-service-util.c b/bt-service-adaptation/services/bt-service-util.c index 6454b6a..bd08056 100755 --- a/bt-service-adaptation/services/bt-service-util.c +++ b/bt-service-adaptation/services/bt-service-util.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -156,3 +157,31 @@ void _bt_service_convert_uuid_type_to_string(char *str, const unsigned char *uui uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); } + +void _bt_service_convert_uuid_string_to_type(unsigned char *uuid, const char *str) +{ + int i = 0; + const char *ptr = str; + + ret_if(str == NULL); + ret_if(uuid == NULL); + + BT_DBG("+"); + + memcpy(uuid, BT_SERVICE_BASE_UUID, BT_UUID_LENGTH_MAX); + + while (*ptr && i < BT_UUID_LENGTH_MAX) { + if (*ptr == '-') { + ptr++; + continue; + } + + if (sscanf(ptr, "%02hhx", &(uuid[i])) != 1) + break; + + i++; + ptr += 2; + } + + BT_DBG("-"); +} diff --git a/bt-service-adaptation/services/include/bt-request-handler.h b/bt-service-adaptation/services/include/bt-request-handler.h index ff482c5..ddb9314 100755 --- a/bt-service-adaptation/services/include/bt-request-handler.h +++ b/bt-service-adaptation/services/include/bt-request-handler.h @@ -60,6 +60,10 @@ void _bt_service_cynara_deinit(void); void _bt_service_method_return(GDBusMethodInvocation *invocation, GArray *out_param, int result); + +void _bt_service_method_return_with_unix_fd_list(GDBusMethodInvocation *invocation, + GArray *out_param, int result, GUnixFDList *fd_list); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bt-service-adaptation/services/include/bt-service-rfcomm.h b/bt-service-adaptation/services/include/bt-service-rfcomm.h new file mode 100644 index 0000000..d40084b --- /dev/null +++ b/bt-service-adaptation/services/include/bt-service-rfcomm.h @@ -0,0 +1,39 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Atul Kumar Rai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __BT_SERVICE_RFCOMM_CLIENT_H__ +#define __BT_SERVICE_RFCOMM_CLIENT_H__ + +#include +#include +#include "bluetooth-api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int _bt_rfcomm_connect_using_uuid(bluetooth_device_address_t *device_address, char *remote_uuid); +int _bt_rfcomm_connect_using_channel(bluetooth_device_address_t *device_address, char *chan_str); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __BT_SERVICE_RFCOMM_CLIENT_H__ */ diff --git a/bt-service-adaptation/services/include/bt-service-socket.h b/bt-service-adaptation/services/include/bt-service-socket.h index 5b0a70c..08e157c 100644 --- a/bt-service-adaptation/services/include/bt-service-socket.h +++ b/bt-service-adaptation/services/include/bt-service-socket.h @@ -30,9 +30,18 @@ extern "C" { #endif +#define SOCK_TYPE_RFCOMM 0 +#define SOCK_TYPE_SCO 1 +#define SOCK_TYPE_L2CAP 2 + +typedef void (*bt_socket_client_conn_cb) (int result, int sock_fd, char *address, char *uuid, int chan); + int _bt_socket_init(void); void _bt_socket_deinit(void); +int _bt_socket_client_connect(int sock_type, char *address, + char *remote_uuid, int channel, bt_socket_client_conn_cb cb); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bt-service-adaptation/services/include/bt-service-util.h b/bt-service-adaptation/services/include/bt-service-util.h index 75df082..efbf808 100755 --- a/bt-service-adaptation/services/include/bt-service-util.h +++ b/bt-service-adaptation/services/include/bt-service-util.h @@ -27,8 +27,15 @@ extern "C" { #endif /* __cplusplus */ #define BT_NODE_NAME_LEN 50 +#define BT_UUID_LENGTH_MAX 16 #define BT_UUID_STRING_SIZE 37 + +static const char BT_SERVICE_BASE_UUID[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb +}; + typedef struct { int req_id; int service_function; @@ -56,6 +63,7 @@ request_info_t *_bt_get_request_info(int req_id); void _bt_clear_request_list(void); void _bt_service_convert_uuid_type_to_string(char *str, const unsigned char *uuid); +void _bt_service_convert_uuid_string_to_type(unsigned char *uuid, const char *str); #ifdef __cplusplus } diff --git a/bt-service-adaptation/services/rfcomm/bt-service-rfcomm.c b/bt-service-adaptation/services/rfcomm/bt-service-rfcomm.c new file mode 100644 index 0000000..544d4c7 --- /dev/null +++ b/bt-service-adaptation/services/rfcomm/bt-service-rfcomm.c @@ -0,0 +1,172 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved. + * + * Author: Atul Kumar Rai + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include + + +#include "bluetooth-api.h" +#include "bt-internal-types.h" +#include "bt-request-handler.h" +#include "bt-service-util.h" +#include "bt-service-event.h" +#include "bt-service-common.h" +#include "bt-service-rfcomm.h" +#include "bt-service-socket.h" + +static void __bt_rfcomm_reply_pending_request(int result, + int service_function, void *user_data, unsigned int size) +{ + GSList *l; + GArray *out_param; + invocation_info_t *req_info; + + /* Get method invocation context */ + for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) { + req_info = l->data; + if (req_info == NULL || req_info->service_function != service_function) + continue; + + /* Create out param */ + out_param = g_array_new(FALSE, FALSE, sizeof(gchar)); + + switch(service_function) { + case BT_RFCOMM_CLIENT_CONNECT: { + GUnixFDList *fd_list = NULL; + GError *error = NULL; + + g_array_append_vals(out_param, user_data, size); + + if (BLUETOOTH_ERROR_NONE == result) { + bluetooth_rfcomm_connection_t *ptr = user_data; + + fd_list = g_unix_fd_list_new(); + g_unix_fd_list_append(fd_list, ptr->socket_fd, &error); + g_assert_no_error (error); + } + + _bt_service_method_return_with_unix_fd_list( + req_info->context, out_param, result, fd_list); + + g_object_unref(fd_list); + break; + } + default: + BT_ERR("Unknown Service function"); + } + + g_array_free(out_param, TRUE); + _bt_free_info_from_invocation_list(req_info); + } + + return; +} + +static void __bt_rfcomm_socket_conn_cb(int result, int sock_fd, char *address, char *uuid, int chan) +{ + bluetooth_rfcomm_connection_t conn_info; + + ret_if(NULL == address); + ret_if(NULL == uuid); + + BT_DBG("+"); + + BT_INFO("result: %d, socket_fd: %d, address: %s, uuid: %s, chan: %d", + result, sock_fd, address, uuid, chan); + + /* Fill RFCOMM connection structure and send reply to pending request */ + memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t)); + conn_info.socket_fd = sock_fd; + conn_info.device_role = RFCOMM_ROLE_CLIENT; + g_strlcpy(conn_info.uuid, uuid, BLUETOOTH_UUID_STRING_MAX); + _bt_convert_addr_string_to_type(conn_info.device_addr.addr, address); + + __bt_rfcomm_reply_pending_request( + result, BT_RFCOMM_CLIENT_CONNECT, + (void *)&conn_info, sizeof(bluetooth_rfcomm_connection_t)); + + /* Send BLUETOOTH_EVENT_RFCOMM_CONNECTED event to application */ + if (result == BLUETOOTH_ERROR_NONE) { + GVariant *param; + + param = g_variant_new("(issn)", BLUETOOTH_ERROR_NONE, + address, conn_info.uuid, sock_fd); + _bt_send_event(BT_RFCOMM_CLIENT_EVENT, + BLUETOOTH_EVENT_RFCOMM_CONNECTED, param); + } + + BT_DBG("-"); +} + +int _bt_rfcomm_connect_using_uuid(bluetooth_device_address_t *device_address, char *remote_uuid) +{ + int result; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + + BT_DBG("+"); + + retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM); + retv_if(NULL == remote_uuid, BLUETOOTH_ERROR_INVALID_PARAM); + + _bt_convert_addr_type_to_string(address, device_address->addr); + BT_INFO("RFCOMM connect called for [%s], uuid: [%s]", address, remote_uuid); + + result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM, + address, remote_uuid, -1, __bt_rfcomm_socket_conn_cb); + if (BLUETOOTH_ERROR_NONE != result) { + BT_ERR("_bt_socket_client_connect failed"); + return result; + } + + BT_DBG("-"); + return BLUETOOTH_ERROR_NONE; +} + +/* Range of the Channel : 0 <= channel <= 30 */ +int _bt_rfcomm_connect_using_channel(bluetooth_device_address_t *device_address, char *chan_str) +{ + int channel; + int result = BLUETOOTH_ERROR_NONE; + char address[BT_ADDRESS_STRING_SIZE] = { 0 }; + + BT_DBG("+"); + + retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM); + retv_if(NULL == chan_str, BLUETOOTH_ERROR_INVALID_PARAM); + + _bt_convert_addr_type_to_string(address, device_address->addr); + channel = atoi(chan_str); + BT_INFO("RFCOMM connect called for [%s], channel: %d", address, channel); + + result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM, + address, NULL, channel, __bt_rfcomm_socket_conn_cb); + if (BLUETOOTH_ERROR_NONE != result) { + BT_ERR("_bt_socket_client_connect failed"); + return result; + } + + BT_DBG("-"); + return result; +} diff --git a/bt-service-adaptation/services/socket/bt-service-socket.c b/bt-service-adaptation/services/socket/bt-service-socket.c index b99e740..4d00088 100644 --- a/bt-service-adaptation/services/socket/bt-service-socket.c +++ b/bt-service-adaptation/services/socket/bt-service-socket.c @@ -33,18 +33,162 @@ #include "bt-service-common.h" #include "bt-service-util.h" #include "bt-service-event-receiver.h" +#include "bt-service-socket.h" + +typedef struct { + int sock_fd; + int chan; + char uuid[BT_UUID_STRING_SIZE]; + char address[BT_ADDRESS_STRING_SIZE]; + bt_socket_client_conn_cb conn_cb; +} bt_socket_info_t; + +bt_socket_info_t *pending_conn_info; + +/* Function to handle socket disconnection */ +void __handle_socket_disconnected(event_socket_client_conn_t *client_info) +{ + char address[BT_ADDRESS_STR_LEN]; + + ret_if(NULL == client_info); + + BT_DBG("+"); + + _bt_convert_addr_type_to_string(address, client_info->address.addr); + + /* + * In case of an already connected socket, if disconnection happens, it will + * automatically detected in corresponding i/o handler and events will be sent + * from there. So here we only handle connection fail case. + */ + if (NULL != pending_conn_info && + !strncasecmp(address, pending_conn_info->address, strlen(address))) { + /* + * Disconnection event is received for ongoing connection, invoke connection + * state callback with error. + */ + BT_INFO("socket_fd: %d, address: %s, uuid: %s, channel: %d", + client_info->fd, address, + pending_conn_info->uuid, + pending_conn_info->chan); + + pending_conn_info->conn_cb(BLUETOOTH_ERROR_INTERNAL, client_info->fd, address, + pending_conn_info->uuid, pending_conn_info->chan); + + g_free(pending_conn_info); + pending_conn_info = NULL; + } else { + BT_INFO("Disconnected Address: [%s], socket_fd: %d", address, client_info->fd); + } + + BT_DBG("-"); +} + +/* Handle outgoing client socket connection event */ +static void __handle_outgoing_client_socket_connected(event_socket_client_conn_t *client_info) +{ + char address[BT_ADDRESS_STR_LEN]; + + ret_if(NULL == client_info); + ret_if(NULL == pending_conn_info); + + BT_DBG("+"); + + /* + * Only one socket connect req at a time is allowed, so received address + * should match with pending request. + */ + _bt_convert_addr_type_to_string(address, client_info->address.addr); + if (strncasecmp(address, pending_conn_info->address, strlen(address))) { + BT_ERR("Address mismatch, Pending connection address: [%s]", + pending_conn_info->address); + BT_ERR("Client connection callback called with address: [%s]", address); + return; + } + + BT_INFO("socket_fd: %d, address: %s, uuid: %s, channel: %d", + client_info->fd, address, + pending_conn_info->uuid, + pending_conn_info->chan); + + pending_conn_info->conn_cb(BLUETOOTH_ERROR_NONE, client_info->fd, address, + pending_conn_info->uuid, pending_conn_info->chan); + + g_free(pending_conn_info); + pending_conn_info = NULL; + BT_DBG("-"); +} static void __bt_socket_event_handler(int event_type, gpointer event_data) { BT_INFO("OAL event = 0x%x, \n", event_type); switch(event_type) { + case OAL_EVENT_SOCKET_OUTGOING_CONNECTED: { + event_socket_client_conn_t *client_info = event_data; + + __handle_outgoing_client_socket_connected(client_info); + break; + } + case OAL_EVENT_SOCKET_DISCONNECTED: { + event_socket_client_conn_t *client_info = event_data; + + __handle_socket_disconnected(client_info); + break; + } default: BT_ERR("Invalid event:%d\n", event_type); break; } } +int _bt_socket_client_connect(int sock_type, char *address, + char *remote_uuid, int channel, bt_socket_client_conn_cb cb) +{ + int sock_fd = -1; + bt_address_t bd; + oal_uuid_t uuid; + + retv_if(NULL == address, BLUETOOTH_ERROR_INVALID_PARAM); + retv_if(NULL != pending_conn_info, BLUETOOTH_ERROR_DEVICE_BUSY); + + BT_DBG("+"); + + + BT_INFO("sock_type: %d, address: %s, remote_uuid: %s, channel: %d", + sock_type, address, remote_uuid, channel); + + _bt_convert_addr_string_to_type(bd.addr, address); + if (remote_uuid) + _bt_service_convert_uuid_string_to_type(uuid.uuid, remote_uuid); + else + memset(&uuid, 0x00, sizeof(oal_uuid_t)); + + switch (sock_type) { + case SOCK_TYPE_RFCOMM: + sock_fd = socket_connect(OAL_SOCK_RFCOMM, &uuid, channel, &bd); + break; + default: + BT_ERR("Socket type: %d not supported"); + return BLUETOOTH_ERROR_NOT_SUPPORT; + } + + if(0 > sock_fd) { + BT_ERR("Bluetooth socket connect failed"); + return BLUETOOTH_ERROR_CONNECTION_ERROR; + } + + pending_conn_info = g_malloc0(sizeof(bt_socket_info_t)); + pending_conn_info->sock_fd = sock_fd; + pending_conn_info->chan = channel; + pending_conn_info->conn_cb = cb; + g_strlcpy(pending_conn_info->address, address, BT_ADDRESS_STRING_SIZE); + g_strlcpy(pending_conn_info->uuid, remote_uuid, BT_UUID_STRING_SIZE); + + BT_DBG("-"); + return BLUETOOTH_ERROR_NONE; +} + int _bt_socket_init(void) { BT_INFO("Socket Init"); -- 2.7.4