From 83cdde0f9b0fe483e93b551fe97f97321a7a0775 Mon Sep 17 00:00:00 2001 From: Gowtham Anandha Babu Date: Mon, 19 Jun 2017 18:53:02 +0530 Subject: [PATCH] [OTP] Handle Object Write request Change-Id: I82634c3334a24b98cf85239de820ca2026f0661f Signed-off-by: Gowtham Anandha Babu --- bt-otp/bt-otpserver.c | 233 +++++++++++++++++++++++++++++++++++++++++--------- bt-otp/bt-otpserver.h | 2 +- 2 files changed, 192 insertions(+), 43 deletions(-) diff --git a/bt-otp/bt-otpserver.c b/bt-otp/bt-otpserver.c index d75ed46..2e88aa6 100644 --- a/bt-otp/bt-otpserver.c +++ b/bt-otp/bt-otpserver.c @@ -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(); } } } diff --git a/bt-otp/bt-otpserver.h b/bt-otp/bt-otpserver.h index 98f6c7a..6b10630 100755 --- a/bt-otp/bt-otpserver.h +++ b/bt-otp/bt-otpserver.h @@ -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" -- 2.7.4