[OTP] Handle Object Write request 26/134626/3
authorGowtham Anandha Babu <gowtham.ab@samsung.com>
Mon, 19 Jun 2017 13:23:02 +0000 (18:53 +0530)
committerGowtham Anandha Babu <gowtham.ab@samsung.com>
Tue, 20 Jun 2017 05:04:14 +0000 (10:34 +0530)
Change-Id: I82634c3334a24b98cf85239de820ca2026f0661f
Signed-off-by: Gowtham Anandha Babu <gowtham.ab@samsung.com>
bt-otp/bt-otpserver.c
bt-otp/bt-otpserver.h

index d75ed46..2e88aa6 100644 (file)
@@ -63,6 +63,7 @@ static int property_sub_id = -1;
 static int adapter_sub_id = -1;
 static int device_sub_id = -1;
 static guint g_owner_id = 0;
+static guint server_watch_id = 0;
 
 struct otp_char_info {
        gchar *char_path;
@@ -94,16 +95,16 @@ struct oacp_operation {
        uint32_t offset;
        uint32_t length;
        uint8_t opcode;
+       uint32_t length_sofar;
        uint8_t mode;
        int fd;
+       FILE *fp;
 };
 
 struct oacp_create_operation {
        char *remote_address;
-       char *filename;
        char *uuid;
        uint32_t size;
-       time_t first_created;
 };
 
 static struct object_metadata *selected_object = NULL;
@@ -117,7 +118,7 @@ static gboolean OLCP_indicate = FALSE;
 char *directory = NULL;
 gboolean mutiple_obj_support = false;
 static gboolean otc_connection_status = FALSE;
-struct oacp_operation *oacp_read = NULL;
+struct oacp_operation *oacp_op = NULL;
 struct oacp_create_operation *oacp_create = NULL;
 unsigned int timeout_id;
 
@@ -143,6 +144,7 @@ void _bt_otp_unregister_interface(void);
 void update_obj_metadata_charc_value(struct object_metadata *object);
 void _bt_convert_device_path_to_address(const char *device_path,
                                                char *device_address);
+int _bt_otp_open_otc_and_listen(char *address, char *method);
 
 static void delete_all_objects(void)
 {
@@ -295,7 +297,7 @@ int _bt_otp_prepare_ots(void)
        char *desc_uuid;
        bt_gatt_characteristic_property_t props;
        bt_gatt_permission_t perms;
-       char supp_feat[OTP_FEATURE_LENGTH] = { 0x88, 0x00, 0x00, 0x00,
+       char supp_feat[OTP_FEATURE_LENGTH] = { 0x8C, 0x00, 0x00, 0x00,
                                                0x80, 0x00, 0x00, 0x00 };
 
        ret = bluetooth_gatt_init();
@@ -509,7 +511,7 @@ void _bt_otp_start_write_on_fd()
 
        if (!selected_object) {
                BT_DBG("Object not selected");
-               goto fail;
+               return;
        }
 
        snprintf(file_path, sizeof(file_path), "%s%s",
@@ -519,11 +521,11 @@ void _bt_otp_start_write_on_fd()
        fp = fopen(file_path, "r");
        if (!fp) {
                BT_DBG("fopen() failed : %s", strerror(errno));
-               goto fail;
+               return;
        }
 
-       BT_DBG("length [%d]", oacp_read->length);
-       length = oacp_read->length;
+       BT_DBG("length [%d]", oacp_op->length);
+       length = oacp_op->length;
 
        while (length > 0) {
                if (length < BT_L2CAP_BUFFER_LEN)
@@ -532,18 +534,136 @@ void _bt_otp_start_write_on_fd()
                        len = BT_L2CAP_BUFFER_LEN;
 
                read = fread(buf, 1, len, fp);
-               written = write(oacp_read->fd, buf, len);
+               written = write(oacp_op->fd, buf, len);
+
+               if (written < 0)
+                       goto fail;
+
                length -= written;
 
                BT_DBG("read [%d], written [%d], rem_len [%d]",
                                                read, written, length);
        }
-
+fail:
        fclose(fp);
+}
+
+
+static bool __bt_otc_connection_timeout_cb(gpointer user_data)
+{
+       int err = BLUETOOTH_ERROR_NONE;
+       char *remote_addr = oacp_op->remote_address;
+
+       err = _bt_otp_open_otc_and_listen(remote_addr, "DisconnectOtc");
+       if (err != BLUETOOTH_ERROR_NONE)
+               BT_ERR("Disconnect OTC failed");
+
+       return TRUE;
+}
+
+static gboolean __server_data_received_cb(GIOChannel *chan, GIOCondition cond,
+                                                               gpointer data)
+{
+       char *remote_addr = oacp_op->remote_address;
+       GIOStatus status = G_IO_STATUS_NORMAL;
+       GError *err = NULL;
+       char *buffer = NULL;
+       gsize len = 0;
+       int written;
+       int fd;
+
+       BT_DBG("");
+
+       fd = g_io_channel_unix_get_fd(chan);
+       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
+               otc_connection_status = FALSE;
+               BT_ERR("OTC disconnected: %d", fd);
+               close(fd);
+               g_source_remove(server_watch_id);
+               return FALSE;
+       }
+
+       buffer = g_malloc0(BT_L2CAP_BUFFER_LEN + 1);
+
+       status = g_io_channel_read_chars(chan, buffer,
+                                                       BT_L2CAP_BUFFER_LEN,
+                                                       &len, &err);
+       if (status != G_IO_STATUS_NORMAL) {
+               BT_ERR("IO Channel read is failed with %d", status);
+
+               g_free(buffer);
+               if (err) {
+                       otc_connection_status = FALSE;
+                       BT_ERR("IO Channel read error [%s]", err->message);
+                       if (status == G_IO_STATUS_ERROR) {
+                               BT_ERR("cond : %d", cond);
+                               g_error_free(err);
+                               close(fd);
+                               g_source_remove(server_watch_id);
+                               return FALSE;
+                       }
+                       g_error_free(err);
+               }
+               return TRUE;
+       }
+
+       BT_DBG("Received data length %d, remote_addr = %s", len, remote_addr);
+
+       if (!oacp_op->fp) {
+               char file_path[BT_FILE_PATH_MAX_LEN] = {0, };
+               FILE *fp = NULL;
+
+               if (!selected_object) {
+                       BT_DBG("Object not selected");
+                       goto fail;
+               }
+
+               snprintf(file_path, sizeof(file_path), "%s%s",
+                                               directory, selected_object->name);
+
+               BT_DBG("file_path = [%s]", file_path);
+               fp = fopen(file_path, "w");
+               if (!fp) {
+                       BT_DBG("fopen() failed : %s", strerror(errno));
+                       goto fail;
+               }
+               oacp_op->fp = fp;
+       }
+
+       if (oacp_op->length_sofar <= oacp_op->length) {
+               written = fwrite(buffer, 1, len, oacp_op->fp);
+               oacp_op->length_sofar += written;
+               BT_DBG("written [%d], length_sofar [%lu], received_buff_len [%d], size [%lu]",
+                                       written, oacp_op->length_sofar, len, oacp_op->length);
+       }
+
+       if (timeout_id > 0) {
+               g_source_remove(timeout_id);
+               timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT,
+                       (GSourceFunc)__bt_otc_connection_timeout_cb, NULL);
+       }
 fail:
-       g_free(oacp_read->remote_address);
-       g_free(oacp_read);
-       oacp_read = NULL;
+       g_free(buffer);
+       return TRUE;
+}
+
+static void _bt_otp_start_read_on_fd()
+{
+       GIOChannel *data_io;
+       data_io = g_io_channel_unix_new(oacp_op->fd);
+
+       g_io_channel_set_encoding(data_io, NULL, NULL);
+       g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
+
+       server_watch_id = g_io_add_watch(data_io,
+               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+               __server_data_received_cb, NULL);
+
+       if (timeout_id > 0)
+                       g_source_remove(timeout_id);
+
+       timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT,
+               (GSourceFunc)__bt_otc_connection_timeout_cb, NULL);
 }
 
 static void _bt_otp_method(GDBusConnection *connection,
@@ -684,12 +804,14 @@ fail:
                _bt_convert_device_path_to_address(dev_path, address);
 
                BT_INFO("OTC Connected fd: %d, address %s", fd, address);
-               if (oacp_read) {
-                       oacp_read->fd = fd;
-                       otc_connection_status = TRUE;
+               otc_connection_status = TRUE;
+               if (oacp_op) {
+                       oacp_op->fd = fd;
 
-                       if (oacp_read->opcode == OACP_READ)
+                       if (oacp_op->opcode == OACP_READ)
                                _bt_otp_start_write_on_fd();
+                       else if (oacp_op->opcode == OACP_WRITE)
+                               _bt_otp_start_read_on_fd();
                }
                g_dbus_method_invocation_return_value(invocation, NULL);
        }
@@ -871,7 +993,7 @@ fail:
        return object_path;
 }
 
-int _bt_otp_open_otc_and_listen(char *address)
+int _bt_otp_open_otc_and_listen(char *address, char *method)
 {
        char *object_path;
        GDBusProxy *device_proxy = NULL;
@@ -879,6 +1001,13 @@ int _bt_otp_open_otc_and_listen(char *address)
        GError *error = NULL;
        int ret = BLUETOOTH_ERROR_NONE;
 
+       if (method == NULL)
+               return BLUETOOTH_ERROR_INTERNAL;
+
+       if (g_strcmp0(method, "ListenOtc") &&
+                       g_strcmp0(method, "DisconnectOtc"))
+               return BLUETOOTH_ERROR_INTERNAL;
+
        object_path = _bt_otp_get_device_object_path(address);
        if (object_path == NULL) {
                ret = BLUETOOTH_ERROR_NOT_PAIRED;
@@ -894,7 +1023,7 @@ int _bt_otp_open_otc_and_listen(char *address)
        }
 
 
-       result = g_dbus_proxy_call_sync(device_proxy, "ListenOtc",
+       result = g_dbus_proxy_call_sync(device_proxy, method,
                                NULL,
                                G_DBUS_CALL_FLAGS_NONE,
                                -1,
@@ -927,6 +1056,22 @@ static bool __bt_oacp_create_timeout_cb(gpointer user_data)
        return TRUE;
 }
 
+static void _bt_otp_free_oacp_op()
+{
+       if (timeout_id > 0) {
+               g_source_remove(timeout_id);
+               timeout_id = 0;
+       }
+
+       if (oacp_op) {
+               g_free(oacp_op->remote_address);
+               if (oacp_op->fp)
+                       fclose(oacp_op->fp);
+               g_free(oacp_op);
+               oacp_op = NULL;
+       }
+}
+
 int _bt_otp_oacp_write_cb(char *value, int len, int offset,
                                                        char *remote_addr, struct indicate_info *info)
 {
@@ -934,6 +1079,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset,
        int app_err = BLUETOOTH_ERROR_NONE;
        int opcode = value[0];
        uint32_t object_offset, length, object_size;
+       uint8_t mode = 0;
        char *uuid;
 
        BT_INFO("OACP Opcode 0x%d", opcode);
@@ -964,7 +1110,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset,
                oacp_create->uuid = g_strdup(uuid);
                if (timeout_id > 0)
                        g_source_remove(timeout_id);
-               timeout_id = g_timeout_add(BT_OACP_CREATE_MAX_TIMEOUT,
+               timeout_id = g_timeout_add(BT_OACP_MAX_TIMEOUT,
                        (GSourceFunc)__bt_oacp_create_timeout_cb, NULL);
                g_free(uuid);
                ret = OACP_SUCCESS;
@@ -979,6 +1125,7 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset,
                ret = OACP_OPCODE_NOT_SUPPORTED;
                break;
        case OACP_READ:
+       case OACP_WRITE:
                object_offset = (uint32_t)(value[4] & 0xFF) << 24 |
                                (uint32_t)(value[3] & 0xFF) << 16 |
                                (uint32_t)(value[2] & 0xFF) << 8  |
@@ -988,32 +1135,37 @@ int _bt_otp_oacp_write_cb(char *value, int len, int offset,
                        (uint32_t)(value[6] & 0xFF) << 8  |
                        (uint32_t)(value[5] & 0xFF);
 
-               BT_INFO("Offset = %lu, Length = %lu", object_offset, length);
+               if (opcode == OACP_WRITE)
+                       mode = (uint8_t)value[9] & 0xFF;
 
-               if (oacp_read && otc_connection_status) {
-                       /* Read operation already going on. */
-                       ret = OACP_OBJECT_LOCKED;
-                       goto fail;
+               BT_INFO("Offset = %lu, Length = %lu", object_offset, length, mode);
+
+               if (oacp_op) {
+                       if (otc_connection_status) {
+                               /* Read/Write operation already going on. */
+                               ret = OACP_OBJECT_LOCKED;
+                               goto fail;
+                       }
+                       _bt_otp_free_oacp_op();
                }
-               oacp_read = g_malloc0(sizeof(struct oacp_operation));
-               oacp_read->offset = object_offset;
-               oacp_read->length = length;
-               oacp_read->remote_address = g_strdup(remote_addr);
-               oacp_read->opcode = OACP_READ;
 
-               app_err = _bt_otp_open_otc_and_listen(remote_addr);
+               oacp_op = g_malloc0(sizeof(struct oacp_operation));
+               oacp_op->offset = object_offset;
+               oacp_op->length = length;
+               oacp_op->remote_address = g_strdup(remote_addr);
+               oacp_op->mode = mode;
+               oacp_op->opcode = opcode;
+               oacp_op->length_sofar = 0;
+               oacp_op->fp = NULL;
+
+               app_err = _bt_otp_open_otc_and_listen(remote_addr, "ListenOtc");
                if (app_err != BLUETOOTH_ERROR_NONE) {
                        ret = OACP_OPERATION_FAILED;
-                       g_free(oacp_read->remote_address);
-                       g_free(oacp_read);
-                       oacp_read = NULL;
+                       _bt_otp_free_oacp_op();
                        goto fail;
                }
                ret = OACP_SUCCESS;
                break;
-       case OACP_WRITE:
-               ret = OACP_OPCODE_NOT_SUPPORTED;
-               break;
        case OACP_ABORT:
                ret = OACP_OPCODE_NOT_SUPPORTED;
                break;
@@ -1574,12 +1726,9 @@ void _bt_otc_disconnected_cb(GDBusConnection *connection,
        if (g_strcmp0(interface_name, BT_DEVICE_INTERFACE) == 0) {
                if (strcasecmp(signal_name, OTC_DISCONNECTED) == 0) {
                        BT_DBG("OTC Channel Disconnected dev_path[%s]",
-                                                                                       object_path);
+                                                               object_path);
                        otc_connection_status = FALSE;
-                       if (oacp_read) {
-                               g_free(oacp_read->remote_address);
-                               g_free(oacp_read);
-                       }
+                       _bt_otp_free_oacp_op();
                }
        }
 }
index 98f6c7a..6b10630 100755 (executable)
@@ -37,7 +37,7 @@
 
 #define BT_OTP_BASE_DIR_PATH "/home/owner/media/otp/"
 
-#define BT_OACP_CREATE_MAX_TIMEOUT 10000 /* Timeout for OACP_CREATE in msec */
+#define BT_OACP_MAX_TIMEOUT 10000 /* Timeout for OACP operation in msec */
 
 /* OTP Service and Chanracteristics UUID */
 #define OTP_UUID                       "1825"