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