Add the sender name in signal subscribe function
[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                         _bt_free_info_from_invocation_list(req_info);
95                         g_array_free(out_param, TRUE);
96                         break;
97                 }
98                 case BT_RFCOMM_LISTEN_AND_ACCEPT:
99                 case BT_RFCOMM_LISTEN: {
100                         GUnixFDList *fd_list = NULL;
101                         GError *error = NULL;
102                         int *socket_fd = user_data;
103
104                         BT_INFO("Server socket fd: %d", *socket_fd);
105
106                         g_array_append_vals(out_param, user_data, size);
107
108                         /* Add socket fd to unix_fd_list */
109                         fd_list = g_unix_fd_list_new();
110                         g_unix_fd_list_append(fd_list, *socket_fd, &error);
111                         g_assert_no_error(error);
112
113                         _bt_service_method_return_with_unix_fd_list(
114                                         req_info->context, out_param, result, fd_list);
115
116                         close(*socket_fd);
117                         g_object_unref(fd_list);
118
119                         _bt_free_info_from_invocation_list(req_info);
120                         g_array_free(out_param, TRUE);
121                         break;
122                 }
123                 default:
124                         BT_ERR("Unknown Service function");
125                 }
126         }
127
128         return;
129 }
130
131 static void __bt_rfcomm_socket_conn_cb(int result, int sock_fd, char *address, char *uuid, int chan)
132 {
133         bluetooth_rfcomm_connection_t conn_info;
134
135         ret_if(NULL == address);
136         ret_if(NULL == uuid);
137
138         BT_DBG("+");
139
140         BT_INFO("result: %d, socket_fd: %d, address: %s, uuid: %s, chan: %d",
141                         result, sock_fd, address, uuid, chan);
142
143         /* Fill RFCOMM connection structure and send reply to pending request */
144         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
145         conn_info.socket_fd = sock_fd;
146         conn_info.device_role = RFCOMM_ROLE_CLIENT;
147         g_strlcpy(conn_info.uuid, uuid, BLUETOOTH_UUID_STRING_MAX);
148         _bt_convert_addr_string_to_type(conn_info.device_addr.addr, address);
149
150         __bt_rfcomm_reply_pending_request(
151                         result, BT_RFCOMM_CLIENT_CONNECT,
152                         (void *)&conn_info, sizeof(bluetooth_rfcomm_connection_t));
153
154         BT_DBG("-");
155 }
156
157 int _bt_rfcomm_connect_using_uuid(bluetooth_device_address_t *device_address, char *remote_uuid)
158 {
159         int result;
160         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
161
162         BT_DBG("+");
163
164         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
165         retv_if(NULL == remote_uuid, BLUETOOTH_ERROR_INVALID_PARAM);
166
167         _bt_convert_addr_type_to_string(address, device_address->addr);
168         BT_INFO("RFCOMM connect called for [%s], uuid: [%s]", address, remote_uuid);
169
170         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
171                         address, remote_uuid, -1, __bt_rfcomm_socket_conn_cb);
172         if (BLUETOOTH_ERROR_NONE != result) {
173                 BT_ERR("_bt_socket_client_connect failed");
174                 return result;
175         }
176
177         BT_DBG("-");
178         return BLUETOOTH_ERROR_NONE;
179 }
180
181 /* Range of the Channel : 0 <= channel <= 30 */
182 int _bt_rfcomm_connect_using_channel(bluetooth_device_address_t *device_address, char *chan_str)
183 {
184         int channel;
185         int result = BLUETOOTH_ERROR_NONE;
186         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
187
188         BT_DBG("+");
189
190         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
191         retv_if(NULL == chan_str, BLUETOOTH_ERROR_INVALID_PARAM);
192
193         _bt_convert_addr_type_to_string(address, device_address->addr);
194         channel = atoi(chan_str);
195         BT_INFO("RFCOMM connect called for [%s], channel: %d", address, channel);
196
197         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
198                         address, NULL, channel, __bt_rfcomm_socket_conn_cb);
199         if (BLUETOOTH_ERROR_NONE != result) {
200                 BT_ERR("_bt_socket_client_connect failed");
201                 return result;
202         }
203
204         BT_DBG("-");
205         return result;
206 }
207
208 gboolean __bt_send_rfcomm_server_fd(gpointer user_data)
209 {
210         BT_DBG("+");
211
212         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
213                         BT_RFCOMM_LISTEN, user_data, sizeof(int));
214
215         g_free(user_data);
216         BT_DBG("-");
217         return FALSE;
218 }
219
220 gboolean __bt_send_rfcomm_server_fd_with_accept(gpointer user_data)
221 {
222         BT_DBG("+");
223
224         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
225                         BT_RFCOMM_LISTEN_AND_ACCEPT, user_data, sizeof(int));
226
227         g_free(user_data);
228         BT_DBG("-");
229         return FALSE;
230 }
231
232 int _bt_rfcomm_socket_listen(char *svc_name, char *uuid, bool accept)
233 {
234         int channel = 0;
235         int sock_fd;
236
237         BT_DBG("+");
238
239         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
240         retv_if(NULL == uuid, BLUETOOTH_ERROR_INVALID_PARAM);
241
242         BT_INFO("RFCOMM create socket called with svc name: [%s], uuid: [%s]", svc_name, uuid);
243         sock_fd = _bt_socket_listen(SOCK_TYPE_RFCOMM, svc_name, uuid, channel);
244         if (sock_fd < 0) {
245                 BT_ERR("_bt_socket_listen failed");
246                 return BLUETOOTH_ERROR_INTERNAL;
247         }
248
249         if (accept == false)
250                 g_idle_add(__bt_send_rfcomm_server_fd, g_memdup(&sock_fd, sizeof(int)));
251         else
252                 g_idle_add(__bt_send_rfcomm_server_fd_with_accept, g_memdup(&sock_fd, sizeof(int)));
253
254         BT_DBG("-");
255         return sock_fd;
256 }
257
258 static bt_rfcomm_conn_info_t* __bt_find_conn_from_list(const char *sender, int role, int socket_fd)
259 {
260         GSList *l;
261         bt_rfcomm_conn_info_t *conn_info;
262
263         retv_if(NULL == sender, NULL);
264
265         for (l = rfcomm_conn_list; l != NULL; l = g_slist_next(l)) {
266                 conn_info = l->data;
267                 if (g_strcmp0(conn_info->sender, sender) == 0) {
268                         if (socket_fd == conn_info->socket_fd &&
269                                  role == conn_info->role)
270                                 return conn_info;
271                 }
272         }
273
274         return NULL;
275 }
276
277 int _bt_rfcomm_conn_added(char *svc_name, int role, int socket_fd)
278 {
279         bt_rfcomm_conn_info_t *conn_info = NULL;
280
281         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
282
283         if (__bt_find_conn_from_list(svc_name, role, socket_fd) != NULL) {
284                 BT_ERR("Socket fd already exist");
285                 return BLUETOOTH_ERROR_INVALID_PARAM;
286         }
287
288         BT_INFO("RFCOMM is connected: [%s], [%d], [%d]", svc_name, role, socket_fd);
289
290         conn_info = g_malloc0(sizeof(bt_rfcomm_conn_info_t));
291
292         if (conn_info == NULL)
293                 return BLUETOOTH_ERROR_MEMORY_ALLOCATION;
294
295         _bt_start_connect_time();
296
297         conn_info->sender = g_strdup(svc_name);
298         conn_info->role = role;
299         conn_info->socket_fd = socket_fd;
300
301         rfcomm_conn_list = g_slist_append(rfcomm_conn_list, conn_info);
302
303         return BLUETOOTH_ERROR_NONE;
304 }
305
306 int _bt_rfcomm_conn_removed(char *svc_name, int role, int socket_fd)
307 {
308         bt_rfcomm_conn_info_t *conn_info = NULL;
309
310         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
311
312         BT_INFO("RFCOMM is connected: [%s], [%d], [%d]", svc_name, role, socket_fd);
313
314         /* Find the first connection */
315         conn_info = __bt_find_conn_from_list(svc_name, role, socket_fd);
316
317         if (conn_info == NULL) {
318                 BT_ERR("No socket fd is in list");
319                 return BLUETOOTH_ERROR_INVALID_PARAM;
320         }
321
322         _bt_stop_connect_time();
323
324         rfcomm_conn_list = g_slist_remove(rfcomm_conn_list, conn_info);
325         g_free(conn_info->sender);
326         g_free(conn_info);
327
328         return BLUETOOTH_ERROR_NONE;
329 }
330
331 void _bt_rfcomm_check_termination(const char *name)
332 {
333         GSList *l;
334         bt_rfcomm_conn_info_t *conn_info = NULL;
335
336         ret_if(NULL == name);
337
338         for (l = rfcomm_conn_list; l != NULL; ) {
339                 conn_info = l->data;
340                 l = g_slist_next(l);
341                 if (g_strcmp0(conn_info->sender, name) == 0) {
342                         _bt_rfcomm_conn_removed((char *)name,
343                                                 conn_info->role,
344                                                 conn_info->socket_fd);
345                 }
346         }
347
348         /* Cleanup osp server */
349         _bt_unregister_osp_server_in_agent_by_sender(name);
350 }
351
352 static void __bt_free_rfcomm_conn(bt_rfcomm_conn_info_t *conn_info)
353 {
354         g_free(conn_info->sender);
355         g_free(conn_info);
356 }
357
358 void _bt_rfcomm_all_conn_removed(void)
359 {
360         g_slist_free_full(rfcomm_conn_list, (GDestroyNotify)__bt_free_rfcomm_conn);
361         rfcomm_conn_list = NULL;
362 }