Modify build feature names as Tizen 3.0 build option naming rule
[platform/core/connectivity/bluetooth-frwk.git] / bt-api / bt-rfcomm-server.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 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
20 #include <gio/gio.h>
21 #include <gio/gunixfdlist.h>
22 #include <sys/socket.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 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
37
38 static GSList *rfcomm_nodes;
39
40 typedef struct {
41         bluetooth_device_address_t addr;
42         int fd;
43         guint watch_id;
44         gboolean disconnected;
45 } rfcomm_conn_t;
46
47 typedef struct {
48         guint object_id;
49         gchar *path;
50         int id;
51         char *uuid;
52         GSList *rfcomm_conns;
53         guint disconnect_idle_id;
54 } rfcomm_info_t;
55
56 static rfcomm_info_t *__find_rfcomm_info_with_id(int id)
57 {
58         GSList *l;
59
60         for (l = rfcomm_nodes; l != NULL; l = l->next) {
61                 rfcomm_info_t *info = l->data;
62
63                 if (info->id == id)
64                         return info;
65         }
66
67         return NULL;
68 }
69
70 static rfcomm_info_t *__find_rfcomm_info_with_fd(int fd)
71 {
72         GSList *l;
73         GSList *ll;
74
75         for (l = rfcomm_nodes; l != NULL; l = l->next) {
76                 rfcomm_info_t *info = l->data;
77
78                 for (ll = info->rfcomm_conns; ll; ll = ll->next) {
79                         rfcomm_conn_t *conn = ll->data;
80
81                         if (conn && conn->fd == fd)
82                                 return info;
83                 }
84         }
85
86         return NULL;
87 }
88
89 static rfcomm_info_t *__find_rfcomm_info_with_path(const gchar *path)
90 {
91         GSList *l;
92
93         for (l = rfcomm_nodes; l != NULL; l = l->next) {
94                 rfcomm_info_t *info = l->data;
95
96                 if (g_strcmp0(info->path, path) == 0)
97                         return info;
98         }
99
100         return NULL;
101 }
102
103 static rfcomm_info_t *__find_rfcomm_info_with_uuid(const char *uuid)
104 {
105         GSList *l;
106
107         for (l = rfcomm_nodes; l != NULL; l = l->next) {
108                 rfcomm_info_t *info = l->data;
109
110                 if (g_strcmp0(info->uuid, uuid) == 0)
111                         return info;
112         }
113
114         return NULL;
115 }
116
117 static rfcomm_conn_t *__find_rfcomm_conn_with_fd(rfcomm_info_t *info,
118                                                       int fd)
119 {
120         GSList *l;
121         rfcomm_conn_t *conn;
122
123         for (l = info->rfcomm_conns; l; l = l->next) {
124                 conn = l->data;
125
126                 if (conn && conn->fd == fd)
127                         return conn;
128         }
129
130         return NULL;
131 }
132
133 static void __rfcomm_remove_conn(rfcomm_info_t *info, int fd)
134 {
135         rfcomm_conn_t *conn;
136
137         conn = __find_rfcomm_conn_with_fd(info, fd);
138         if (conn == NULL)
139                 return;
140
141         info->rfcomm_conns = g_slist_remove(info->rfcomm_conns, conn);
142
143         if (conn->watch_id > 0)
144                 g_source_remove(conn->watch_id);
145         g_free(conn);
146 }
147
148 gboolean _check_uuid_path(char *path, char *uuid)
149 {
150         rfcomm_info_t *info = NULL;
151         info = __find_rfcomm_info_with_path(path);
152         if (!info)
153                 return FALSE;
154
155         if (strcmp(info->uuid, uuid) == 0)
156                 return TRUE;
157
158         return FALSE;
159 }
160
161 static void __connected_cb(rfcomm_info_t *info, rfcomm_conn_t *conn,
162                            bt_event_info_t *event_info)
163 {
164         bluetooth_rfcomm_connection_t conn_info;
165
166         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
167
168         conn_info.device_role = RFCOMM_ROLE_SERVER;
169         g_strlcpy(conn_info.uuid, info->uuid, BLUETOOTH_UUID_STRING_MAX);
170         conn_info.socket_fd = conn->fd;
171         conn_info.device_addr = conn->addr;
172         conn_info.server_id = info->id;
173
174         BT_INFO_C("### Connected [RFCOMM Server]");
175         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_CONNECTED,
176                         BLUETOOTH_ERROR_NONE, &conn_info,
177                         event_info->cb, event_info->user_data);
178 }
179
180 static void __rfcomm_server_disconnect_conn(rfcomm_conn_t *conn,
181                                             rfcomm_info_t *info)
182 {
183         bluetooth_rfcomm_disconnection_t disconn_info;
184         bt_event_info_t *event_info;
185
186         if (conn == NULL)
187                 return;
188
189         if (conn->disconnected == FALSE)
190                 return;
191
192         if (conn->watch_id > 0) {
193                 g_source_remove(conn->watch_id);
194                 conn->watch_id = 0;
195         }
196
197         event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
198         if (event_info == NULL) {
199                 __rfcomm_remove_conn(info, conn->fd);
200                 return;
201         }
202
203         memset(&disconn_info, 0x00, sizeof(bluetooth_rfcomm_disconnection_t));
204         disconn_info.device_role = RFCOMM_ROLE_SERVER;
205         g_strlcpy(disconn_info.uuid, info->uuid, BLUETOOTH_UUID_STRING_MAX);
206         disconn_info.device_addr = conn->addr;
207
208         BT_DBG("Disconnected FD [%d]", conn->fd);
209         disconn_info.socket_fd = conn->fd;
210
211         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DISCONNECTED,
212                         BLUETOOTH_ERROR_NONE, &disconn_info,
213                         event_info->cb, event_info->user_data);
214
215         __rfcomm_remove_conn(info, conn->fd);
216 }
217
218 static gboolean __rfcomm_server_disconnect(rfcomm_info_t *info)
219 {
220         BT_INFO_C("### Disconnected [RFCOMM Server]");
221
222         if (g_slist_find(rfcomm_nodes, info) == NULL) {
223                 BT_INFO("rfcomm resource is already freed");
224                 return FALSE;
225         }
226
227         info->disconnect_idle_id = 0;
228
229         g_slist_foreach(info->rfcomm_conns,
230                         (GFunc)__rfcomm_server_disconnect_conn, info);
231
232         BT_DBG("-");
233         return FALSE;
234 }
235
236 static gboolean __is_error_by_disconnect(GError *err)
237 {
238         return !g_strcmp0(err->message, "Connection reset by peer") ||
239                         !g_strcmp0(err->message, "Connection timed out") ||
240                         !g_strcmp0(err->message, "Software caused connection abort");
241 }
242
243 static gboolean __data_received_cb(GIOChannel *chan, GIOCondition cond,
244                                                                 gpointer data)
245 {
246         char *buffer = NULL;
247         gsize len = 0;
248         int result = BLUETOOTH_ERROR_NONE;
249         rfcomm_info_t *info = data;
250         rfcomm_conn_t *conn;
251         bt_event_info_t *event_info;
252         bluetooth_rfcomm_received_data_t data_r;
253         GIOStatus status = G_IO_STATUS_NORMAL;
254         GError *err = NULL;
255         int fd;
256
257         retv_if(info == NULL, FALSE);
258
259         fd = g_io_channel_unix_get_fd(chan);
260         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
261                 BT_ERR_C("RFComm Server disconnected: %d", fd);
262
263                 if (info->disconnect_idle_id > 0) {
264                         BT_INFO("Disconnect idle still not process remove source");
265                         g_source_remove(info->disconnect_idle_id);
266                         info->disconnect_idle_id = 0;
267                 }
268
269                 conn = __find_rfcomm_conn_with_fd(info, fd);
270                 if (conn == NULL) {
271                         BT_ERR("No Connection info found with FD [%d]", fd);
272                         return FALSE;
273                 }
274
275                 if (conn->disconnected == FALSE) {
276                         close(conn->fd);
277                         conn->disconnected = TRUE;
278                 }
279                 __rfcomm_server_disconnect(info);
280                 return FALSE;
281         }
282
283         buffer = g_malloc0(BT_RFCOMM_BUFFER_LEN + 1);
284
285         status =  g_io_channel_read_chars(chan, buffer, BT_RFCOMM_BUFFER_LEN,
286                                                 &len, &err);
287         if (status != G_IO_STATUS_NORMAL) {
288                 BT_ERR("IO Channel read is failed with %d", status);
289
290                 g_free(buffer);
291                 if (!err)
292                         return TRUE;
293
294                 BT_ERR("IO Channel read error [%s]", err->message);
295                 if (status == G_IO_STATUS_ERROR &&
296                     __is_error_by_disconnect(err)) {
297                         BT_ERR("cond : %d", cond);
298                         g_error_free(err);
299
300                         if (info->disconnect_idle_id > 0) {
301                                 BT_INFO("Disconnect idle still not process remove source");
302                                 g_source_remove(info->disconnect_idle_id);
303                                 info->disconnect_idle_id = 0;
304                         }
305
306                         conn = __find_rfcomm_conn_with_fd(info, fd);
307                         if (conn == NULL) {
308                                 BT_ERR("No Connection info found with FD [%d]", fd);
309                                 return FALSE;
310                         }
311
312                         if (conn->disconnected == FALSE) {
313                                 close(conn->fd);
314                                 conn->disconnected = TRUE;
315                         }
316                         __rfcomm_server_disconnect(info);
317                         return FALSE;
318                 }
319                 g_error_free(err);
320                 return TRUE;
321         }
322
323         if (len == 0)
324                 BT_ERR("Length is zero");
325
326         event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
327         if (event_info == NULL) {
328                 g_free(buffer);
329                 return TRUE;
330         }
331
332         data_r.socket_fd = fd;
333         data_r.buffer_size = len;
334         data_r.buffer = buffer;
335
336         _bt_common_event_cb(BLUETOOTH_EVENT_RFCOMM_DATA_RECEIVED,
337                         result, &data_r,
338                         event_info->cb, event_info->user_data);
339
340         g_free(buffer);
341
342         return TRUE;
343 }
344
345 int new_server_connection(const char *path, int fd, bluetooth_device_address_t *addr)
346 {
347         rfcomm_info_t *info;
348         rfcomm_conn_t *conn;
349         GIOChannel *data_io;
350         bt_event_info_t *event_info;
351
352         BT_DBG("%s %d", path, fd);
353
354         info = __find_rfcomm_info_with_path(path);
355         if (info == NULL)
356                 return -1;
357
358 #ifdef TIZEN_FEATURE_BT_DPM
359         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
360                 char addr_str[20];
361
362                 BT_ERR("Not allow to use SPP profile");
363
364                 close(fd);
365                 _bt_convert_addr_type_to_string(addr_str, addr->addr);
366                 _bt_disconnect_profile(addr_str, info->uuid, NULL,NULL);
367
368                 return -1;
369         }
370 #endif
371
372         conn = g_new0(rfcomm_conn_t, 1);
373         conn->fd = fd;
374         memcpy(&conn->addr, addr, sizeof(bluetooth_device_address_t));
375         info->rfcomm_conns = g_slist_append(info->rfcomm_conns, conn);
376
377         data_io = g_io_channel_unix_new(conn->fd);
378
379         g_io_channel_set_encoding(data_io, NULL, NULL);
380         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
381
382         conn->watch_id = g_io_add_watch(data_io,
383                            G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
384                            __data_received_cb, info);
385
386         g_io_channel_unref(data_io);
387
388         event_info = _bt_event_get_cb_data(BT_RFCOMM_SERVER_EVENT);
389         if (event_info)
390                 __connected_cb(info, conn, event_info);
391
392         return 0;
393 }
394
395 static rfcomm_info_t *__register_method()
396 {
397         gchar *path;
398         rfcomm_info_t *info;
399         int object_id;
400         int id;
401
402         id = __rfcomm_assign_id();
403         if (id < 0)
404                 return NULL;
405
406         path = g_strdup_printf("/org/socket/server/%d/%d", getpid(), id);
407
408         object_id = _bt_register_new_conn(path, new_server_connection);
409         if (object_id < 0) {
410                 __rfcomm_delete_id(id);
411                 return NULL;
412         }
413         info = g_new0(rfcomm_info_t, 1);
414         info->object_id = (guint)object_id;
415         info->path = path;
416         info->id = id;
417
418         rfcomm_nodes = g_slist_append(rfcomm_nodes, info);
419
420         return info;
421 }
422
423 static rfcomm_info_t *__register_method_2(const char *path, const char *bus_name)
424 {
425         rfcomm_info_t *info;
426         int object_id;
427
428         object_id = _bt_register_new_conn_ex(path, bus_name, new_server_connection);
429         if (object_id < 0)
430                 return NULL;
431
432         info = g_new0(rfcomm_info_t, 1);
433         info->object_id = (guint)object_id;
434         info->path = g_strdup(path);
435         info->id = -1;
436
437         rfcomm_nodes = g_slist_append(rfcomm_nodes, info);
438
439         return info;
440 }
441
442 void free_rfcomm_conn(rfcomm_conn_t *conn, rfcomm_info_t *info)
443 {
444         if (conn->disconnected == FALSE) {
445                 close(conn->fd);
446                 conn->disconnected = TRUE;
447         }
448         __rfcomm_server_disconnect_conn(conn, info);
449 }
450
451 void free_rfcomm_info(rfcomm_info_t *info)
452 {
453         BT_DBG("");
454
455         if (info->disconnect_idle_id > 0) {
456                 BT_INFO("Disconnect idle still not process remove source");
457                 g_source_remove(info->disconnect_idle_id);
458                 info->disconnect_idle_id = 0;
459         }
460
461         __rfcomm_delete_id(info->id);
462         _bt_unregister_gdbus(info->object_id);
463
464         g_slist_foreach(info->rfcomm_conns, (GFunc)free_rfcomm_conn, info);
465
466         g_free(info->path);
467         g_free(info->uuid);
468         g_free(info);
469 }
470
471 void _bt_rfcomm_server_free_all(void)
472 {
473         BT_DBG("Free all the servers");
474
475         g_slist_free_full(rfcomm_nodes, (GDestroyNotify)free_rfcomm_info);
476         rfcomm_nodes = NULL;
477 }
478
479 void _bt_rfcomm_server_disconnect_all(void)
480 {
481         GSList *server;
482         GSList *conn;
483         char addr[20];
484
485         BT_INFO("### Disconnect all RFCOMM server connections");
486
487         for (server = rfcomm_nodes; server; ) {
488                 rfcomm_info_t *info = server->data;
489
490                 for (conn = info->rfcomm_conns; conn; conn = conn->next) {
491                         rfcomm_conn_t *conn_info = conn->data;
492
493                         if (conn_info == NULL)
494                                 continue;
495
496                         if (conn_info->watch_id == 0 || conn_info->disconnected)
497                                 continue;
498
499                         close(conn_info->fd);
500                         conn_info->disconnected = TRUE;
501
502                         _bt_convert_addr_type_to_string(addr,
503                                                         conn_info->addr.addr);
504                         _bt_disconnect_profile(addr, info->uuid, NULL,NULL);
505                 }
506
507                 server = server->next;
508                 __rfcomm_server_disconnect(info);
509         }
510
511         return;
512 }
513 #endif
514
515 BT_EXPORT_API int bluetooth_rfcomm_create_socket(const char *uuid)
516 {
517 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
518         rfcomm_info_t *info;
519 #else
520         int result;
521         int socket_fd = -1;
522         char uuid_str[BLUETOOTH_UUID_STRING_MAX];
523 #endif
524
525         BT_CHECK_ENABLED(return);
526         BT_CHECK_PARAMETER(uuid, return);
527         BT_INFO("UUID Provided %s", uuid);
528
529         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_RFCOMM_CREATE_SOCKET)
530                 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
531                 BT_ERR("Don't have a privilege to use this API");
532                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
533         }
534
535 #ifdef TIZEN_FEATURE_BT_DPM
536         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
537                 BT_ERR("Not allow to use SPP profile");
538                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
539         }
540 #endif
541
542 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
543         BT_INFO("<<<<<<<<< RFCOMM Create socket from app >>>>>>>>>");
544         info = __register_method();
545         if (info == NULL)
546                 return -1;
547
548         info->uuid = g_strdup(uuid);
549         info->disconnect_idle_id = 0;
550         return info->id;
551 #else
552
553         BT_INIT_PARAMS();
554         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
555
556         g_strlcpy(uuid_str, uuid, sizeof(uuid_str));
557         g_array_append_vals(in_param1, uuid_str, BLUETOOTH_UUID_STRING_MAX);
558
559         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_CREATE_SOCKET,
560                 in_param1, in_param2, in_param3, in_param4, &out_param);
561
562         BT_DBG("result: %x", result);
563
564         if (result == BLUETOOTH_ERROR_NONE)
565                 socket_fd = g_array_index(out_param, int, 0);
566         else
567                 BT_ERR("Fail to send request");
568
569         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
570
571         return socket_fd;
572 #endif
573 }
574
575 BT_EXPORT_API int bluetooth_rfcomm_create_socket_ex(const char *uuid, const char *bus_name, const char *path)
576 {
577 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
578         rfcomm_info_t *info;
579
580         BT_CHECK_ENABLED(return);
581         BT_CHECK_PARAMETER(path, return);
582         BT_INFO("PATH Provided %s", path);
583
584         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_RFCOMM_CREATE_SOCKET_EX)
585                 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
586                 BT_ERR("Don't have a privilege to use this API");
587                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
588         }
589
590 #ifdef TIZEN_FEATURE_BT_DPM
591         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
592                 BT_ERR("Not allow to use SPP profile");
593                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
594         }
595 #endif
596
597         BT_INFO("<<<<<<<<< RFCOMM Create socket from app >>>>>>>>>");
598         info = __register_method_2(path, bus_name);
599         if (info == NULL)
600                 return BLUETOOTH_ERROR_IN_PROGRESS;
601         info->uuid = g_strdup(uuid);
602         info->disconnect_idle_id = 0;
603
604         return BLUETOOTH_ERROR_NONE;
605 #else
606         return BLUETOOTH_ERROR_NOT_SUPPORT;
607 #endif
608 }
609
610
611 BT_EXPORT_API int bluetooth_rfcomm_remove_socket(int id)
612 {
613 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
614         rfcomm_info_t *info;
615 #else
616         int result;
617 #endif
618
619         BT_CHECK_ENABLED(return);
620
621         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_RFCOMM_REMOVE_SOCKET)
622                 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
623                 BT_ERR("Don't have a privilege to use this API");
624                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
625         }
626
627         if (id < 0) {
628                 BT_ERR("Invalid ID");
629                 return BLUETOOTH_ERROR_INVALID_PARAM;
630         }
631
632 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
633         BT_INFO("RFCOMM Remove socket request from app, ID [%d]", id);
634
635         info = __find_rfcomm_info_with_id(id);
636         if (info == NULL)
637                 return BLUETOOTH_ERROR_INVALID_PARAM;
638
639         _bt_unregister_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid);
640         _bt_unregister_profile(info->path);
641
642         rfcomm_nodes = g_slist_remove(rfcomm_nodes, info);
643         free_rfcomm_info(info);
644
645         return BLUETOOTH_ERROR_NONE;
646 #else
647         BT_INIT_PARAMS();
648         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
649
650         g_array_append_vals(in_param1, &id, sizeof(int));
651
652         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_REMOVE_SOCKET,
653                 in_param1, in_param2, in_param3, in_param4, &out_param);
654
655         BT_DBG("result: %x", result);
656
657         if (result == BLUETOOTH_ERROR_NONE)
658                 _bt_remove_server(id);
659
660         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
661
662         return result;
663 #endif
664 }
665
666 BT_EXPORT_API int bluetooth_rfcomm_remove_socket_ex(const char *uuid)
667 {
668 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
669         rfcomm_info_t *info;
670
671         BT_CHECK_ENABLED(return);
672
673         if (_bt_check_privilege(BT_BLUEZ_SERVICE, BT_RFCOMM_REMOVE_SOCKET)
674                 == BLUETOOTH_ERROR_PERMISSION_DEINED) {
675                 BT_ERR("Don't have a privilege to use this API");
676                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
677         }
678
679         BT_INFO("RFCOMM Remove socket request from app, uuid=[%s]", uuid);
680
681         info = __find_rfcomm_info_with_uuid(uuid);
682         if (info == NULL)
683                 return BLUETOOTH_ERROR_INVALID_PARAM;
684
685         _bt_unregister_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid);
686         _bt_unregister_profile(info->path);
687
688         rfcomm_nodes = g_slist_remove(rfcomm_nodes, info);
689         free_rfcomm_info(info);
690
691         return BLUETOOTH_ERROR_NONE;
692 #else
693         return BLUETOOTH_ERROR_NOT_SUPPORT;
694 #endif
695 }
696
697 BT_EXPORT_API int bluetooth_rfcomm_server_disconnect(int socket_fd)
698 {
699 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
700         rfcomm_info_t *info;
701         rfcomm_conn_t *conn;
702
703         char address[20];
704
705         BT_INFO("### Disconnect RFCOMM server");
706         if (socket_fd < 0) {
707                 BT_ERR("Invalid FD");
708                 return BLUETOOTH_ERROR_INVALID_PARAM;
709         }
710
711         info = __find_rfcomm_info_with_fd(socket_fd);
712         if (info == NULL)
713                 return BLUETOOTH_ERROR_INVALID_PARAM;
714
715         conn = __find_rfcomm_conn_with_fd(info, socket_fd);
716         if (conn == NULL)
717                 return BLUETOOTH_ERROR_INVALID_PARAM;
718
719         if (conn->watch_id == 0 || conn->disconnected)
720                 return BLUETOOTH_ERROR_NOT_CONNECTED;
721
722         close(conn->fd);
723         conn->disconnected = TRUE;
724
725         _bt_convert_addr_type_to_string(address, conn->addr.addr);
726
727         BT_DBG("Address %s", address);
728         _bt_disconnect_profile(address, info->uuid, NULL, NULL);
729
730         if (info->disconnect_idle_id == 0)
731                 info->disconnect_idle_id = g_idle_add(
732                                 (GSourceFunc)__rfcomm_server_disconnect, info);
733         BT_DBG("-");
734
735         return BLUETOOTH_ERROR_NONE;
736 #else
737         int result;
738
739         BT_CHECK_ENABLED(return);
740
741         BT_INIT_PARAMS();
742         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
743
744         g_array_append_vals(in_param1, &socket_fd, sizeof(int));
745
746         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_SOCKET_DISCONNECT,
747                 in_param1, in_param2, in_param3, in_param4, &out_param);
748
749         BT_DBG("result: %x", result);
750
751         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
752
753         return result;
754 #endif
755 }
756
757 BT_EXPORT_API gboolean bluetooth_rfcomm_is_server_uuid_available(const char *uuid)
758 {
759         int result;
760         gboolean available = TRUE;
761         char uuid_str[BLUETOOTH_UUID_STRING_MAX];
762
763         retv_if(uuid == NULL, FALSE);
764         retv_if(bluetooth_check_adapter() ==
765                                 BLUETOOTH_ADAPTER_DISABLED, FALSE);
766
767         BT_INIT_PARAMS();
768         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
769
770         g_strlcpy(uuid_str, uuid, sizeof(uuid_str));
771         g_array_append_vals(in_param1, uuid_str, BLUETOOTH_UUID_STRING_MAX);
772
773         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_IS_UUID_AVAILABLE,
774                 in_param1, in_param2, in_param3, in_param4, &out_param);
775
776         BT_DBG("result: %x", result);
777
778         if (result == BLUETOOTH_ERROR_NONE)
779                 available = g_array_index(out_param, gboolean, 0);
780
781         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
782
783         BT_DBG("available: %d", available);
784
785         return available;
786 }
787
788 BT_EXPORT_API int bluetooth_rfcomm_server_is_connected(const bluetooth_device_address_t *device_address, gboolean *connected)
789 {
790         GSList *l;
791         GSList *ll;
792         rfcomm_info_t *info;
793         rfcomm_conn_t *conn;
794
795         BT_CHECK_PARAMETER(device_address, return);
796         BT_CHECK_PARAMETER(connected, return);
797
798         *connected = FALSE;
799
800         for (l = rfcomm_nodes; l; l = l->next) {
801                 info = l->data;
802
803                 if (info == NULL || info->rfcomm_conns == NULL)
804                         continue;
805
806                 for (ll = info->rfcomm_conns; ll; ll = ll->next) {
807                         conn = ll->data;
808
809                         if (memcmp(device_address, &conn->addr,
810                                         sizeof(bluetooth_device_address_t)))
811                                 continue;
812
813                         *connected = TRUE;
814                         return BLUETOOTH_ERROR_NONE;
815                 }
816         }
817
818         return BLUETOOTH_ERROR_NONE;
819 }
820
821 BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept(int id, int max_pending_connection)
822 {
823 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
824         rfcomm_info_t *info;
825 #else
826         int result;
827         gboolean native_service = TRUE;
828 #endif
829
830         BT_CHECK_ENABLED(return);
831         if (id < 0) {
832                 BT_ERR("Invalid ID");
833                 return BLUETOOTH_ERROR_INVALID_PARAM;
834         }
835
836 #ifdef TIZEN_FEATURE_BT_DPM
837         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
838                 BT_ERR("Not allow to use SPP profile");
839                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
840         }
841 #endif
842
843 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
844         BT_INFO("RFCOMM Listen & accept from app");
845
846         info = __find_rfcomm_info_with_id(id);
847         if (info == NULL)
848                 return BLUETOOTH_ERROR_INVALID_PARAM;
849
850         bt_register_profile_info_t profile_info;
851         int result;
852
853         profile_info.authentication = TRUE;
854         profile_info.authorization = TRUE;
855         profile_info.obj_path = info->path;
856         profile_info.role = NULL;
857         profile_info.service = info->uuid;
858         profile_info.uuid = info->uuid;
859
860         BT_INFO("uuid %s", profile_info.uuid);
861         result = _bt_register_profile(&profile_info, TRUE);
862
863         return result;
864 #else
865         BT_INIT_PARAMS();
866         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
867
868         g_array_append_vals(in_param1, &id, sizeof(int));
869         g_array_append_vals(in_param2, &max_pending_connection, sizeof(int));
870         g_array_append_vals(in_param3, &native_service, sizeof(gboolean));
871
872         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN,
873                 in_param1, in_param2, in_param3, in_param4, &out_param);
874
875         BT_DBG("result: %x", result);
876
877         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
878
879         return result;
880 #endif
881 }
882
883 BT_EXPORT_API int bluetooth_rfcomm_listen_and_accept_ex(const char *uuid,
884                                         int max_pending_connection,
885                                         const char *bus_name, const char *path)
886 {
887 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
888         rfcomm_info_t *info;
889
890         BT_CHECK_ENABLED(return);
891
892 #ifdef TIZEN_FEATURE_BT_DPM
893         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
894                 BT_ERR("Not allow to use SPP profile");
895                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
896         }
897 #endif
898
899         BT_INFO("RFCOMM Listen & accept from app");
900
901         info = __find_rfcomm_info_with_uuid(uuid);
902         if (info == NULL)
903                 return BLUETOOTH_ERROR_INVALID_PARAM;
904
905         bt_register_profile_info_t profile_info;
906         int result;
907
908         profile_info.authentication = TRUE;
909         profile_info.authorization = TRUE;
910         profile_info.obj_path = info->path;
911         profile_info.role = NULL;
912         profile_info.service = info->uuid;
913         profile_info.uuid = info->uuid;
914
915         BT_INFO("uuid %s", profile_info.uuid);
916         result = _bt_register_profile_ex(&profile_info, TRUE, bus_name, path);
917
918         return result;
919 #else
920         return BLUETOOTH_ERROR_NOT_SUPPORT;
921 #endif
922 }
923
924 BT_EXPORT_API int bluetooth_rfcomm_listen(int id, int max_pending_connection)
925 {
926 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
927         rfcomm_info_t *info;
928 #else
929         int result;
930         gboolean native_service = FALSE;
931 #endif
932
933         BT_CHECK_ENABLED(return);
934         if (id < 0) {
935                 BT_ERR("Invalid ID");
936                 return BLUETOOTH_ERROR_INVALID_PARAM;
937         }
938
939 #ifdef TIZEN_FEATURE_BT_DPM
940         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
941                 BT_ERR("Not allow to use SPP profile");
942                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
943         }
944 #endif
945
946 #ifdef TIZEN_FEATURE_BT_RFCOMM_DIRECT
947         BT_INFO("RFCOMM Listen");
948
949         info = __find_rfcomm_info_with_id(id);
950         if (info == NULL)
951                 return BLUETOOTH_ERROR_INVALID_PARAM;
952
953         bt_register_profile_info_t profile_info;
954         int result;
955
956         profile_info.authentication = TRUE;
957         profile_info.authorization = TRUE;
958         profile_info.obj_path = info->path;
959         profile_info.role = NULL;
960         profile_info.service = info->uuid;
961         profile_info.uuid = info->uuid;
962         BT_INFO("UUID %s", info->uuid);
963         BT_INFO("PATH %s", info->path);
964         result = _bt_register_profile_platform(&profile_info, TRUE);
965         if (result != BLUETOOTH_ERROR_NONE)
966                 return result;
967
968         return _bt_register_osp_server_in_agent(BT_RFCOMM_SERVER, info->uuid,
969                                                 info->path, id);
970
971 #else
972         BT_INIT_PARAMS();
973         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
974
975         g_array_append_vals(in_param1, &id, sizeof(int));
976         g_array_append_vals(in_param2, &max_pending_connection, sizeof(int));
977         g_array_append_vals(in_param3, &native_service, sizeof(gboolean));
978
979         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_LISTEN,
980                 in_param1, in_param2, in_param3, in_param4, &out_param);
981
982         BT_DBG("result: %x", result);
983
984         if (result == BLUETOOTH_ERROR_NONE)
985                 _bt_add_server(id);
986
987         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
988
989         return result;
990 #endif
991 }
992
993 BT_EXPORT_API int bluetooth_rfcomm_accept_connection(int server_fd)
994 {
995         int result;
996
997         BT_CHECK_ENABLED(return);
998
999 #ifdef TIZEN_FEATURE_BT_DPM
1000         if (_bt_check_dpm(BT_DPM_SPP, NULL) == BT_DPM_RESTRICTED) {
1001                 BT_ERR("Not allow to use SPP profile");
1002                 return BLUETOOTH_ERROR_DEVICE_POLICY_RESTRICTION;
1003         }
1004 #endif
1005
1006         if (server_fd < 0) {
1007                 BT_ERR("Invalid FD");
1008                 return BLUETOOTH_ERROR_INVALID_PARAM;
1009         }
1010
1011         BT_INIT_PARAMS();
1012         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1013
1014         g_array_append_vals(in_param1, &server_fd, sizeof(int));
1015
1016         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_ACCEPT_CONNECTION,
1017                 in_param1, in_param2, in_param3, in_param4, &out_param);
1018
1019         BT_DBG("result: %x", result);
1020
1021         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1022
1023         return result;
1024 }
1025
1026 BT_EXPORT_API int bluetooth_rfcomm_reject_connection(int server_fd)
1027 {
1028         int result;
1029
1030         BT_CHECK_ENABLED(return);
1031
1032         if (server_fd < 0) {
1033                 BT_ERR("Invalid FD");
1034                 return BLUETOOTH_ERROR_INVALID_PARAM;
1035         }
1036
1037         BT_INFO("+");
1038
1039         BT_INIT_PARAMS();
1040         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1041
1042         g_array_append_vals(in_param1, &server_fd, sizeof(int));
1043
1044         result = _bt_send_request(BT_BLUEZ_SERVICE, BT_RFCOMM_REJECT_CONNECTION,
1045                 in_param1, in_param2, in_param3, in_param4, &out_param);
1046
1047         BT_DBG("result: %x", result);
1048
1049         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
1050
1051         return result;
1052 }
1053