2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include "bt-httpproxy.h"
24 #include "bluetooth-api.h"
26 #include <libsoup/soup.h>
31 #define LOG_TAG "BLUETOOTH_HPS"
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)
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;
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;
52 struct hps_notify_read_info {
59 struct hps_char_info {
65 static GSList *hps_notify_read_list = NULL;
66 static GSList *hps_char_list = NULL;
69 static GDBusConnection *conn;
70 static GDBusConnection *g_conn;
71 static guint g_owner_id = 0;
72 GDBusNodeInfo *hps_node_info = NULL;
75 char *g_header = NULL;
76 char *g_entity = NULL;
78 static SoupSession *hps_soup_session = NULL;
79 static SoupMessage *hps_soup_msg = NULL;
82 static const gchar hps_introspection_xml[] =
84 " <interface name='org.projectx.httpproxy_service'>"
85 " <method name='enable'>"
86 " <arg type='y' name='status' direction='out'/>"
88 " <method name='disable'>"
89 " <arg type='y' name='status' direction='out'/>"
95 static void _bt_hps_set_char_value(const char *obj_path, const char* value, int value_length);
97 static void _hps_convert_address_to_hex(bluetooth_device_address_t *addr_hex, const char *addr_str)
100 unsigned int addr[BLUETOOTH_ADDRESS_LENGTH] = { 0, };
102 if (addr_str == NULL || addr_str[0] == '\0')
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);
110 for (i = 0; i < BLUETOOTH_ADDRESS_LENGTH; i++) {
111 addr_hex->addr[i] = (unsigned char)addr[i];
115 static void _bt_hps_send_status_notification(unsigned short http_status,
116 unsigned char data_status,
117 bluetooth_device_address_t *unicast_address)
119 char status[3] = {0x00};
120 int ret = BLUETOOTH_ERROR_NONE;
124 status[0] = http_status & 0xFF;
125 status[1] = (http_status >> 8) & 0xFF;
126 status[2] = data_status;
127 BT_DBG("Status %d %04x", http_status, http_status);
129 /* Store the status value */
130 _bt_hps_set_char_value(http_status_obj_path, status, 3);
132 /* Send unicast notification */
133 ret = bluetooth_gatt_server_set_notification(http_status_obj_path, unicast_address);
134 if (ret != BLUETOOTH_ERROR_NONE) {
135 BT_ERR("_bt_hps_send_status_notification failed");
138 ret = bluetooth_gatt_update_characteristic(http_status_obj_path, status, 3);
139 if (ret != BLUETOOTH_ERROR_NONE) {
140 BT_ERR("_bt_hps_send_status_notification failed");
146 static void _bt_httpproxy_method(GDBusConnection *connection,
148 const gchar *object_path,
149 const gchar *interface_name,
150 const gchar *method_name,
151 GVariant *parameters,
152 GDBusMethodInvocation *invocation,
157 BT_DBG("Method[%s] Object Path[%s] Interface Name[%s]",
158 method_name, object_path, interface_name);
160 if (g_strcmp0(method_name, "enable") == 0) {
161 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
162 } else if (g_strcmp0(method_name, "disable") == 0) {
164 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
170 static const GDBusInterfaceVTable hps_method_table = {
171 _bt_httpproxy_method,
176 static void _bt_hps_on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
179 GError *error = NULL;
185 object_id = g_dbus_connection_register_object(connection, BT_HPS_OBJECT_PATH,
186 hps_node_info->interfaces[0],
189 if (object_id == 0) {
190 BT_ERR("Failed to register method table: %s", error->message);
192 g_dbus_node_info_unref(hps_node_info);
198 static void _bt_hps_on_name_acquired(GDBusConnection *connection,
206 static void _bt_hps_on_name_lost(GDBusConnection *connection,
211 g_object_unref(g_conn);
213 g_dbus_node_info_unref(hps_node_info);
214 g_bus_unown_name(g_owner_id);
219 int _bt_hps_register_interface(void)
221 GError *error = NULL;
226 hps_node_info = g_dbus_node_info_new_for_xml(hps_introspection_xml, &error);
227 if (!hps_node_info) {
228 BT_ERR("Failed to install: %s", error->message);
229 return BLUETOOTH_ERROR_INTERNAL;
232 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
234 G_BUS_NAME_OWNER_FLAGS_NONE,
235 _bt_hps_on_bus_acquired, _bt_hps_on_name_acquired, _bt_hps_on_name_lost,
237 g_owner_id = owner_id;
238 BT_DBG("owner_id is [%d]\n", owner_id);
240 return BLUETOOTH_ERROR_NONE;
243 void _bt_hps_unregister_interface(void)
247 g_object_unref(g_conn);
249 g_dbus_node_info_unref(hps_node_info);
250 g_bus_unown_name(g_owner_id);
256 static struct hps_char_info *hps_get_char_value(const char *path)
260 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
262 struct hps_char_info *char_info = tmp->data;
263 if (!g_strcmp0(char_info->char_path, path))
270 static int char_info_cmp(gconstpointer a1, gconstpointer a2)
272 const struct hps_char_info *attrib1 = a1;
273 const struct hps_char_info *attrib2 = a2;
275 return g_strcmp0(attrib1->char_path, attrib2->char_path);
278 static int notify_info_cmp(gconstpointer a1, gconstpointer a2)
280 const struct hps_notify_read_info *attrib1 = a1;
281 const struct hps_notify_read_info *attrib2 = a2;
283 return g_strcmp0(attrib1->char_path, attrib2->char_path);
286 static void _bt_hps_set_char_value(const char *obj_path, const char* value, int value_length)
292 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
294 struct hps_char_info *char_info = tmp->data;
295 if (!g_strcmp0(char_info->char_path, obj_path)) {
296 char_info->char_value = g_try_realloc(char_info->char_value, value_length);
297 if (char_info->char_value) {
298 memcpy(char_info->char_value, value, value_length);
299 char_info->value_length = value_length;
300 hps_char_list = g_slist_insert_sorted(hps_char_list,
301 char_info, char_info_cmp);
310 static void _bt_hps_set_notify_read_status(const char *obj_path,
311 guint offset_status, guint read_status, int https_status)
313 struct hps_notify_read_info *notify_read_info = NULL;
316 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
318 notify_read_info = tmp->data;
319 if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
320 notify_read_info->read_status = read_status;
321 notify_read_info->offset_status = offset_status;
322 notify_read_info->https_status = https_status;
323 hps_notify_read_list = g_slist_insert_sorted(hps_notify_read_list,
324 notify_read_info, notify_info_cmp);
330 if (!hps_notify_read_list) {
331 /* Store Notification information */
332 notify_read_info = g_new0(struct hps_notify_read_info, 1);
333 if (notify_read_info) {
334 notify_read_info->char_path = g_strdup(obj_path);
335 notify_read_info->read_status = read_status;
336 notify_read_info->offset_status = offset_status;
337 notify_read_info->https_status = https_status;
338 hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
342 /* Store Notification information */
343 notify_read_info = g_new0(struct hps_notify_read_info, 1);
344 if (notify_read_info) {
345 notify_read_info->char_path = g_strdup(obj_path);
346 notify_read_info->read_status = read_status;
347 notify_read_info->offset_status = offset_status;
348 notify_read_info->https_status = https_status;
349 hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
355 static struct hps_notify_read_info *_bt_hps_get_notify_read_status(const char *obj_path)
359 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
361 struct hps_notify_read_info *notify_read_info = tmp->data;
362 if (!g_strcmp0(notify_read_info->char_path, obj_path))
363 return notify_read_info;
370 static void delete_all_characterisitc(void)
373 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
375 struct hps_char_info *char_info = tmp->data;
376 if (char_info->char_path)
377 g_free(char_info->char_path);
378 if (char_info->char_value)
379 g_free(char_info->char_value);
380 hps_char_list = g_slist_delete_link(hps_char_list, tmp->data);
383 g_slist_free(hps_char_list);
384 hps_char_list = NULL;
387 static void delete_all_notify_read_status(void)
390 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
392 struct hps_notify_read_info *notify_read_info = tmp->data;
393 if (notify_read_info->char_path)
394 g_free(notify_read_info->char_path);
395 hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
398 g_slist_free(hps_notify_read_list);
399 hps_notify_read_list = NULL;
402 static void delete_notify_read_status(const char *obj_path)
405 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
407 struct hps_notify_read_info *notify_read_info = tmp->data;
408 if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
409 if (notify_read_info->char_path)
410 g_free(notify_read_info->char_path);
411 hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
419 int _bt_hps_uri_write_cb(char *uri, int len)
421 if ((len < 1) || (len > MAX_URI_LENGTH)) {
422 BT_ERR("Wrong URI length %d", len);
423 return BLUETOOTH_ERROR_INTERNAL;
426 /* g_uri will be used commonly for all HTTP methods whereever applicable */
429 g_uri = g_strndup(uri, len);
431 _bt_hps_set_char_value(http_uri_obj_path, g_uri, len);
433 return BLUETOOTH_ERROR_NONE;
436 int _bt_hps_http_header_write_cb(char *header, int len)
438 if ((len < 1) || (len > MAX_HEADER_LENGTH)) {
439 BT_ERR("Wrong Header length %d", len);
440 return BLUETOOTH_ERROR_INTERNAL;
443 /* g_header will be used commonly for all HTTP methods where ever applicable
444 general-header, request-header, entity-header
448 g_header = g_strndup(header, len);
450 _bt_hps_set_char_value(http_hdr_obj_path, g_header, len);
453 return BLUETOOTH_ERROR_NONE;
456 int _bt_hps_entity_body_write_cb(char *entity, int len)
458 if ((len < 1) || (len > MAX_ENTITY_LENGTH)) {
459 BT_ERR("Wrong Entity length %d", len);
460 return BLUETOOTH_ERROR_INTERNAL;
463 /* g_entity will be used commonly for all HTTP methods whereever applicable */
466 g_entity = g_strndup(entity, len);
468 _bt_hps_set_char_value(http_entity_obj_path, g_entity, len);
471 return BLUETOOTH_ERROR_NONE;
475 int _bt_hps_read_cb(const char *obj_path, char **value, int *len)
477 struct hps_char_info *info = NULL;
478 struct hps_notify_read_info *notify_read_info = NULL;
479 guint data_status = -1;
481 gboolean is_header = FALSE;
484 BT_ERR("Wrong Obj path");
488 if (!g_strcmp0(http_hdr_obj_path, obj_path))
491 info = hps_get_char_value(obj_path);
494 if (info->char_value == NULL || info->value_length == 0)
497 notify_read_info = _bt_hps_get_notify_read_status(obj_path);
498 if (notify_read_info && notify_read_info->read_status != DS_BODY_RECEIVED &&
499 notify_read_info->read_status != DS_HEADER_RECEIVED) {
500 offset = notify_read_info->offset_status;
501 if ((info->value_length - offset) > 0 &&
502 (info->value_length - offset) > MAX_ENTITY_LENGTH) {
504 data_status = DS_HEADER_TRUNCATED;
506 data_status = DS_BODY_TRUNCATED;
507 _bt_hps_set_notify_read_status(obj_path, offset + MAX_ENTITY_LENGTH,
508 data_status, notify_read_info->https_status);
509 *value = g_strdup(&info->char_value[offset]);
510 *len = info->value_length;
511 } else if ((info->value_length - offset) > 0 &&
512 (info->value_length - offset) <= MAX_ENTITY_LENGTH) {
514 data_status = DS_HEADER_RECEIVED;
516 data_status = DS_BODY_RECEIVED;
517 _bt_hps_set_notify_read_status(obj_path, offset, data_status, notify_read_info->https_status);
518 *value = g_strdup(&info->char_value[offset]);
519 *len = info->value_length;
521 } else if (notify_read_info && (notify_read_info->read_status == DS_BODY_RECEIVED ||
522 notify_read_info->read_status == DS_HEADER_RECEIVED)) {
524 data_status = DS_HEADER_RECEIVED;
526 data_status = DS_BODY_RECEIVED;
527 delete_notify_read_status(obj_path);
528 *value = g_strdup(&info->char_value[offset]);
529 *len = info->value_length;
537 void _bt_hps_head_response_cb(SoupSession *session,
538 SoupMessage *msg, gpointer user_data)
540 unsigned short http_status = 0x00;
542 unsigned char status[3] = {0x00};
544 const char *device_address = user_data;
545 bluetooth_device_address_t addr_hex = { {0,} };
546 unsigned char data_status = DS_NONE;
547 _hps_convert_address_to_hex(&addr_hex, device_address);
550 if (hps_soup_session != session) {
551 BT_ERR("Wrong Session");
556 BT_ERR("Wrong Message");
561 req_state = HTTP_REQ_STATE_EXECUTED;
563 http_status = msg->status_code;
565 // Process Header in Response Body
566 if (msg->response_headers) {
568 const char *content = NULL;
569 const char *length = NULL;
572 length = soup_message_headers_get_one(msg->request_headers,
574 // Check "Content-MD5" is the right name to get header content
575 content = soup_message_headers_get_one(msg->response_headers,
577 if (content == NULL || length == NULL) {
578 BT_ERR("Wrong Response Header");
579 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
583 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
585 // Write Data to Header Characteristic
587 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len);
589 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
591 // TODO : Handle Truncated Header
593 // Write Data to Status Code Characteristic
595 data_status = (hdr_len > MAX_ENTITY_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
596 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
597 _bt_hps_set_notify_read_status(http_hdr_obj_path, data_status, 0, http_status);
599 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
601 status[0] = http_status & 0x0F;
602 status[1] = (http_status >> 8) & 0x0F;
603 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
605 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
608 BT_ERR("HEAD Response is NULL");
609 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
615 void _bt_hps_http_response_cb(SoupSession *session,
616 SoupMessage *msg, gpointer user_data)
618 unsigned short http_status = 0x00;
620 unsigned char status[3] = {0x00};
622 const char *device_address = user_data;
623 bluetooth_device_address_t addr_hex = { {0,} };
624 unsigned char data_status = DS_NONE;
625 _hps_convert_address_to_hex(&addr_hex, device_address);
628 if (hps_soup_session != session) {
629 BT_ERR("Wrong Session");
634 BT_ERR("Wrong Message");
640 req_state = HTTP_REQ_STATE_EXECUTED;
642 http_status = msg->status_code;
644 // Write Data to Status Code Characteristic
646 status[0] = http_status & 0x0F;
647 status[1] = (http_status >> 8) & 0x0F;
648 status[2] = DS_HEADER_RECEIVED;
649 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
651 data_status = DS_HEADER_RECEIVED;
652 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
658 void _bt_hps_get_response_cb(SoupSession *session,
659 SoupMessage *msg, gpointer user_data)
661 SoupBuffer *body = NULL;
662 unsigned short http_status = 0x00;
664 unsigned char status[3] = {0x00};
666 const char *device_address = user_data;
667 bluetooth_device_address_t addr_hex = { {0,} };
668 unsigned char data_status = DS_NONE;
669 _hps_convert_address_to_hex(&addr_hex, device_address);
672 if (hps_soup_session != session) {
673 BT_ERR("Wrong Session");
678 BT_ERR("Wrong Message");
684 req_state = HTTP_REQ_STATE_EXECUTED;
686 http_status = msg->status_code;
688 // Process Entity Body in Response Message
689 if (msg->response_body) {
691 body = soup_message_body_flatten(msg->response_body);
693 BT_ERR("Wrong Response Body");
695 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
699 if (body->data == NULL || body->length <= 0) {
700 BT_ERR("Wrong Response");
701 soup_buffer_free(body);
703 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
707 // Write Data to Entity Body Characteristic
709 _bt_hps_set_char_value(http_entity_obj_path, body->data, body->length);
711 bluetooth_gatt_set_characteristic_value(http_entity_obj_path, body->data, body->length);
713 // TODO : Handle Truncated Entiry Body
715 // Write Data to Status Code Characteristic
717 data_status = (body->length > MAX_ENTITY_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_RECEIVED;
718 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
719 _bt_hps_set_notify_read_status(http_entity_obj_path, data_status, 0, http_status);
721 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
724 status[0] = http_status & 0x0F;
725 status[1] = (http_status >> 8) & 0x0F;
726 status[2] = (body->length > MAX_HEADER_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_TRUNCATED;
728 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
730 soup_buffer_free(body);
732 BT_ERR("GET Response Body is NULL");
734 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
738 // Process Header in Response Body
739 if (msg->response_headers) {
741 const char *content = NULL;
742 const char *length = NULL;
745 length = soup_message_headers_get_one(msg->request_headers,
747 // Check "Content-MD5" is the right name to get header content
748 content = soup_message_headers_get_one(msg->response_headers,
750 if (content == NULL || length == NULL) {
751 BT_ERR("Wrong Response Header");
752 data_status = DS_NONE;
753 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
757 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
758 // Write Data to Header Characteristic
760 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len);
762 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
764 // TODO : Handle Truncated Header
766 // Write Data to Status Code Characteristic
768 data_status = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
769 if (data_status == DS_HEADER_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
770 _bt_hps_set_notify_read_status(http_hdr_obj_path, data_status, 0, http_status);
772 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
774 status[0] = http_status & 0x0F;
775 status[1] = (http_status >> 8) & 0x0F;
776 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
778 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
781 BT_ERR("GET Response Header is NULL");
783 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
791 int _bt_hps_control_point_write_cb(const char *value, int len, char *addr)
793 int _bt_hps_control_point_write_cb(char *value, int len)
797 GTlsCertificate *cert = NULL;
798 GTlsCertificateFlags flags;
799 gboolean https_status = FALSE;
800 int result = BLUETOOTH_ERROR_NONE;
801 BT_INFO("Opcode %0x", opcode);
804 _bt_hps_set_char_value(http_cp_obj_path, value, len);
808 case HTTP_GET_REQUEST:
809 if (req_state == HTTP_REQ_STATE_EXECUTED) {
810 req_state = HTTP_REQ_STATE_INPROGRESS;
811 hps_soup_msg = soup_message_new("GET", g_uri);
813 g_object_ref(hps_soup_msg);
814 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
816 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
819 BT_ERR("HTTP GET request in progress, message dropped");
820 result = BLUETOOTH_ERROR_INTERNAL;
824 case HTTP_POST_REQUEST:
825 if (req_state == HTTP_REQ_STATE_EXECUTED) {
826 req_state = HTTP_REQ_STATE_INPROGRESS;
827 hps_soup_msg = soup_message_new("POST", g_uri);
828 if (hps_soup_msg == NULL || g_entity == NULL) {
829 BT_ERR("Soup Message NULL");
830 result = BLUETOOTH_ERROR_INTERNAL;
831 req_state = HTTP_REQ_STATE_EXECUTED;
834 soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_COPY,
835 g_entity, strlen(g_entity));
837 g_object_ref(hps_soup_msg);
838 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
840 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
843 BT_ERR("HTTP POST request in progress, message dropped");
844 result = BLUETOOTH_ERROR_INTERNAL;
848 case HTTP_HEAD_REQUEST:
849 if (req_state == HTTP_REQ_STATE_EXECUTED) {
850 req_state = HTTP_REQ_STATE_INPROGRESS;
851 hps_soup_msg = soup_message_new("HEAD", g_uri);
852 if (hps_soup_msg == NULL) {
853 BT_ERR("Soup Message NULL");
854 result = BLUETOOTH_ERROR_INTERNAL;
855 req_state = HTTP_REQ_STATE_EXECUTED;
859 g_object_ref(hps_soup_msg);
860 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
862 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
865 BT_ERR("HTTP HEAD request in progress, message dropped");
866 result = BLUETOOTH_ERROR_INTERNAL;
870 case HTTP_PUT_REQUEST:
871 if (req_state == HTTP_REQ_STATE_EXECUTED) {
873 req_state = HTTP_REQ_STATE_INPROGRESS;
874 hps_soup_msg = soup_message_new("PUT", g_uri);
875 if (hps_soup_msg == NULL || g_entity == NULL) {
876 BT_ERR("Soup Message NULL");
877 result = BLUETOOTH_ERROR_INTERNAL;
878 req_state = HTTP_REQ_STATE_EXECUTED;
881 buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
882 soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
883 soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
885 g_object_ref(hps_soup_msg);
886 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
888 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
892 BT_ERR("HTTP PUT request in progress, message dropped");
893 result = BLUETOOTH_ERROR_INTERNAL;
897 case HTTP_DELETE_REQUEST:
898 if (req_state == HTTP_REQ_STATE_EXECUTED) {
899 req_state = HTTP_REQ_STATE_INPROGRESS;
900 hps_soup_msg = soup_message_new("DELETE", g_uri);
901 if (hps_soup_msg == NULL) {
902 BT_ERR("Soup Message NULL");
903 result = BLUETOOTH_ERROR_INTERNAL;
904 req_state = HTTP_REQ_STATE_EXECUTED;
908 g_object_ref(hps_soup_msg);
909 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
911 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
914 BT_ERR("HTTP DELETE request in progress, message dropped");
915 result = BLUETOOTH_ERROR_INTERNAL;
919 case HTTPS_GET_REQUEST:
920 if (req_state == HTTP_REQ_STATE_EXECUTED) {
921 req_state = HTTP_REQ_STATE_INPROGRESS;
922 hps_soup_msg = soup_message_new("GET", g_uri);
923 if (hps_soup_msg == NULL) {
924 BT_ERR("Soup Message NULL");
925 result = BLUETOOTH_ERROR_INTERNAL;
926 req_state = HTTP_REQ_STATE_EXECUTED;
930 g_object_ref(hps_soup_msg);
931 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
933 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
935 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
937 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1);
939 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
942 BT_ERR("HTTPS GET request in progress, message dropped");
943 result = BLUETOOTH_ERROR_INTERNAL;
947 case HTTPS_HEAD_REQUEST:
948 if (req_state == HTTP_REQ_STATE_EXECUTED) {
949 req_state = HTTP_REQ_STATE_INPROGRESS;
950 hps_soup_msg = soup_message_new("HEAD", g_uri);
951 if (hps_soup_msg == NULL) {
952 BT_ERR("Soup Message NULL");
953 result = BLUETOOTH_ERROR_INTERNAL;
954 req_state = HTTP_REQ_STATE_EXECUTED;
958 g_object_ref(hps_soup_msg);
959 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
961 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
963 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
965 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1);
967 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
970 BT_ERR("HTTPS HEAD request in progress, message dropped");
971 result = BLUETOOTH_ERROR_INTERNAL;
975 case HTTPS_POST_REQUEST:
976 if (req_state == HTTP_REQ_STATE_EXECUTED) {
977 req_state = HTTP_REQ_STATE_INPROGRESS;
978 hps_soup_msg = soup_message_new("POST", g_uri);
979 if (hps_soup_msg == NULL) {
980 BT_ERR("Soup Message NULL");
981 result = BLUETOOTH_ERROR_INTERNAL;
982 req_state = HTTP_REQ_STATE_EXECUTED;
985 soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_STATIC,
986 g_entity, strlen(g_entity));
988 g_object_ref(hps_soup_msg);
989 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
991 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
994 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
996 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1);
998 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1001 BT_ERR("HTTPS POST request in progress, message dropped");
1002 result = BLUETOOTH_ERROR_INTERNAL;
1006 case HTTPS_PUT_REQUEST:
1007 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1009 req_state = HTTP_REQ_STATE_INPROGRESS;
1010 hps_soup_msg = soup_message_new("PUT", g_uri);
1011 if (hps_soup_msg == NULL) {
1012 BT_ERR("Soup Message NULL");
1013 result = BLUETOOTH_ERROR_INTERNAL;
1014 req_state = HTTP_REQ_STATE_EXECUTED;
1017 buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
1018 soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
1019 soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
1021 g_object_ref(hps_soup_msg);
1022 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1024 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1026 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1028 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1);
1030 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1033 BT_ERR("HTTPS PUT request in progress, message dropped");
1034 result = BLUETOOTH_ERROR_INTERNAL;
1038 case HTTPS_DELETE_REQUEST:
1039 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1040 req_state = HTTP_REQ_STATE_INPROGRESS;
1041 hps_soup_msg = soup_message_new("DELETE", g_uri);
1042 if (hps_soup_msg == NULL) {
1043 BT_ERR("Soup Message NULL");
1044 result = BLUETOOTH_ERROR_INTERNAL;
1045 req_state = HTTP_REQ_STATE_EXECUTED;
1049 g_object_ref(hps_soup_msg);
1050 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1052 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1055 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1057 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1);
1059 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1062 BT_ERR("HTTPS DELETE request in progress, message dropped");
1063 result = BLUETOOTH_ERROR_INTERNAL;
1067 case HTTP_REQUEST_CANCEL:
1068 /* Cancel the outstanding request */
1069 if (req_state == HTTP_REQ_STATE_INPROGRESS) {
1070 req_state = HTTP_REQ_STATE_IDLE;
1071 if (hps_soup_msg == NULL) {
1072 BT_ERR("Soup Message NULL");
1073 result = BLUETOOTH_ERROR_INTERNAL;
1074 req_state = HTTP_REQ_STATE_EXECUTED;
1077 soup_session_cancel_message(hps_soup_session, hps_soup_msg, SOUP_STATUS_CANCELLED);
1078 hps_soup_msg = NULL;
1083 BT_ERR("Unknown opcode %0x", opcode);
1084 result = BLUETOOTH_ERROR_INTERNAL;
1091 void _bt_hps_security_read_cb(char *value, int len)
1093 BT_INFO("HPS Client Read the value");
1098 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1101 int result = BLUETOOTH_ERROR_NONE;
1102 GVariantIter value_iter;
1103 const char *property = NULL;
1104 const char * char_path = NULL;
1105 const char * svc_handle = NULL;
1106 GVariant *var = NULL;
1107 GVariant *val = NULL;
1108 g_variant_iter_init(&value_iter, msg);
1110 while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &var))) {
1112 if (property == NULL) {
1113 BT_ERR("Property NULL");
1117 if (!g_strcmp0(property, "WriteValue")) {
1119 BT_INFO("WriteValue");
1120 BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1127 g_variant_get(var, "(&s&s&syq@ay)", &char_path,
1128 &svc_handle, &addr, &req_id, &offset, &val);
1130 len = g_variant_get_size(val);
1132 BT_DBG("Len = %d", len);
1134 value = (char *) g_variant_get_data(val);
1137 if (!g_strcmp0(char_path, http_uri_obj_path)) {
1139 result = _bt_hps_uri_write_cb(value, len);
1140 } else if (!g_strcmp0(char_path, http_hdr_obj_path)) {
1141 /* Retrive HEADER */
1142 result = _bt_hps_http_header_write_cb(value, len);
1143 } else if (!g_strcmp0(char_path, http_entity_obj_path)) {
1144 /* Retrive ENTITY BODY */
1145 result = _bt_hps_entity_body_write_cb(value, len);
1146 } else if (!g_strcmp0(char_path, http_cp_obj_path)) {
1147 result = _bt_hps_control_point_write_cb(value, len, addr);
1149 BT_ERR("Wrong Object Path %s", char_path);
1150 result = BLUETOOTH_ERROR_INTERNAL;
1152 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_WRITE, result, 0, NULL, 0);
1154 BT_ERR("Array Len 0");
1157 BT_ERR("var==NULL");
1159 } else if (!g_strcmp0(property, "ReadValue")) {
1165 int data_status = -1;
1166 BT_INFO("ReadValue");
1167 BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1169 g_variant_get(var, "(&s&s&syq)", &char_path, &svc_handle,
1170 &addr, &req_id, &offset);
1172 data_status = _bt_hps_read_cb(char_path, &value, &len);
1173 if (data_status >= DS_NONE) {
1174 struct hps_notify_read_info *notify_read_info = NULL;
1175 bluetooth_device_address_t addr_hex = { {0,} };
1176 _hps_convert_address_to_hex(&addr_hex, addr);
1177 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1178 BLUETOOTH_ERROR_NONE, offset, value, len);
1179 notify_read_info = _bt_hps_get_notify_read_status(char_path);
1180 if (notify_read_info) {
1181 _bt_hps_send_status_notification(notify_read_info->https_status,
1182 data_status, &addr_hex);
1184 if (data_status == DS_BODY_RECEIVED ||
1185 data_status == DS_HEADER_RECEIVED) {
1186 _bt_hps_set_char_value(char_path, NULL, 0);
1192 BT_ERR("ReadValue failed %s", char_path);
1193 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1194 BLUETOOTH_ERROR_INTERNAL, offset, NULL, 0);
1201 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1204 GVariantIter value_iter;
1205 char *property = NULL;
1206 char * char_handle = NULL;
1207 GVariant *val = NULL;
1208 int result = BLUETOOTH_ERROR_NONE;
1209 GVariant *param = NULL;
1210 g_variant_iter_init(&value_iter, msg);
1211 char_handle = g_strdup(path);
1213 while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &val))) {
1215 if (property == NULL) {
1216 BT_ERR("Property NULL");
1220 if (strcasecmp(property, "ChangedValue") == 0) {
1223 GByteArray *gp_byte_array = NULL;
1224 BT_INFO("Type '%s'\n", g_variant_get_type_string(val));
1227 gp_byte_array = g_byte_array_new();
1228 len = g_variant_get_size(val);
1229 BT_DBG("Len = %d", len);
1230 g_byte_array_append(gp_byte_array,
1231 (const guint8 *)g_variant_get_data(val), len);
1232 if (gp_byte_array->len != 0) {
1233 GVariant *byte_array = NULL;
1234 byte_array = g_variant_new_from_data(
1235 G_VARIANT_TYPE_BYTESTRING,
1236 gp_byte_array->data,
1239 param = g_variant_new("(is@ay)", result, char_handle,
1242 if (strcmp(path, http_uri_obj_path)) {
1244 _bt_hps_uri_write_cb(NULL, len);
1245 } else if (strcmp(path, http_hdr_obj_path)) {
1247 _bt_hps_http_header_write_cb(NULL, len);
1248 } else if (strcmp(path, http_entity_obj_path)) {
1249 //Retrive ENTITY BODY
1250 _bt_hps_entity_body_write_cb(NULL, len);
1251 } else if (strcmp(path, http_cp_obj_path)) {
1252 _bt_hps_control_point_write_cb(NULL, len);
1253 } else if (strcmp(path, http_security_obj_path)) {
1254 _bt_hps_security_read_cb(NULL, len);
1256 BT_ERR("Wrong Object Path %s", path);
1259 BT_ERR("Array Len 0");
1261 g_byte_array_free(gp_byte_array, TRUE);
1263 BT_ERR("val==NULL");
1267 g_free(char_handle);
1273 void _bt_hps_property_event_filter(GDBusConnection *connection,
1274 const gchar *sender_name,
1275 const gchar *object_path,
1276 const gchar *interface_name,
1277 const gchar *signal_name,
1278 GVariant *parameters,
1283 if (signal_name == NULL) {
1284 BT_ERR("Wrong Signal");
1289 if (g_strcmp0(signal_name, PROPERTIES_CHANGED) == 0) {
1291 g_variant_get(parameters, "(@a{sv}@as)", &value, NULL);
1293 _bt_hps_gatt_char_property_changed_event(value, object_path);
1295 if (g_strcmp0(interface_name, BT_HPS_PROPERTIES_INTERFACE) == 0) {
1297 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1299 _bt_hps_gatt_char_property_changed_event(value, object_path);
1302 //BT_ERR("Wrong Interface %s", interface_name);
1309 void _bt_hps_adapter_event_filter(GDBusConnection *connection,
1310 const gchar *sender_name,
1311 const gchar *object_path,
1312 const gchar *interface_name,
1313 const gchar *signal_name,
1314 GVariant *parameters,
1317 int result = BLUETOOTH_ERROR_NONE;
1320 if (signal_name == NULL) {
1321 BT_ERR("Wrong Signal");
1325 BT_INFO("Interface %s, Signal %s", interface_name, signal_name);
1327 if (g_strcmp0(interface_name, BT_HPS_INTERFACE_NAME) == 0) {
1329 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1331 if (strcasecmp(signal_name, BLE_ENABLED) == 0) {
1332 g_variant_get(parameters, "(i)", &result);
1334 if (_bt_hps_prepare_httpproxy() != BLUETOOTH_ERROR_NONE) {
1335 BT_ERR("Fail to prepare HTTP Proxy");
1339 if (_bt_hps_set_advertising_data() != BLUETOOTH_ERROR_NONE) {
1340 BT_ERR("Fail to set advertising data");
1345 BT_ERR("Wrong Signal %s", signal_name);
1352 int _bt_hps_init_event_receiver()
1354 GError *error = NULL;
1359 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
1360 if (error != NULL) {
1361 BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
1362 g_clear_error(&error);
1366 property_sub_id = g_dbus_connection_signal_subscribe(conn,
1367 NULL, BT_HPS_INTERFACE_NAME,
1368 PROPERTIES_CHANGED, BT_HPS_OBJECT_PATH, NULL, 0,
1369 _bt_hps_property_event_filter,
1372 adapter_sub_id = g_dbus_connection_signal_subscribe(conn,
1373 NULL, BT_HPS_INTERFACE_NAME,
1374 BLE_ENABLED, BT_HPS_OBJECT_PATH, NULL, 0,
1375 _bt_hps_adapter_event_filter,
1381 void _bt_hps_deinit_event_receiver(void)
1384 g_dbus_connection_signal_unsubscribe(conn, property_sub_id);
1385 g_dbus_connection_signal_unsubscribe(conn, adapter_sub_id);
1390 int _bt_hps_set_advertising_data(void)
1395 // Temporary UUID is used. SIG have not yet defined the UUID yet
1396 guint8 data[4] = {0x03, 0x02, 0x00, 0x19};
1397 bluetooth_advertising_data_t adv;
1399 BT_DBG("%x %x %x %x", data[0], data[1], data[2], data[3]);
1400 memcpy(adv.data, data, sizeof(data));
1401 ret = bluetooth_set_advertising_data(0, &adv, sizeof(data));
1402 if (ret != BLUETOOTH_ERROR_NONE) {
1403 BT_ERR("Failed to set ADV data %d", ret);
1407 ret = bluetooth_set_advertising(0, TRUE);
1408 if (ret != BLUETOOTH_ERROR_NONE) {
1409 BT_ERR("Failed to set ADV %d", ret);
1416 int _bt_hps_prepare_httpproxy(void)
1418 int ret = BLUETOOTH_ERROR_NONE;
1422 bt_gatt_characteristic_property_t props;
1424 char value[MAX_URI_LENGTH] = { 0 };
1425 struct hps_char_info *char_info = NULL;
1427 char status[3] = { 0 };
1432 ret = bluetooth_gatt_init();
1433 if (ret != BLUETOOTH_ERROR_NONE) {
1434 BT_ERR("Failed to Init GATT %d", ret);
1438 service_uuid = g_strdup(HPS_UUID);
1439 ret = bluetooth_gatt_add_service(service_uuid, &hps_obj_path);
1440 if (ret != BLUETOOTH_ERROR_NONE) {
1441 BT_ERR("Failed to add service %d", ret);
1445 /* Characteristic URI */
1446 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1447 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1448 char_uuid = g_strdup(HTTP_URI_UUID);
1449 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_uri_obj_path);
1450 if (ret != BLUETOOTH_ERROR_NONE) {
1451 BT_ERR("Failed to add new char %d", ret);
1456 ret = bluetooth_gatt_set_characteristic_value(http_uri_obj_path, value, MAX_URI_LENGTH);
1457 if (ret != BLUETOOTH_ERROR_NONE) {
1458 BT_ERR("Failed to add new char %d", ret);
1462 /* Store requets information */
1463 char_info = g_new0(struct hps_char_info, 1);
1464 char_info->char_path = g_strdup(http_uri_obj_path);
1465 _bt_hps_set_char_value(http_uri_obj_path, value, MAX_URI_LENGTH);
1466 hps_char_list = g_slist_append(hps_char_list, char_info);
1469 /* Characteristic HTTP Headers */
1470 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1471 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1472 char_uuid = g_strdup(HTTP_HDR_UUID);
1473 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_hdr_obj_path);
1474 if (ret != BLUETOOTH_ERROR_NONE) {
1475 BT_ERR("Failed to add new char %d", ret);
1479 ret = bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH);
1480 if (ret != BLUETOOTH_ERROR_NONE) {
1481 BT_ERR("Failed to add new char %d", ret);
1485 /* Store Characterisitc information */
1486 char_info = g_new0(struct hps_char_info, 1);
1487 char_info->char_path = g_strdup(http_hdr_obj_path);
1488 _bt_hps_set_char_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH);
1489 hps_char_list = g_slist_append(hps_char_list, char_info);
1492 /* Characteristic HTTP Entity Body */
1493 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1494 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1495 char_uuid = g_strdup(HTTP_ENTITY_UUID);
1496 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_entity_obj_path);
1497 if (ret != BLUETOOTH_ERROR_NONE) {
1498 BT_ERR("Failed to add new char %d", ret);
1502 ret = bluetooth_gatt_set_characteristic_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH);
1503 if (ret != BLUETOOTH_ERROR_NONE) {
1504 BT_ERR("Failed to add new char %d", ret);
1508 /* Store Characterisitc information */
1509 char_info = g_new0(struct hps_char_info, 1);
1510 char_info->char_path = g_strdup(http_entity_obj_path);
1511 _bt_hps_set_char_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH);
1512 hps_char_list = g_slist_append(hps_char_list, char_info);
1515 /* Characteristic HTTP Control Point */
1516 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1517 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1518 char_uuid = g_strdup(HTTP_CP_UUID);
1519 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_cp_obj_path);
1520 if (ret != BLUETOOTH_ERROR_NONE) {
1521 BT_ERR("Failed to add new char %d", ret);
1525 ret = bluetooth_gatt_set_characteristic_value(http_cp_obj_path, &cp, 1);
1526 if (ret != BLUETOOTH_ERROR_NONE) {
1527 BT_ERR("Failed to add new char %d", ret);
1531 /* Store Characterisitc information */
1532 char_info = g_new0(struct hps_char_info, 1);
1533 char_info->char_path = g_strdup(http_cp_obj_path);
1534 _bt_hps_set_char_value(http_cp_obj_path, &cp, 1);
1535 hps_char_list = g_slist_append(hps_char_list, char_info);
1538 /* Characteristic HTTP Status Code */
1539 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1540 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE |
1541 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
1542 char_uuid = g_strdup(HTTP_STATUS_UUID);
1543 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_status_obj_path);
1544 if (ret != BLUETOOTH_ERROR_NONE) {
1545 BT_ERR("Failed to add new char %d", ret);
1549 ret = bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
1550 if (ret != BLUETOOTH_ERROR_NONE) {
1551 BT_ERR("Failed to add new char %d", ret);
1555 desc_uuid = g_strdup(HTTP_STATUS_CCC_DESC_UUID);
1556 ret = bluetooth_gatt_add_descriptor(http_status_obj_path, desc_uuid,
1557 (BLUETOOTH_GATT_PERMISSION_READ | BLUETOOTH_GATT_PERMISSION_WRITE),
1558 &http_status_desc_obj_path);
1559 if (ret != BLUETOOTH_ERROR_NONE) {
1560 BT_ERR("Failed to add new char descriptor %d", ret);
1564 /* Store Characterisitc information */
1565 char_info = g_new0(struct hps_char_info, 1);
1566 char_info->char_path = g_strdup(http_status_obj_path);
1567 _bt_hps_set_char_value(http_status_obj_path, status, 3);
1568 hps_char_list = g_slist_append(hps_char_list, char_info);
1571 /* Characteristic HTTPS Security */
1572 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1573 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1574 char_uuid = g_strdup(HTTP_SECURITY_UUID);
1575 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_security_obj_path);
1576 if (ret != BLUETOOTH_ERROR_NONE) {
1577 BT_ERR("Failed to add new char %d", ret);
1581 ret = bluetooth_gatt_set_characteristic_value(http_security_obj_path, &cp, 1);
1582 if (ret != BLUETOOTH_ERROR_NONE) {
1583 BT_ERR("Failed to add new char %d", ret);
1587 /* Store Characterisitc information */
1588 char_info = g_new0(struct hps_char_info, 1);
1589 char_info->char_path = g_strdup(http_security_obj_path);
1590 _bt_hps_set_char_value(http_security_obj_path, &cp, 1);
1591 hps_char_list = g_slist_append(hps_char_list, char_info);
1594 ret = bluetooth_gatt_register_service(hps_obj_path);
1595 if (ret != BLUETOOTH_ERROR_NONE) {
1596 BT_ERR("Failed to register service %d", ret);
1600 ret = bluetooth_gatt_register_application();
1601 if (ret != BLUETOOTH_ERROR_NONE) {
1602 BT_ERR("Failed to register application %d", ret);
1610 delete_all_characterisitc();
1611 delete_all_notify_read_status();
1617 static void _bt_hps_sig_handler(int sig)
1623 BT_DBG("caught signal - sigterm\n");
1626 BT_DBG("caught signal - sigint\n");
1629 BT_DBG("caught signal - sigkill\n");
1632 BT_DBG("caught signal %d and ignored\n", sig);
1637 void _bt_hps_exit(void)
1642 if (g_uri != NULL) {
1647 if (g_header != NULL) {
1652 if (g_entity != NULL) {
1657 soup_session_abort(hps_soup_session);
1658 g_assert_cmpint(G_OBJECT(hps_soup_session)->ref_count, ==, 1);
1659 g_object_unref(hps_soup_session);
1662 delete_all_characterisitc();
1665 ret = bluetooth_gatt_deinit();
1666 if (ret != BLUETOOTH_ERROR_NONE)
1667 BT_ERR("Failed to Deinit GATT %d", ret);
1669 ret = bluetooth_unregister_callback();
1670 if (ret != BLUETOOTH_ERROR_NONE)
1671 BT_ERR("Failed to Unregister callback %d", ret);
1673 _bt_hps_deinit_event_receiver();
1675 _bt_hps_unregister_interface();
1677 if (main_loop != NULL) {
1678 g_main_loop_quit(main_loop);
1682 void bt_hps_event_callback(int event, bluetooth_event_param_t* param,
1685 BT_DBG("HPS event %d", event);
1689 /* HTTP Proxy Service Main loop */
1692 struct sigaction sa;
1694 BT_ERR("Starting the bt-httpproxy daemon");
1696 /* Values taken from http://www.browserscope.org/ following
1697 * the rule "Do What Every Other Modern Browser Is Doing". They seem
1698 * to significantly improve page loading time compared to soup's
1700 * Change MAX_CONNECTIONS_PER_HOST value 6 -> 12, and maxConnections is changed from 35 to 60.
1701 * Enhanced network loading speed apply tunning value. */
1702 static const int maxConnections = 60;
1703 static const int maxConnectionsPerHost = 12;
1705 memset(&sa, 0, sizeof(sa));
1706 sa.sa_handler = _bt_hps_sig_handler;
1707 sa.sa_flags = SA_SIGINFO;
1708 sigaction(SIGINT, &sa, NULL);
1709 sigaction(SIGTERM, &sa, NULL);
1710 sigaction(SIGKILL, &sa, NULL);
1713 if (bluetooth_register_callback(bt_hps_event_callback, NULL) != BLUETOOTH_ERROR_NONE) {
1714 BT_ERR("bluetooth_register_callback returned failiure");
1719 if (_bt_hps_register_interface() != BLUETOOTH_ERROR_NONE) {
1720 BT_ERR("Fail to register http proxy service");
1724 if (_bt_hps_init_event_receiver() != BLUETOOTH_ERROR_NONE) {
1725 BT_ERR("Fail to init event reciever");
1729 hps_soup_session = soup_session_async_new();
1730 if (hps_soup_session == NULL) {
1731 BT_ERR("Failed to soup_session_async_new");
1734 /* Set Soup Session Fetures */
1735 g_object_set(hps_soup_session,
1736 SOUP_SESSION_MAX_CONNS, maxConnections,
1737 SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
1738 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
1739 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER,
1740 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
1741 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
1744 main_loop = g_main_loop_new(NULL, FALSE);
1746 g_main_loop_run(main_loop);
1748 BT_DBG("g_main_loop_quit called!");
1750 if (main_loop != NULL) {
1751 g_main_loop_unref(main_loop);