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