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