Fix the svace issue - DEREF_AFTER_NULL
[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         if (_bt_common_send_rfcomm_conn_info(RFCOMM_ROLE_CLIENT,
324                         FALSE, disconn_info.socket_fd) != BLUETOOTH_ERROR_NONE)
325                 BT_ERR("Fail to send the connection info");
326
327         BT_DBG("-");
328 }
329
330 static gboolean __rfcomm_client_disconnect(gpointer user_data)
331 {
332         rfcomm_cb_data_t *info = (rfcomm_cb_data_t *)user_data;
333
334         BT_INFO_C("### Disconnected [RFCOMM Client]");
335
336         retv_if(info == NULL, FALSE);
337
338         if (g_slist_find(rfcomm_clients, info) == NULL) {
339                 BT_INFO("rfcomm resource is already freed");
340                 return FALSE;
341         }
342         info->idle_id = 0;
343
344         g_slist_foreach(info->rfcomm_conns,
345                 (GFunc)_bt_rfcomm_disconnect_conn_info, info);
346
347         BT_DBG("-");
348         return FALSE;
349 }
350
351 static gboolean __is_error_by_disconnect(GError *err)
352 {
353         return !g_strcmp0(err->message, "Connection reset by peer") ||
354                         !g_strcmp0(err->message, "Connection timed out") ||
355                         !g_strcmp0(err->message, "Software caused connection abort");
356 }
357
358 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond,
359                                                                 gpointer data)
360 {
361         char *buffer = NULL;
362         gsize len = 0;
363         int result = BLUETOOTH_ERROR_NONE;
364         rfcomm_cb_data_t *info = data;
365         rfcomm_conn_info_t *conn_info = NULL;
366         bt_event_info_t *event_info;
367         bluetooth_rfcomm_received_data_t data_r;
368         GIOStatus status = G_IO_STATUS_NORMAL;
369         GError *err = NULL;
370         int fd;
371
372         retv_if(info == NULL, FALSE);
373         fd = g_io_channel_unix_get_fd(chan);
374         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
375                 BT_ERR_C("RFComm Client  disconnected: %d", fd);
376
377                 conn_info = __get_conn_info_from_fd(info, fd);
378                 if (conn_info == NULL) {
379                         BT_ERR("No Connection info found with FD [%d]", fd);
380                         return FALSE;
381                 }
382
383                 if (conn_info->disconnected == FALSE) {
384                         close(conn_info->fd);
385                         conn_info->disconnected = TRUE;
386                 }
387                 __rfcomm_client_disconnect(info);
388                 return FALSE;
389         }
390
391         buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
392
393         status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
394                         &len, &err);
395         if (status != G_IO_STATUS_NORMAL) {
396                 BT_ERR("IO Channel read is failed with %d", status);
397
398                 g_free(buffer);
399                 if (err || status == G_IO_STATUS_EOF) {
400                         if (err)
401                                 BT_ERR("IO Channel read error [%s]", err->message);
402                         if ((status == G_IO_STATUS_EOF) ||
403                                         (status == G_IO_STATUS_ERROR &&
404                                         __is_error_by_disconnect(err))) {
405
406                                 BT_ERR("cond : %d", cond);
407                                 if (err)
408                                         g_error_free(err);
409
410                                 conn_info = __get_conn_info_from_fd(info, fd);
411                                 if (conn_info == NULL) {
412                                         BT_ERR("No Connection info found with FD [%d]", fd);
413                                         return FALSE;
414                                 }
415
416                                 if (conn_info->disconnected == FALSE) {
417                                         close(conn_info->fd);
418                                         conn_info->disconnected = TRUE;
419                                 }
420                                 __rfcomm_client_disconnect(info);
421                                 return FALSE;
422                         }
423                         if (err)
424                                 g_error_free(err);
425                 }
426                 return TRUE;
427         }
428
429         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
430         if (event_info == NULL) {
431                 g_free(buffer);
432                 return TRUE;
433         }
434
435         data_r.socket_fd = fd;
436         data_r.buffer_size = len;
437         data_r.buffer = buffer;
438
439         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED,
440                         result, &data_r,
441                         event_info->cb, event_info->user_data);
442
443         if (bluetooth_get_battery_monitor_state()) {
444                 if (rx_tag == 0) {
445                         BT_INFO("Adding rfcomm rx timeout function for battery monitor");
446                         rx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_rx_data, NULL);
447                 }
448                 rx_data += len;
449         }
450
451         g_free(buffer);
452         return TRUE;
453 }
454
455 static void __client_connected_cb(rfcomm_cb_data_t *cb_data, char *dev_address,
456         int result)
457 {
458         bluetooth_rfcomm_connection_t conn_info;
459         bt_event_info_t *event_info;
460         rfcomm_conn_info_t *conn_list_info = NULL;
461
462         if (result == BLUETOOTH_ERROR_NONE)
463                 BT_INFO_C("### Connected [RFCOMM Client]");
464
465         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
466         if (event_info == NULL)
467                 return;
468
469         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
470         conn_info.device_role = RFCOMM_ROLE_CLIENT;
471         g_strlcpy(conn_info.uuid, cb_data->uuid, BLUETOOTH_UUID_STRING_MAX);
472         _bt_convert_addr_string_to_type(conn_info.device_addr.addr,
473                         dev_address);
474         conn_list_info = __get_conn_info_from_address(cb_data, dev_address);
475         if (conn_list_info == NULL) {
476                 BT_ERR("Device addres %s not found in connection list", dev_address);
477                 return;
478         }
479         conn_info.socket_fd = conn_list_info->fd;
480         conn_info.server_id = -1;
481
482         if (_bt_common_send_rfcomm_conn_info(RFCOMM_ROLE_CLIENT,
483                         TRUE, conn_info.socket_fd) != BLUETOOTH_ERROR_NONE)
484                 BT_ERR("Fail to send the connection info");
485
486         BT_DBG("Connection Result[%d] BT_ADDRESS[%s] UUID[%s] FD[%d]",
487                         result, conn_list_info->bt_addr, cb_data->uuid, conn_list_info->fd);
488         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_CONNECTED,
489                         result, &conn_info,
490                         event_info->cb, event_info->user_data);
491         BT_DBG("-");
492 }
493
494 void _bt_rfcomm_client_disconnect_all(void)
495 {
496         GSList *client;
497         GSList *conn;
498
499         BT_INFO_C("### Disconnect all RFCOMM client connections");
500
501         for (client = rfcomm_clients; client; ) {
502                 rfcomm_cb_data_t *info = client->data;
503
504                 for (conn = info->rfcomm_conns; conn; conn = conn->next) {
505                         rfcomm_conn_info_t *conn_info = conn->data;
506
507                         if (conn_info == NULL)
508                                 continue;
509
510                         if (conn_info->watch_id == 0 || conn_info->disconnected)
511                                 continue;
512
513                         close(conn_info->fd);
514                         conn_info->disconnected = TRUE;
515
516                         _bt_disconnect_ext_profile(conn_info->bt_addr,
517                                                    info->obj_path);
518                 }
519
520                 client = client->next;
521                 __rfcomm_client_disconnect(info);
522         }
523
524         return;
525 }
526
527 void _bt_rfcomm_client_reset_timer(void)
528 {
529         if (rx_tag > 0) {
530                 rx_tag = 0;
531                 g_source_remove(rx_tag);
532         }
533
534         if (tx_tag > 0) {
535                 g_source_remove(tx_tag);
536                 tx_tag = 0;
537         }
538
539         rx_data = 0;
540         tx_data = 0;
541 }
542
543 int new_connection(const char *path, int fd, bluetooth_device_address_t *addr)
544 {
545         rfcomm_cb_data_t *info;
546         GIOChannel *data_io;
547         rfcomm_conn_info_t *conn_info = NULL;
548         char address[BT_ADDRESS_STRING_SIZE];
549
550         BT_INFO("%s %d", path, fd);
551
552         _bt_convert_addr_type_to_string(address,
553                                 (unsigned char *)addr);
554
555         info = __find_rfcomm_info_from_path(path);
556         if (info == NULL) {
557                 BT_ERR("rfcomm info is NULL");
558                 return -1;
559         }
560
561         conn_info = __get_conn_info_from_address(info, address);
562         if (conn_info == NULL) {
563                 BT_ERR("connection info is NULL");
564                 return -1;
565         }
566
567         conn_info->fd = fd;
568
569         data_io = g_io_channel_unix_new(fd);
570
571         g_io_channel_set_encoding(data_io, NULL, NULL);
572         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
573
574         conn_info->watch_id = g_io_add_watch(data_io,
575                                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
576                                 __client_data_received_cb, info);
577
578         g_io_channel_unref(data_io);
579
580         __client_connected_cb(info, address, BLUETOOTH_ERROR_NONE);
581
582         return 0;
583 }
584
585 static void __bt_connect_response_cb(GDBusProxy *proxy, GAsyncResult *res,
586                                                         gpointer user_data)
587
588 {
589         GError *error = NULL;
590         GVariant *value;
591         rfcomm_cb_data_t *cb_data;
592         char dev_address[BT_ADDRESS_STRING_SIZE];
593         const char *path;
594         BT_DBG("+");
595
596         ret_if(user_data == NULL);
597
598         cb_data = user_data;
599
600         value = g_dbus_proxy_call_finish(proxy, res, &error);
601         if (value == NULL) {
602                 int result;
603                 g_dbus_error_strip_remote_error(error);
604                 BT_ERR("Error : %s \n", error->message);
605
606                 if (g_strcmp0(error->message, "In Progress") == 0)
607                         result = BLUETOOTH_ERROR_DEVICE_BUSY;
608                 else
609                         result = BLUETOOTH_ERROR_INTERNAL;
610                 path = g_dbus_proxy_get_object_path(proxy);
611                 _bt_convert_device_path_to_address(path, dev_address);
612                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
613
614                 g_error_free(error);
615         } else {
616                 g_variant_unref(value);
617         }
618
619         if (proxy)
620                 g_object_unref(proxy);
621
622         BT_DBG("-");
623 }
624
625 static void __bt_discover_service_response_cb(GDBusProxy *proxy,
626                                 GAsyncResult *res, gpointer user_data)
627 {
628         rfcomm_cb_data_t *cb_data;
629         int ret = 0;
630         GError *err = NULL;
631         GVariant *value;
632         bt_register_profile_info_t info = {0};
633         int result = BLUETOOTH_ERROR_NONE;
634         char dev_address[BT_ADDRESS_STRING_SIZE];
635         const char *path;
636
637         BT_DBG("+");
638
639         ret_if(user_data == NULL);
640
641         cb_data = user_data;
642
643         path = g_dbus_proxy_get_object_path(proxy);
644
645         _bt_convert_device_path_to_address(path, dev_address);
646         BT_DBG("Device Adress [%s]", dev_address);
647         value = g_dbus_proxy_call_finish(proxy, res, &err);
648         if (proxy)
649                 g_object_unref(proxy);
650         if (value)
651                 g_variant_unref(value);
652
653         if (err != NULL) {
654                 g_dbus_error_strip_remote_error(err);
655                 BT_ERR("Error occured in Proxy call [%s]\n", err->message);
656                 if (!strcmp("Operation canceled", err->message)) {
657                         result = BLUETOOTH_ERROR_CANCEL_BY_USER;
658                 } else if (!strcmp("In Progress", err->message)) {
659                         result = BLUETOOTH_ERROR_IN_PROGRESS;
660                 } else if (!strcmp("Host is down", err->message)) {
661                         result = BLUETOOTH_ERROR_HOST_DOWN;
662                 } else if (!strcmp(BT_TIMEOUT_MESSAGE, err->message)) {
663                         result = BLUETOOTH_ERROR_SERVICE_SEARCH_ERROR;
664                         ret = _bt_cancel_discovers(dev_address);
665                         if (ret != BLUETOOTH_ERROR_NONE)
666                                 BT_ERR("Error: While CancelDiscovery");
667                 } else {
668                         result = BLUETOOTH_ERROR_CONNECTION_ERROR;
669                 }
670                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
671                 goto done;
672         } else {
673                 BT_INFO("Services are Updated checking required uuid is there");
674                 /* Check here for uuid present */
675                 ret = _bt_discover_service_uuids(dev_address, (char *)cb_data->uuid);
676                 if (ret == BLUETOOTH_ERROR_NONE) {
677                         info.uuid = (char *)cb_data->uuid;
678                         info.obj_path = cb_data->obj_path;
679                         info.role = "client";
680
681                         ret = _bt_register_profile(&info, FALSE);
682                         if (ret < 0)
683                                 BT_DBG("Error: register profile");
684                         ret = _bt_connect_profile(dev_address, cb_data->uuid,
685                                                 __bt_connect_response_cb, cb_data);
686
687                         if (ret != BLUETOOTH_ERROR_NONE) {
688                                 BT_ERR("ConnectProfile failed");
689                                 result = BLUETOOTH_ERROR_CONNECTION_ERROR;
690                                 __rfcomm_client_connected_cb(cb_data, dev_address, result);
691                                 goto done;
692                         }
693                 } else {
694                         BT_ERR("remote uuid not found");
695                         result = BLUETOOTH_ERROR_SERVICE_NOT_FOUND;
696                         __rfcomm_client_connected_cb(cb_data, dev_address, result);
697                 }
698         }
699 done:
700         if (err)
701                 g_clear_error(&err);
702 }
703 #else
704 GSList *rfcomm_clients;
705
706 typedef struct {
707         char *uuid;
708         char *remote_addr;
709         int sock_fd;
710         int watch_id;
711 } rfcomm_client_conn_info_t;
712
713 static gboolean __is_error_by_disconnect(GError *err)
714 {
715         return !g_strcmp0(err->message, "Connection reset by peer") ||
716                 !g_strcmp0(err->message, "Connection timed out") ||
717                 !g_strcmp0(err->message, "Software caused connection abort");
718 }
719
720 static rfcomm_client_conn_info_t *__find_rfcomm_conn_info_with_fd(int fd)
721 {
722         GSList *l;
723
724         BT_DBG("+");
725
726         for (l = rfcomm_clients; l != NULL; l = l->next) {
727                 rfcomm_client_conn_info_t *info = l->data;
728
729                 if (info && info->sock_fd == fd) {
730                         BT_INFO("Match found");
731                         return info;
732                 }
733         }
734
735         BT_DBG("-");
736         return NULL;
737 }
738
739 static void __rfcomm_remove_client_conn_info_t(rfcomm_client_conn_info_t *info)
740 {
741         ret_if(info == NULL);
742
743         rfcomm_clients = g_slist_remove(rfcomm_clients, info);
744         g_free(info->uuid);
745         g_free(info->remote_addr);
746 }
747
748 static void __bt_rfcomm_client_disconnected(rfcomm_client_conn_info_t *conn_info)
749 {
750
751         bluetooth_rfcomm_disconnection_t disconn_info;
752         bt_event_info_t *event_info = NULL;
753
754         ret_if(conn_info == NULL);
755
756         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
757         ret_if(event_info == NULL);
758
759         memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t));
760         disconn_info.device_role = RFCOMM_ROLE_CLIENT;
761         disconn_info.socket_fd = conn_info->sock_fd;
762         g_strlcpy(disconn_info.uuid, conn_info->uuid, BLUETOOTH_UUID_STRING_MAX);
763         _bt_convert_addr_string_to_type(disconn_info.device_addr.addr,
764                         conn_info->remote_addr);
765
766         BT_DBG("Disconnection Result[%d] BT_ADDRESS[%s] UUID[%s] FD[%d]",
767                         BLUETOOTH_ERROR_NONE, conn_info->remote_addr,
768                         conn_info->uuid, conn_info->sock_fd);
769         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED,
770                         BLUETOOTH_ERROR_NONE, &disconn_info,
771                         event_info->cb, event_info->user_data);
772
773         BT_DBG("-");
774 }
775
776 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
777 {
778         bt_event_info_t *event_info;
779         bluetooth_rfcomm_received_data_t data_r;
780         rfcomm_client_conn_info_t *conn_info;
781
782         int fd;
783         gsize len = 0;
784         char *buffer;
785         GError *err = NULL;
786         GIOStatus status = G_IO_STATUS_NORMAL;
787
788         BT_DBG("+");
789
790         fd = g_io_channel_unix_get_fd(chan);
791         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
792                 BT_ERR_C("RFComm Client  disconnected: %d", fd);
793                 goto fail;
794         }
795
796         buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
797         status = g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
798                         &len, &err);
799         if (status != G_IO_STATUS_NORMAL) {
800                 BT_ERR("IO Channel read is failed with %d", status);
801                 g_free(buffer);
802                 if (err) {
803                         BT_ERR("IO Channel read error [%s]", err->message);
804                         if (status == G_IO_STATUS_ERROR &&
805                                         __is_error_by_disconnect(err)) {
806                                 BT_ERR("cond : %d", cond);
807                                 g_error_free(err);
808                                 goto fail;
809                         }
810                         g_error_free(err);
811                 }
812
813                 return TRUE;
814         }
815
816         if (len == 0) {
817                 BT_ERR("Length is zero, remote end hang up");
818                 goto fail;
819         }
820
821         BT_DBG("fd: %d, len: %d, buffer: %s", fd, len, buffer);
822
823         event_info = _bt_event_get_cb_data(BT_RFCOMM_CLIENT_EVENT);
824         if (event_info == NULL) {
825                 BT_INFO("event_info == NULL");
826                 g_free(buffer);
827                 return TRUE;
828         }
829
830         data_r.socket_fd = fd;
831         data_r.buffer_size = len;
832         data_r.buffer = buffer;
833
834         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED,
835                         BLUETOOTH_ERROR_NONE, &data_r,
836                         event_info->cb, event_info->user_data);
837
838         g_free(buffer);
839         return TRUE;
840
841 fail:
842         conn_info = __find_rfcomm_conn_info_with_fd(fd);
843         if (conn_info) {
844                 __bt_rfcomm_client_disconnected(conn_info);
845                 __rfcomm_remove_client_conn_info_t(conn_info);
846         } else {
847                 BT_ERR("RFCOMM client conn_info not found");
848         }
849         return FALSE;
850 }
851
852 static void __rfcomm_client_connection_create_watch(rfcomm_client_conn_info_t *conn_info)
853 {
854         GIOChannel *data_io;
855
856         ret_if(NULL == conn_info);
857
858         BT_DBG("+");
859
860         data_io = g_io_channel_unix_new(conn_info->sock_fd);
861         g_io_channel_set_encoding(data_io, NULL, NULL);
862         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
863         conn_info->watch_id = g_io_add_watch(data_io,
864                         G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
865                         __client_data_received_cb, NULL);
866         g_io_channel_unref(data_io);
867
868         BT_DBG("-");
869 }
870
871 static void __bt_rfcomm_handle_new_client_connection(bluetooth_rfcomm_connection_t *info)
872 {
873         rfcomm_client_conn_info_t *conn_info;
874
875         ret_if(NULL == info);
876
877         BT_DBG("+");
878
879         conn_info = g_malloc0(sizeof(rfcomm_client_conn_info_t));
880         conn_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
881         _bt_convert_addr_type_to_string(
882                         conn_info->remote_addr, info->device_addr.addr);
883         conn_info->uuid = g_strdup(info->uuid);
884         conn_info->sock_fd = info->socket_fd;
885
886         BT_DBG("Address:%s, UUID:%s Socket: %d",
887                         conn_info->remote_addr, conn_info->uuid, conn_info->sock_fd);
888
889         rfcomm_clients = g_slist_append(rfcomm_clients, conn_info);
890         __rfcomm_client_connection_create_watch(conn_info);
891
892         BT_DBG("-");
893 }
894
895 static void __bt_fill_garray_from_variant(GVariant *var, GArray *param)
896 {
897         char *data;
898         int size;
899
900         size = g_variant_get_size(var);
901         if (size > 0) {
902                 data = (char *)g_variant_get_data(var);
903                 if (data)
904                         param = g_array_append_vals(param, data, size);
905
906         }
907 }
908
909
910 /* TODO_40 : 4.0 merge  */
911 /* Don't use this function directly. Instead of it, get the out parameter only */
912 static void __bt_get_event_info(int service_function, GArray *output,
913                         int *event, int *event_type, void **param_data)
914 {
915         ret_if(event == NULL);
916
917         BT_DBG("service_function : %s (0x%x)",
918                 _bt_convert_service_function_to_string(service_function),
919                 service_function);
920         switch (service_function) {
921         case BT_RFCOMM_CLIENT_CONNECT:
922                 *event_type = BT_RFCOMM_CLIENT_EVENT;
923                 *event = BLUETOOTH_EVENT_RFCOMM_CONNECTED;
924                 ret_if(output == NULL);
925                 *param_data = &g_array_index(output,
926                                 bluetooth_rfcomm_connection_t, 0);
927                 break;
928         default:
929                 BT_ERR("Unknown function");
930                 return;
931         }
932 }
933
934
935 static void __async_req_cb_with_unix_fd_list(GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
936 {
937         int result = BLUETOOTH_ERROR_NONE;
938         int event_type = BT_ADAPTER_EVENT;
939         bt_req_info_t *cb_data = user_data;
940         bluetooth_event_param_t bt_event;
941
942         GError *error = NULL;
943         GVariant *value;
944         GVariant *param1;
945         GArray *out_param1 = NULL;
946         GUnixFDList *out_fd_list = NULL;
947
948         BT_DBG("+");
949
950         memset(&bt_event, 0x00, sizeof(bluetooth_event_param_t));
951
952         value = g_dbus_proxy_call_with_unix_fd_list_finish(proxy, &out_fd_list, res, &error);
953         if (value == NULL) {
954                 if (error) {
955                         /* dBUS gives error cause */
956                         BT_ERR("D-Bus API failure: message[%s]",
957                                         error->message);
958                         g_clear_error(&error);
959                 }
960                 result = BLUETOOTH_ERROR_TIMEOUT;
961
962                 ret_if(cb_data == NULL);
963
964                 __bt_get_event_info(cb_data->service_function, NULL,
965                                 &bt_event.event, &event_type,
966                                 &bt_event.param_data);
967                 goto failed;
968         }
969
970         g_variant_get(value, "(iv)", &result, &param1);
971         g_variant_unref(value);
972
973         if (param1) {
974                 out_param1 = g_array_new(TRUE, TRUE, sizeof(gchar));
975                 __bt_fill_garray_from_variant(param1, out_param1);
976                 g_variant_unref(param1);
977         }
978
979         if (!cb_data)
980                 goto done;
981
982         __bt_get_event_info(cb_data->service_function, out_param1,
983                         &bt_event.event, &event_type,
984                         &bt_event.param_data);
985
986         if (result == BLUETOOTH_ERROR_NONE && out_param1) {
987                 if (BT_RFCOMM_CLIENT_CONNECT == cb_data->service_function) {
988                         int *fd_list_array;
989                         int len = 0;
990                         bluetooth_rfcomm_connection_t *conn_info;
991
992                         conn_info = (bluetooth_rfcomm_connection_t *)bt_event.param_data;
993                         if (!out_fd_list) {
994                                 BT_ERR("out_fd_list is NULL");
995                                 goto failed;
996                         }
997
998                         fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
999                         BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
1000                         conn_info->socket_fd = fd_list_array[0];
1001
1002                         BT_DBG("conn_info->socket_fd: %d", conn_info->socket_fd);
1003                         __bt_rfcomm_handle_new_client_connection(conn_info);
1004
1005                         if (cb_data->cb != NULL) {
1006                                 /* Send client connected event */
1007                                 bt_event.result = result;
1008                                 BT_INFO("event_type[%d], result=[%d]", event_type, result);
1009                                 ((bluetooth_cb_func_ptr)cb_data->cb)(
1010                                         bt_event.event, &bt_event, cb_data->user_data);
1011                         }
1012
1013                         g_free(fd_list_array);
1014                         g_object_unref(out_fd_list);
1015                 }
1016                 goto done;
1017         }
1018
1019 failed:
1020         if (cb_data->cb == NULL)
1021                 goto done;
1022
1023         /* Only if fail case, call the callback function*/
1024         bt_event.result = result;
1025
1026         BT_INFO("event_type[%d], result=[%d]", event_type, result);
1027         if (event_type == BT_RFCOMM_CLIENT_EVENT) {
1028                 ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
1029                         &bt_event, cb_data->user_data);
1030         } else {
1031                 BT_INFO("Not handled event type : %d", event_type);
1032         }
1033 done:
1034         if (out_param1)
1035                 g_array_free(out_param1, TRUE);
1036
1037         g_free(cb_data);
1038         BT_DBG("-");
1039 }
1040 #endif
1041
1042 BT_EXPORT_API int bluetooth_rfcomm_connect(
1043                 const bluetooth_device_address_t *remote_bt_address,
1044                 const char *remote_uuid)
1045 {
1046
1047 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1048         rfcomm_cb_data_t *cb_data = NULL;
1049         rfcomm_conn_info_t *conn = NULL;
1050 #else
1051         int result;
1052         int connect_type;
1053         bt_user_info_t *user_info;
1054         char uuid[BLUETOOTH_UUID_STRING_MAX];
1055 #endif
1056         BT_CHECK_PARAMETER(remote_bt_address, return);
1057         BT_CHECK_PARAMETER(remote_uuid, return);
1058         BT_CHECK_ENABLED(return);
1059
1060 #ifdef TIZEN_FEATURE_BT_DPM
1061         if (_bt_check_dpm(BT_DPM_ADDRESS, (void *)remote_bt_address) == BT_DPM_RESTRICTED) {
1062                 BT_ERR("Blacklist device");
1063                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1064         }
1065
1066         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED ||
1067                 _bt_check_dpm(BT_DPM_HF_ONLY, NULL) == BT_DPM_RESTRICTED) {
1068                 BT_ERR("Not allow to connect the RFCOMM service");
1069                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1070         }
1071
1072         if (_bt_check_dpm(BT_DPM_DESKTOP, NULL) == BT_DPM_RESTRICTED) {
1073                 char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1074                 bluetooth_device_class_t dev_class;
1075
1076                 _bt_convert_addr_type_to_string(address, (unsigned char *)remote_bt_address->addr);
1077                 _bt_get_cod_by_address(address, &dev_class);
1078
1079                 if (dev_class.major_class == BLUETOOTH_DEVICE_MAJOR_CLASS_COMPUTER) {
1080                         BT_ERR("Reject a authorization due to MDM Policy");
1081                         return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1082                 }
1083         }
1084 #endif
1085
1086 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1087         BT_INFO_C("### Connect RFCOMM");
1088         int ret;
1089         int id, object_id;
1090         char *path;
1091
1092         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CLIENT_CONNECT)
1093              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1094                 BT_ERR("Don't have a privilege to use this API");
1095                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1096         }
1097
1098         id = __rfcomm_assign_id();
1099         if (id < 0)
1100                 return BLUETOOTH_ERROR_INTERNAL;
1101
1102         cb_data = __find_rfcomm_info_from_uuid(remote_uuid);
1103         if (!cb_data) {
1104                 path = g_strdup_printf("/org/socket/client/%d/%d", getpid(), id);
1105
1106                 object_id = _bt_register_new_conn(path, new_connection);
1107                 if (object_id < 0) {
1108                         __rfcomm_delete_id(id);
1109                         g_free(path);
1110                         return BLUETOOTH_ERROR_INTERNAL;
1111                 }
1112
1113                 cb_data = g_new0(rfcomm_cb_data_t, 1);
1114                 g_strlcpy(cb_data->uuid, remote_uuid, BLUETOOTH_UUID_STRING_MAX);
1115                 cb_data->obj_path = path;
1116                 cb_data->object_id = object_id;
1117                 cb_data->id = id;
1118         }
1119
1120         conn = g_new0(rfcomm_conn_info_t, 1);
1121         conn->fd = -1;
1122         _bt_convert_addr_type_to_string(conn->bt_addr,
1123                                 (unsigned char *)remote_bt_address->addr);
1124
1125         BT_DBG("Connecting to %s uuid %s", conn->bt_addr, remote_uuid);
1126         cb_data->rfcomm_conns = g_slist_append(cb_data->rfcomm_conns, conn);
1127
1128         ret = _bt_discover_services(conn->bt_addr, (char *)remote_uuid,
1129                                 __bt_discover_service_response_cb, cb_data);
1130         if (ret != BLUETOOTH_ERROR_NONE) {
1131                 BT_ERR("Error returned while service discovery");
1132                 __rfcomm_remove_conn_info_t(cb_data, conn->bt_addr);
1133                 if (cb_data->rfcomm_conns == NULL)
1134                         rfcomm_cb_data_remove(cb_data);
1135                 return BLUETOOTH_ERROR_INTERNAL;
1136         }
1137
1138         if (g_slist_find(rfcomm_clients, cb_data) == NULL) {
1139                 BT_INFO("Adding callback information to rfcomm_clients");
1140                 rfcomm_clients = g_slist_append(rfcomm_clients, cb_data);
1141         } else
1142                 BT_INFO("Callback information is already added");
1143
1144         return BLUETOOTH_ERROR_NONE;
1145 #else
1146         user_info = _bt_get_user_data(BT_COMMON);
1147         retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
1148
1149         /* connect_type:  BT_RFCOMM_UUID / BT_RFCOMM_CHANNEL*/
1150         /* In now, we only support to connecty using UUID */
1151         connect_type = BT_RFCOMM_UUID;
1152
1153         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_CLIENT_CONNECT)
1154              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1155                 BT_ERR("Don't have a privilege to use this API");
1156                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1157         }
1158
1159         BT_INIT_PARAMS();
1160         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1161
1162         g_array_append_vals(in_param1, remote_bt_address,
1163                                 sizeof(bluetooth_device_address_t));
1164
1165         g_strlcpy(uuid, remote_uuid, sizeof(uuid));
1166         g_array_append_vals(in_param2, uuid, BLUETOOTH_UUID_STRING_MAX);
1167
1168         g_array_append_vals(in_param3, &connect_type, sizeof(int));
1169
1170         result = _bt_send_request_async_with_unix_fd_list(BT_BLUEZ_SERVICE,
1171                                 BT_RFCOMM_CLIENT_CONNECT,
1172                                 in_param1, in_param2,
1173                                 in_param3, in_param4,
1174                                 user_info->cb, user_info->user_data,
1175                                 NULL, (GAsyncReadyCallback)__async_req_cb_with_unix_fd_list);
1176
1177         BT_DBG("result: %x", result);
1178
1179         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1180
1181         return result;
1182 #endif
1183 }
1184
1185 BT_EXPORT_API int bluetooth_rfcomm_client_is_connected(const bluetooth_device_address_t *device_address, gboolean *connected)
1186 {
1187 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1188         GSList *l;
1189         GSList *conn_list = NULL;
1190         rfcomm_cb_data_t *client_info;
1191         rfcomm_conn_info_t *conn_info;
1192         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1193
1194         BT_CHECK_PARAMETER(device_address, return);
1195         BT_CHECK_PARAMETER(connected, return);
1196
1197         _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
1198         *connected = FALSE;
1199
1200         for (l = rfcomm_clients; l != NULL; l = l->next) {
1201                 client_info = l->data;
1202                 if (client_info == NULL)
1203                         continue;
1204                 for (conn_list = client_info->rfcomm_conns;
1205                         conn_list != NULL; conn_list = conn_list->next) {
1206                         conn_info = conn_list->data;
1207                         if (conn_info == NULL)
1208                                 continue;
1209
1210                         if (g_strcmp0(address, conn_info->bt_addr) == 0) {
1211                                 *connected = TRUE;
1212                                 return BLUETOOTH_ERROR_NONE;
1213                         }
1214                 }
1215         }
1216
1217         return BLUETOOTH_ERROR_NONE;
1218 #else
1219         GSList *l;
1220         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
1221
1222         BT_CHECK_PARAMETER(device_address, return);
1223         BT_CHECK_PARAMETER(connected, return);
1224
1225         BT_DBG("+");
1226
1227         *connected = FALSE;
1228         _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
1229         BT_INFO("Client address: [%s]", address);
1230
1231         for (l = rfcomm_clients; l != NULL; l = l->next) {
1232                 rfcomm_client_conn_info_t *info = l->data;
1233
1234                 if (info && !strncasecmp(info->remote_addr, address, BT_ADDRESS_STRING_SIZE)) {
1235                         BT_INFO("Match found");
1236                         *connected = TRUE;
1237                         return BLUETOOTH_ERROR_NONE;
1238                 }
1239         }
1240
1241         BT_DBG("-");
1242         return BLUETOOTH_ERROR_NONE;
1243 #endif
1244 }
1245
1246 BT_EXPORT_API gboolean bluetooth_rfcomm_is_client_connected(void)
1247 {
1248         int result;
1249         int connected = FALSE;
1250
1251         BT_CHECK_ENABLED(return);
1252
1253         BT_INIT_PARAMS();
1254         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1255
1256         result = _bt_send_request(BT_BLUEZ_SERVICE,
1257                         BT_RFCOMM_CLIENT_IS_CONNECTED,
1258                         in_param1, in_param2, in_param3,
1259                         in_param4, &out_param);
1260
1261         BT_DBG("result: %x", result);
1262
1263         if (result == BLUETOOTH_ERROR_NONE) {
1264                 connected = g_array_index(out_param,
1265                                 int, 0);
1266         } else {
1267                 BT_ERR("Fail to send request");
1268         }
1269
1270         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1271
1272         return connected;
1273 }
1274
1275 BT_EXPORT_API int bluetooth_rfcomm_disconnect(int socket_fd)
1276 {
1277 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1278         rfcomm_cb_data_t *info;
1279         rfcomm_conn_info_t *conn_info;
1280
1281         BT_INFO_C("### Disconnect RFCOMM");
1282
1283         BT_CHECK_ENABLED(return);
1284
1285         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_DISCONNECT)
1286              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1287                 BT_ERR("Don't have a privilege to use this API");
1288                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1289         }
1290
1291         BT_DBG("Requested FD %d", socket_fd);
1292         if (socket_fd < 0) {
1293                 BT_ERR("Invalid FD");
1294                 return BLUETOOTH_ERROR_INVALID_PARAM;
1295         }
1296         BT_DBG("FDD %d", socket_fd);
1297
1298         info = __find_rfcomm_info_with_fd(socket_fd);
1299         if (info == NULL) {
1300                 BT_DBG("Could not find in client, so check in server");
1301                 return bluetooth_rfcomm_server_disconnect(socket_fd);
1302         }
1303
1304         conn_info = __get_conn_info_from_fd(info, socket_fd);
1305         if (conn_info == NULL) {
1306                 BT_ERR("Could not find connection info");
1307                 return BLUETOOTH_ERROR_INTERNAL;
1308         }
1309
1310         if (conn_info->watch_id == 0 || conn_info->disconnected) {
1311                 BT_ERR("Invalid state");
1312                 return BLUETOOTH_ERROR_NOT_CONNECTED;
1313         }
1314
1315         close(conn_info->fd);
1316         conn_info->disconnected = TRUE;
1317
1318         BT_INFO("conn_info %s", conn_info->bt_addr);
1319         _bt_disconnect_ext_profile(conn_info->bt_addr, info->obj_path);
1320
1321         if (info->idle_id == 0)
1322                 info->idle_id = g_idle_add(__rfcomm_client_disconnect, info);
1323
1324         return BLUETOOTH_ERROR_NONE;
1325 #else
1326         rfcomm_client_conn_info_t *conn_info;
1327
1328         BT_INFO_C("<<<<<<<<< RFCOMM Disconnect request from app >>>>>>>>");
1329
1330         BT_CHECK_ENABLED(return);
1331         retv_if(socket_fd < 0, BLUETOOTH_ERROR_INVALID_PARAM);
1332
1333         if (_bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_DISCONNECT)
1334                         == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1335                 BT_ERR("Don't have a privilege to use this API");
1336                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1337         }
1338
1339         BT_DBG("FD %d", socket_fd);
1340
1341         conn_info = __find_rfcomm_conn_info_with_fd(socket_fd);
1342         if (conn_info == NULL) {
1343                 BT_DBG("Could not find in client, so check in server");
1344                 /* Check for fd in server list and perform the disconnection if present */
1345                 return bluetooth_rfcomm_server_disconnect(socket_fd);
1346         }
1347
1348         if (conn_info->watch_id <= 0) {
1349                 BT_ERR("Invalid state");
1350                 return BLUETOOTH_ERROR_NOT_CONNECTED;
1351         }
1352
1353         /*
1354          * Just close socket here and return. Socket close will be detected via I/O watch
1355          * and disconnection event as well as info cleanup will be performed there.
1356          */
1357         close(conn_info->sock_fd);
1358
1359         return BLUETOOTH_ERROR_NONE;
1360 #endif
1361 }
1362
1363 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1364 #else
1365 static int __write_all(int fd, const char *buf, int len)
1366 {
1367         int sent = 0, try = 0;
1368
1369         BT_DBG("+");
1370         while (len > 0) {
1371                 int written;
1372
1373                 written = write(fd, buf, len);
1374                 BT_DBG("written: %d", written);
1375                 if (written < 0) {
1376                         if (errno == EINTR || errno == EAGAIN) {
1377                                 try++;
1378                                 if (try <= 49)
1379                                         continue;
1380                         }
1381                         return -1;
1382                 }
1383
1384                 if (!written)
1385                         return 0;
1386
1387                 len -= written;
1388                 buf += written;
1389                 sent += written;
1390                 try = 0;
1391         }
1392
1393         BT_DBG("-");
1394         return sent;
1395 }
1396 #endif
1397
1398 BT_EXPORT_API int bluetooth_rfcomm_write(int fd, const char *buf, int length)
1399 {
1400 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1401         int written;
1402 #endif
1403         int result;
1404
1405 #ifndef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1406         BT_CHECK_ENABLED(return);
1407 #endif
1408         BT_CHECK_PARAMETER(buf, return);
1409         if (fd < 0) {
1410                 BT_ERR("Invalid FD");
1411                 return BLUETOOTH_ERROR_INVALID_PARAM;
1412         }
1413
1414         retv_if(length <= 0, BLUETOOTH_ERROR_INVALID_PARAM);
1415
1416         switch (privilege_token) {
1417         case 0:
1418                 result = _bt_check_privilege(BT_CHECK_PRIVILEGE, BT_RFCOMM_SOCKET_WRITE);
1419
1420                 if (result == BLUETOOTH_ERROR_NONE) {
1421                         privilege_token = 1; /* Have a permission */
1422                 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
1423                         BT_ERR("Don't have a privilege to use this API");
1424                         privilege_token = -1; /* Don't have a permission */
1425                         return BLUETOOTH_ERROR_PERMISSION_DEINED;
1426                 } else {
1427                         /* Just break - It is not related with permission error */
1428                 }
1429                 break;
1430         case 1:
1431                 /* Already have a privilege */
1432                 break;
1433         case -1:
1434                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
1435         default:
1436                 /* Invalid privilge token value */
1437                 return BLUETOOTH_ERROR_INTERNAL;
1438         }
1439
1440 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
1441         written = write(fd, buf, length);
1442         /*BT_DBG("Length %d, written = %d, balance(%d)",
1443                         length, written, length - written); */
1444         if (written > 0 && bluetooth_get_battery_monitor_state()) {
1445                 if (tx_tag == 0) {
1446                         BT_INFO("Adding rfcomm tx timeout function for battery monitor");
1447                         tx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_tx_data, NULL);
1448                 }
1449                 tx_data += written;
1450         }
1451         return written;
1452 #else
1453         result = __write_all(fd, buf, length);
1454         if (result > 0 && bluetooth_get_battery_monitor_state()) {
1455                 if (tx_tag == 0) {
1456                         BT_INFO("Adding rfcomm tx timeout function for battery monitor");
1457                         tx_tag = g_timeout_add_seconds(BATTERY_MONITOR_RFCOMM_INTERVAL, (GSourceFunc)__rfcomm_record_tx_data, NULL);
1458                 }
1459                 tx_data += written;
1460         }
1461         return result;
1462 #endif
1463 }