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;
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;
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;
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)
{
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();
if (!selected_object) {
BT_DBG("Object not selected");
- goto fail;
+ return;
}
snprintf(file_path, sizeof(file_path), "%s%s",
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)
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,
_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);
}
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;
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;
}
- 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,
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)
{
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);
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;
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 |
(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;
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();
}
}
}