9bfa821a4e5f3b2531dd9779d839c33039dbe532
[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
38 static void __bt_rfcomm_reply_pending_request(int result,
39                 int service_function, void *user_data, unsigned int size)
40 {
41         GSList *l;
42         GArray *out_param;
43         invocation_info_t *req_info;
44
45         /* Get method invocation context */
46         for (l = _bt_get_invocation_list(); l != NULL; l = g_slist_next(l)) {
47                 req_info = l->data;
48                 if (req_info == NULL || req_info->service_function != service_function)
49                         continue;
50
51                 /* Create out param */
52                 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
53
54                 switch (service_function) {
55                 case BT_RFCOMM_CLIENT_CONNECT: {
56                         GUnixFDList *fd_list = NULL;
57                         GError *error = NULL;
58                         char address[BT_ADDRESS_STRING_SIZE];
59                         bluetooth_rfcomm_connection_t *ptr = user_data;
60
61                         /* Check if connect address matched with requested address */
62                         _bt_convert_addr_type_to_string(address, ptr->device_addr.addr);
63                         if (strncasecmp(address, (char *)req_info->user_data,
64                                                 BT_ADDRESS_STRING_SIZE)) {
65                                 BT_INFO("RFCOMM connected addr: [%s], requested addr: [%s]",
66                                                 address, (char *)req_info->user_data);
67                                 break;
68                         }
69
70                         g_array_append_vals(out_param, user_data, size);
71
72                         if (BLUETOOTH_ERROR_NONE == result) {
73                                 fd_list = g_unix_fd_list_new();
74                                 g_unix_fd_list_append(fd_list, ptr->socket_fd, &error);
75                                 g_assert_no_error(error);
76                                 close(ptr->socket_fd);
77                         }
78
79                         _bt_service_method_return_with_unix_fd_list(
80                                         req_info->context, out_param, result, fd_list);
81                         if (fd_list)
82                                 g_object_unref(fd_list);
83
84                         g_free(req_info->user_data);
85                         _bt_free_info_from_invocation_list(req_info);
86                         g_array_free(out_param, TRUE);
87                         break;
88                 }
89                 case BT_RFCOMM_LISTEN_AND_ACCEPT:
90                 case BT_RFCOMM_LISTEN: {
91                         GUnixFDList *fd_list = NULL;
92                         GError *error = NULL;
93                         int *socket_fd = user_data;
94
95                         BT_INFO("Server socket fd: %d", *socket_fd);
96
97                         g_array_append_vals(out_param, user_data, size);
98
99                         /* Add socket fd to unix_fd_list */
100                         fd_list = g_unix_fd_list_new();
101                         g_unix_fd_list_append(fd_list, *socket_fd, &error);
102                         g_assert_no_error(error);
103
104                         _bt_service_method_return_with_unix_fd_list(
105                                         req_info->context, out_param, result, fd_list);
106
107                         close(*socket_fd);
108                         g_object_unref(fd_list);
109
110                         _bt_free_info_from_invocation_list(req_info);
111                         g_array_free(out_param, TRUE);
112                         break;
113                 }
114                 default:
115                         BT_ERR("Unknown Service function");
116                 }
117         }
118
119         return;
120 }
121
122 static void __bt_rfcomm_socket_conn_cb(int result, int sock_fd, char *address, char *uuid, int chan)
123 {
124         bluetooth_rfcomm_connection_t conn_info;
125
126         ret_if(NULL == address);
127         ret_if(NULL == uuid);
128
129         BT_DBG("+");
130
131         BT_INFO("result: %d, socket_fd: %d, address: %s, uuid: %s, chan: %d",
132                         result, sock_fd, address, uuid, chan);
133
134         /* Fill RFCOMM connection structure and send reply to pending request */
135         memset(&conn_info, 0x00, sizeof(bluetooth_rfcomm_connection_t));
136         conn_info.socket_fd = sock_fd;
137         conn_info.device_role = RFCOMM_ROLE_CLIENT;
138         g_strlcpy(conn_info.uuid, uuid, BLUETOOTH_UUID_STRING_MAX);
139         _bt_convert_addr_string_to_type(conn_info.device_addr.addr, address);
140
141         __bt_rfcomm_reply_pending_request(
142                         result, BT_RFCOMM_CLIENT_CONNECT,
143                         (void *)&conn_info, sizeof(bluetooth_rfcomm_connection_t));
144
145         BT_DBG("-");
146 }
147
148 int _bt_rfcomm_connect_using_uuid(bluetooth_device_address_t *device_address, char *remote_uuid)
149 {
150         int result;
151         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
152
153         BT_DBG("+");
154
155         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
156         retv_if(NULL == remote_uuid, BLUETOOTH_ERROR_INVALID_PARAM);
157
158         _bt_convert_addr_type_to_string(address, device_address->addr);
159         BT_INFO("RFCOMM connect called for [%s], uuid: [%s]", address, remote_uuid);
160
161         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
162                         address, remote_uuid, -1, __bt_rfcomm_socket_conn_cb);
163         if (BLUETOOTH_ERROR_NONE != result) {
164                 BT_ERR("_bt_socket_client_connect failed");
165                 return result;
166         }
167
168         BT_DBG("-");
169         return BLUETOOTH_ERROR_NONE;
170 }
171
172 /* Range of the Channel : 0 <= channel <= 30 */
173 int _bt_rfcomm_connect_using_channel(bluetooth_device_address_t *device_address, char *chan_str)
174 {
175         int channel;
176         int result = BLUETOOTH_ERROR_NONE;
177         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
178
179         BT_DBG("+");
180
181         retv_if(NULL == device_address, BLUETOOTH_ERROR_INVALID_PARAM);
182         retv_if(NULL == chan_str, BLUETOOTH_ERROR_INVALID_PARAM);
183
184         _bt_convert_addr_type_to_string(address, device_address->addr);
185         channel = atoi(chan_str);
186         BT_INFO("RFCOMM connect called for [%s], channel: %d", address, channel);
187
188         result = _bt_socket_client_connect(SOCK_TYPE_RFCOMM,
189                         address, NULL, channel, __bt_rfcomm_socket_conn_cb);
190         if (BLUETOOTH_ERROR_NONE != result) {
191                 BT_ERR("_bt_socket_client_connect failed");
192                 return result;
193         }
194
195         BT_DBG("-");
196         return result;
197 }
198
199 gboolean __bt_send_rfcomm_server_fd(gpointer user_data)
200 {
201         BT_DBG("+");
202
203         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
204                         BT_RFCOMM_LISTEN, user_data, sizeof(int));
205
206         g_free(user_data);
207         BT_DBG("-");
208         return FALSE;
209 }
210
211 gboolean __bt_send_rfcomm_server_fd_with_accept(gpointer user_data)
212 {
213         BT_DBG("+");
214
215         __bt_rfcomm_reply_pending_request(BLUETOOTH_ERROR_NONE,
216                         BT_RFCOMM_LISTEN_AND_ACCEPT, user_data, sizeof(int));
217
218         g_free(user_data);
219         BT_DBG("-");
220         return FALSE;
221 }
222
223 int _bt_rfcomm_socket_listen(char *svc_name, char *uuid, bool accept)
224 {
225         int channel = 0;
226         int sock_fd;
227
228         BT_DBG("+");
229
230         retv_if(NULL == svc_name, BLUETOOTH_ERROR_INVALID_PARAM);
231         retv_if(NULL == uuid, BLUETOOTH_ERROR_INVALID_PARAM);
232
233         BT_INFO("RFCOMM create socket called with svc name: [%s], uuid: [%s]", svc_name, uuid);
234         sock_fd = _bt_socket_listen(SOCK_TYPE_RFCOMM, svc_name, uuid, channel);
235         if (sock_fd < 0) {
236                 BT_ERR("_bt_socket_listen failed");
237                 return BLUETOOTH_ERROR_INTERNAL;
238         }
239
240         if (accept == false)
241                 g_idle_add(__bt_send_rfcomm_server_fd, g_memdup(&sock_fd, sizeof(int)));
242         else
243                 g_idle_add(__bt_send_rfcomm_server_fd_with_accept, g_memdup(&sock_fd, sizeof(int)));
244
245         BT_DBG("-");
246         return sock_fd;
247 }