Fix Coverity Issue
[platform/core/connectivity/bluetooth-frwk.git] / bt-api / bt-l2cap-le-client.c
1 /*
2  * Copyright (c) 2022 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 #include <sys/socket.h>
21
22 #include "bluetooth-api.h"
23 #include "bt-internal-types.h"
24
25 #include "bt-common.h"
26 #include "bt-request-sender.h"
27 #include "bt-event-handler.h"
28
29 /* Variable for privilege, only for write API,
30   before we should reduce time to bt-service dbus calling
31   -1 : Don't have a permission to access API
32   0 : Initial value, not yet check
33   1 : Have a permission to access API
34 */
35 static int privilege_token;
36
37 GSList *l2cap_le_clients;
38
39 typedef struct {
40         int psm;
41         char *remote_addr;
42         int sock_fd;
43         int watch_id;
44 } l2cap_le_client_conn_info_t;
45
46 static gboolean __is_error_by_disconnect(GError *err)
47 {
48         return !g_strcmp0(err->message, "Connection reset by peer") ||
49                 !g_strcmp0(err->message, "Connection timed out") ||
50                 !g_strcmp0(err->message, "Software caused connection abort");
51 }
52
53 static l2cap_le_client_conn_info_t *__find_l2cap_le_conn_info_with_fd(int fd)
54 {
55         GSList *l;
56
57         BT_DBG("+");
58
59         for (l = l2cap_le_clients; l != NULL; l = l->next) {
60                 l2cap_le_client_conn_info_t *info = l->data;
61
62                 if (info && info->sock_fd == fd) {
63                         BT_INFO("Match found");
64                         return info;
65                 }
66         }
67
68         BT_DBG("-");
69         return NULL;
70 }
71
72 static void __l2cap_le_remove_client_conn_info_t(
73                                                 l2cap_le_client_conn_info_t *info)
74 {
75         ret_if(info == NULL);
76
77         l2cap_le_clients = g_slist_remove(l2cap_le_clients, info);
78         g_free(info->remote_addr);
79
80         if (info->sock_fd > 0) {
81             shutdown(info->sock_fd, SHUT_RDWR);
82             close(info->sock_fd);
83         }
84
85         if (info->watch_id > 0)
86                 g_source_remove(info->watch_id);
87         g_free(info);
88 }
89
90 static void __bt_l2cap_le_client_disconnected(
91                                                 l2cap_le_client_conn_info_t *conn_info)
92 {
93         bluetooth_l2cap_le_disconnection_t disconn_info;
94         bt_event_info_t *event_info = NULL;
95
96         BT_DBG("+");
97
98         ret_if(conn_info == NULL);
99
100         event_info = _bt_event_get_cb_data(BT_L2CAP_LE_CLIENT_EVENT);
101         ret_if(event_info == NULL);
102
103         memset(&disconn_info, 0x00, sizeof(bluetooth_l2cap_le_disconnection_t));
104         disconn_info.device_role = L2CAP_LE_ROLE_CLIENT;
105         disconn_info.socket_fd = conn_info->sock_fd;
106         disconn_info.psm = conn_info->psm;
107         _bt_convert_addr_string_to_type(disconn_info.device_addr.addr,
108                         conn_info->remote_addr);
109
110         BT_INFO("Disconnection Result[%d] BT_ADDRESS[%s] FD[%d] PSM[%d]",
111                         BLUETOOTH_ERROR_NONE, conn_info->remote_addr,
112                         conn_info->sock_fd, conn_info->psm);
113         _bt_common_event_cb(BLUETOOTH_EVENT_L2CAP_LE_DISCONNECTED,
114                         BLUETOOTH_ERROR_NONE, &disconn_info,
115                         event_info->cb, event_info->user_data);
116
117         BT_DBG("-");
118 }
119
120 static gboolean __client_data_received_cb(GIOChannel *chan, GIOCondition cond,
121                                                 gpointer data)
122 {
123         bt_event_info_t *event_info;
124         bluetooth_l2cap_le_received_data_t data_r;
125         l2cap_le_client_conn_info_t *conn_info;
126         int fd;
127         gsize len = 0;
128         char *buffer;
129         GError *err = NULL;
130         GIOStatus status = G_IO_STATUS_NORMAL;
131         static int resource_unavailable_cnt = 0;
132
133         BT_DBG("+");
134
135         fd = g_io_channel_unix_get_fd(chan);
136         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
137                 BT_ERR_C("L2cap_le Client disconnected: %d", fd);
138                 goto fail;
139         }
140
141         buffer = g_malloc0(BT_L2CAP_LE_BUFFER_LEN + 1);
142         g_io_channel_set_buffer_size(chan, BT_L2CAP_LE_BUFFER_LEN);
143         status = g_io_channel_read_chars(chan, buffer, BT_L2CAP_LE_BUFFER_LEN,
144                         &len, &err);
145         if (status != G_IO_STATUS_NORMAL) {
146                 BT_ERR("IO Channel read is failed with %d", status);
147                 g_free(buffer);
148                 if (err) {
149                         BT_ERR("IO Channel read error [%s]", err->message);
150                         if (status == G_IO_STATUS_ERROR &&
151                                         __is_error_by_disconnect(err)) {
152                                 BT_ERR("cond : %d", cond);
153                                 g_error_free(err);
154                                 goto fail;
155                         }
156                         g_error_free(err);
157                 }
158
159                 if (status == G_IO_STATUS_ERROR ||
160                         status == G_IO_STATUS_EOF) {
161                         goto fail;
162                 } else if (status == G_IO_STATUS_AGAIN) {
163                         resource_unavailable_cnt++;
164                         if (resource_unavailable_cnt > 10)
165                                 goto fail;
166                 }
167
168                 return TRUE;
169         }
170         resource_unavailable_cnt = 0;
171
172         if (len == 0) {
173                 BT_ERR("Length is zero, remote end hang up");
174                 g_free(buffer);
175                 goto fail;
176         }
177
178         BT_DBG("fd: %d, len: %zd, buffer: %s", fd, len, buffer);
179
180         event_info = _bt_event_get_cb_data(BT_L2CAP_LE_CLIENT_EVENT);
181         if (event_info == NULL) {
182                 BT_INFO("event_info == NULL");
183                 g_free(buffer);
184                 return TRUE;
185         }
186
187         data_r.socket_fd = fd;
188         data_r.buffer_size = len;
189         data_r.buffer = buffer;
190
191         _bt_common_event_cb(BLUETOOTH_EVENT_L2CAP_LE_DATA_RECEIVED,
192                         BLUETOOTH_ERROR_NONE, &data_r,
193                         event_info->cb, event_info->user_data);
194
195         g_free(buffer);
196         return TRUE;
197
198 fail:
199         conn_info = __find_l2cap_le_conn_info_with_fd(fd);
200         if (conn_info) {
201                 BT_INFO("Disconnecting client, fd %d", fd);
202                 __bt_l2cap_le_client_disconnected(conn_info);
203                 __l2cap_le_remove_client_conn_info_t(conn_info);
204         } else {
205                 BT_ERR("l2cap_le client conn_info not found");
206         }
207
208         BT_DBG("-");
209         return FALSE;
210 }
211
212 static void __l2cap_le_client_connection_create_watch(
213                                                 l2cap_le_client_conn_info_t *conn_info)
214 {
215         GIOChannel *data_io;
216
217         BT_DBG("+");
218
219         ret_if(NULL == conn_info);
220
221         data_io = g_io_channel_unix_new(conn_info->sock_fd);
222         g_io_channel_set_encoding(data_io, NULL, NULL);
223         g_io_channel_set_flags(data_io, G_IO_FLAG_NONBLOCK, NULL);
224         conn_info->watch_id = g_io_add_watch(data_io,
225                         G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
226                         __client_data_received_cb, NULL);
227         g_io_channel_unref(data_io);
228
229         BT_DBG("-");
230 }
231
232 static void __bt_l2cap_le_handle_new_client_connection(
233                                                 bluetooth_l2cap_le_connection_t *info)
234 {
235         l2cap_le_client_conn_info_t *conn_info;
236
237         BT_DBG("+");
238
239         ret_if(NULL == info);
240
241         conn_info = g_malloc0(sizeof(l2cap_le_client_conn_info_t));
242         conn_info->remote_addr = g_malloc0(BT_ADDRESS_STRING_SIZE);
243         _bt_convert_addr_type_to_string(
244                         conn_info->remote_addr, info->device_addr.addr);
245         conn_info->sock_fd = info->socket_fd;
246         conn_info->psm = info->psm;
247
248         BT_INFO("Address:%s, Socket: %d, psm: %d",
249                         conn_info->remote_addr, conn_info->sock_fd, conn_info->psm);
250
251         l2cap_le_clients = g_slist_append(l2cap_le_clients, conn_info);
252         __l2cap_le_client_connection_create_watch(conn_info);
253
254         BT_DBG("-");
255 }
256
257 static void __async_req_cb_with_unix_fd_list(GDBusProxy *proxy,
258                                                 GAsyncResult *res, gpointer user_data)
259 {
260         int result = BLUETOOTH_ERROR_NONE;
261         int event_type = BT_LE_ADAPTER_EVENT;
262         gboolean fail = false;
263
264         bt_req_info_t *cb_data = user_data;
265         bluetooth_event_param_t bt_event;
266         GArray *out_param1 = NULL;
267         GUnixFDList *out_fd_list = NULL;
268         bt_l2cap_user_info_t *l2cap_user_info = NULL;
269
270         BT_DBG("+");
271
272         if (cb_data)
273                 l2cap_user_info = (bt_l2cap_user_info_t *)cb_data->user_data;
274
275         if (l2cap_user_info)
276                 cb_data->user_data = (void *)l2cap_user_info->user_data;
277
278         _bt_get_fd_list_info(proxy, res, user_data, &bt_event, &out_param1,
279                 &event_type, &out_fd_list, &result, &fail);
280
281         if (fail) {
282                 BT_INFO("Connection failed due to error: %d", result);
283                 bluetooth_l2cap_le_connection_t *conn_info;
284
285                 conn_info = g_malloc0(sizeof(bluetooth_l2cap_le_connection_t));
286                 memset(conn_info, 0x00, sizeof(bluetooth_l2cap_le_connection_t));
287
288                 if (l2cap_user_info) {
289                         conn_info->psm = l2cap_user_info->psm;
290                         memcpy(&conn_info->device_addr, &l2cap_user_info->device_addr,
291                                 sizeof(bluetooth_device_address_t));
292                 }
293
294                 bt_event.param_data = (void *)conn_info;
295                 goto failed;
296         }
297
298         if (!cb_data)
299                 goto done;
300
301         if (result == BLUETOOTH_ERROR_NONE && out_param1) {
302                 if (BT_L2CAP_LE_CLIENT_CONNECT == cb_data->service_function) {
303                         int *fd_list_array;
304                         int len = 0;
305                         bluetooth_l2cap_le_connection_t *conn_info;
306
307                         conn_info = (bluetooth_l2cap_le_connection_t *)bt_event.param_data;
308                         if (!out_fd_list) {
309                                 BT_ERR("out_fd_list is NULL");
310                                 goto failed;
311                         }
312
313                         fd_list_array = g_unix_fd_list_steal_fds(out_fd_list, &len);
314                         BT_INFO("Num fds in fd_list is : %d, fd_list[0]: %d", len, fd_list_array[0]);
315                         conn_info->socket_fd = fd_list_array[0];
316
317                         BT_INFO("conn_info->socket_fd: %d", conn_info->socket_fd);
318                         __bt_l2cap_le_handle_new_client_connection(conn_info);
319
320                         if (cb_data->cb != NULL) {
321                                 /* Send client connected event */
322                                 bt_event.result = result;
323                                 BT_INFO("send client connected event event_type[%d], result=[%d]", event_type, result);
324                                 ((bluetooth_cb_func_ptr)cb_data->cb)(
325                                         bt_event.event, &bt_event, cb_data->user_data);
326                         }
327
328                         g_free(fd_list_array);
329                         g_object_unref(out_fd_list);
330                 }
331                 goto done;
332         }
333
334 failed:
335         if (cb_data->cb == NULL)
336                 goto done;
337
338         /* Only if fail case, call the callback function*/
339         bt_event.result = result;
340
341         BT_INFO("send fail event event_type[%d], result=[%d]", event_type, result);
342         if (event_type == BT_L2CAP_LE_CLIENT_EVENT) {
343                 BT_INFO("l2cap_le client event");
344                 ((bluetooth_cb_func_ptr)cb_data->cb)(bt_event.event,
345                         &bt_event, cb_data->user_data);
346         } else {
347                 BT_INFO("Not handled event type : %d", event_type);
348         }
349 done:
350         if (out_param1)
351                 g_array_free(out_param1, TRUE);
352
353         g_free(l2cap_user_info);
354         g_free(cb_data);
355         BT_DBG("-");
356 }
357
358 BT_EXPORT_API int bluetooth_l2cap_le_connect(
359                 const bluetooth_device_address_t *remote_bt_address, int psm)
360 {
361         int result;
362         bt_user_info_t *user_info;
363         int t_psm;
364         bt_l2cap_user_info_t *l2cap_user_info;
365
366         BT_CHECK_PARAMETER(remote_bt_address, return);
367         BT_CHECK_ENABLED_LE(return);
368
369         BT_INFO_C("connect l2cap_le psm %d", psm);
370         user_info = _bt_get_user_data(BT_COMMON);
371         retv_if(user_info->cb == NULL, BLUETOOTH_ERROR_INTERNAL);
372
373
374         if (_bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_CLIENT_CONNECT)
375              == BLUETOOTH_ERROR_PERMISSION_DEINED) {
376                 BT_ERR("Don't have a privilege to use this API");
377         }
378
379         l2cap_user_info = g_malloc0(sizeof(bt_l2cap_user_info_t));
380         l2cap_user_info->psm = psm;
381         l2cap_user_info->user_data = user_info->user_data;
382         memcpy(&l2cap_user_info->device_addr, remote_bt_address,
383                         sizeof(bluetooth_device_address_t));
384
385         BT_INIT_PARAMS();
386         BT_ALLOC_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
387
388         g_array_append_vals(in_param1, remote_bt_address,
389                                 sizeof(bluetooth_device_address_t));
390
391         t_psm = psm;
392         g_array_append_vals(in_param2, &t_psm, sizeof(int));
393
394         result = _bt_send_request_async_with_unix_fd_list(BT_BLUEZ_SERVICE,
395                                 BT_L2CAP_LE_CLIENT_CONNECT,
396                                 in_param1, in_param2,
397                                 in_param3, in_param4,
398                                 user_info->cb, (void *)l2cap_user_info,
399                                 NULL, (GAsyncReadyCallback)__async_req_cb_with_unix_fd_list);
400
401         BT_INFO("result: %x", result);
402
403         BT_FREE_PARAMS(in_param1, in_param2, in_param3, in_param4, out_param);
404
405         return result;
406 }
407
408 BT_EXPORT_API int bluetooth_l2cap_le_client_is_connected(
409                 const bluetooth_device_address_t *device_address, gboolean *connected)
410 {
411         GSList *l;
412         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
413
414         BT_CHECK_PARAMETER(device_address, return);
415         BT_CHECK_PARAMETER(connected, return);
416
417         BT_DBG("+");
418
419         *connected = FALSE;
420         _bt_convert_addr_type_to_string(address, (unsigned char *)device_address->addr);
421         BT_INFO("Client address: [%s]", address);
422
423         for (l = l2cap_le_clients; l != NULL; l = l->next) {
424                 l2cap_le_client_conn_info_t *info = l->data;
425
426                 if (info && !strncasecmp(info->remote_addr, address, BT_ADDRESS_STRING_SIZE)) {
427                         BT_INFO("Match found");
428                         *connected = TRUE;
429                         return BLUETOOTH_ERROR_NONE;
430                 }
431         }
432
433         BT_DBG("-");
434         return BLUETOOTH_ERROR_NONE;
435 }
436
437 BT_EXPORT_API int bluetooth_l2cap_le_disconnect(int socket_fd)
438 {
439         l2cap_le_client_conn_info_t *conn_info;
440
441         BT_INFO_C("<<<<<<<<< L2CAP_LE Disconnect request from app >>>>>>>>");
442
443         BT_CHECK_ENABLED_ANY(return);
444         retv_if(socket_fd < 0, BLUETOOTH_ERROR_INVALID_PARAM);
445
446         if (_bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_SOCKET_DISCONNECT)
447                         == BLUETOOTH_ERROR_PERMISSION_DEINED) {
448                 BT_ERR("Don't have a privilege to use this API");
449         }
450
451         BT_INFO("FD %d", socket_fd);
452
453         conn_info = __find_l2cap_le_conn_info_with_fd(socket_fd);
454         if (conn_info == NULL) {
455                 BT_INFO("Could not find in client, so check in server");
456                 /* Check for fd in server list and perform the disconnection if present */
457                 return bluetooth_l2cap_le_server_disconnect(socket_fd);
458         }
459
460         if (conn_info->watch_id <= 0) {
461                 BT_ERR("Invalid state");
462                 return BLUETOOTH_ERROR_NOT_CONNECTED;
463         }
464
465         __bt_l2cap_le_client_disconnected(conn_info);
466         __l2cap_le_remove_client_conn_info_t(conn_info);
467
468         return BLUETOOTH_ERROR_NONE;
469 }
470
471 static int __write_all(int fd, const char *buf, int len)
472 {
473         int sent = 0, try = 0;
474
475         BT_DBG("+");
476         while (len > 0) {
477                 int written;
478
479                 written = write(fd, buf, len);
480                 BT_DBG("written: %d, len %d", written, len);
481                 if (written < 0) {
482                         if (errno == EINTR || errno == EAGAIN) {
483                                 try++;
484                                 if (try <= 49)
485                                         continue;
486                         }
487                         return -1;
488                 }
489
490                 if (!written)
491                         return 0;
492
493                 len -= written;
494                 buf += written;
495                 sent += written;
496                 try = 0;
497         }
498
499         BT_DBG("-");
500         return sent;
501 }
502
503 BT_EXPORT_API int bluetooth_l2cap_le_write(int fd, const char *buf, int length)
504 {
505         int result;
506
507         BT_CHECK_ENABLED_LE(return);
508         BT_CHECK_PARAMETER(buf, return);
509
510         if (fd < 0) {
511                 BT_ERR("Invalid FD");
512                 return BLUETOOTH_ERROR_INVALID_PARAM;
513         }
514
515         retv_if(length <= 0, BLUETOOTH_ERROR_INVALID_PARAM);
516
517         switch (privilege_token) {
518         case 0:
519                 result = _bt_check_privilege_le(BT_CHECK_PRIVILEGE, BT_L2CAP_LE_SOCKET_WRITE);
520
521                 if (result == BLUETOOTH_ERROR_NONE) {
522                         privilege_token = 1; /* Have a permission */
523                 } else if (result == BLUETOOTH_ERROR_PERMISSION_DEINED) {
524                         BT_ERR("Don't have a privilege to use this API");
525                         privilege_token = -1; /* Don't have a permission */
526                         return BLUETOOTH_ERROR_PERMISSION_DEINED;
527                 } else {
528                         BT_ERR("Some error occurred");
529                         /* Just break - It is not related with permission error */
530                 }
531                 break;
532         case 1:
533                 /* Already have a privilege */
534                 break;
535         case -1:
536                 return BLUETOOTH_ERROR_PERMISSION_DEINED;
537         default:
538                 /* Invalid privilge token value */
539                 return BLUETOOTH_ERROR_INTERNAL;
540         }
541
542         result = __write_all(fd, buf, length);
543
544         return result;
545 }
546
547 BT_EXPORT_API int bluetooth_l2cap_le_get_max_buffer_size(int *size)
548 {
549         BT_CHECK_ENABLED_LE(return);
550         BT_CHECK_PARAMETER(size, return);
551
552         *size = BT_L2CAP_LE_BUFFER_LEN;
553
554         return BLUETOOTH_ERROR_NONE;
555 }