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