Change sscanf to strtol function for the secure coding
[platform/core/connectivity/bluetooth-frwk.git] / bt-httpproxy / bt-httpproxy.c
1 /*
2  * Copyright (c) 2015 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 <dlog.h>
19 #include <gio/gio.h>
20
21 #include <stdio.h>
22
23 #include "bt-httpproxy.h"
24 #include "bluetooth-api.h"
25
26 #include <libsoup/soup.h>
27
28 #ifdef TIZEN_FEATURE_BT_HPS
29
30 #undef LOG_TAG
31 #define LOG_TAG "BLUETOOTH_HPS"
32
33 #define BT_INFO(fmt, arg...) SLOGI(fmt, ##arg)
34 #define BT_ERR(fmt, arg...) SLOGE(fmt, ##arg)
35 #define BT_DBG(fmt, arg...) SLOGD(fmt, ##arg)
36
37 char *hps_obj_path = NULL;
38 char *http_uri_obj_path = NULL;
39 char *http_hdr_obj_path = NULL;
40 char *http_entity_obj_path = NULL;
41 char *http_cp_obj_path = NULL;
42 char *http_status_obj_path = NULL;
43 char *http_status_desc_obj_path = NULL;
44 char *http_security_obj_path = NULL;
45
46 static GMainLoop *main_loop;
47 static int property_sub_id = -1;
48 static int adapter_sub_id = -1;
49 static http_request_state req_state;
50
51 #ifdef  HPS_GATT_DB
52 struct hps_notify_read_info {
53         gchar *char_path;
54         guint  read_status;
55         guint  offset_status;
56         int  https_status;
57 };
58
59 struct hps_char_info {
60         gchar *char_path;
61         gchar *char_value;
62         int value_length;
63 };
64
65 static GSList *hps_notify_read_list = NULL;
66 static GSList *hps_char_list = NULL;
67 #endif
68
69 static GDBusConnection *conn;
70 static GDBusConnection *g_conn;
71 static guint g_owner_id = 0;
72 GDBusNodeInfo *hps_node_info = NULL;
73
74 char *g_uri = NULL;
75 char *g_header = NULL;
76 char *g_entity = NULL;
77
78 static SoupSession *hps_soup_session = NULL;
79 static SoupMessage *hps_soup_msg = NULL;
80
81
82 static const gchar hps_introspection_xml[] =
83 "<node name='/'>"
84 "       <interface name='org.projectx.httpproxy_service'>"
85 "               <method name='enable'>"
86 "                       <arg type='y' name='status' direction='out'/>"
87 "               </method>"
88 "               <method name='disable'>"
89 "                       <arg type='y' name='status' direction='out'/>"
90 "               </method>"
91 "       </interface>"
92 "</node>";
93
94 #ifdef  HPS_GATT_DB
95 static void _bt_hps_set_char_value(const char *obj_path, const char* value, int value_length, int offset);
96
97 static void _hps_convert_address_to_hex(bluetooth_device_address_t *addr_hex, const char *addr_str)
98 {
99         char *ptr1, *ptr2, *ptr3, *ptr4, *ptr5;
100
101         if (addr_str == NULL || addr_str[0] == '\0')
102                 return;
103
104         addr_hex->addr[0] = strtol(addr_str, &ptr5, 16);
105         addr_hex->addr[1] = strtol(ptr5 + 1, &ptr4, 16);
106         addr_hex->addr[2] = strtol(ptr4 + 1, &ptr3, 16);
107         addr_hex->addr[3] = strtol(ptr3 + 1, &ptr2, 16);
108         addr_hex->addr[4] = strtol(ptr2 + 1, &ptr1, 16);
109         addr_hex->addr[5] = strtol(ptr1 + 1, NULL, 16);
110 }
111
112 static char *__hps_convert_uuid_to_uuid128(const char *uuid)
113 {
114         int len;
115         char *uuid128;
116
117         len = strlen(uuid);
118
119         switch (len) {
120         case 4:
121                 /* UUID 16bits */
122                 uuid128 = g_strdup_printf("0000%s-0000-1000-8000-00805F9B34FB", uuid);
123                 break;
124
125         case 8:
126                 /* UUID 32bits */
127                 uuid128 = g_strdup_printf("%s-0000-1000-8000-00805F9B34FB", uuid);
128                 break;
129
130         case 36:
131                 /* UUID 128bits */
132                 uuid128 = strdup(uuid);
133                 break;
134
135         default:
136                 return NULL;
137         }
138
139         return uuid128;
140 }
141
142 static void _bt_hps_send_status_notification(unsigned short http_status,
143                         unsigned char data_status,
144                         bluetooth_device_address_t *unicast_address)
145 {
146         char status[3] = {0x00};
147         int ret = BLUETOOTH_ERROR_NONE;
148
149         BT_DBG("");
150
151         status[0] = http_status & 0xFF;
152         status[1] = (http_status >> 8) & 0xFF;
153         status[2] = data_status;
154         BT_DBG("Status %d %04x", http_status, http_status);
155
156         /* Store the status value */
157         _bt_hps_set_char_value(http_status_obj_path, status, 3, 0);
158
159         /* Send unicast notification */
160         ret = bluetooth_gatt_server_set_notification(http_status_obj_path, unicast_address);
161         if (ret != BLUETOOTH_ERROR_NONE) {
162                 BT_ERR("_bt_hps_send_status_notification failed");
163                 return;
164         }
165         ret = bluetooth_gatt_update_characteristic(http_status_obj_path, status, 3);
166         if (ret != BLUETOOTH_ERROR_NONE) {
167                 BT_ERR("_bt_hps_send_status_notification failed");
168                 return;
169         }
170 }
171 #endif
172
173 static void _bt_httpproxy_method(GDBusConnection *connection,
174                 const gchar *sender,
175                 const gchar *object_path,
176                 const gchar *interface_name,
177                 const gchar *method_name,
178                 GVariant *parameters,
179                 GDBusMethodInvocation *invocation,
180                 gpointer user_data)
181 {
182         int status = 0;
183
184         BT_DBG("Method[%s] Object Path[%s] Interface Name[%s]",
185                         method_name, object_path, interface_name);
186
187         if (g_strcmp0(method_name, "enable") == 0) {
188                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
189         } else if (g_strcmp0(method_name, "disable") == 0) {
190                 _bt_hps_exit();
191                 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
192         }
193
194         return;
195 }
196
197 static const GDBusInterfaceVTable hps_method_table = {
198         _bt_httpproxy_method,
199         NULL,
200         NULL,
201 };
202
203 static void _bt_hps_on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
204 {
205         guint object_id;
206         GError *error = NULL;
207
208         BT_DBG("");
209
210         g_conn = connection;
211
212         object_id = g_dbus_connection_register_object(connection, BT_HPS_OBJECT_PATH,
213                                                 hps_node_info->interfaces[0],
214                                                 &hps_method_table,
215                                                 NULL, NULL, &error);
216         if (object_id == 0) {
217                 BT_ERR("Failed to register method table: %s", error->message);
218                 g_error_free(error);
219                 g_dbus_node_info_unref(hps_node_info);
220         }
221
222         return;
223 }
224
225 static void _bt_hps_on_name_acquired(GDBusConnection *connection,
226                                         const gchar     *name,
227                                         gpointer user_data)
228 {
229         BT_DBG("");
230         return;
231 }
232
233 static void _bt_hps_on_name_lost(GDBusConnection *connection,
234                                 const gchar     *name,
235                                 gpointer user_data)
236 {
237         BT_DBG("");
238         g_object_unref(g_conn);
239         g_conn = NULL;
240         g_dbus_node_info_unref(hps_node_info);
241         g_bus_unown_name(g_owner_id);
242
243         return;
244 }
245
246 int _bt_hps_register_interface(void)
247 {
248         GError *error = NULL;
249         guint owner_id;
250
251         BT_DBG("");
252
253         hps_node_info = g_dbus_node_info_new_for_xml(hps_introspection_xml, &error);
254         if (!hps_node_info) {
255                 BT_ERR("Failed to install: %s", error->message);
256                 return BLUETOOTH_ERROR_INTERNAL;
257         }
258
259         owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
260                                 BT_HPS_SERVICE_NAME,
261                                 G_BUS_NAME_OWNER_FLAGS_NONE,
262                                 _bt_hps_on_bus_acquired, _bt_hps_on_name_acquired, _bt_hps_on_name_lost,
263                                 NULL, NULL);
264         g_owner_id = owner_id;
265         BT_DBG("owner_id is [%d]\n", owner_id);
266
267         return BLUETOOTH_ERROR_NONE;
268 }
269
270 void _bt_hps_unregister_interface(void)
271 {
272         BT_DBG("");
273
274         g_object_unref(g_conn);
275         g_conn = NULL;
276         g_dbus_node_info_unref(hps_node_info);
277         g_bus_unown_name(g_owner_id);
278
279         return;
280 }
281
282 #ifdef  HPS_GATT_DB
283 static struct hps_char_info *hps_get_char_value(const char *path)
284 {
285         GSList *tmp = NULL;
286
287         for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
288                 if (tmp->data) {
289                         struct hps_char_info *char_info = tmp->data;
290                         if (!g_strcmp0(char_info->char_path, path))
291                                 return char_info;
292                 }
293         }
294         return NULL;
295 }
296
297 static int char_info_cmp(gconstpointer a1, gconstpointer a2)
298 {
299         const struct hps_char_info *attrib1 = a1;
300         const struct hps_char_info *attrib2 = a2;
301
302         return g_strcmp0(attrib1->char_path, attrib2->char_path);
303 }
304
305 static int notify_info_cmp(gconstpointer a1, gconstpointer a2)
306 {
307         const struct hps_notify_read_info *attrib1 = a1;
308         const struct hps_notify_read_info *attrib2 = a2;
309
310         return g_strcmp0(attrib1->char_path, attrib2->char_path);
311 }
312
313 static void _bt_hps_set_char_value(const char *obj_path, const char* value, int value_length, int offset)
314 {
315         GSList *tmp = NULL;
316         if (!value)
317                 return;
318
319         for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
320                 if (tmp->data) {
321                         struct hps_char_info *char_info = tmp->data;
322                         if (!g_strcmp0(char_info->char_path, obj_path)) {
323                                 gchar *str = NULL;
324                                 if (offset > 0) {
325                                         str = g_strdup(char_info->char_value);
326                                         char_info->char_value = g_try_realloc(char_info->char_value, offset + value_length);
327                                 } else {
328                                         char_info->char_value = g_try_realloc(char_info->char_value, value_length);
329                                 }
330                                 if (char_info->char_value) {
331                                         if (str) {
332                                                 memcpy(char_info->char_value, str, strlen(str));
333                                         }
334                                         if (offset > 0) {
335                                                 memcpy(&char_info->char_value[offset], value, value_length);
336                                                 char_info->value_length = offset + value_length;
337                                         } else {
338                                                 memcpy(char_info->char_value, value, value_length);
339                                                 char_info->value_length = value_length;
340                                         }
341                                         hps_char_list = g_slist_insert_sorted(hps_char_list,
342                                                                         char_info, char_info_cmp);
343                                 }
344                                 g_free(str);
345                                 return;
346                         }
347                 }
348         }
349         return;
350 }
351
352 static void _bt_hps_set_notify_read_status(const char *obj_path,
353                         guint offset_status, guint read_status, int https_status)
354 {
355         struct hps_notify_read_info *notify_read_info = NULL;
356         GSList *tmp = NULL;
357
358         for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
359                 if (tmp->data) {
360                         notify_read_info = tmp->data;
361                         if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
362                                 notify_read_info->read_status = read_status;
363                                 notify_read_info->offset_status = offset_status;
364                                 notify_read_info->https_status = https_status;
365                                 hps_notify_read_list = g_slist_insert_sorted(hps_notify_read_list,
366                                                                 notify_read_info, notify_info_cmp);
367                                 return;
368                         }
369                 }
370         }
371
372         if (!hps_notify_read_list) {
373                 /* Store Notification information */
374                 notify_read_info = g_new0(struct hps_notify_read_info, 1);
375                 if (notify_read_info) {
376                         notify_read_info->char_path = g_strdup(obj_path);
377                         notify_read_info->read_status = read_status;
378                         notify_read_info->offset_status = offset_status;
379                         notify_read_info->https_status = https_status;
380                         hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
381                 }
382                 return;
383         } else {
384                 /* Store Notification information */
385                 notify_read_info = g_new0(struct hps_notify_read_info, 1);
386                 if (notify_read_info) {
387                         notify_read_info->char_path = g_strdup(obj_path);
388                         notify_read_info->read_status = read_status;
389                         notify_read_info->offset_status = offset_status;
390                         notify_read_info->https_status = https_status;
391                         hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
392                 }
393                 return;
394         }
395 }
396
397 static struct hps_notify_read_info *_bt_hps_get_notify_read_status(const char *obj_path)
398 {
399         GSList *tmp = NULL;
400
401         for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
402                 if (tmp->data) {
403                         struct hps_notify_read_info *notify_read_info = tmp->data;
404                         if (!g_strcmp0(notify_read_info->char_path, obj_path))
405                                 return notify_read_info;
406                 }
407         }
408
409         return NULL;
410 }
411
412 static void delete_all_characterisitc(void)
413 {
414         GSList *tmp = NULL;
415         for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
416                 if (tmp->data) {
417                         struct hps_char_info *char_info = tmp->data;
418                         if (char_info->char_path)
419                                 g_free(char_info->char_path);
420                         if (char_info->char_value)
421                                 g_free(char_info->char_value);
422                         hps_char_list = g_slist_delete_link(hps_char_list, tmp->data);
423                 }
424         }
425         g_slist_free(hps_char_list);
426         hps_char_list = NULL;
427 }
428
429 static void delete_all_notify_read_status(void)
430 {
431         GSList *tmp = NULL;
432         for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
433                 if (tmp->data) {
434                         struct hps_notify_read_info *notify_read_info = tmp->data;
435                         if (notify_read_info->char_path)
436                                 g_free(notify_read_info->char_path);
437                         hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
438                 }
439         }
440         g_slist_free(hps_notify_read_list);
441         hps_notify_read_list = NULL;
442 }
443
444 static void delete_notify_read_status(const char *obj_path)
445 {
446         GSList *tmp = NULL;
447         for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
448                 if (tmp->data) {
449                         struct hps_notify_read_info *notify_read_info = tmp->data;
450                         if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
451                                 if (notify_read_info->char_path)
452                                         g_free(notify_read_info->char_path);
453                                 hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
454                                 return;
455                         }
456                 }
457         }
458 }
459 #endif
460
461 int _bt_hps_uri_write_cb(char *uri, int len, int offset)
462 {
463         if ((len < 1) || (len > MAX_URI_LENGTH)) {
464                 BT_ERR("Wrong URI length %d", len);
465                 return BLUETOOTH_ERROR_INTERNAL;
466         }
467
468         /* g_uri will be used commonly for all HTTP methods whereever applicable */
469         if (g_uri)
470                 g_free(g_uri);
471         g_uri = g_strndup(uri, len);
472 #ifdef  HPS_GATT_DB
473         _bt_hps_set_char_value(http_uri_obj_path, g_uri, len, offset);
474 #endif
475         return BLUETOOTH_ERROR_NONE;
476 }
477
478 int _bt_hps_http_header_write_cb(char *header, int len, int offset)
479 {
480         if ((len < 1) || (len > MAX_HEADER_LENGTH)) {
481                 BT_ERR("Wrong Header length %d", len);
482                 return BLUETOOTH_ERROR_INTERNAL;
483         }
484
485         /* g_header will be used commonly for all HTTP methods where ever applicable
486            general-header, request-header, entity-header
487         */
488         if (g_header)
489                 g_free(g_header);
490         g_header = g_strndup(header, len);
491 #ifdef  HPS_GATT_DB
492         _bt_hps_set_char_value(http_hdr_obj_path, g_header, len, offset);
493 #endif
494
495         return BLUETOOTH_ERROR_NONE;
496 }
497
498 int _bt_hps_entity_body_write_cb(char *entity, int len, int offset)
499 {
500         if ((len < 1) || (len > MAX_ENTITY_LENGTH)) {
501                 BT_ERR("Wrong Entity length %d", len);
502                 return BLUETOOTH_ERROR_INTERNAL;
503         }
504
505         /* g_entity will be used commonly for all HTTP methods whereever applicable */
506         if (g_entity)
507                 g_free(g_entity);
508         g_entity = g_strndup(entity, len);
509 #ifdef  HPS_GATT_DB
510         _bt_hps_set_char_value(http_entity_obj_path, g_entity, len, offset);
511 #endif
512
513         return BLUETOOTH_ERROR_NONE;
514 }
515
516 #ifdef  HPS_GATT_DB
517 int _bt_hps_read_cb(const char *obj_path, char **value, int *len)
518 {
519         struct hps_char_info *info = NULL;
520         struct hps_notify_read_info *notify_read_info = NULL;
521         guint data_status = -1;
522         guint offset = 0;
523         gboolean is_header = FALSE;
524
525         if (!obj_path) {
526                 BT_ERR("Wrong Obj path");
527                 return data_status;
528         }
529
530         if (!g_strcmp0(http_hdr_obj_path, obj_path))
531                 is_header = TRUE;
532
533         info = hps_get_char_value(obj_path);
534         if (info) {
535
536                 if (info->char_value == NULL || info->value_length == 0)
537                         return data_status;
538
539                 notify_read_info = _bt_hps_get_notify_read_status(obj_path);
540                 if (notify_read_info && notify_read_info->read_status != DS_BODY_RECEIVED &&
541                                 notify_read_info->read_status != DS_HEADER_RECEIVED) {
542                         offset = notify_read_info->offset_status;
543                         if ((info->value_length - offset) > 0 &&
544                                 (info->value_length - offset) > MAX_ENTITY_LENGTH)  {
545                                 if (is_header)
546                                         data_status = DS_HEADER_TRUNCATED;
547                                 else
548                                         data_status = DS_BODY_TRUNCATED;
549                                 _bt_hps_set_notify_read_status(obj_path, offset + MAX_ENTITY_LENGTH,
550                                                                 data_status, notify_read_info->https_status);
551                                 *value = g_strdup(&info->char_value[offset]);
552                                 *len = MAX_ENTITY_LENGTH;
553                         } else if ((info->value_length - offset) > 0 &&
554                                 (info->value_length - offset) <= MAX_ENTITY_LENGTH) {
555                                 if (is_header)
556                                         data_status = DS_HEADER_RECEIVED;
557                                 else
558                                         data_status = DS_BODY_RECEIVED;
559                                 _bt_hps_set_notify_read_status(obj_path, offset, data_status, notify_read_info->https_status);
560                                 *value = g_strdup(&info->char_value[offset]);
561                                 *len = info->value_length - offset;
562                         }
563                 } else if (notify_read_info && (notify_read_info->read_status == DS_BODY_RECEIVED ||
564                                                 notify_read_info->read_status == DS_HEADER_RECEIVED)) {
565                                 if (is_header)
566                                         data_status = DS_HEADER_RECEIVED;
567                                 else
568                                         data_status = DS_BODY_RECEIVED;
569                                 delete_notify_read_status(obj_path);
570                                 *value = g_strdup(&info->char_value[offset]);
571                                 *len = info->value_length;
572                 }
573         }
574
575         return data_status;
576 }
577 #endif
578
579 void _bt_hps_head_response_cb(SoupSession *session,
580                         SoupMessage *msg, gpointer user_data)
581 {
582         unsigned short http_status = 0x00;
583 #ifndef HPS_GATT_DB
584         unsigned char status[3] = {0x00};
585 #else
586         const char *device_address = user_data;
587         bluetooth_device_address_t addr_hex = { {0,} };
588         unsigned char data_status = DS_NONE;
589         _hps_convert_address_to_hex(&addr_hex, device_address);
590 #endif
591
592         if (hps_soup_session != session) {
593                 BT_ERR("Wrong Session");
594                 return;
595         }
596
597         if (msg == NULL) {
598                 BT_ERR("Wrong Message");
599                 return;
600         }
601         hps_soup_msg = NULL;
602
603         req_state = HTTP_REQ_STATE_EXECUTED;
604
605         http_status = msg->status_code;
606
607         // Process Header in Response Body
608         if (msg->response_headers) {
609
610                 const char *content = NULL;
611                 const char *length = NULL;
612                 guint hdr_len = 0;
613
614                 length = soup_message_headers_get_one(msg->request_headers,
615                                                                 "Content-Length");
616                 // Check "Content-MD5" is the right name to get header content
617                 content = soup_message_headers_get_one(msg->response_headers,
618                                                                 "Content-MD5");
619                 if (content == NULL || length == NULL) {
620                         BT_ERR("Wrong Response Header");
621                         _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
622                         return;
623                 }
624
625                 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
626
627                 // Write Data to Header Characteristic
628 #ifdef  HPS_GATT_DB
629                 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len, 0);
630 #else
631                 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
632 #endif
633                 // TODO : Handle Truncated Header
634
635                 // Write Data to Status Code Characteristic
636 #ifdef  HPS_GATT_DB
637                 data_status = (hdr_len > MAX_ENTITY_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
638
639                 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status))
640                         _bt_hps_set_notify_read_status(http_hdr_obj_path, 0, data_status, http_status);
641
642                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
643 #else
644                 status[0] = http_status & 0x0F;
645                 status[1] = (http_status >> 8) & 0x0F;
646                 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
647
648                 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
649 #endif
650         } else {
651                 BT_ERR("HEAD Response is NULL");
652                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
653         }
654
655         return;
656 }
657
658 void _bt_hps_http_response_cb(SoupSession *session,
659                         SoupMessage *msg, gpointer user_data)
660 {
661         unsigned short http_status = 0x00;
662 #ifndef HPS_GATT_DB
663         unsigned char status[3] = {0x00};
664 #else
665         const char *device_address = user_data;
666         bluetooth_device_address_t addr_hex = { {0,} };
667         unsigned char data_status = DS_NONE;
668         _hps_convert_address_to_hex(&addr_hex, device_address);
669 #endif
670
671         if (hps_soup_session != session) {
672                 BT_ERR("Wrong Session");
673                 return;
674         }
675
676         if (msg == NULL) {
677                 BT_ERR("Wrong Message");
678                 return;
679         }
680
681         hps_soup_msg = NULL;
682
683         req_state = HTTP_REQ_STATE_EXECUTED;
684
685         http_status = msg->status_code;
686
687         // Write Data to Status Code Characteristic
688 #ifndef HPS_GATT_DB
689         status[0] = http_status & 0x0F;
690         status[1] = (http_status >> 8) & 0x0F;
691         status[2] = DS_HEADER_RECEIVED;
692         bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
693 #else
694         data_status = DS_HEADER_RECEIVED;
695         _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
696 #endif
697
698         return;
699 }
700
701 void _bt_hps_get_response_cb(SoupSession *session,
702                         SoupMessage *msg, gpointer user_data)
703 {
704         SoupBuffer *body = NULL;
705         unsigned short http_status = 0x00;
706 #ifndef HPS_GATT_DB
707         unsigned char status[3] = {0x00};
708 #else
709         const char *device_address = user_data;
710         bluetooth_device_address_t addr_hex = { {0,} };
711         unsigned char data_status = DS_NONE;
712         _hps_convert_address_to_hex(&addr_hex, device_address);
713 #endif
714
715         if (hps_soup_session != session) {
716                 BT_ERR("Wrong Session");
717                 return;
718         }
719
720         if (msg == NULL) {
721                 BT_ERR("Wrong Message");
722                 return;
723         }
724
725         hps_soup_msg = NULL;
726
727         req_state = HTTP_REQ_STATE_EXECUTED;
728
729         http_status = msg->status_code;
730
731         // Process Entity Body in Response Message
732         if (msg->response_body) {
733
734                 body = soup_message_body_flatten(msg->response_body);
735                 if (body == NULL) {
736                         BT_ERR("Wrong Response Body");
737 #ifdef HPS_GATT_DB
738                         _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
739 #endif
740                         return;
741                 }
742                 if (body->data == NULL || body->length <= 0) {
743                         BT_ERR("Wrong Response");
744                         soup_buffer_free(body);
745 #ifdef HPS_GATT_DB
746                         _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
747 #endif
748                         return;
749                 }
750                 // Write Data to Entity Body Characteristic
751 #ifdef  HPS_GATT_DB
752                 _bt_hps_set_char_value(http_entity_obj_path, body->data, body->length, 0);
753 #else
754                 bluetooth_gatt_set_characteristic_value(http_entity_obj_path, body->data, body->length);
755 #endif
756                 // TODO : Handle Truncated Entiry Body
757
758                 // Write Data to Status Code Characteristic
759 #ifdef  HPS_GATT_DB
760                 data_status = (body->length > MAX_ENTITY_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_RECEIVED;
761
762                 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status))
763                         _bt_hps_set_notify_read_status(http_entity_obj_path, 0, data_status, http_status);
764
765                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
766
767 #else
768                 status[0] = http_status & 0x0F;
769                 status[1] = (http_status >> 8) & 0x0F;
770                 status[2] = (body->length > MAX_HEADER_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_TRUNCATED;
771
772                 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
773 #endif
774                 soup_buffer_free(body);
775         } else {
776                 BT_ERR("GET Response Body is NULL");
777 #ifdef HPS_GATT_DB
778                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
779 #endif
780         }
781
782         // Process Header in Response Body
783         if (msg->response_headers) {
784
785                 const char *content = NULL;
786                 const char *length = NULL;
787                 guint hdr_len = 0;
788
789                 length = soup_message_headers_get_one(msg->request_headers,
790                                                                 "Content-Length");
791                 // Check "Content-MD5" is the right name to get header content
792                 content = soup_message_headers_get_one(msg->response_headers,
793                                                                 "Content-MD5");
794                 if (content == NULL || length == NULL) {
795                         BT_ERR("Wrong Response Header");
796                         data_status = DS_NONE;
797                         _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
798                         return;
799                 }
800
801                 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
802                 // Write Data to Header Characteristic
803 #ifdef  HPS_GATT_DB
804                 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len, 0);
805 #else
806                 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
807 #endif
808                 // TODO : Handle Truncated Header
809
810                 // Write Data to Status Code Characteristic
811 #ifdef  HPS_GATT_DB
812                 data_status = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
813
814                 if (data_status == DS_HEADER_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status))
815                         _bt_hps_set_notify_read_status(http_hdr_obj_path, 0, data_status, http_status);
816
817                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
818 #else
819                 status[0] = http_status & 0x0F;
820                 status[1] = (http_status >> 8) & 0x0F;
821                 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
822
823                 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
824 #endif
825         } else {
826                 BT_ERR("GET Response Header is NULL");
827 #ifdef HPS_GATT_DB
828                 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
829 #endif
830         }
831
832         return;
833 }
834
835 #ifdef  HPS_GATT_DB
836 int _bt_hps_control_point_write_cb(const char *value, int len, char *addr)
837 #else
838 int _bt_hps_control_point_write_cb(char *value, int len)
839 #endif
840 {
841         int opcode = *value;
842         GTlsCertificate *cert = NULL;
843         GTlsCertificateFlags flags;
844         gboolean https_status = FALSE;
845         int result = BLUETOOTH_ERROR_NONE;
846         BT_INFO("Opcode %0x", opcode);
847
848 #ifdef  HPS_GATT_DB
849         _bt_hps_set_char_value(http_cp_obj_path, value, len, 0);
850 #endif
851
852         switch (opcode) {
853         case HTTP_GET_REQUEST:
854                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
855                         req_state = HTTP_REQ_STATE_INPROGRESS;
856                         hps_soup_msg = soup_message_new("GET", g_uri);
857 #ifdef  HPS_GATT_DB
858                         g_object_ref(hps_soup_msg);
859                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
860 #else
861                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
862 #endif
863                 } else {
864                         BT_ERR("HTTP GET request in progress, message dropped");
865                         result = BLUETOOTH_ERROR_INTERNAL;
866                 }
867                 break;
868
869         case HTTP_POST_REQUEST:
870                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
871                         req_state = HTTP_REQ_STATE_INPROGRESS;
872                         hps_soup_msg = soup_message_new("POST", g_uri);
873                         if (hps_soup_msg == NULL || g_entity == NULL) {
874                                 BT_ERR("Soup Message NULL");
875                                 result = BLUETOOTH_ERROR_INTERNAL;
876                                 req_state = HTTP_REQ_STATE_EXECUTED;
877                                 break;
878                         }
879                         soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_COPY,
880                                                   g_entity, strlen(g_entity));
881 #ifdef  HPS_GATT_DB
882                         g_object_ref(hps_soup_msg);
883                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
884 #else
885                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
886 #endif
887                 } else {
888                         BT_ERR("HTTP POST request in progress, message dropped");
889                         result = BLUETOOTH_ERROR_INTERNAL;
890                 }
891                 break;
892
893         case HTTP_HEAD_REQUEST:
894                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
895                         req_state = HTTP_REQ_STATE_INPROGRESS;
896                         hps_soup_msg = soup_message_new("HEAD", g_uri);
897                         if (hps_soup_msg == NULL) {
898                                 BT_ERR("Soup Message NULL");
899                                 result = BLUETOOTH_ERROR_INTERNAL;
900                                 req_state = HTTP_REQ_STATE_EXECUTED;
901                                 break;
902                         }
903 #ifdef  HPS_GATT_DB
904                         g_object_ref(hps_soup_msg);
905                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
906 #else
907                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
908 #endif
909                 } else {
910                         BT_ERR("HTTP HEAD request in progress, message dropped");
911                         result = BLUETOOTH_ERROR_INTERNAL;
912                 }
913                 break;
914
915         case HTTP_PUT_REQUEST:
916                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
917                         SoupBuffer *buf;
918                         req_state = HTTP_REQ_STATE_INPROGRESS;
919                         hps_soup_msg = soup_message_new("PUT", g_uri);
920                         if (hps_soup_msg == NULL  || g_entity == NULL) {
921                                 BT_ERR("Soup Message NULL");
922                                 result = BLUETOOTH_ERROR_INTERNAL;
923                                 req_state = HTTP_REQ_STATE_EXECUTED;
924                                 break;
925                         }
926                         buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
927                         soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
928                         soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
929 #ifdef  HPS_GATT_DB
930                         g_object_ref(hps_soup_msg);
931                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
932 #else
933                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
934 #endif
935
936                 } else {
937                         BT_ERR("HTTP PUT request in progress, message dropped");
938                         result = BLUETOOTH_ERROR_INTERNAL;
939                 }
940                 break;
941
942         case HTTP_DELETE_REQUEST:
943                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
944                         req_state = HTTP_REQ_STATE_INPROGRESS;
945                         hps_soup_msg = soup_message_new("DELETE", g_uri);
946                         if (hps_soup_msg == NULL) {
947                                 BT_ERR("Soup Message NULL");
948                                 result = BLUETOOTH_ERROR_INTERNAL;
949                                 req_state = HTTP_REQ_STATE_EXECUTED;
950                                 break;
951                         }
952 #ifdef  HPS_GATT_DB
953                         g_object_ref(hps_soup_msg);
954                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
955 #else
956                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
957 #endif
958                 } else {
959                         BT_ERR("HTTP DELETE request in progress, message dropped");
960                         result = BLUETOOTH_ERROR_INTERNAL;
961                 }
962                 break;
963
964         case HTTPS_GET_REQUEST:
965                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
966                         req_state = HTTP_REQ_STATE_INPROGRESS;
967                         hps_soup_msg = soup_message_new("GET", g_uri);
968                         if (hps_soup_msg == NULL) {
969                                 BT_ERR("Soup Message NULL");
970                                 result = BLUETOOTH_ERROR_INTERNAL;
971                                 req_state = HTTP_REQ_STATE_EXECUTED;
972                                 break;
973                         }
974 #ifdef  HPS_GATT_DB
975                         g_object_ref(hps_soup_msg);
976                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
977 #else
978                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
979 #endif
980                         https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
981 #ifdef  HPS_GATT_DB
982                         _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
983 #else
984                         bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
985 #endif
986                 } else {
987                         BT_ERR("HTTPS GET request in progress, message dropped");
988                         result = BLUETOOTH_ERROR_INTERNAL;
989                 }
990                 break;
991
992         case HTTPS_HEAD_REQUEST:
993                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
994                         req_state = HTTP_REQ_STATE_INPROGRESS;
995                         hps_soup_msg = soup_message_new("HEAD", g_uri);
996                         if (hps_soup_msg == NULL) {
997                                 BT_ERR("Soup Message NULL");
998                                 result = BLUETOOTH_ERROR_INTERNAL;
999                                 req_state = HTTP_REQ_STATE_EXECUTED;
1000                                 break;
1001                         }
1002 #ifdef  HPS_GATT_DB
1003                         g_object_ref(hps_soup_msg);
1004                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
1005 #else
1006                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
1007 #endif
1008                         https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1009 #ifdef  HPS_GATT_DB
1010                         _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1011 #else
1012                         bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1013 #endif
1014                 } else {
1015                         BT_ERR("HTTPS HEAD request in progress, message dropped");
1016                         result = BLUETOOTH_ERROR_INTERNAL;
1017                 }
1018                 break;
1019
1020         case HTTPS_POST_REQUEST:
1021                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1022                         req_state = HTTP_REQ_STATE_INPROGRESS;
1023                         hps_soup_msg = soup_message_new("POST", g_uri);
1024                         if (hps_soup_msg == NULL) {
1025                                 BT_ERR("Soup Message NULL");
1026                                 result = BLUETOOTH_ERROR_INTERNAL;
1027                                 req_state = HTTP_REQ_STATE_EXECUTED;
1028                                 break;
1029                         }
1030                         soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_STATIC,
1031                                                   g_entity, strlen(g_entity));
1032 #ifdef  HPS_GATT_DB
1033                         g_object_ref(hps_soup_msg);
1034                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1035 #else
1036                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1037
1038 #endif
1039                         https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1040 #ifdef  HPS_GATT_DB
1041                         _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1042 #else
1043                         bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1044 #endif
1045                 } else {
1046                         BT_ERR("HTTPS POST request in progress, message dropped");
1047                         result = BLUETOOTH_ERROR_INTERNAL;
1048                 }
1049                 break;
1050
1051         case HTTPS_PUT_REQUEST:
1052                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1053                         SoupBuffer *buf;
1054                         req_state = HTTP_REQ_STATE_INPROGRESS;
1055                         hps_soup_msg = soup_message_new("PUT", g_uri);
1056                         if (hps_soup_msg == NULL) {
1057                                 BT_ERR("Soup Message NULL");
1058                                 result = BLUETOOTH_ERROR_INTERNAL;
1059                                 req_state = HTTP_REQ_STATE_EXECUTED;
1060                                 break;
1061                         }
1062                         buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
1063                         soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
1064                         soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
1065 #ifdef  HPS_GATT_DB
1066                         g_object_ref(hps_soup_msg);
1067                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1068 #else
1069                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1070 #endif
1071                         https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1072 #ifdef  HPS_GATT_DB
1073                         _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1074 #else
1075                         bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1076 #endif
1077                 } else {
1078                         BT_ERR("HTTPS PUT request in progress, message dropped");
1079                         result = BLUETOOTH_ERROR_INTERNAL;
1080                 }
1081                 break;
1082
1083         case HTTPS_DELETE_REQUEST:
1084                 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1085                         req_state = HTTP_REQ_STATE_INPROGRESS;
1086                         hps_soup_msg = soup_message_new("DELETE", g_uri);
1087                         if (hps_soup_msg == NULL) {
1088                                 BT_ERR("Soup Message NULL");
1089                                 result = BLUETOOTH_ERROR_INTERNAL;
1090                                 req_state = HTTP_REQ_STATE_EXECUTED;
1091                                 break;
1092                         }
1093 #ifdef  HPS_GATT_DB
1094                         g_object_ref(hps_soup_msg);
1095                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1096 #else
1097                         soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1098 #endif
1099
1100                         https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1101 #ifdef  HPS_GATT_DB
1102                         _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1103 #else
1104                         bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1105 #endif
1106                 } else {
1107                         BT_ERR("HTTPS DELETE request in progress, message dropped");
1108                         result = BLUETOOTH_ERROR_INTERNAL;
1109                 }
1110                 break;
1111
1112         case HTTP_REQUEST_CANCEL:
1113                 /* Cancel the outstanding request */
1114                 if (req_state == HTTP_REQ_STATE_INPROGRESS) {
1115                         req_state = HTTP_REQ_STATE_IDLE;
1116                         if (hps_soup_msg == NULL) {
1117                                 BT_ERR("Soup Message NULL");
1118                                 result = BLUETOOTH_ERROR_INTERNAL;
1119                                 req_state = HTTP_REQ_STATE_EXECUTED;
1120                                 break;
1121                         }
1122                         soup_session_cancel_message(hps_soup_session, hps_soup_msg, SOUP_STATUS_CANCELLED);
1123                         hps_soup_msg = NULL;
1124                 }
1125                 break;
1126
1127         default:
1128                 BT_ERR("Unknown opcode %0x", opcode);
1129                 result = BLUETOOTH_ERROR_INTERNAL;
1130                 break;
1131         }
1132
1133         return result;
1134 }
1135
1136 void _bt_hps_security_read_cb(char *value, int len)
1137 {
1138         BT_INFO("HPS Client Read the value");
1139         return;
1140 }
1141
1142 #ifdef  HPS_GATT_DB
1143 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1144                                 const char *path)
1145 {
1146         int result = BLUETOOTH_ERROR_NONE;
1147         GVariantIter value_iter;
1148         const char *property = NULL;
1149         const char * char_path = NULL;
1150         const char * svc_handle = NULL;
1151         GVariant *var = NULL;
1152         GVariant *val = NULL;
1153         g_variant_iter_init(&value_iter, msg);
1154
1155         while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &var))) {
1156
1157                 if (property == NULL) {
1158                         BT_ERR("Property NULL");
1159                         return;
1160                 }
1161
1162                 if (!g_strcmp0(property, "WriteValue")) {
1163                         int len = 0;
1164                         BT_INFO("WriteValue");
1165                         BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1166
1167                         if (var) {
1168                                 gchar *addr = NULL;
1169                                 guint8 req_id = 1;
1170                                 guint16 offset = 0;
1171                                 char *value = NULL;
1172                                 g_variant_get(var, "(&s&s&syq@ay)", &char_path,
1173                                                 &svc_handle, &addr, &req_id, &offset, &val);
1174
1175                                 len = g_variant_get_size(val);
1176
1177                                 BT_DBG("Len = %d, Offset = %d", len, offset);
1178
1179                                 value = (char *) g_variant_get_data(val);
1180
1181                                 if (len != 0) {
1182                                         if (!g_strcmp0(char_path, http_uri_obj_path)) {
1183                                                 /* Retrive URI */
1184                                                 result = _bt_hps_uri_write_cb(value, len, offset);;
1185                                         } else if (!g_strcmp0(char_path, http_hdr_obj_path)) {
1186                                                 /* Retrive HEADER */
1187                                                 result = _bt_hps_http_header_write_cb(value, len, offset);
1188                                         } else if (!g_strcmp0(char_path, http_entity_obj_path)) {
1189                                                 /* Retrive ENTITY BODY */
1190                                                 result = _bt_hps_entity_body_write_cb(value, len, offset);
1191                                         } else if (!g_strcmp0(char_path, http_cp_obj_path)) {
1192                                                 result = _bt_hps_control_point_write_cb(value, len, addr);
1193                                         } else {
1194                                                 BT_ERR("Wrong Object Path %s", char_path);
1195                                                 result = BLUETOOTH_ERROR_INTERNAL;
1196                                         }
1197                                 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_WRITE, result, 0, NULL, 0);
1198                                 } else {
1199                                         BT_ERR("Array Len 0");
1200                                 }
1201                         } else {
1202                                 BT_ERR("var==NULL");
1203                         }
1204                 } else if (!g_strcmp0(property, "ReadValue")) {
1205                         gchar *addr = NULL;
1206                         guint8 req_id = 1;
1207                         guint16 offset = 0;
1208                         char *value = NULL;
1209                         int len = 0;
1210                         int data_status = -1;
1211                         BT_INFO("ReadValue");
1212                         BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1213
1214                         g_variant_get(var, "(&s&s&syq)", &char_path, &svc_handle,
1215                                                                 &addr, &req_id, &offset);
1216
1217                         data_status = _bt_hps_read_cb(char_path, &value, &len);
1218                         if (data_status >= DS_NONE) {
1219                                 struct hps_notify_read_info *notify_read_info = NULL;
1220                                 bluetooth_device_address_t addr_hex = { {0,} };
1221                                 _hps_convert_address_to_hex(&addr_hex, addr);
1222                                 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1223                                                                 BLUETOOTH_ERROR_NONE, offset, value, len);
1224                                 notify_read_info = _bt_hps_get_notify_read_status(char_path);
1225                                 if (notify_read_info) {
1226                                         _bt_hps_send_status_notification(notify_read_info->https_status,
1227                                                                         data_status, &addr_hex);
1228                                 } else {
1229                                         if (data_status == DS_BODY_RECEIVED ||
1230                                                 data_status == DS_HEADER_RECEIVED) {
1231                                                 _bt_hps_set_char_value(char_path, NULL, 0, 0);
1232                                         }
1233                                 }
1234                                 if (value)
1235                                         g_free(value);
1236                         } else {
1237                                 BT_ERR("ReadValue failed %s", char_path);
1238                                 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1239                                                                 BLUETOOTH_ERROR_INTERNAL, offset, NULL, 0);
1240                         }
1241                 }
1242         }
1243         return;
1244 }
1245 #else
1246 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1247                                 const char *path)
1248 {
1249         GVariantIter value_iter;
1250         char *property = NULL;
1251         char * char_handle = NULL;
1252         GVariant *val = NULL;
1253         int result = BLUETOOTH_ERROR_NONE;
1254         GVariant *param = NULL;
1255         g_variant_iter_init(&value_iter, msg);
1256         char_handle = g_strdup(path);
1257
1258         while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &val))) {
1259
1260                 if (property == NULL) {
1261                         BT_ERR("Property NULL");
1262                         return;
1263                 }
1264
1265                 if (strcasecmp(property, "ChangedValue") == 0) {
1266
1267                         int len = 0;
1268                         GByteArray *gp_byte_array = NULL;
1269                         BT_INFO("Type '%s'\n", g_variant_get_type_string(val));
1270
1271                         if (val) {
1272                                 gp_byte_array = g_byte_array_new();
1273                                 len = g_variant_get_size(val);
1274                                 BT_DBG("Len = %d", len);
1275                                 g_byte_array_append(gp_byte_array,
1276                                         (const guint8 *)g_variant_get_data(val), len);
1277                                 if (gp_byte_array->len != 0) {
1278                                         GVariant *byte_array = NULL;
1279                                         byte_array = g_variant_new_from_data(
1280                                                                 G_VARIANT_TYPE_BYTESTRING,
1281                                                                 gp_byte_array->data,
1282                                                                 gp_byte_array->len,
1283                                                                 TRUE, NULL, NULL);
1284                                         param = g_variant_new("(is@ay)", result, char_handle,
1285                                                                 byte_array);
1286
1287                                         if (strcmp(path, http_uri_obj_path)) {
1288                                                 //Retrive URI
1289                                                 _bt_hps_uri_write_cb(NULL, len);
1290                                         } else if (strcmp(path, http_hdr_obj_path)) {
1291                                                 //Retrive HEADER
1292                                                 _bt_hps_http_header_write_cb(NULL, len);
1293                                         } else if (strcmp(path, http_entity_obj_path)) {
1294                                                 //Retrive ENTITY BODY
1295                                                 _bt_hps_entity_body_write_cb(NULL, len);
1296                                         } else if (strcmp(path, http_cp_obj_path)) {
1297                                                 _bt_hps_control_point_write_cb(NULL, len);
1298                                         } else if (strcmp(path, http_security_obj_path)) {
1299                                                 _bt_hps_security_read_cb(NULL, len);
1300                                         } else {
1301                                                 BT_ERR("Wrong Object Path %s", path);
1302                                         }
1303                                 } else {
1304                                         BT_ERR("Array Len 0");
1305                                 }
1306                                 g_byte_array_free(gp_byte_array, TRUE);
1307                         } else {
1308                                 BT_ERR("val==NULL");
1309                         }
1310                 }
1311         }
1312         g_free(char_handle);
1313
1314         return;
1315 }
1316 #endif
1317
1318 void _bt_hps_property_event_filter(GDBusConnection *connection,
1319                                         const gchar *sender_name,
1320                                         const gchar *object_path,
1321                                         const gchar *interface_name,
1322                                         const gchar *signal_name,
1323                                         GVariant *parameters,
1324                                         gpointer user_data)
1325 {
1326         GVariant *value;
1327
1328         if (signal_name == NULL) {
1329                 BT_ERR("Wrong Signal");
1330                 return;
1331         }
1332
1333 #ifdef  HPS_GATT_DB
1334         if (g_strcmp0(signal_name, PROPERTIES_CHANGED) == 0) {
1335
1336                 g_variant_get(parameters, "(@a{sv}@as)", &value, NULL);
1337
1338                 _bt_hps_gatt_char_property_changed_event(value, object_path);
1339 #else
1340         if (g_strcmp0(interface_name, BT_HPS_PROPERTIES_INTERFACE) == 0) {
1341
1342                 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1343
1344                 _bt_hps_gatt_char_property_changed_event(value, object_path);
1345 #endif
1346         } else {
1347                 //BT_ERR("Wrong Interface %s", interface_name);
1348         }
1349
1350         return;
1351 }
1352
1353
1354 void _bt_hps_adapter_event_filter(GDBusConnection *connection,
1355                                         const gchar *sender_name,
1356                                         const gchar *object_path,
1357                                         const gchar *interface_name,
1358                                         const gchar *signal_name,
1359                                         GVariant *parameters,
1360                                         gpointer user_data)
1361 {
1362         int result = BLUETOOTH_ERROR_NONE;
1363         GVariant *value;
1364
1365         if (signal_name == NULL) {
1366                 BT_ERR("Wrong Signal");
1367                 return;
1368         }
1369
1370         BT_INFO("Interface %s, Signal %s", interface_name, signal_name);
1371
1372         if (g_strcmp0(interface_name, BT_HPS_INTERFACE_NAME) == 0) {
1373
1374                 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1375
1376                 if (strcasecmp(signal_name, BLE_ENABLED) == 0) {
1377                         g_variant_get(parameters, "(i)", &result);
1378
1379                         if (_bt_hps_prepare_httpproxy() != BLUETOOTH_ERROR_NONE) {
1380                                 BT_ERR("Fail to prepare HTTP Proxy");
1381                                 return;
1382                         }
1383
1384                         if (_bt_hps_set_advertising_data() != BLUETOOTH_ERROR_NONE) {
1385                                 BT_ERR("Fail to set advertising data");
1386                                 return;
1387                         }
1388
1389                 } else {
1390                         BT_ERR("Wrong Signal %s", signal_name);
1391                 }
1392         }
1393
1394         return;
1395 }
1396
1397 int _bt_hps_init_event_receiver()
1398 {
1399         GError *error = NULL;
1400
1401         BT_DBG("");
1402
1403         if (conn == NULL) {
1404                 conn =  g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
1405                 if (error != NULL) {
1406                         BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
1407                         g_clear_error(&error);
1408                 }
1409         }
1410
1411         property_sub_id = g_dbus_connection_signal_subscribe(conn,
1412                 NULL, BT_HPS_INTERFACE_NAME,
1413                 PROPERTIES_CHANGED, BT_HPS_OBJECT_PATH, NULL, 0,
1414                 _bt_hps_property_event_filter,
1415                 NULL, NULL);
1416
1417         adapter_sub_id = g_dbus_connection_signal_subscribe(conn,
1418                 NULL, BT_HPS_INTERFACE_NAME,
1419                 BLE_ENABLED, BT_HPS_OBJECT_PATH, NULL, 0,
1420                 _bt_hps_adapter_event_filter,
1421                 NULL, NULL);
1422
1423         return 0;
1424 }
1425
1426 void _bt_hps_deinit_event_receiver(void)
1427 {
1428         BT_DBG("");
1429         g_dbus_connection_signal_unsubscribe(conn, property_sub_id);
1430         g_dbus_connection_signal_unsubscribe(conn, adapter_sub_id);
1431         conn = NULL;
1432         return;
1433 }
1434
1435 int _bt_hps_set_advertising_data(void)
1436 {
1437         int ret;
1438         BT_DBG("");
1439
1440         guint8 data[4]  = {0x03, 0x02, 0x23, 0x18};
1441         bluetooth_advertising_data_t adv;
1442
1443         BT_DBG("%x %x %x %x", data[0], data[1], data[2], data[3]);
1444         memcpy(adv.data, data, sizeof(data));
1445         ret = bluetooth_set_advertising_data(0, &adv, sizeof(data));
1446         if (ret != BLUETOOTH_ERROR_NONE) {
1447                 BT_ERR("Failed to set ADV data %d", ret);
1448                 return ret;
1449         }
1450
1451         ret = bluetooth_set_advertising(0, TRUE);
1452         if (ret != BLUETOOTH_ERROR_NONE) {
1453                 BT_ERR("Failed to set ADV %d", ret);
1454                 return ret;
1455         }
1456
1457         return 0;
1458 }
1459
1460 int _bt_hps_prepare_httpproxy(void)
1461 {
1462         int ret = BLUETOOTH_ERROR_NONE;
1463         char *char_uuid;
1464         char *service_uuid;
1465         char *desc_uuid;
1466         bt_gatt_characteristic_property_t props;
1467 #ifdef  HPS_GATT_DB
1468         char value[MAX_URI_LENGTH] = { 0 };
1469         struct hps_char_info *char_info = NULL;
1470         char cp = 0x00;
1471         char status[3] = { 0 };
1472 #endif
1473
1474         BT_DBG("");
1475
1476         ret = bluetooth_gatt_init();
1477         if (ret != BLUETOOTH_ERROR_NONE) {
1478                 BT_ERR("Failed to Init GATT %d", ret);
1479                 goto fail;
1480         }
1481
1482         service_uuid = __hps_convert_uuid_to_uuid128(HPS_UUID);
1483         ret = bluetooth_gatt_add_service(service_uuid, &hps_obj_path);
1484         if (ret != BLUETOOTH_ERROR_NONE) {
1485                 BT_ERR("Failed to add service %d", ret);
1486                 goto fail;
1487         }
1488
1489         /* Characteristic URI */
1490         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1491         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_URI_UUID);
1492         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_uri_obj_path);
1493         if (ret != BLUETOOTH_ERROR_NONE) {
1494                 BT_ERR("Failed to add new char %d", ret);
1495                 goto fail;
1496         }
1497
1498 #ifdef  HPS_GATT_DB
1499         ret = bluetooth_gatt_set_characteristic_value(http_uri_obj_path, value, MAX_URI_LENGTH);
1500         if (ret != BLUETOOTH_ERROR_NONE) {
1501                 BT_ERR("Failed to add new char %d", ret);
1502                 goto fail;
1503         }
1504
1505         /* Store requets information */
1506         char_info = g_new0(struct hps_char_info, 1);
1507         char_info->char_path = g_strdup(http_uri_obj_path);
1508         hps_char_list = g_slist_append(hps_char_list, char_info);
1509         _bt_hps_set_char_value(http_uri_obj_path, value, MAX_URI_LENGTH, 0);
1510 #endif
1511
1512         /* Characteristic HTTP Headers */
1513         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1514                         BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1515         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_HDR_UUID);
1516         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_hdr_obj_path);
1517         if (ret != BLUETOOTH_ERROR_NONE) {
1518                 BT_ERR("Failed to add new char %d", ret);
1519                 goto fail;
1520         }
1521 #ifdef  HPS_GATT_DB
1522         ret = bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH);
1523         if (ret != BLUETOOTH_ERROR_NONE) {
1524                 BT_ERR("Failed to add new char %d", ret);
1525                 goto fail;
1526         }
1527
1528         /* Store Characterisitc information */
1529         char_info = g_new0(struct hps_char_info, 1);
1530         char_info->char_path = g_strdup(http_hdr_obj_path);
1531         hps_char_list = g_slist_append(hps_char_list, char_info);
1532         _bt_hps_set_char_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH, 0);
1533 #endif
1534
1535         /* Characteristic HTTP Entity Body */
1536         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1537                         BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1538         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_ENTITY_UUID);
1539         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_entity_obj_path);
1540         if (ret != BLUETOOTH_ERROR_NONE) {
1541                 BT_ERR("Failed to add new char %d", ret);
1542                 goto fail;
1543         }
1544 #ifdef  HPS_GATT_DB
1545         ret = bluetooth_gatt_set_characteristic_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH);
1546         if (ret != BLUETOOTH_ERROR_NONE) {
1547                 BT_ERR("Failed to add new char %d", ret);
1548                 goto fail;
1549         }
1550
1551         /* Store Characterisitc information */
1552         char_info = g_new0(struct hps_char_info, 1);
1553         char_info->char_path = g_strdup(http_entity_obj_path);
1554         hps_char_list = g_slist_append(hps_char_list, char_info);
1555         _bt_hps_set_char_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH, 0);
1556 #endif
1557
1558         /* Characteristic HTTP Control Point */
1559         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1560         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_CP_UUID);
1561         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_cp_obj_path);
1562         if (ret != BLUETOOTH_ERROR_NONE) {
1563                 BT_ERR("Failed to add new char %d", ret);
1564                 goto fail;
1565         }
1566 #ifdef  HPS_GATT_DB
1567         ret = bluetooth_gatt_set_characteristic_value(http_cp_obj_path, &cp, 1);
1568         if (ret != BLUETOOTH_ERROR_NONE) {
1569                 BT_ERR("Failed to add new char %d", ret);
1570                 goto fail;
1571         }
1572
1573         /* Store Characterisitc information */
1574         char_info = g_new0(struct hps_char_info, 1);
1575         char_info->char_path = g_strdup(http_cp_obj_path);
1576         hps_char_list = g_slist_append(hps_char_list, char_info);
1577         _bt_hps_set_char_value(http_cp_obj_path, &cp, 1, 0);
1578 #endif
1579
1580         /* Characteristic HTTP Status Code */
1581         props =  BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
1582         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_STATUS_UUID);
1583         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_status_obj_path);
1584         if (ret != BLUETOOTH_ERROR_NONE) {
1585                 BT_ERR("Failed to add new char %d", ret);
1586                 goto fail;
1587         }
1588 #ifdef  HPS_GATT_DB
1589         ret = bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
1590         if (ret != BLUETOOTH_ERROR_NONE) {
1591                 BT_ERR("Failed to add new char %d", ret);
1592                 goto fail;
1593         }
1594 #endif
1595         desc_uuid = __hps_convert_uuid_to_uuid128(HTTP_STATUS_CCC_DESC_UUID);
1596         ret = bluetooth_gatt_add_descriptor(http_status_obj_path, desc_uuid,
1597                                         (BLUETOOTH_GATT_PERMISSION_READ | BLUETOOTH_GATT_PERMISSION_WRITE),
1598                                         &http_status_desc_obj_path);
1599         if (ret != BLUETOOTH_ERROR_NONE) {
1600                 BT_ERR("Failed to add new char descriptor %d", ret);
1601                 goto fail;
1602         }
1603 #ifdef  HPS_GATT_DB
1604         /* Store Characterisitc information */
1605         char_info = g_new0(struct hps_char_info, 1);
1606         char_info->char_path = g_strdup(http_status_obj_path);
1607         hps_char_list = g_slist_append(hps_char_list, char_info);
1608         _bt_hps_set_char_value(http_status_obj_path, status, 3, 0);
1609 #endif
1610
1611         /* Characteristic HTTPS Security */
1612         props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
1613         char_uuid = __hps_convert_uuid_to_uuid128(HTTP_SECURITY_UUID);
1614         ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_security_obj_path);
1615         if (ret != BLUETOOTH_ERROR_NONE) {
1616                 BT_ERR("Failed to add new char %d", ret);
1617                 goto fail;
1618         }
1619 #ifdef  HPS_GATT_DB
1620         ret = bluetooth_gatt_set_characteristic_value(http_security_obj_path, &cp, 1);
1621         if (ret != BLUETOOTH_ERROR_NONE) {
1622                 BT_ERR("Failed to add new char %d", ret);
1623                 goto fail;
1624         }
1625
1626         /* Store Characterisitc information */
1627         char_info = g_new0(struct hps_char_info, 1);
1628         char_info->char_path = g_strdup(http_security_obj_path);
1629         hps_char_list = g_slist_append(hps_char_list, char_info);
1630         _bt_hps_set_char_value(http_security_obj_path, &cp, 1, 0);
1631 #endif
1632
1633         ret = bluetooth_gatt_register_service(hps_obj_path);
1634         if (ret != BLUETOOTH_ERROR_NONE) {
1635                 BT_ERR("Failed to register service %d", ret);
1636                 goto fail;
1637         }
1638
1639         ret = bluetooth_gatt_register_application();
1640         if (ret != BLUETOOTH_ERROR_NONE) {
1641                 BT_ERR("Failed to register application %d", ret);
1642                 goto fail;
1643         }
1644
1645         return ret;
1646
1647 fail:
1648 #ifdef  HPS_GATT_DB
1649         delete_all_characterisitc();
1650         delete_all_notify_read_status();
1651 #endif
1652         return ret;
1653 }
1654
1655
1656 static void _bt_hps_sig_handler(int sig)
1657 {
1658         BT_DBG("");
1659
1660         switch (sig) {
1661         case SIGTERM:
1662                 BT_DBG("caught signal - sigterm\n");
1663                 break;
1664         case SIGINT:
1665                 BT_DBG("caught signal - sigint\n");
1666                 break;
1667         case SIGKILL:
1668                 BT_DBG("caught signal - sigkill\n");
1669                 break;
1670         default:
1671                 BT_DBG("caught signal %d and ignored\n", sig);
1672                 break;
1673         }
1674 }
1675
1676 void _bt_hps_exit(void)
1677 {
1678         int ret;
1679         BT_DBG("");
1680
1681         if (g_uri != NULL) {
1682                 g_free(g_uri);
1683                 g_uri = NULL;
1684         }
1685
1686         if (g_header != NULL) {
1687                 g_free(g_header);
1688                 g_header = NULL;
1689         }
1690
1691         if (g_entity != NULL) {
1692                 g_free(g_entity);
1693                 g_entity = NULL;
1694         }
1695
1696         soup_session_abort(hps_soup_session);
1697         g_assert_cmpint(G_OBJECT(hps_soup_session)->ref_count, ==, 1);
1698         g_object_unref(hps_soup_session);
1699
1700 #ifdef  HPS_GATT_DB
1701         delete_all_characterisitc();
1702 #endif
1703
1704         ret = bluetooth_gatt_deinit();
1705         if (ret != BLUETOOTH_ERROR_NONE)
1706                 BT_ERR("Failed to Deinit GATT %d", ret);
1707
1708         ret = bluetooth_unregister_callback();
1709         if (ret != BLUETOOTH_ERROR_NONE)
1710                 BT_ERR("Failed to Unregister callback %d", ret);
1711
1712         _bt_hps_deinit_event_receiver();
1713
1714         _bt_hps_unregister_interface();
1715
1716         if (main_loop != NULL)
1717                 g_main_loop_quit(main_loop);
1718 }
1719
1720 void bt_hps_event_callback(int event, bluetooth_event_param_t* param,
1721                                                         void *user_data)
1722 {
1723         BT_DBG("HPS event %d", event);
1724         return;
1725 }
1726
1727 /* HTTP Proxy Service Main loop */
1728 int main(void)
1729 {
1730         struct sigaction sa;
1731
1732         BT_ERR("Starting the bt-httpproxy daemon");
1733
1734         /* Values taken from http://www.browserscope.org/  following
1735           * the rule "Do What Every Other Modern Browser Is Doing". They seem
1736           * to significantly improve page loading time compared to soup's
1737           * default values.
1738           * Change MAX_CONNECTIONS_PER_HOST value 6 -> 12, and maxConnections is changed from 35 to 60.
1739           * Enhanced network loading speed apply tunning value. */
1740         static const int maxConnections = 60;
1741         static const int maxConnectionsPerHost = 12;
1742
1743         memset(&sa, 0, sizeof(sa));
1744         sa.sa_handler = _bt_hps_sig_handler;
1745         sa.sa_flags = SA_SIGINFO;
1746         sigaction(SIGINT, &sa, NULL);
1747         sigaction(SIGTERM, &sa, NULL);
1748         sigaction(SIGKILL, &sa, NULL);
1749
1750 #ifndef HPS_GATT_DB
1751         if (bluetooth_register_callback(bt_hps_event_callback, NULL) != BLUETOOTH_ERROR_NONE) {
1752                 BT_ERR("bluetooth_register_callback returned failiure");
1753                 return -3;
1754         }
1755 #endif
1756
1757         if (_bt_hps_register_interface() != BLUETOOTH_ERROR_NONE) {
1758                 BT_ERR("Fail to register http proxy service");
1759                 return -4;
1760         }
1761
1762         if (_bt_hps_init_event_receiver() != BLUETOOTH_ERROR_NONE) {
1763                 BT_ERR("Fail to init event reciever");
1764                 return -5;
1765         }
1766
1767         hps_soup_session = soup_session_async_new();
1768         if (hps_soup_session == NULL) {
1769                 BT_ERR("Failed to soup_session_async_new");
1770                 return -6;
1771         }
1772         /* Set Soup Session Fetures */
1773         g_object_set(hps_soup_session,
1774                         SOUP_SESSION_MAX_CONNS, maxConnections,
1775                         SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
1776                         SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
1777                         SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER,
1778                         SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
1779                         SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
1780                         NULL);
1781
1782         main_loop = g_main_loop_new(NULL, FALSE);
1783
1784         g_main_loop_run(main_loop);
1785
1786         BT_DBG("g_main_loop_quit called!");
1787
1788         if (main_loop != NULL)
1789                 g_main_loop_unref(main_loop);
1790
1791         return 0;
1792 }
1793
1794 #endif