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