[OTP] Add support for Object Transfer Channel 77/130877/2
authorGowtham Anandha Babu <gowtham.ab@samsung.com>
Wed, 24 May 2017 08:04:58 +0000 (13:34 +0530)
committerGowtham Anandha Babu <gowtham.ab@samsung.com>
Wed, 24 May 2017 08:36:16 +0000 (08:36 +0000)
Expose below DBus APIs:
* ConnectOtc - bt_io_connect()
* DisconnectOtc - shutdown()
* ListenOtc - bt_io_listen()

Change-Id: Ifa4379508e0d35500b141b597f30a9429d2e695a
Signed-off-by: Gowtham Anandha Babu <gowtham.ab@samsung.com>
src/device.c

index 217e402..959fb22 100755 (executable)
@@ -356,6 +356,34 @@ typedef enum {
 
 #endif
 
+#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
+#define OTP_PSM 0x0025
+
+/* OTP Client */
+#define BT_OTC_SERVICE_NAME    "org.otp.client"
+#define BT_OTC_OBJECT_PATH     "/org/otp/client"
+#define BT_OTC_INTERFACE_NAME  "org.otp.otc_channel"
+
+/* OTP Server */
+#define BT_OTS_SERVICE_NAME    "org.projectx.otp"
+#define BT_OTS_OBJECT_PATH     "/org/projectx/otp"
+#define BT_OTS_INTERFACE_NAME  "org.projectx.otp_service"
+
+typedef enum {
+       BT_OTP_CLIENT_ROLE = 0x00,
+       BT_OTP_SERVER_ROLE,
+} bt_otp_role_e;
+
+struct otc_conn_info {
+       const char *dev_path;
+       bt_otp_role_e role;
+       GIOChannel *io;
+       bool otc_connected;
+};
+
+GSList *otc_connection_list = NULL;
+#endif
+
 static int device_browse_gatt(struct btd_device *device, DBusMessage *msg);
 static int device_browse_sdp(struct btd_device *device, DBusMessage *msg);
 
@@ -3475,6 +3503,268 @@ static DBusMessage *disconnect_ipsp(DBusConnection *conn, DBusMessage *msg,
        return dbus_message_new_method_return(msg);;
 }
 
+#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
+static GSList *find_otc_conn_info(GSList *list, const char *path)
+{
+       GSList *l;
+
+       for (l = list; l != NULL; l = g_slist_next(l)) {
+               struct otc_conn_info *info = l->data;
+
+               if (g_strcmp0(info->dev_path, path) == 0)
+                       return l;
+       }
+
+       return NULL;
+}
+
+static gboolean otc_disconnected_cb(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct otc_conn_info *conn_info;
+       const char *dev_path = (const char *) user_data;
+       GSList *l;
+
+       DBG("OTC Disconnected");
+
+       l = find_otc_conn_info(otc_connection_list, dev_path);
+       if (!l)
+               return FALSE;
+
+       conn_info = l->data;
+       conn_info->otc_connected = false;
+
+       g_dbus_emit_signal(dbus_conn, dev_path,
+                               DEVICE_INTERFACE, "OtcDisconnected",
+                               DBUS_TYPE_INVALID);
+
+       if (conn_info->io) {
+               g_io_channel_shutdown(conn_info->io, TRUE, NULL);
+               g_io_channel_unref(conn_info->io);
+       }
+
+       otc_connection_list = g_slist_remove(otc_connection_list, conn_info);
+       g_free(conn_info);
+
+       return FALSE;
+}
+
+static void otc_connect_cb(GIOChannel *chan, GError *gerr,
+                                               gpointer user_data)
+{
+       const char *dev_path;
+       GSList *l;
+       struct otc_conn_info *conn_info = NULL;
+       DBusMessage *msg = NULL;
+       DBusMessageIter iter;
+       int fd;
+
+       if (gerr)
+               return;
+
+       dev_path = (const char *) user_data;
+       l = find_otc_conn_info(otc_connection_list, dev_path);
+
+       if (!l)
+               return;
+
+       conn_info = l->data;
+       conn_info->otc_connected = true;
+
+       fd = g_io_channel_unix_get_fd(chan);
+
+       DBG("OTC Connected fd [%d], role [%s]",
+                       fd, conn_info->role ? "server" : "client");
+       DBG("dev_path [%s]", dev_path);
+
+       g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                       otc_disconnected_cb, (gpointer) dev_path);
+
+       if (conn_info->role == BT_OTP_CLIENT_ROLE) {
+               msg = dbus_message_new_method_call(BT_OTC_SERVICE_NAME,
+                                                       BT_OTC_OBJECT_PATH,
+                                                       BT_OTC_INTERFACE_NAME,
+                                                       "NewConnection");
+       } else if (conn_info->role == BT_OTP_SERVER_ROLE) {
+               msg = dbus_message_new_method_call(BT_OTS_SERVICE_NAME,
+                                                       BT_OTS_OBJECT_PATH,
+                                                       BT_OTS_INTERFACE_NAME,
+                                                       "NewConnection");
+       }
+
+       if (!msg) {
+               error("Unable to create NewConnection call");
+               return;
+       }
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &dev_path);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+
+       if (!g_dbus_send_message(dbus_conn, msg)) {
+               error("sending NewConnection failed");
+               dbus_message_unref(msg);
+       }
+}
+
+int btd_adapter_connect_otc(struct btd_device *device)
+{
+       struct btd_adapter *adapter = device_get_adapter(device);
+       const bdaddr_t *src = btd_adapter_get_address(adapter);
+       uint8_t src_type = btd_adapter_get_le_address_type(adapter);
+       const bdaddr_t *dest = device_get_address(device);
+       uint8_t dest_type = device->bdaddr_type;
+       struct otc_conn_info *conn_info = NULL;
+       const char *dev_path = device_get_path(device);
+       GError *gerr = NULL;
+
+       conn_info = g_malloc0(sizeof(struct otc_conn_info));
+
+       conn_info->io = bt_io_connect(otc_connect_cb,
+                                       (gpointer) dev_path, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, src,
+                                       BT_IO_OPT_SOURCE_TYPE, src_type,
+                                       BT_IO_OPT_DEST_BDADDR, dest,
+                                       BT_IO_OPT_DEST_TYPE, dest_type,
+                                       BT_IO_OPT_PSM, OTP_PSM,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+
+       if (!conn_info->io) {
+               error("OTC Connect failed : %s", gerr->message);
+               g_error_free(gerr);
+               g_io_channel_unref(conn_info->io);
+               g_free(conn_info);
+               return -EIO;
+       }
+
+       conn_info->dev_path = dev_path;
+       conn_info->role = BT_OTP_CLIENT_ROLE;
+       conn_info->otc_connected = false;
+       g_io_channel_set_close_on_unref(conn_info->io, FALSE);
+
+       otc_connection_list = g_slist_append(otc_connection_list, conn_info);
+       return 0;
+}
+
+static DBusMessage *connect_otc(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+       GSList *l;
+
+       if (device == NULL)
+               return btd_error_invalid_args(msg);
+
+       l = find_otc_conn_info(otc_connection_list, device_get_path(device));
+
+       if (l) {
+               struct otc_conn_info *info = l->data;
+               if (info->otc_connected)
+                       return btd_error_already_connected(msg);
+               else
+                       return btd_error_busy(msg);
+       }
+
+       if (btd_adapter_connect_otc(device) != 0)
+               return btd_error_failed(msg, "ConnectFailed");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disconnect_otc(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+       struct otc_conn_info *info = NULL;
+       GError *gerr = NULL;
+       GSList *l;
+       int sock;
+
+       l = find_otc_conn_info(otc_connection_list, device_get_path(device));
+
+       if (!l)
+               return btd_error_does_not_exist(msg);
+
+       info = l->data;
+
+       if (!info->otc_connected)
+               return btd_error_not_connected(msg);
+
+       sock = g_io_channel_unix_get_fd(info->io);
+
+       shutdown(sock, SHUT_RDWR);
+
+       g_io_channel_shutdown(info->io, FALSE, NULL);
+
+       g_io_channel_unref(info->io);
+       info->io = NULL;
+
+       return dbus_message_new_method_return(msg);
+}
+
+int btd_adapter_listen_otc(struct btd_device *device)
+{
+       struct btd_adapter *adapter = device_get_adapter(device);
+       const bdaddr_t *src = btd_adapter_get_address(adapter);
+       uint8_t type = btd_adapter_get_le_address_type(adapter);
+       struct otc_conn_info *conn_info = NULL;
+       const char *dev_path = device_get_path(device);
+       GError *gerr = NULL;
+
+       conn_info = g_malloc0(sizeof(struct otc_conn_info));
+
+       conn_info->io = bt_io_listen(otc_connect_cb, NULL, (gpointer) dev_path,
+                               NULL, &gerr,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_SOURCE_TYPE, type,
+                               BT_IO_OPT_PSM, OTP_PSM,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+
+       if (!conn_info->io) {
+               error("OTC Listen failed : %s", gerr->message);
+               g_error_free(gerr);
+               return -EIO;
+       }
+
+       conn_info->dev_path = dev_path;
+       conn_info->otc_connected = false;
+       conn_info->role = BT_OTP_SERVER_ROLE;
+       g_io_channel_set_close_on_unref(conn_info->io, FALSE);
+
+       otc_connection_list = g_slist_append(otc_connection_list, conn_info);
+       return 0;
+}
+
+static DBusMessage *listen_otc(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *device = user_data;
+       GSList *l;
+
+       if (device == NULL)
+               return btd_error_invalid_args(msg);
+
+       l = find_otc_conn_info(otc_connection_list, device_get_path(device));
+
+       if (l) {
+               struct otc_conn_info *info = l->data;
+               if (info->otc_connected)
+                       return btd_error_already_connected(msg);
+               else
+                       return btd_error_busy(msg);
+       }
+
+       if (btd_adapter_listen_otc(device) != 0)
+               return btd_error_failed(msg, "ListenFailed");
+
+       return dbus_message_new_method_return(msg);
+}
+#endif
+
 static DBusMessage *le_set_data_length(
                        DBusConnection *conn, DBusMessage *msg,
                        void *user_data)
@@ -3856,6 +4146,11 @@ static const GDBusMethodTable device_methods[] = {
        { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) },
        { GDBUS_ASYNC_METHOD("ConnectIpsp", NULL, NULL, connect_ipsp) },
        { GDBUS_ASYNC_METHOD("DisconnectIpsp", NULL, NULL, disconnect_ipsp) },
+#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
+       { GDBUS_METHOD("ConnectOtc", NULL, NULL, connect_otc) },
+       { GDBUS_METHOD("DisconnectOtc", NULL, NULL, disconnect_otc) },
+       { GDBUS_METHOD("ListenOtc", NULL, NULL, listen_otc) },
+#endif
        { GDBUS_ASYNC_METHOD("LESetDataLength",
                        GDBUS_ARGS({"max_tx_octets", "q" },
                        { "max_tx_time", "q" }), NULL,