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