Add the session timer to handle the exception case
[platform/core/connectivity/bluetooth-frwk.git] / bt-api / bt-rfcomm-client.c
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *              http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <string.h>
19 #include <gio/gunixfdlist.h>
20
21 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
22 #include <errno.h>
23 #endif
24
25 #include "bluetooth-api.h"
26 #include "bt-internal-types.h"
27
28 #include "bt-common.h"
29 #include "bt-request-sender.h"
30 #include "bt-event-handler.h"
31
32 #ifdef TIZEN_FEATURE_BT_DPM
33 #include "bt-dpm.h"
34 #endif
35
36 /* Variable for privilege, only for write API,
37   before we should reduce time to bt-service dbus calling
38   -1 : Don't have a permission to access API
39   0 : Initial value, not yet check
40   1 : Have a permission to access API
41 */
42 static int privilege_token;
43
44
45 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
46 #define BT_TIMEOUT_MESSAGE "Did not receive a reply. Possible causes include: " \
47                         "the remote application did not send a reply, " \
48                         "the message bus security policy blocked the reply, " \
49                         "the reply timeout expired, or the network connection " \
50                         "was broken."
51
52 #define BATTERY_MONITOR_RFCOMM_INTERVAL 5
53
54 static GSList *rfcomm_clients;
55
56 typedef struct {
57         char bt_addr[BT_ADDRESS_STRING_SIZE];
58         int fd;
59         guint watch_id;
60         gboolean disconnected;
61 } rfcomm_conn_info_t;
62
63 typedef struct {
64         char uuid[BLUETOOTH_UUID_STRING_MAX];
65         char *device_path;
66         char *obj_path;
67         int object_id;
68         int id;
69         GSList *rfcomm_conns;
70         unsigned int idle_id;
71 } rfcomm_cb_data_t;
72
73 static unsigned int rx_data = 0, tx_data = 0;
74 static guint tx_tag = 0, rx_tag = 0;
75
76 static void __client_connected_cb(rfcomm_cb_data_t *cb_data,
77         char *dev_address, int result);
78
79 static bool __rfcomm_record_tx_data(void)
80 {
81         if (tx_data > 0) {
82                 int ret = _bt_common_send_rfcomm_tx_details(tx_data);
83                 if (ret == BLUETOOTH_ERROR_NONE) {
84                         tx_data = 0;
85                         return TRUE;
86                 } else {
87                         BT_ERR("RFCOMM tx data could not be registered");
88                 }
89         }
90
91         tx_data = 0;
92         tx_tag = 0;
93
94         return FALSE;
95 }
96
97 static bool __rfcomm_record_rx_data(void)
98 {
99         if (rx_data) {
100                 int ret = _bt_common_send_rfcomm_rx_details(rx_data);
101                 if (ret == BLUETOOTH_ERROR_NONE) {
102                         rx_data = 0;
103                         return TRUE;
104                 } else {
105                         BT_ERR("RFCOMM rx data could not be registered");
106                 }
107         }
108
109         rx_data = 0;
110         rx_tag = 0;
111
112         return FALSE;
113 }
114
115 static void __bt_free_cb_data(rfcomm_cb_data_t *cb_data)
116 {
117         BT_DBG("+");
118
119         if (cb_data->id >= 0)
120                 __rfcomm_delete_id(cb_data->id);
121
122         if (cb_data->object_id > 0)
123                 _bt_unregister_gdbus(cb_data->object_id);
124
125         if (cb_data->obj_path) {
126                 BT_INFO("Unregister profile");
127                 _bt_unregister_profile(cb_data->obj_path);
128         }
129
130         if (cb_data->idle_id != 0) {
131                 BT_INFO("Removing idle source");
132                 g_source_remove(cb_data->idle_id);
133         }
134
135         g_free(cb_data->obj_path);
136
137         g_free(cb_data->device_path);
138         g_free(cb_data);
139         BT_DBG("-");
140 }
141
142 static void rfcomm_cb_data_remove(rfcomm_cb_data_t *info)
143 {
144         if (info) {
145                 BT_INFO("No more device connected remove info");
146                 rfcomm_clients = g_slist_remove(rfcomm_clients, info);
147                 __bt_free_cb_data(info);
148         }
149 }
150
151 gint compare(gpointer *a, gpointer *b)
152 {
153         rfcomm_conn_info_t *node = (rfcomm_conn_info_t *)a;
154         char *address = (char *)b;
155         return g_strcmp0(node->bt_addr, address);
156 }
157
158 gint compare_fd(gpointer *a, gpointer *b)
159 {
160         rfcomm_conn_info_t *node = (rfcomm_conn_info_t *)a;
161         int *fd = (int *)b;
162         if (node->fd == *fd)
163                 return 0;
164
165         return 1;
166 }
167 static void __bt_free_conn(rfcomm_conn_info_t *conn)
168 {
169         BT_DBG("+");
170
171         if (conn == NULL)
172                 return;
173
174         if (conn->watch_id > 0) {
175                 g_source_remove(conn->watch_id);
176                 conn->watch_id = 0;
177         }
178
179         g_free(conn);
180
181         BT_DBG("-");
182 }
183
184 static void __rfcomm_remove_conn_info_t(rfcomm_cb_data_t *info, char *address)
185 {
186         GSList *l = NULL;
187         rfcomm_conn_info_t *conn_info = NULL;
188         l = g_slist_find_custom(info->rfcomm_conns, address, (GCompareFunc)compare);
189         if (l)
190                 conn_info = l->data;
191         if (conn_info) {
192                 info->rfcomm_conns = g_slist_remove(info->rfcomm_conns, conn_info);
193                 __bt_free_conn(conn_info);
194         }
195 }
196
197 static rfcomm_conn_info_t *__get_conn_info_from_fd(rfcomm_cb_data_t *info,
198         int fd)
199 {
200         GSList *l;
201         rfcomm_conn_info_t *device_node = NULL;
202         for (l = info->rfcomm_conns; l != NULL; l = l->next) {
203                 device_node = l->data;
204                 if (device_node && device_node->fd == fd)
205                         return device_node;
206         }
207         return NULL;
208 }
209
210 static rfcomm_conn_info_t *__get_conn_info_from_address(rfcomm_cb_data_t *info,
211                 char *dev_address)
212 {
213         GSList *l = NULL;
214         rfcomm_conn_info_t *conn_info = NULL;
215         l = g_slist_find_custom(info->rfcomm_conns, dev_address,
216                 (GCompareFunc)compare);
217         if (l)
218                 conn_info = l->data;
219         return conn_info;
220 }
221
222 static void __rfcomm_client_connected_cb(rfcomm_cb_data_t *info,
223         char *dev_address, int result)
224 {
225         if (g_slist_find(rfcomm_clients, info) == NULL) {
226                 BT_INFO("rfcomm resource is already freed");
227                 return;
228         }
229
230         __client_connected_cb(info, dev_address, result);
231         __rfcomm_remove_conn_info_t(info, dev_address);
232
233         if (info->rfcomm_conns == NULL)
234                 rfcomm_cb_data_remove(info);
235 }
236
237 static rfcomm_cb_data_t *__find_rfcomm_info_with_fd(int fd)
238 {
239         GSList *l;
240         GSList *device_fd;
241         for (l = rfcomm_clients; l != NULL; l = l->next) {
242                 rfcomm_cb_data_t *info = l->data;
243                 device_fd = g_slist_find_custom(info->rfcomm_conns, &fd,
244                         (GCompareFunc)compare_fd);
245                 if (device_fd)
246                         return info;
247         }
248
249         return NULL;
250 }
251
252 static rfcomm_cb_data_t *__find_rfcomm_info_from_path(const char *path)
253 {
254         GSList *l;
255
256         for (l = rfcomm_clients; l != NULL; l = l->next) {
257                 rfcomm_cb_data_t *info = l->data;
258
259                 if (info != NULL)
260                         if (g_strcmp0(info->obj_path, path) == 0)
261                                 return info;
262         }
263
264         return NULL;
265 }
266
267 static rfcomm_cb_data_t *__find_rfcomm_info_from_uuid(const char *uuid)
268 {
269         GSList *l;
270
271         for (l = rfcomm_clients; l != NULL; l = l->next) {
272                 rfcomm_cb_data_t *info = l->data;
273
274                 if (g_strcmp0(info->uuid, uuid) == 0)
275                         return info;
276         }
277
278         return NULL;
279 }
280
281 static void _bt_rfcomm_disconnect_conn_info(rfcomm_conn_info_t *conn_info,
282         rfcomm_cb_data_t *info)
283 {
284         if (conn_info == NULL)
285                 return;
286
287         bluetooth_rfcomm_disconnection_t disconn_info;
288         bt_event_info_t *event_info = NULL;
289
290         if (conn_info->disconnected == FALSE)
291                 return;
292
293         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
294         if (event_info == NULL) {
295                 __rfcomm_remove_conn_info_t(info, conn_info->bt_addr);
296
297                 if (info->rfcomm_conns == NULL)
298                         rfcomm_cb_data_remove(info);
299                 return;
300         }
301
302         memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t));
303         disconn_info.device_role = RFCOMM_ROLE_CLIENT;
304         g_strlcpy(disconn_info.uuid, info->uuid, BLUETOOTH_UUID_STRING_MAX);
305         _bt_convert_addr_string_to_type(disconn_info.device_addr.addr,
306                                         conn_info->bt_addr);
307
308         BT_DBG("Disconnected FD [%d]", conn_info->fd);
309         disconn_info.socket_fd = conn_info->fd;
310
311         BT_DBG("Disconnection Result[%d] BT_ADDRESS[%s] UUID[%s] FD[%d]",
312                         BLUETOOTH_ERROR_NONE, conn_info->bt_addr,
313                         info->uuid, conn_info->fd);
314         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED,
315                         BLUETOOTH_ERROR_NONE, &disconn_info,
316                         event_info->cb, event_info->user_data);
317
318         __rfcomm_remove_conn_info_t(info, conn_info->bt_addr);
319
320         if (info->rfcomm_conns == NULL)
321                 rfcomm_cb_data_remove(info);
322
323         BT_DBG("-");
324 }
325
326 static gboolean __rfcomm_client_disconnect(gpointer user_data)
327 {
328         rfcomm_cb_data_t *info = (rfcomm_cb_data_t *)user_data;
329
330         BT_INFO_C("### Disconnected [RFCOMM Client]");
331
332         retv_if(info == NULL, FALSE);
333
334         if (g_slist_find(rfcomm_clients, info) == NULL) {
335                 BT_INFO("rfcomm resource is already freed");
336                 return FALSE;
337         }
338         info->idle_id = 0;
339
340         g_slist_foreach(info->rfcomm_conns,
341                 (GFunc)_bt_rfcomm_disconnect_conn_info, info);
342
343         BT_DBG("-");
344         return FALSE;
345 }
346
347 static gboolean __is_error_by_disconnect(GError *err)
348 {
349         return !g_strcmp0(err->message, "Connection reset by peer") ||
350                         !g_strcmp0(err->message, "Connection timed out") ||
351                         !g_strcmp0(err->message, "Software caused connection abort");
352 }
353
354 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond,
355                                                                 gpointer data)
356 {
357         char *buffer = NULL;
358         gsize len = 0;
359         int result = BLUETOOTH_ERROR_NONE;
360         rfcomm_cb_data_t *info = data;
361         rfcomm_conn_info_t *conn_info = NULL;
362         bt_event_info_t *event_info;
363         bluetooth_rfcomm_received_data_t data_r;
364         GIOStatus status = G_IO_STATUS_NORMAL;
365         GError *err = NULL;
366         int fd;
367
368         retv_if(info == NULL, FALSE);
369         fd = g_io_channel_unix_get_fd(chan);
370         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
371                 BT_ERR_C("RFComm Client  disconnected: %d", fd);
372
373                 conn_info = __get_conn_info_from_fd(info, fd);
374                 if (conn_info == NULL) {
375                         BT_ERR("No Connection info found with FD [%d]", fd);
376                         return FALSE;
377                 }
378
379                 if (conn_info->disconnected == FALSE) {
380                         close(conn_info->fd);
381                         conn_info->disconnected = TRUE;
382                 }
383                 __rfcomm_client_disconnect(info);
384                 return FALSE;
385         }
386
387         buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
388
389         status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
390                         &len, &err);
391         if (status != G_IO_STATUS_NORMAL) {
392                 BT_ERR("IO Channel read is failed with %d", status);
393
394                 g_free(buffer);
395                 if (err || status == G_IO_STATUS_EOF) {
396                         if (err)
397                                 BT_ERR("IO Channel read error [%s]", err->message);
398                         if ((status == G_IO_STATUS_EOF) ||
399                                         (status == G_IO_STATUS_ERROR &&
400                                         __is_error_by_disconnect(err))) {
401
402                                 BT_ERR("cond : %d", cond);
403                                 if (err)
404                                         g_error_free(err);
405
406                                 conn_info = __get_conn_info_from_fd(info, fd);
407                                 if (conn_info == NULL) {
408                                         BT_ERR("No Connection info found with FD [%d]", fd);
409                                         return FALSE;
410                                 }
411
412                                 if (conn_info->disconnected == FALSE) {
413                                         close(conn_info->fd);
414                                         conn_info->disconnected = TRUE;
415                                 }
416                                 __rfcomm_client_disconnect(info);
417                                 return FALSE;
418                         }
419                         if (err)
420                                 g_error_free(err);
421                 }
422                 return TRUE;
423         }
424
425         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
426         if (event_info == NULL) {
427                 g_free(buffer);
428                 return TRUE;
429         }
430
431         data_r.socket_fd = fd;
432         data_r.buffer_size = len;
433         data_r.buffer = buffer;
434
435         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED,
436                         result, &data_r,
437                         event_info->cb, event_info->user_data);
438
439         if (bluetooth_get_battery_monitor_state()) {
440                 if (rx_tag == 0) {
441                         BT_INFO("Adding rfcomm rx timeout function for battery monitor");
442                         rx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_rx_data, NULL);
443                 }
444                 rx_data += len;
445         }
446
447         g_free(buffer);
448         return TRUE;
449 }
450
451 static void __client_connected_cb(rfcomm_cb_data_t *cb_data, char *dev_address,
452         int result)
453 {
454         bluetooth_rfcomm_connection_t conn_info;
455         bt_event_info_t *event_info;
456         rfcomm_conn_info_t *conn_list_info = NULL;
457
458         if (result == BLUETOOTH_ERROR_NONE)
459                 BT_INFO_C("### Connected [RFCOMM Client]");
460
461         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
462         if (event_info == NULL)
463                 return;
464
465         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
466         conn_info.device_role = RFCOMM_ROLE_CLIENT;
467         g_strlcpy(conn_info.uuid, cb_data->uuid, BLUETOOTH_UUID_STRING_MAX);
468         _bt_convert_addr_string_to_type(conn_info.device_addr.addr,
469                         dev_address);
470         conn_list_info = __get_conn_info_from_address(cb_data, dev_address);
471         if (conn_list_info == NULL) {
472                 BT_ERR("Device addres %s not found in connection list", dev_address);
473                 return;
474         }
475         conn_info.socket_fd = conn_list_info->fd;
476         conn_info.server_id = -1;
477
478         BT_DBG("Connection Result[%d] BT_ADDRESS[%s] UUID[%s] FD[%d]",
479                         result, conn_list_info->bt_addr, cb_data->uuid, conn_list_info->fd);
480         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_CONNECTED,
481                         result, &conn_info,
482                         event_info->cb, event_info->user_data);
483         BT_DBG("-");
484 }
485
486 void _bt_rfcomm_client_disconnect_all(void)
487 {
488         GSList *client;
489         GSList *conn;
490
491         BT_INFO_C("### Disconnect all RFCOMM client connections");
492
493         for (client = rfcomm_clients; client; ) {
494                 rfcomm_cb_data_t *info = client->data;
495
496                 for (conn = info->rfcomm_conns; conn; conn = conn->next) {
497                         rfcomm_conn_info_t *conn_info = conn->data;
498
499                         if (conn_info == NULL)
500                                 continue;
501
502                         if (conn_info->watch_id == 0 || conn_info->disconnected)
503                                 continue;
504
505                         close(conn_info->fd);
506                         conn_info->disconnected = TRUE;
507
508                         _bt_disconnect_ext_profile(conn_info->bt_addr,
509                                                    info->obj_path);
510                 }
511
512                 client = client->next;
513                 __rfcomm_client_disconnect(info);
514         }
515
516         return;
517 }
518
519 void _bt_rfcomm_client_reset_timer(void)
520 {
521         if (rx_tag > 0) {
522                 rx_tag = 0;
523                 g_source_remove(rx_tag);
524         }
525
526         if (tx_tag > 0) {
527                 g_source_remove(tx_tag);
528                 tx_tag = 0;
529         }
530
531         rx_data = 0;
532         tx_data = 0;
533 }
534
535 int new_connection(const char *path, int fd, bluetooth_device_address_t *addr)
536 {
537         rfcomm_cb_data_t *info;
538         GIOChannel *data_io;
539         rfcomm_conn_info_t *conn_info = NULL;
540         char address[BT_ADDRESS_STRING_SIZE];
541
542         BT_INFO("%s %d", path, fd);
543
544         _bt_convert_addr_type_to_string(address,
545                                 (unsigned char *)addr);
546
547         info = __find_rfcomm_info_from_path(path);
548         if (info == NULL) {
549                 BT_ERR("rfcomm info is NULL");
550                 return -1;
551         }
552
553         conn_info = __get_conn_info_from_address(info, address);
554         if (conn_info == NULL) {
555                 BT_ERR("connection info is NULL");
556                 return -1;
557         }
558
559         conn_info->fd = fd;
560
561         data_io = g_io_channel_unix_new(fd);
562
563         g_io_channel_set_encoding(data_io, NULL, NULL);
564         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
565
566         conn_info->watch_id = g_io_add_watch(data_io,
567                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
568                                 __client_data_received_cb, info);
569
570         g_io_channel_unref(data_io);
571
572         __client_connected_cb(info, address, BLUETOOTH_ERROR_NONE);
573
574         return 0;
575 }
576
577 static void __bt_connect_response_cb(GDBusProxy *proxy, GAsyncResult *res,
578                                                         gpointer user_data)
579
580 {
581         GError *error = NULL;
582         GVariant *value;
583         rfcomm_cb_data_t *cb_data;
584         char dev_address[BT_ADDRESS_STRING_SIZE];
585         const char *path;
586         BT_DBG("+");
587
588         ret_if(user_data == NULL);
589
590         cb_data = user_data;
591
592         value = g_dbus_proxy_call_finish(proxy, res, &error);
593         if (value == NULL) {
594                 int result;
595                 g_dbus_error_strip_remote_error(error);
596                 BT_ERR("Error : %s \n", error->message);
597
598                 if (g_strcmp0(error->message, "In Progress") == 0)
599                         result = BLUETOOTH_ERROR_DEVICE_BUSY;
600                 else
601                         result = BLUETOOTH_ERROR_INTERNAL;
602                 path = g_dbus_proxy_get_object_path(proxy);
603                 _bt_convert_device_path_to_address(path, dev_address);
604                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
605
606                 g_error_free(error);
607         } else {
608                 g_variant_unref(value);
609         }
610
611         if (proxy)
612                 g_object_unref(proxy);
613
614         BT_DBG("-");
615 }
616
617 static void __bt_discover_service_response_cb(GDBusProxy *proxy,
618                                 GAsyncResult *res, gpointer user_data)
619 {
620         rfcomm_cb_data_t *cb_data;
621         int ret = 0;
622         GError *err = NULL;
623         GVariant *value;
624         bt_register_profile_info_t info = {0};
625         int result = BLUETOOTH_ERROR_NONE;
626         char dev_address[BT_ADDRESS_STRING_SIZE];
627         const char *path;
628
629         BT_DBG("+");
630
631         ret_if(user_data == NULL);
632
633         cb_data = user_data;
634
635         path = g_dbus_proxy_get_object_path(proxy);
636
637         _bt_convert_device_path_to_address(path, dev_address);
638         BT_DBG("Device Adress [%s]", dev_address);
639         value = g_dbus_proxy_call_finish(proxy, res, &err);
640         if (proxy)
641                 g_object_unref(proxy);
642         if (value)
643                 g_variant_unref(value);
644
645         if (err != NULL) {
646                 g_dbus_error_strip_remote_error(err);
647                 BT_ERR("Error occured in Proxy call [%s]\n", err->message);
648                 if (!strcmp("Operation canceled", err->message)) {
649                         result = BLUETOOTH_ERROR_CANCEL_BY_USER;
650                 } else if (!strcmp("In Progress", err->message)) {
651                         result = BLUETOOTH_ERROR_IN_PROGRESS;
652                 } else if (!strcmp("Host is down", err->message)) {
653                         result = BLUETOOTH_ERROR_HOST_DOWN;
654                 } else if (!strcmp(BT_TIMEOUT_MESSAGE, err->message)) {
655                         result = BLUETOOTH_ERROR_SERVICE_SEARCH_ERROR;
656                         ret = _bt_cancel_discovers(dev_address);
657                         if (ret != BLUETOOTH_ERROR_NONE)
658                                 BT_ERR("Error: While CancelDiscovery");
659                 } else {
660                         result = BLUETOOTH_ERROR_CONNECTION_ERROR;
661                 }
662                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
663                 goto done;
664         } else {
665                 BT_INFO("Services are Updated checking required uuid is there");
666                 /* Check here for uuid present */
667                 ret = _bt_discover_service_uuids(dev_address, (char *)cb_data->uuid);
668                 if (ret == BLUETOOTH_ERROR_NONE) {
669                         info.uuid = (char *)cb_data->uuid;
670                         info.obj_path = cb_data->obj_path;
671                         info.role = "client";
672
673                         ret = _bt_register_profile(&info, FALSE);
674                         if (ret < 0)
675                                 BT_DBG("Error: register profile");
676                         ret = _bt_connect_profile(dev_address, cb_data->uuid,
677                                                 __bt_connect_response_cb, cb_data);
678
679                         if (ret != BLUETOOTH_ERROR_NONE) {
680                                 BT_ERR("ConnectProfile failed");
681                                 result = BLUETOOTH_ERROR_CONNECTION_ERROR;
682                                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
683                                 goto done;
684                         }
685                 } else {
686                         BT_ERR("remote uuid not found");
687                         result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND;
688                         __rfcomm_client_connected_cb(cb_data, dev_address, result);
689                 }
690         }
691 done:
692         if (err)
693                 g_clear_error(&err);
694 }
695 #else
696 GSList *rfcomm_clients;
697
698 typedef struct {
699         char *uuid;
700         char *remote_addr;
701         int sock_fd;
702         int watch_id;
703 } rfcomm_client_conn_info_t;
704
705 static gboolean __is_error_by_disconnect(GError *err)
706 {
707         return !g_strcmp0(err->message, "Connection reset by peer") ||
708                 !g_strcmp0(err->message, "Connection timed out") ||
709                 !g_strcmp0(err->message, "Software caused connection abort");
710 }
711
712 static rfcomm_client_conn_info_t *__find_rfcomm_conn_info_with_fd(int fd)
713 {
714         GSList *l;
715
716         BT_DBG("+");
717
718         for (l = rfcomm_clients; l != NULL; l = l->next) {
719                 rfcomm_client_conn_info_t *info = l->data;
720
721                 if (info && info->sock_fd == fd) {
722                         BT_INFO("Match found");
723                         return info;
724                 }
725         }
726
727         BT_DBG("-");
728         return NULL;
729 }
730
731 static void __rfcomm_remove_client_conn_info_t(rfcomm_client_conn_info_t *info)
732 {
733         ret_if(info == NULL);
734
735         rfcomm_clients = g_slist_remove(rfcomm_clients, info);
736         g_free(info->uuid);
737         g_free(info->remote_addr);
738 }
739
740 static void __bt_rfcomm_client_disconnected(rfcomm_client_conn_info_t *conn_info)
741 {
742
743         bluetooth_rfcomm_disconnection_t disconn_info;
744         bt_event_info_t *event_info = NULL;
745
746         ret_if(conn_info == NULL);
747
748         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
749         ret_if(event_info == NULL);
750
751         memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t));
752         disconn_info.device_role = RFCOMM_ROLE_CLIENT;
753         disconn_info.socket_fd = conn_info->sock_fd;
754         g_strlcpy(disconn_info.uuid, conn_info->uuid, BLUETOOTH_UUID_STRING_MAX);
755         _bt_convert_addr_string_to_type(disconn_info.device_addr.addr,
756                         conn_info->remote_addr);
757
758         BT_DBG("Disconnection Result[%d] BT_ADDRESS[%s] UUID[%s] FD[%d]",
759                         BLUETOOTH_ERROR_NONE, conn_info->remote_addr,
760                         conn_info->uuid, conn_info->sock_fd);
761         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED,
762                         BLUETOOTH_ERROR_NONE, &disconn_info,
763                         event_info->cb, event_info->user_data);
764
765         BT_DBG("-");
766 }
767
768 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
769 {
770         bt_event_info_t *event_info;
771         bluetooth_rfcomm_received_data_t data_r;
772         rfcomm_client_conn_info_t *conn_info;
773
774         int fd;
775         gsize len = 0;
776         char *buffer;
777         GError *err = NULL;
778         GIOStatus status = G_IO_STATUS_NORMAL;
779
780         BT_DBG("+");
781
782         fd = g_io_channel_unix_get_fd(chan);
783         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
784                 BT_ERR_C("RFComm Client  disconnected: %d", fd);
785                 goto fail;
786         }
787
788         buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
789         status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
790                         &len, &err);
791         if (status != G_IO_STATUS_NORMAL) {
792                 BT_ERR("IO Channel read is failed with %d", status);
793                 g_free(buffer);
794                 if (err) {
795                         BT_ERR("IO Channel read error [%s]", err->message);
796                         if (status == G_IO_STATUS_ERROR &&
797                                         __is_error_by_disconnect(err)) {
798                                 BT_ERR("cond : %d", cond);
799                                 g_error_free(err);
800                                 goto fail;
801                         }
802                         g_error_free(err);
803                 }
804
805                 return TRUE;
806         }
807
808         if (len == 0) {
809                 BT_ERR("Length is zero, remote end hang up");
810                 goto fail;
811         }
812
813         BT_DBG("fd: %d, len: %d, buffer: %s", fd, len, buffer);
814
815         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
816         if (event_info == NULL) {
817                 BT_INFO("event_info == NULL");
818                 g_free(buffer);
819                 return TRUE;
820         }
821
822         data_r.socket_fd = fd;
823         data_r.buffer_size = len;
824         data_r.buffer = buffer;
825
826         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED,
827                         BLUETOOTH_ERROR_NONE, &data_r,
828                         event_info->cb, event_info->user_data);
829
830         g_free(buffer);
831         return TRUE;
832
833 fail:
834         conn_info = __find_rfcomm_conn_info_with_fd(fd);
835         if (conn_info) {
836                 __bt_rfcomm_client_disconnected(conn_info);
837                 __rfcomm_remove_client_conn_info_t(conn_info);
838         } else {
839                 BT_ERR("RFCOMM client conn_info not found");
840         }
841         return FALSE;
842 }
843
844 static void __rfcomm_client_connection_create_watch(rfcomm_client_conn_info_t *conn_info)
845 {
846         GIOChannel *data_io;
847
848         ret_if(NULL == conn_info);
849
850         BT_DBG("+");
851
852         data_io = g_io_channel_unix_new(conn_info->sock_fd);
853         g_io_channel_set_encoding(data_io, NULL, NULL);
854         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
855         conn_info->watch_id = g_io_add_watch(data_io,
856                         G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
857                         __client_data_received_cb, NULL);
858         g_io_channel_unref(data_io);
859
860         BT_DBG("-");
861 }
862
863 static void __bt_rfcomm_handle_new_client_connection(bluetooth_rfcomm_connection_t *info)
864 {
865         rfcomm_client_conn_info_t *conn_info;
866
867         ret_if(NULL == info);
868
869         BT_DBG("+");
870
871         conn_info = g_malloc0(sizeof(rfcomm_client_conn_info_t));
872         conn_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
873         _bt_convert_addr_type_to_string(
874                         conn_info->remote_addr, info->device_addr.addr);
875         conn_info->uuid = g_strdup(info->uuid);
876         conn_info->sock_fd = info->socket_fd;
877
878         BT_DBG("Address:%s, UUID:%s Socket: %d",
879                         conn_info->remote_addr, conn_info->uuid, conn_info->sock_fd);
880
881         rfcomm_clients = g_slist_append(rfcomm_clients, conn_info);
882         __rfcomm_client_connection_create_watch(conn_info);
883
884         BT_DBG("-");
885 }
886
887 static void __bt_fill_garray_from_variant(GVariant *var, GArray *param)
888 {
889         char *data;
890         int size;
891
892         size = g_variant_get_size(var);
893         if (size > 0) {
894                 data = (char *)g_variant_get_data(var);
895                 if (data)
896                         param = g_array_append_vals(param, data, size);
897
898         }
899 }
900
901
902 /* TODO_40 : 4.0 merge  */
903 /* Don't use this function directly. Instead of it, get the out parameter only */
904 static void __bt_get_event_info(int service_function, GArray *output,
905                         int *event, int *event_type, void **param_data)
906 {
907         ret_if(event == NULL);
908
909         BT_DBG("service_function : %s (0x%x)",
910                 _bt_convert_service_function_to_string(service_function),
911                 service_function);
912         switch (service_function) {
913         case BT_RFCOMM_CLIENT_CONNECT:
914                 *event_type = BT_RFCOMM_CLIENT_EVENT;
915                 *event = BLUETOOTH_EVENT_RFCOMM_CONNECTED;
916                 ret_if(output == NULL);
917                 *param_data = &g_array_index(output,
918                                 bluetooth_rfcomm_connection_t, 0);
919                 break;
920         default:
921                 BT_ERR("Unknown function");
922                 return;
923         }
924 }
925
926
927 static void __async_req_cb_with_unix_fd_list(GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
928 {
929         int result = BLUETOOTH_ERROR_NONE;
930         int event_type = BT_ADAPTER_EVENT;
931         bt_req_info_t *cb_data = user_data;
932         bluetooth_event_param_t bt_event;
933
934         GError *error = NULL;
935         GVariant *value;
936         GVariant *param1;
937         GArray *out_param1 = NULL;
938         GUnixFDList *out_fd_list = NULL;
939
940         BT_DBG("+");
941
942         memset(&bt_event, 0x00, sizeof(bluetooth_event_param_t));
943
944         value = g_dbus_proxy_call_with_unix_fd_list_finish(proxy, &out_fd_list, res, &error);
945         if (value == NULL) {
946                 if (error) {
947                         /* dBUS gives error cause */
948                         BT_ERR("D-Bus API failure: message[%s]",
949                                         error->message);
950                         g_clear_error(&error);
951                 }
952                 result = BLUETOOTH_ERROR_TIMEOUT;
953
954                 ret_if(cb_data == NULL);
955
956                 __bt_get_event_info(cb_data->service_function, NULL,
957                                 &bt_event.event, &event_type,
958                                 &bt_event.param_data);
959                 goto failed;
960         }
961
962         g_variant_get(value, "(iv)", &result, &param1);
963         g_variant_unref(value);
964
965         if (param1) {
966                 out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
967                 __bt_fill_garray_from_variant(param1, out_param1);
968                 g_variant_unref(param1);
969         }
970
971         if (!cb_data)
972                 goto done;
973
974         __bt_get_event_info(cb_data->service_function, out_param1,
975                         &bt_event.event, &event_type,
976                         &bt_event.param_data);
977
978         if (result == BLUETOOTH_ERROR_NONE && out_param1) {
979                 if (BT_RFCOMM_CLIENT_CONNECT == cb_data->service_function) {
980                         int *fd_list_array;
981                         int len = 0;
982                         bluetooth_rfcomm_connection_t *conn_info;
983
984                         conn_info = (bluetooth_rfcomm_connection_t *)bt_event.param_data;
985                         if (!out_fd_list) {
986                                 BT_ERR("out_fd_list is NULL");
987                                 goto failed;
988                         }
989
990                         fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
991                         BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
992                         conn_info->socket_fd = fd_list_array[0];
993
994                         BT_DBG("conn_info->socket_fd: %d", conn_info->socket_fd);
995                         __bt_rfcomm_handle_new_client_connection(conn_info);
996
997                         if (cb_data->cb != NULL) {
998                                 /* Send client connected event */
999                                 bt_event.result = result;
1000                                 BT_INFO("event_type[%d], result=[%d]", event_type, result);
1001                                 ((bluetooth_cb_func_ptr)cb_data->cb)(
1002                                         bt_event.event, &bt_event, cb_data->user_data);
1003                         }
1004
1005                         g_free(fd_list_array);
1006                         g_object_unref(out_fd_list);
1007                 }
1008                 goto done;
1009         }
1010
1011 failed:
1012         if (cb_data->cb == NULL)
1013                 goto done;
1014
1015         /* Only if fail case, call the callback function*/
1016         bt_event.result = result;
1017
1018         BT_INFO("event_type[%d], result=[%d]", event_type, result);
1019         if (event_type == BT_RFCOMM_CLIENT_EVENT) {
1020                 ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
1021                         &bt_event, cb_data->user_data);
1022         } else {
1023                 BT_INFO("Not handled event type : %d", event_type);
1024         }
1025 done:
1026         if (out_param1)
1027                 g_array_free(out_param1, TRUE);
1028
1029         g_free(cb_data);
1030         BT_DBG("-");
1031 }
1032 #endif
1033
1034 BT_EXPORT_API int bluetooth_rfcomm_connect(
1035                 const bluetooth_device_address_t *remote_bt_address,
1036                 const char *remote_uuid)
1037 {
1038
1039 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1040         rfcomm_cb_data_t *cb_data = NULL;
1041         rfcomm_conn_info_t *conn = NULL;
1042 #else
1043         int result;
1044         int connect_type;
1045         bt_user_info_t *user_info;
1046         char uuid[BLUETOOTH_UUID_STRING_MAX];
1047 #endif
1048         BT_CHECK_PARAMETER(remote_bt_address, return);
1049         BT_CHECK_PARAMETER(remote_uuid, return);
1050         BT_CHECK_ENABLED(return);
1051
1052 #ifdef TIZEN_FEATURE_BT_DPM
1053         if (_bt_check_dpm(BT_DPM_ADDRESS, (void *)remote_bt_address) == BT_DPM_RESTRICTED) {
1054                 BT_ERR("Blacklist device");
1055                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1056         }
1057
1058         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED ||
1059                 _bt_check_dpm(BT_DPM_HF_ONLY, NULL) == BT_DPM_RESTRICTED) {
1060                 BT_ERR("Not allow to connect the RFCOMM service");
1061                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1062         }
1063
1064         if (_bt_check_dpm(BT_DPM_DESKTOP, NULL) == BT_DPM_RESTRICTED) {
1065                 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1066                 bluetooth_device_class_t dev_class;
1067
1068                 _bt_convert_addr_type_to_string(address, (unsigned char *)remote_bt_address->addr);
1069                 _bt_get_cod_by_address(address, &dev_class);
1070
1071                 if (dev_class.major_class == BLUETOOTH_DEVICE_MAJOR_CLASS_COMPUTER) {
1072                         BT_ERR("Reject a authorization due to MDM Policy");
1073                         return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1074                 }
1075         }
1076 #endif
1077
1078 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1079         BT_INFO_C("### Connect RFCOMM");
1080         int ret;
1081         int id, object_id;
1082         char *path;
1083
1084         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CLIENT_CONNECT)
1085              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1086                 BT_ERR("Don't have a privilege to use this API");
1087                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1088         }
1089
1090         id = __rfcomm_assign_id();
1091         if (id < 0)
1092                 return BLUETOOTH_ERROR_INTERNAL;
1093
1094         cb_data = __find_rfcomm_info_from_uuid(remote_uuid);
1095         if (!cb_data) {
1096                 path = g_strdup_printf("/org/socket/client/%d/%d", getpid(), id);
1097
1098                 object_id = _bt_register_new_conn(path, new_connection);
1099                 if (object_id < 0) {
1100                         __rfcomm_delete_id(id);
1101                         g_free(path);
1102                         return BLUETOOTH_ERROR_INTERNAL;
1103                 }
1104
1105                 cb_data = g_new0(rfcomm_cb_data_t, 1);
1106                 g_strlcpy(cb_data->uuid, remote_uuid, BLUETOOTH_UUID_STRING_MAX);
1107                 cb_data->obj_path = path;
1108                 cb_data->object_id = object_id;
1109                 cb_data->id = id;
1110         }
1111
1112         conn = g_new0(rfcomm_conn_info_t, 1);
1113         conn->fd = -1;
1114         _bt_convert_addr_type_to_string(conn->bt_addr,
1115                                 (unsigned char *)remote_bt_address->addr);
1116
1117         BT_DBG("Connecting to %s uuid %s", conn->bt_addr, remote_uuid);
1118         cb_data->rfcomm_conns = g_slist_append(cb_data->rfcomm_conns, conn);
1119
1120         ret = _bt_discover_services(conn->bt_addr, (char *)remote_uuid,
1121                                 __bt_discover_service_response_cb, cb_data);
1122         if (ret != BLUETOOTH_ERROR_NONE) {
1123                 BT_ERR("Error returned while service discovery");
1124                 __rfcomm_remove_conn_info_t(cb_data, conn->bt_addr);
1125                 if (cb_data->rfcomm_conns == NULL)
1126                         rfcomm_cb_data_remove(cb_data);
1127                 return BLUETOOTH_ERROR_INTERNAL;
1128         }
1129
1130         if (g_slist_find(rfcomm_clients, cb_data) == NULL) {
1131                 BT_INFO("Adding callback information to rfcomm_clients");
1132                 rfcomm_clients = g_slist_append(rfcomm_clients, cb_data);
1133         } else
1134                 BT_INFO("Callback information is already added");
1135
1136         return BLUETOOTH_ERROR_NONE;
1137 #else
1138         user_info = _bt_get_user_data(BT_COMMON);
1139         retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
1140
1141         /* connect_type:  BT_RFCOMM_UUID / BT_RFCOMM_CHANNEL*/
1142         /* In now, we only support to connecty using UUID */
1143         connect_type = BT_RFCOMM_UUID;
1144
1145         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CLIENT_CONNECT)
1146              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1147                 BT_ERR("Don't have a privilege to use this API");
1148                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1149         }
1150
1151         BT_INIT_PARAMS();
1152         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1153
1154         g_array_append_vals(in_param1, remote_bt_address,
1155                                 sizeof(bluetooth_device_address_t));
1156
1157         g_strlcpy(uuid, remote_uuid, sizeof(uuid));
1158         g_array_append_vals(in_param2, uuid, BLUETOOTH_UUID_STRING_MAX);
1159
1160         g_array_append_vals(in_param3, &connect_type, sizeof(int));
1161
1162         result = _bt_send_request_async_with_unix_fd_list(BT_BLUEZ_SERVICE,
1163                                 BT_RFCOMM_CLIENT_CONNECT,
1164                                 in_param1, in_param2,
1165                                 in_param3, in_param4,
1166                                 user_info->cb, user_info->user_data,
1167                                 NULL, (GAsyncReadyCallback)__async_req_cb_with_unix_fd_list);
1168
1169         BT_DBG("result: %x", result);
1170
1171         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1172
1173         return result;
1174 #endif
1175 }
1176
1177 BT_EXPORT_API int bluetooth_rfcomm_client_is_connected(const bluetooth_device_address_t *device_address, gboolean *connected)
1178 {
1179 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1180         GSList *l;
1181         GSList *conn_list = NULL;
1182         rfcomm_cb_data_t *client_info;
1183         rfcomm_conn_info_t *conn_info;
1184         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1185
1186         BT_CHECK_PARAMETER(device_address, return);
1187         BT_CHECK_PARAMETER(connected, return);
1188
1189         _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
1190         *connected = FALSE;
1191
1192         for (l = rfcomm_clients; l != NULL; l = l->next) {
1193                 client_info = l->data;
1194                 if (client_info == NULL)
1195                         continue;
1196                 for (conn_list = client_info->rfcomm_conns;
1197                         conn_list != NULL; conn_list = conn_list->next) {
1198                         conn_info = conn_list->data;
1199                         if (conn_info == NULL)
1200                                 continue;
1201
1202                         if (g_strcmp0(address, conn_info->bt_addr) == 0) {
1203                                 *connected = TRUE;
1204                                 return BLUETOOTH_ERROR_NONE;
1205                         }
1206                 }
1207         }
1208
1209         return BLUETOOTH_ERROR_NONE;
1210 #else
1211         GSList *l;
1212         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1213
1214         BT_CHECK_PARAMETER(device_address, return);
1215         BT_CHECK_PARAMETER(connected, return);
1216
1217         BT_DBG("+");
1218
1219         *connected = FALSE;
1220         _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
1221         BT_INFO("Client address: [%s]", address);
1222
1223         for (l = rfcomm_clients; l != NULL; l = l->next) {
1224                 rfcomm_client_conn_info_t *info = l->data;
1225
1226                 if (info && !strncasecmp(info->remote_addr, address, BT_ADDRESS_STRING_SIZE)) {
1227                         BT_INFO("Match found");
1228                         *connected = TRUE;
1229                         return BLUETOOTH_ERROR_NONE;
1230                 }
1231         }
1232
1233         BT_DBG("-");
1234         return BLUETOOTH_ERROR_NONE;
1235 #endif
1236 }
1237
1238 BT_EXPORT_API gboolean bluetooth_rfcomm_is_client_connected(void)
1239 {
1240         int result;
1241         int connected = FALSE;
1242
1243         BT_CHECK_ENABLED(return);
1244
1245         BT_INIT_PARAMS();
1246         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1247
1248         result = _bt_send_request(BT_BLUEZ_SERVICE,
1249                         BT_RFCOMM_CLIENT_IS_CONNECTED,
1250                         in_param1, in_param2, in_param3,
1251                         in_param4, &out_param);
1252
1253         BT_DBG("result: %x", result);
1254
1255         if (result == BLUETOOTH_ERROR_NONE) {
1256                 connected = g_array_index(out_param,
1257                                 int, 0);
1258         } else {
1259                 BT_ERR("Fail to send request");
1260         }
1261
1262         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1263
1264         return connected;
1265 }
1266
1267 BT_EXPORT_API int bluetooth_rfcomm_disconnect(int socket_fd)
1268 {
1269 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1270         rfcomm_cb_data_t *info;
1271         rfcomm_conn_info_t *conn_info;
1272
1273         BT_INFO_C("### Disconnect RFCOMM");
1274
1275         BT_CHECK_ENABLED(return);
1276
1277         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_DISCONNECT)
1278              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1279                 BT_ERR("Don't have a privilege to use this API");
1280                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1281         }
1282
1283         BT_DBG("Requested FD %d", socket_fd);
1284         if (socket_fd < 0) {
1285                 BT_ERR("Invalid FD");
1286                 return BLUETOOTH_ERROR_INVALID_PARAM;
1287         }
1288         BT_DBG("FDD %d", socket_fd);
1289
1290         info = __find_rfcomm_info_with_fd(socket_fd);
1291         if (info == NULL) {
1292                 BT_DBG("Could not find in client, so check in server");
1293                 return bluetooth_rfcomm_server_disconnect(socket_fd);
1294         }
1295
1296         conn_info = __get_conn_info_from_fd(info, socket_fd);
1297         if (conn_info == NULL) {
1298                 BT_ERR("Could not find connection info");
1299                 return BLUETOOTH_ERROR_INTERNAL;
1300         }
1301
1302         if (conn_info->watch_id == 0 || conn_info->disconnected) {
1303                 BT_ERR("Invalid state");
1304                 return BLUETOOTH_ERROR_NOT_CONNECTED;
1305         }
1306
1307         close(conn_info->fd);
1308         conn_info->disconnected = TRUE;
1309
1310         BT_INFO("conn_info %s", conn_info->bt_addr);
1311         _bt_disconnect_ext_profile(conn_info->bt_addr, info->obj_path);
1312
1313         if (info->idle_id == 0)
1314                 info->idle_id = g_idle_add(__rfcomm_client_disconnect, info);
1315
1316         return BLUETOOTH_ERROR_NONE;
1317 #else
1318         rfcomm_client_conn_info_t *conn_info;
1319
1320         BT_INFO_C("<<<<<<<<< RFCOMM Disconnect request from app >>>>>>>>");
1321
1322         BT_CHECK_ENABLED(return);
1323         retv_if(socket_fd < 0, BLUETOOTH_ERROR_INVALID_PARAM);
1324
1325         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_DISCONNECT)
1326                         == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1327                 BT_ERR("Don't have a privilege to use this API");
1328                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1329         }
1330
1331         BT_DBG("FD %d", socket_fd);
1332
1333         conn_info = __find_rfcomm_conn_info_with_fd(socket_fd);
1334         if (conn_info == NULL) {
1335                 BT_DBG("Could not find in client, so check in server");
1336                 /* Check for fd in server list and perform the disconnection if present */
1337                 return bluetooth_rfcomm_server_disconnect(socket_fd);
1338         }
1339
1340         if (conn_info->watch_id <= 0) {
1341                 BT_ERR("Invalid state");
1342                 return BLUETOOTH_ERROR_NOT_CONNECTED;
1343         }
1344
1345         /*
1346          * Just close socket here and return. Socket close will be detected via I/O watch
1347          * and disconnection event as well as info cleanup will be performed there.
1348          */
1349         close(conn_info->sock_fd);
1350
1351         return BLUETOOTH_ERROR_NONE;
1352 #endif
1353 }
1354
1355 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1356 #else
1357 static int __write_all(int fd, const char *buf, int len)
1358 {
1359         int sent = 0, try = 0;
1360
1361         BT_DBG("+");
1362         while (len > 0) {
1363                 int written;
1364
1365                 written = write(fd, buf, len);
1366                 BT_DBG("written: %d", written);
1367                 if (written < 0) {
1368                         if (errno == EINTR || errno == EAGAIN) {
1369                                 try++;
1370                                 if (try <= 49)
1371                                         continue;
1372                         }
1373                         return -1;
1374                 }
1375
1376                 if (!written)
1377                         return 0;
1378
1379                 len -= written;
1380                 buf += written;
1381                 sent += written;
1382                 try = 0;
1383         }
1384
1385         BT_DBG("-");
1386         return sent;
1387 }
1388 #endif
1389
1390 BT_EXPORT_API int bluetooth_rfcomm_write(int fd, const char *buf, int length)
1391 {
1392 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1393         int written;
1394 #endif
1395         int result;
1396
1397 #ifndef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1398         BT_CHECK_ENABLED(return);
1399 #endif
1400         BT_CHECK_PARAMETER(buf, return);
1401         if (fd < 0) {
1402                 BT_ERR("Invalid FD");
1403                 return BLUETOOTH_ERROR_INVALID_PARAM;
1404         }
1405
1406         retv_if(length <= 0, BLUETOOTH_ERROR_INVALID_PARAM);
1407
1408         switch (privilege_token) {
1409         case 0:
1410                 result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_WRITE);
1411
1412                 if (result == BLUETOOTH_ERROR_NONE) {
1413                         privilege_token = 1; /* Have a permission */
1414                 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1415                         BT_ERR("Don't have a privilege to use this API");
1416                         privilege_token = -1; /* Don't have a permission */
1417                         return BLUETOOTH_ERROR_PERMISSION_DEINED;
1418                 } else {
1419                         /* Just break - It is not related with permission error */
1420                 }
1421                 break;
1422         case 1:
1423                 /* Already have a privilege */
1424                 break;
1425         case -1:
1426                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1427         default:
1428                 /* Invalid privilge token value */
1429                 return BLUETOOTH_ERROR_INTERNAL;
1430         }
1431
1432 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1433         written = write(fd, buf, length);
1434         /*BT_DBG("Length %d, written = %d, balance(%d)",
1435                         length, written, length - written); */
1436         if (written > 0 && bluetooth_get_battery_monitor_state()) {
1437                 if (tx_tag == 0) {
1438                         BT_INFO("Adding rfcomm tx timeout function for battery monitor");
1439                         tx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_tx_data, NULL);
1440                 }
1441                 tx_data += length;
1442         }
1443         return written;
1444 #else
1445         result = __write_all(fd, buf, length);
1446         if (result > 0 && bluetooth_get_battery_monitor_state()) {
1447                 if (tx_tag == 0) {
1448                         BT_INFO("Adding rfcomm tx timeout function for battery monitor");
1449                         tx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_tx_data, NULL);
1450                 }
1451                 tx_data += length;
1452         }
1453         return result;
1454 #endif
1455 }