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