a7558ab252e163a6741a5640176c6dcec1a44471
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / rfcomm / bt-service-rfcomm.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Author:  Atul Kumar Rai <a.rai@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <glib.h>
24 #include <gio/gio.h>
25 #include <gio/gunixfdlist.h>
26 #include <dlog.h>
27 #include <string.h>
28
29 #include "bluetooth-api.h"
30 #include "bt-internal-types.h"
31 #include "bt-request-handler.h"
32 #include "bt-service-util.h"
33 #include "bt-service-event.h"
34 #include "bt-service-common.h"
35 #include "bt-service-rfcomm.h"
36 #include "bt-service-socket.h"
37 #include "bt-service-battery-monitor.h"
38
39 typedef struct {
40         char *sender;
41         int role;
42         int socket_fd;
43 } bt_rfcomm_conn_info_t;
44
45 static GSList *rfcomm_conn_list = NULL;
46
47 static void __bt_rfcomm_reply_pending_request(int result,
48                 int service_function, void *user_data, unsigned int size)
49 {
50         GSList *l;
51         GArray *out_param;
52         invocation_info_t *req_info;
53
54         /* Get method invocation context */
55         for (l = _bt_get_invocation_list(); l != NULL; ) {
56                 req_info = l->data;
57                 l = g_slist_next(l);
58                 if (req_info == NULL || req_info->service_function != service_function)
59                         continue;
60
61                 /* Create out param */
62                 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
63
64                 switch (service_function) {
65                 case BT_RFCOMM_CLIENT_CONNECT: {
66                         GUnixFDList *fd_list = NULL;
67                         GError *error = NULL;
68                         char address[BT_ADDRESS_STRING_SIZE];
69                         bluetooth_rfcomm_connection_t *ptr = user_data;
70
71                         /* Check if connect address matched with requested address */
72                         _bt_convert_addr_type_to_string(address, ptr->device_addr.addr);
73                         if (strncasecmp(address, (char *)req_info->user_data,
74                                                 BT_ADDRESS_STRING_SIZE)) {
75                                 BT_INFO("RFCOMM connected addr: [%s], requested addr: [%s]",
76                                                 address, (char *)req_info->user_data);
77                                 break;
78                         }
79
80                         g_array_append_vals(out_param, user_data, size);
81
82                         if (BLUETOOTH_ERROR_NONE == result) {
83                                 fd_list = g_unix_fd_list_new();
84                                 g_unix_fd_list_append(fd_list, ptr->socket_fd, &error);
85                                 g_assert_no_error(error);
86                                 close(ptr->socket_fd);
87                         }
88
89                         _bt_service_method_return_with_unix_fd_list(
90                                         req_info->context, out_param, result, fd_list);
91                         if (fd_list)
92                                 g_object_unref(fd_list);
93
94                         g_free(req_info->user_data);
95                         _bt_free_info_from_invocation_list(req_info);
96                         g_array_free(out_param, TRUE);
97                         break;
98                 }
99                 case BT_RFCOMM_LISTEN_AND_ACCEPT:
100                 case BT_RFCOMM_LISTEN: {
101                         GUnixFDList *fd_list = NULL;
102                         GError *error = NULL;
103                         int *socket_fd = user_data;
104
105                         BT_INFO("Server socket fd: %d", *socket_fd);
106
107                         g_array_append_vals(out_param, user_data, size);
108
109                         /* Add socket fd to unix_fd_list */
110                         fd_list = g_unix_fd_list_new();
111                         g_unix_fd_list_append(fd_list, *socket_fd, &error);
112                         g_assert_no_error(error);
113
114                         _bt_service_method_return_with_unix_fd_list(
115                                         req_info->context, out_param, result, fd_list);
116
117                         close(*socket_fd);
118                         g_object_unref(fd_list);
119
120                         _bt_free_info_from_invocation_list(req_info);
121                         g_array_free(out_param, TRUE);
122                         break;
123                 }
124                 default:
125                         BT_ERR("Unknown Service function");
126                 }
127         }
128
129         return;
130 }
131
132 static void __bt_rfcomm_socket_conn_cb(int result, int sock_fd, char *address, char *uuid, int chan)
133 {
134         bluetooth_rfcomm_connection_t conn_info;
135
136         ret_if(NULL == address);
137         ret_if(NULL == uuid);
138
139         BT_DBG("+");
140
141         BT_INFO("result: %d, socket_fd: %d, address: %s, uuid: %s, chan: %d",
142                         result, sock_fd, address, uuid, chan);
143
144         /* Fill RFCOMM connection structure and send reply to pending request */
145         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
146         conn_info.socket_fd = sock_fd;
147         conn_info.device_role = RFCOMM_ROLE_CLIENT;
148         g_strlcpy(conn_info.uuid, uuid, BLUETOOTH_UUID_STRING_MAX);
149         _bt_convert_addr_string_to_type(conn_info.device_addr.addr, address);
150
151         __bt_rfcomm_reply_pending_request(
152                         result, BT_RFCOMM_CLIENT_CONNECT,
153                         (void *)&conn_info, sizeof(bluetooth_rfcomm_connection_t));
154
155         BT_DBG("-");
156 }
157
158 int _bt_rfcomm_connect_using_uuid(bluetooth_device_address_t *device_address, char *remote_uuid)
159 {
160         int result;
161         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
162
163         BT_DBG("+");
164
165         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
166         retv_if(NULL == remote_uuid, BLUETOOTH_ERROR_INVALID_PARAM);
167
168         _bt_convert_addr_type_to_string(address, device_address->addr);
169         BT_INFO("RFCOMM connect called for [%s], uuid: [%s]", address, remote_uuid);
170
171         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
172                         address, remote_uuid, -1, __bt_rfcomm_socket_conn_cb);
173         if (BLUETOOTH_ERROR_NONE != result) {
174                 BT_ERR("_bt_socket_client_connect failed");
175                 return result;
176         }
177
178         BT_DBG("-");
179         return BLUETOOTH_ERROR_NONE;
180 }
181
182 /* Range of the Channel : 0 <= channel <= 30 */
183 int _bt_rfcomm_connect_using_channel(bluetooth_device_address_t *device_address, char *chan_str)
184 {
185         int channel;
186         int result = BLUETOOTH_ERROR_NONE;
187         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
188
189         BT_DBG("+");
190
191         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
192         retv_if(NULL == chan_str, BLUETOOTH_ERROR_INVALID_PARAM);
193
194         _bt_convert_addr_type_to_string(address, device_address->addr);
195         channel = atoi(chan_str);
196         BT_INFO("RFCOMM connect called for [%s], channel: %d", address, channel);
197
198         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
199                         address, NULL, channel, __bt_rfcomm_socket_conn_cb);
200         if (BLUETOOTH_ERROR_NONE != result) {
201                 BT_ERR("_bt_socket_client_connect failed");
202                 return result;
203         }
204
205         BT_DBG("-");
206         return result;
207 }
208
209 gboolean __bt_send_rfcomm_server_fd(gpointer user_data)
210 {
211         BT_DBG("+");
212
213         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
214                         BT_RFCOMM_LISTEN, user_data, sizeof(int));
215
216         g_free(user_data);
217         BT_DBG("-");
218         return FALSE;
219 }
220
221 gboolean __bt_send_rfcomm_server_fd_with_accept(gpointer user_data)
222 {
223         BT_DBG("+");
224
225         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
226                         BT_RFCOMM_LISTEN_AND_ACCEPT, user_data, sizeof(int));
227
228         g_free(user_data);
229         BT_DBG("-");
230         return FALSE;
231 }
232
233 int _bt_rfcomm_socket_listen(char *svc_name, char *uuid, bool accept)
234 {
235         int channel = 0;
236         int sock_fd;
237
238         BT_DBG("+");
239
240         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
241         retv_if(NULL == uuid, BLUETOOTH_ERROR_INVALID_PARAM);
242
243         BT_INFO("RFCOMM create socket called with svc name: [%s], uuid: [%s]", svc_name, uuid);
244         sock_fd = _bt_socket_listen(SOCK_TYPE_RFCOMM, svc_name, uuid, channel);
245         if (sock_fd < 0) {
246                 BT_ERR("_bt_socket_listen failed");
247                 return BLUETOOTH_ERROR_INTERNAL;
248         }
249
250         if (accept == false)
251                 g_idle_add(__bt_send_rfcomm_server_fd, g_memdup(&sock_fd, sizeof(int)));
252         else
253                 g_idle_add(__bt_send_rfcomm_server_fd_with_accept, g_memdup(&sock_fd, sizeof(int)));
254
255         BT_DBG("-");
256         return sock_fd;
257 }
258
259 static bt_rfcomm_conn_info_t* __bt_find_conn_from_list(const char *sender, int role, int socket_fd)
260 {
261         GSList *l;
262         bt_rfcomm_conn_info_t *conn_info;
263
264         retv_if(NULL == sender, NULL);
265
266         for (l = rfcomm_conn_list; l != NULL; l = g_slist_next(l)) {
267                 conn_info = l->data;
268                 if (g_strcmp0(conn_info->sender, sender) == 0) {
269                         if (socket_fd == conn_info->socket_fd &&
270                                  role == conn_info->role)
271                                 return conn_info;
272                 }
273         }
274
275         return NULL;
276 }
277
278 int _bt_rfcomm_conn_added(char *svc_name, int role, int socket_fd)
279 {
280         bt_rfcomm_conn_info_t *conn_info = NULL;
281
282         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
283
284         if (__bt_find_conn_from_list(svc_name, role, socket_fd) != NULL) {
285                 BT_ERR("Socket fd already exist");
286                 return BLUETOOTH_ERROR_INVALID_PARAM;
287         }
288
289         BT_INFO("RFCOMM is connected: [%s], [%d], [%d]", svc_name, role, socket_fd);
290
291         conn_info = g_malloc0(sizeof(bt_rfcomm_conn_info_t));
292
293         if (conn_info == NULL)
294                 return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
295
296         _bt_start_connect_time();
297
298         conn_info->sender = g_strdup(svc_name);
299         conn_info->role = role;
300         conn_info->socket_fd = socket_fd;
301
302         rfcomm_conn_list = g_slist_append(rfcomm_conn_list, conn_info);
303
304         return BLUETOOTH_ERROR_NONE;
305 }
306
307 int _bt_rfcomm_conn_removed(char *svc_name, int role, int socket_fd)
308 {
309         bt_rfcomm_conn_info_t *conn_info = NULL;
310
311         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
312
313         BT_INFO("RFCOMM is connected: [%s], [%d], [%d]", svc_name, role, socket_fd);
314
315         /* Find the first connection */
316         conn_info = __bt_find_conn_from_list(svc_name, role, socket_fd);
317
318         if (conn_info == NULL) {
319                 BT_ERR("No socket fd is in list");
320                 return BLUETOOTH_ERROR_INVALID_PARAM;
321         }
322
323         _bt_stop_connect_time();
324
325         rfcomm_conn_list = g_slist_remove(rfcomm_conn_list, conn_info);
326         g_free(conn_info->sender);
327         g_free(conn_info);
328
329         return BLUETOOTH_ERROR_NONE;
330 }
331
332 void _bt_rfcomm_check_termination(const char *name)
333 {
334         GSList *l;
335         bt_rfcomm_conn_info_t *conn_info = NULL;
336
337         ret_if(NULL == name);
338
339         for (l = rfcomm_conn_list; l != NULL; ) {
340                 conn_info = l->data;
341                 l = g_slist_next(l);
342                 if (g_strcmp0(conn_info->sender, name) == 0) {
343                         _bt_rfcomm_conn_removed((char *)name,
344                                                 conn_info->role,
345                                                 conn_info->socket_fd);
346                 }
347         }
348
349         /* Cleanup osp server */
350         _bt_unregister_osp_server_in_agent_by_sender(name);
351 }
352
353 static void __bt_free_rfcomm_conn(bt_rfcomm_conn_info_t *conn_info)
354 {
355         g_free(conn_info->sender);
356         g_free(conn_info);
357 }
358
359 void _bt_rfcomm_all_conn_removed(void)
360 {
361         g_slist_free_full(rfcomm_conn_list, (GDestroyNotify)__bt_free_rfcomm_conn);
362         rfcomm_conn_list = NULL;
363 }