[Adapt] Implement rfcomm socket connect APIs 72/80072/1
authorAtul Rai <a.rai@samsung.com>
Thu, 14 Jul 2016 09:53:16 +0000 (18:53 +0900)
committerAtul Rai <a.rai@samsung.com>
Thu, 14 Jul 2016 10:11:59 +0000 (19:11 +0900)
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 <a.rai@samsung.com>
bt-service-adaptation/CMakeLists.txt
bt-service-adaptation/services/bt-request-handler.c
bt-service-adaptation/services/bt-service-event-receiver.c
bt-service-adaptation/services/bt-service-util.c
bt-service-adaptation/services/include/bt-request-handler.h
bt-service-adaptation/services/include/bt-service-rfcomm.h [new file with mode: 0644]
bt-service-adaptation/services/include/bt-service-socket.h
bt-service-adaptation/services/include/bt-service-util.h
bt-service-adaptation/services/rfcomm/bt-service-rfcomm.c [new file with mode: 0644]
bt-service-adaptation/services/socket/bt-service-socket.c

index 661ccfb..462991a 100644 (file)
@@ -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 "")
index 022ae2f..8319541 100644 (file)
@@ -19,6 +19,7 @@
 #include <glib.h>
 #include <dlog.h>
 #include <gio/gio.h>
+#include <gio/gunixfdlist.h>
 #include <cynara-client.h>
 #include <cynara-creds-gdbus.h>
 
@@ -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("-");
+}
index 912c3a6..a832bea 100644 (file)
@@ -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;
index 6454b6a..bd08056 100755 (executable)
@@ -16,6 +16,7 @@
  */
 
 #include <string.h>
+#include <stdio.h>
 #include <glib.h>
 #include <dlog.h>
 #include <gio/gio.h>
@@ -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("-");
+}
index ff482c5..ddb9314 100755 (executable)
@@ -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 (file)
index 0000000..d40084b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:  Atul Kumar Rai <a.rai@samsung.com>
+ *
+ * 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 <glib.h>
+#include <sys/types.h>
+#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__ */
index 5b0a70c..08e157c 100644 (file)
 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 */
index 75df082..efbf808 100755 (executable)
@@ -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 (file)
index 0000000..544d4c7
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Author:  Atul Kumar Rai <a.rai@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+#include <dlog.h>
+#include <string.h>
+
+
+#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;
+}
index b99e740..4d00088 100644 (file)
 #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");