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, int offset);
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);
109 for (i = 0; i < BLUETOOTH_ADDRESS_LENGTH; i++)
110 addr_hex->addr[i] = (unsigned char)addr[i];
113 static char *__hps_convert_uuid_to_uuid128(const char *uuid)
121 case 4: /* UUID 16bits */
122 uuid128 = g_strdup_printf("0000%s-0000-1000-8000-00805F9B34FB", uuid);
125 case 8: /* UUID 32bits */
126 uuid128 = g_strdup_printf("%s-0000-1000-8000-00805F9B34FB", uuid);
129 case 36: /* UUID 128bits */
130 uuid128 = strdup(uuid);
140 static void _bt_hps_send_status_notification(unsigned short http_status,
141 unsigned char data_status,
142 bluetooth_device_address_t *unicast_address)
144 char status[3] = {0x00};
145 int ret = BLUETOOTH_ERROR_NONE;
149 status[0] = http_status & 0xFF;
150 status[1] = (http_status >> 8) & 0xFF;
151 status[2] = data_status;
152 BT_DBG("Status %d %04x", http_status, http_status);
154 /* Store the status value */
155 _bt_hps_set_char_value(http_status_obj_path, status, 3, 0);
157 /* Send unicast notification */
158 ret = bluetooth_gatt_server_set_notification(http_status_obj_path, unicast_address);
159 if (ret != BLUETOOTH_ERROR_NONE) {
160 BT_ERR("_bt_hps_send_status_notification failed");
163 ret = bluetooth_gatt_update_characteristic(http_status_obj_path, status, 3);
164 if (ret != BLUETOOTH_ERROR_NONE) {
165 BT_ERR("_bt_hps_send_status_notification failed");
171 static void _bt_httpproxy_method(GDBusConnection *connection,
173 const gchar *object_path,
174 const gchar *interface_name,
175 const gchar *method_name,
176 GVariant *parameters,
177 GDBusMethodInvocation *invocation,
182 BT_DBG("Method[%s] Object Path[%s] Interface Name[%s]",
183 method_name, object_path, interface_name);
185 if (g_strcmp0(method_name, "enable") == 0) {
186 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
187 } else if (g_strcmp0(method_name, "disable") == 0) {
189 g_dbus_method_invocation_return_value(invocation, g_variant_new("(y)", status));
195 static const GDBusInterfaceVTable hps_method_table = {
196 _bt_httpproxy_method,
201 static void _bt_hps_on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
204 GError *error = NULL;
210 object_id = g_dbus_connection_register_object(connection, BT_HPS_OBJECT_PATH,
211 hps_node_info->interfaces[0],
214 if (object_id == 0) {
215 BT_ERR("Failed to register method table: %s", error->message);
217 g_dbus_node_info_unref(hps_node_info);
223 static void _bt_hps_on_name_acquired(GDBusConnection *connection,
231 static void _bt_hps_on_name_lost(GDBusConnection *connection,
236 g_object_unref(g_conn);
238 g_dbus_node_info_unref(hps_node_info);
239 g_bus_unown_name(g_owner_id);
244 int _bt_hps_register_interface(void)
246 GError *error = NULL;
251 hps_node_info = g_dbus_node_info_new_for_xml(hps_introspection_xml, &error);
252 if (!hps_node_info) {
253 BT_ERR("Failed to install: %s", error->message);
254 return BLUETOOTH_ERROR_INTERNAL;
257 owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
259 G_BUS_NAME_OWNER_FLAGS_NONE,
260 _bt_hps_on_bus_acquired, _bt_hps_on_name_acquired, _bt_hps_on_name_lost,
262 g_owner_id = owner_id;
263 BT_DBG("owner_id is [%d]\n", owner_id);
265 return BLUETOOTH_ERROR_NONE;
268 void _bt_hps_unregister_interface(void)
272 g_object_unref(g_conn);
274 g_dbus_node_info_unref(hps_node_info);
275 g_bus_unown_name(g_owner_id);
281 static struct hps_char_info *hps_get_char_value(const char *path)
285 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
287 struct hps_char_info *char_info = tmp->data;
288 if (!g_strcmp0(char_info->char_path, path))
295 static int char_info_cmp(gconstpointer a1, gconstpointer a2)
297 const struct hps_char_info *attrib1 = a1;
298 const struct hps_char_info *attrib2 = a2;
300 return g_strcmp0(attrib1->char_path, attrib2->char_path);
303 static int notify_info_cmp(gconstpointer a1, gconstpointer a2)
305 const struct hps_notify_read_info *attrib1 = a1;
306 const struct hps_notify_read_info *attrib2 = a2;
308 return g_strcmp0(attrib1->char_path, attrib2->char_path);
311 static void _bt_hps_set_char_value(const char *obj_path, const char* value, int value_length, int offset)
317 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
319 struct hps_char_info *char_info = tmp->data;
320 if (!g_strcmp0(char_info->char_path, obj_path)) {
323 str = g_strdup(char_info->char_value);
324 char_info->char_value = g_try_realloc(char_info->char_value, offset + value_length);
326 char_info->char_value = g_try_realloc(char_info->char_value, value_length);
328 if (char_info->char_value) {
330 memcpy(char_info->char_value, str, strlen(str));
334 memcpy(&char_info->char_value[offset], value, value_length);
335 char_info->value_length = offset + value_length;
337 memcpy(char_info->char_value, value, value_length);
338 char_info->value_length = value_length;
340 hps_char_list = g_slist_insert_sorted(hps_char_list,
341 char_info, char_info_cmp);
350 static void _bt_hps_set_notify_read_status(const char *obj_path,
351 guint offset_status, guint read_status, int https_status)
353 struct hps_notify_read_info *notify_read_info = NULL;
356 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
358 notify_read_info = tmp->data;
359 if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
360 notify_read_info->read_status = read_status;
361 notify_read_info->offset_status = offset_status;
362 notify_read_info->https_status = https_status;
363 hps_notify_read_list = g_slist_insert_sorted(hps_notify_read_list,
364 notify_read_info, notify_info_cmp);
370 if (!hps_notify_read_list) {
371 /* Store Notification information */
372 notify_read_info = g_new0(struct hps_notify_read_info, 1);
373 if (notify_read_info) {
374 notify_read_info->char_path = g_strdup(obj_path);
375 notify_read_info->read_status = read_status;
376 notify_read_info->offset_status = offset_status;
377 notify_read_info->https_status = https_status;
378 hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
382 /* Store Notification information */
383 notify_read_info = g_new0(struct hps_notify_read_info, 1);
384 if (notify_read_info) {
385 notify_read_info->char_path = g_strdup(obj_path);
386 notify_read_info->read_status = read_status;
387 notify_read_info->offset_status = offset_status;
388 notify_read_info->https_status = https_status;
389 hps_notify_read_list = g_slist_append(hps_notify_read_list, notify_read_info);
395 static struct hps_notify_read_info *_bt_hps_get_notify_read_status(const char *obj_path)
399 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
401 struct hps_notify_read_info *notify_read_info = tmp->data;
402 if (!g_strcmp0(notify_read_info->char_path, obj_path))
403 return notify_read_info;
410 static void delete_all_characterisitc(void)
413 for (tmp = hps_char_list; tmp != NULL; tmp = tmp->next) {
415 struct hps_char_info *char_info = tmp->data;
416 if (char_info->char_path)
417 g_free(char_info->char_path);
418 if (char_info->char_value)
419 g_free(char_info->char_value);
420 hps_char_list = g_slist_delete_link(hps_char_list, tmp->data);
423 g_slist_free(hps_char_list);
424 hps_char_list = NULL;
427 static void delete_all_notify_read_status(void)
430 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
432 struct hps_notify_read_info *notify_read_info = tmp->data;
433 if (notify_read_info->char_path)
434 g_free(notify_read_info->char_path);
435 hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
438 g_slist_free(hps_notify_read_list);
439 hps_notify_read_list = NULL;
442 static void delete_notify_read_status(const char *obj_path)
445 for (tmp = hps_notify_read_list; tmp != NULL; tmp = tmp->next) {
447 struct hps_notify_read_info *notify_read_info = tmp->data;
448 if (!g_strcmp0(notify_read_info->char_path, obj_path)) {
449 if (notify_read_info->char_path)
450 g_free(notify_read_info->char_path);
451 hps_notify_read_list = g_slist_delete_link(hps_notify_read_list, tmp->data);
459 int _bt_hps_uri_write_cb(char *uri, int len, int offset)
461 if ((len < 1) || (len > MAX_URI_LENGTH)) {
462 BT_ERR("Wrong URI length %d", len);
463 return BLUETOOTH_ERROR_INTERNAL;
466 /* g_uri will be used commonly for all HTTP methods whereever applicable */
469 g_uri = g_strndup(uri, len);
471 _bt_hps_set_char_value(http_uri_obj_path, g_uri, len, offset);
473 return BLUETOOTH_ERROR_NONE;
476 int _bt_hps_http_header_write_cb(char *header, int len, int offset)
478 if ((len < 1) || (len > MAX_HEADER_LENGTH)) {
479 BT_ERR("Wrong Header length %d", len);
480 return BLUETOOTH_ERROR_INTERNAL;
483 /* g_header will be used commonly for all HTTP methods where ever applicable
484 general-header, request-header, entity-header
488 g_header = g_strndup(header, len);
490 _bt_hps_set_char_value(http_hdr_obj_path, g_header, len, offset);
493 return BLUETOOTH_ERROR_NONE;
496 int _bt_hps_entity_body_write_cb(char *entity, int len, int offset)
498 if ((len < 1) || (len > MAX_ENTITY_LENGTH)) {
499 BT_ERR("Wrong Entity length %d", len);
500 return BLUETOOTH_ERROR_INTERNAL;
503 /* g_entity will be used commonly for all HTTP methods whereever applicable */
506 g_entity = g_strndup(entity, len);
508 _bt_hps_set_char_value(http_entity_obj_path, g_entity, len, offset);
511 return BLUETOOTH_ERROR_NONE;
515 int _bt_hps_read_cb(const char *obj_path, char **value, int *len)
517 struct hps_char_info *info = NULL;
518 struct hps_notify_read_info *notify_read_info = NULL;
519 guint data_status = -1;
521 gboolean is_header = FALSE;
524 BT_ERR("Wrong Obj path");
528 if (!g_strcmp0(http_hdr_obj_path, obj_path))
531 info = hps_get_char_value(obj_path);
534 if (info->char_value == NULL || info->value_length == 0)
537 notify_read_info = _bt_hps_get_notify_read_status(obj_path);
538 if (notify_read_info && notify_read_info->read_status != DS_BODY_RECEIVED &&
539 notify_read_info->read_status != DS_HEADER_RECEIVED) {
540 offset = notify_read_info->offset_status;
541 if ((info->value_length - offset) > 0 &&
542 (info->value_length - offset) > MAX_ENTITY_LENGTH) {
544 data_status = DS_HEADER_TRUNCATED;
546 data_status = DS_BODY_TRUNCATED;
547 _bt_hps_set_notify_read_status(obj_path, offset + MAX_ENTITY_LENGTH,
548 data_status, notify_read_info->https_status);
549 *value = g_strdup(&info->char_value[offset]);
550 *len = MAX_ENTITY_LENGTH;
551 } else if ((info->value_length - offset) > 0 &&
552 (info->value_length - offset) <= MAX_ENTITY_LENGTH) {
554 data_status = DS_HEADER_RECEIVED;
556 data_status = DS_BODY_RECEIVED;
557 _bt_hps_set_notify_read_status(obj_path, offset, data_status, notify_read_info->https_status);
558 *value = g_strdup(&info->char_value[offset]);
559 *len = info->value_length - offset;
561 } else if (notify_read_info && (notify_read_info->read_status == DS_BODY_RECEIVED ||
562 notify_read_info->read_status == DS_HEADER_RECEIVED)) {
564 data_status = DS_HEADER_RECEIVED;
566 data_status = DS_BODY_RECEIVED;
567 delete_notify_read_status(obj_path);
568 *value = g_strdup(&info->char_value[offset]);
569 *len = info->value_length;
577 void _bt_hps_head_response_cb(SoupSession *session,
578 SoupMessage *msg, gpointer user_data)
580 unsigned short http_status = 0x00;
582 unsigned char status[3] = {0x00};
584 const char *device_address = user_data;
585 bluetooth_device_address_t addr_hex = { {0,} };
586 unsigned char data_status = DS_NONE;
587 _hps_convert_address_to_hex(&addr_hex, device_address);
590 if (hps_soup_session != session) {
591 BT_ERR("Wrong Session");
596 BT_ERR("Wrong Message");
601 req_state = HTTP_REQ_STATE_EXECUTED;
603 http_status = msg->status_code;
605 // Process Header in Response Body
606 if (msg->response_headers) {
608 const char *content = NULL;
609 const char *length = NULL;
612 length = soup_message_headers_get_one(msg->request_headers,
614 // Check "Content-MD5" is the right name to get header content
615 content = soup_message_headers_get_one(msg->response_headers,
617 if (content == NULL || length == NULL) {
618 BT_ERR("Wrong Response Header");
619 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
623 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
625 // Write Data to Header Characteristic
627 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len, 0);
629 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
631 // TODO : Handle Truncated Header
633 // Write Data to Status Code Characteristic
635 data_status = (hdr_len > MAX_ENTITY_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
636 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
637 _bt_hps_set_notify_read_status(http_hdr_obj_path, 0, data_status, http_status);
639 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
641 status[0] = http_status & 0x0F;
642 status[1] = (http_status >> 8) & 0x0F;
643 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
645 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
648 BT_ERR("HEAD Response is NULL");
649 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
655 void _bt_hps_http_response_cb(SoupSession *session,
656 SoupMessage *msg, gpointer user_data)
658 unsigned short http_status = 0x00;
660 unsigned char status[3] = {0x00};
662 const char *device_address = user_data;
663 bluetooth_device_address_t addr_hex = { {0,} };
664 unsigned char data_status = DS_NONE;
665 _hps_convert_address_to_hex(&addr_hex, device_address);
668 if (hps_soup_session != session) {
669 BT_ERR("Wrong Session");
674 BT_ERR("Wrong Message");
680 req_state = HTTP_REQ_STATE_EXECUTED;
682 http_status = msg->status_code;
684 // Write Data to Status Code Characteristic
686 status[0] = http_status & 0x0F;
687 status[1] = (http_status >> 8) & 0x0F;
688 status[2] = DS_HEADER_RECEIVED;
689 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
691 data_status = DS_HEADER_RECEIVED;
692 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
698 void _bt_hps_get_response_cb(SoupSession *session,
699 SoupMessage *msg, gpointer user_data)
701 SoupBuffer *body = NULL;
702 unsigned short http_status = 0x00;
704 unsigned char status[3] = {0x00};
706 const char *device_address = user_data;
707 bluetooth_device_address_t addr_hex = { {0,} };
708 unsigned char data_status = DS_NONE;
709 _hps_convert_address_to_hex(&addr_hex, device_address);
712 if (hps_soup_session != session) {
713 BT_ERR("Wrong Session");
718 BT_ERR("Wrong Message");
724 req_state = HTTP_REQ_STATE_EXECUTED;
726 http_status = msg->status_code;
728 // Process Entity Body in Response Message
729 if (msg->response_body) {
731 body = soup_message_body_flatten(msg->response_body);
733 BT_ERR("Wrong Response Body");
735 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
739 if (body->data == NULL || body->length <= 0) {
740 BT_ERR("Wrong Response");
741 soup_buffer_free(body);
743 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
747 // Write Data to Entity Body Characteristic
749 _bt_hps_set_char_value(http_entity_obj_path, body->data, body->length, 0);
751 bluetooth_gatt_set_characteristic_value(http_entity_obj_path, body->data, body->length);
753 // TODO : Handle Truncated Entiry Body
755 // Write Data to Status Code Characteristic
757 data_status = (body->length > MAX_ENTITY_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_RECEIVED;
758 if (data_status == DS_BODY_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
759 _bt_hps_set_notify_read_status(http_entity_obj_path, 0, data_status, http_status);
761 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
764 status[0] = http_status & 0x0F;
765 status[1] = (http_status >> 8) & 0x0F;
766 status[2] = (body->length > MAX_HEADER_LENGTH) ? DS_BODY_TRUNCATED : DS_BODY_TRUNCATED;
768 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
770 soup_buffer_free(body);
772 BT_ERR("GET Response Body is NULL");
774 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
778 // Process Header in Response Body
779 if (msg->response_headers) {
781 const char *content = NULL;
782 const char *length = NULL;
785 length = soup_message_headers_get_one(msg->request_headers,
787 // Check "Content-MD5" is the right name to get header content
788 content = soup_message_headers_get_one(msg->response_headers,
790 if (content == NULL || length == NULL) {
791 BT_ERR("Wrong Response Header");
792 data_status = DS_NONE;
793 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
797 hdr_len = soup_message_headers_get_content_length(msg->response_headers);
798 // Write Data to Header Characteristic
800 _bt_hps_set_char_value(http_hdr_obj_path, content, hdr_len, 0);
802 bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, content, hdr_len);
804 // TODO : Handle Truncated Header
806 // Write Data to Status Code Characteristic
808 data_status = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
809 if (data_status == DS_HEADER_TRUNCATED && SOUP_STATUS_IS_SUCCESSFUL(http_status)) {
810 _bt_hps_set_notify_read_status(http_hdr_obj_path, 0, data_status, http_status);
812 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
814 status[0] = http_status & 0x0F;
815 status[1] = (http_status >> 8) & 0x0F;
816 status[2] = (hdr_len > MAX_HEADER_LENGTH) ? DS_HEADER_TRUNCATED : DS_HEADER_RECEIVED;
818 bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
821 BT_ERR("GET Response Header is NULL");
823 _bt_hps_send_status_notification(http_status, data_status, &addr_hex);
831 int _bt_hps_control_point_write_cb(const char *value, int len, char *addr)
833 int _bt_hps_control_point_write_cb(char *value, int len)
837 GTlsCertificate *cert = NULL;
838 GTlsCertificateFlags flags;
839 gboolean https_status = FALSE;
840 int result = BLUETOOTH_ERROR_NONE;
841 BT_INFO("Opcode %0x", opcode);
844 _bt_hps_set_char_value(http_cp_obj_path, value, len, 0);
848 case HTTP_GET_REQUEST:
849 if (req_state == HTTP_REQ_STATE_EXECUTED) {
850 req_state = HTTP_REQ_STATE_INPROGRESS;
851 hps_soup_msg = soup_message_new("GET", g_uri);
853 g_object_ref(hps_soup_msg);
854 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
856 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
859 BT_ERR("HTTP GET request in progress, message dropped");
860 result = BLUETOOTH_ERROR_INTERNAL;
864 case HTTP_POST_REQUEST:
865 if (req_state == HTTP_REQ_STATE_EXECUTED) {
866 req_state = HTTP_REQ_STATE_INPROGRESS;
867 hps_soup_msg = soup_message_new("POST", g_uri);
868 if (hps_soup_msg == NULL || g_entity == NULL) {
869 BT_ERR("Soup Message NULL");
870 result = BLUETOOTH_ERROR_INTERNAL;
871 req_state = HTTP_REQ_STATE_EXECUTED;
874 soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_COPY,
875 g_entity, strlen(g_entity));
877 g_object_ref(hps_soup_msg);
878 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
880 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
883 BT_ERR("HTTP POST request in progress, message dropped");
884 result = BLUETOOTH_ERROR_INTERNAL;
888 case HTTP_HEAD_REQUEST:
889 if (req_state == HTTP_REQ_STATE_EXECUTED) {
890 req_state = HTTP_REQ_STATE_INPROGRESS;
891 hps_soup_msg = soup_message_new("HEAD", g_uri);
892 if (hps_soup_msg == NULL) {
893 BT_ERR("Soup Message NULL");
894 result = BLUETOOTH_ERROR_INTERNAL;
895 req_state = HTTP_REQ_STATE_EXECUTED;
899 g_object_ref(hps_soup_msg);
900 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
902 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
905 BT_ERR("HTTP HEAD request in progress, message dropped");
906 result = BLUETOOTH_ERROR_INTERNAL;
910 case HTTP_PUT_REQUEST:
911 if (req_state == HTTP_REQ_STATE_EXECUTED) {
913 req_state = HTTP_REQ_STATE_INPROGRESS;
914 hps_soup_msg = soup_message_new("PUT", g_uri);
915 if (hps_soup_msg == NULL || g_entity == NULL) {
916 BT_ERR("Soup Message NULL");
917 result = BLUETOOTH_ERROR_INTERNAL;
918 req_state = HTTP_REQ_STATE_EXECUTED;
921 buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
922 soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
923 soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
925 g_object_ref(hps_soup_msg);
926 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
928 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
932 BT_ERR("HTTP PUT request in progress, message dropped");
933 result = BLUETOOTH_ERROR_INTERNAL;
937 case HTTP_DELETE_REQUEST:
938 if (req_state == HTTP_REQ_STATE_EXECUTED) {
939 req_state = HTTP_REQ_STATE_INPROGRESS;
940 hps_soup_msg = soup_message_new("DELETE", g_uri);
941 if (hps_soup_msg == NULL) {
942 BT_ERR("Soup Message NULL");
943 result = BLUETOOTH_ERROR_INTERNAL;
944 req_state = HTTP_REQ_STATE_EXECUTED;
948 g_object_ref(hps_soup_msg);
949 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
951 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
954 BT_ERR("HTTP DELETE request in progress, message dropped");
955 result = BLUETOOTH_ERROR_INTERNAL;
959 case HTTPS_GET_REQUEST:
960 if (req_state == HTTP_REQ_STATE_EXECUTED) {
961 req_state = HTTP_REQ_STATE_INPROGRESS;
962 hps_soup_msg = soup_message_new("GET", g_uri);
963 if (hps_soup_msg == NULL) {
964 BT_ERR("Soup Message NULL");
965 result = BLUETOOTH_ERROR_INTERNAL;
966 req_state = HTTP_REQ_STATE_EXECUTED;
970 g_object_ref(hps_soup_msg);
971 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, addr);
973 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_get_response_cb, NULL);
975 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
977 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
979 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
982 BT_ERR("HTTPS GET request in progress, message dropped");
983 result = BLUETOOTH_ERROR_INTERNAL;
987 case HTTPS_HEAD_REQUEST:
988 if (req_state == HTTP_REQ_STATE_EXECUTED) {
989 req_state = HTTP_REQ_STATE_INPROGRESS;
990 hps_soup_msg = soup_message_new("HEAD", g_uri);
991 if (hps_soup_msg == NULL) {
992 BT_ERR("Soup Message NULL");
993 result = BLUETOOTH_ERROR_INTERNAL;
994 req_state = HTTP_REQ_STATE_EXECUTED;
998 g_object_ref(hps_soup_msg);
999 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, addr);
1001 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_head_response_cb, NULL);
1003 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1005 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1007 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1010 BT_ERR("HTTPS HEAD request in progress, message dropped");
1011 result = BLUETOOTH_ERROR_INTERNAL;
1015 case HTTPS_POST_REQUEST:
1016 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1017 req_state = HTTP_REQ_STATE_INPROGRESS;
1018 hps_soup_msg = soup_message_new("POST", g_uri);
1019 if (hps_soup_msg == NULL) {
1020 BT_ERR("Soup Message NULL");
1021 result = BLUETOOTH_ERROR_INTERNAL;
1022 req_state = HTTP_REQ_STATE_EXECUTED;
1025 soup_message_set_request(hps_soup_msg, "text/xml", SOUP_MEMORY_STATIC,
1026 g_entity, strlen(g_entity));
1028 g_object_ref(hps_soup_msg);
1029 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1031 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1034 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1036 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1038 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1041 BT_ERR("HTTPS POST request in progress, message dropped");
1042 result = BLUETOOTH_ERROR_INTERNAL;
1046 case HTTPS_PUT_REQUEST:
1047 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1049 req_state = HTTP_REQ_STATE_INPROGRESS;
1050 hps_soup_msg = soup_message_new("PUT", g_uri);
1051 if (hps_soup_msg == NULL) {
1052 BT_ERR("Soup Message NULL");
1053 result = BLUETOOTH_ERROR_INTERNAL;
1054 req_state = HTTP_REQ_STATE_EXECUTED;
1057 buf = soup_buffer_new(SOUP_MEMORY_TAKE, g_entity, strlen(g_entity));
1058 soup_message_body_append_buffer(hps_soup_msg->request_body, buf);
1059 soup_message_body_set_accumulate(hps_soup_msg->request_body, FALSE);
1061 g_object_ref(hps_soup_msg);
1062 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1064 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1066 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1068 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1070 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1073 BT_ERR("HTTPS PUT request in progress, message dropped");
1074 result = BLUETOOTH_ERROR_INTERNAL;
1078 case HTTPS_DELETE_REQUEST:
1079 if (req_state == HTTP_REQ_STATE_EXECUTED) {
1080 req_state = HTTP_REQ_STATE_INPROGRESS;
1081 hps_soup_msg = soup_message_new("DELETE", g_uri);
1082 if (hps_soup_msg == NULL) {
1083 BT_ERR("Soup Message NULL");
1084 result = BLUETOOTH_ERROR_INTERNAL;
1085 req_state = HTTP_REQ_STATE_EXECUTED;
1089 g_object_ref(hps_soup_msg);
1090 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, addr);
1092 soup_session_queue_message(hps_soup_session, hps_soup_msg, _bt_hps_http_response_cb, NULL);
1095 https_status = soup_message_get_https_status(hps_soup_msg, &cert, &flags);
1097 _bt_hps_set_char_value(http_security_obj_path, (const char *)&https_status, 1, 0);
1099 bluetooth_gatt_set_characteristic_value(http_security_obj_path, (char *)&https_status, 1);
1102 BT_ERR("HTTPS DELETE request in progress, message dropped");
1103 result = BLUETOOTH_ERROR_INTERNAL;
1107 case HTTP_REQUEST_CANCEL:
1108 /* Cancel the outstanding request */
1109 if (req_state == HTTP_REQ_STATE_INPROGRESS) {
1110 req_state = HTTP_REQ_STATE_IDLE;
1111 if (hps_soup_msg == NULL) {
1112 BT_ERR("Soup Message NULL");
1113 result = BLUETOOTH_ERROR_INTERNAL;
1114 req_state = HTTP_REQ_STATE_EXECUTED;
1117 soup_session_cancel_message(hps_soup_session, hps_soup_msg, SOUP_STATUS_CANCELLED);
1118 hps_soup_msg = NULL;
1123 BT_ERR("Unknown opcode %0x", opcode);
1124 result = BLUETOOTH_ERROR_INTERNAL;
1131 void _bt_hps_security_read_cb(char *value, int len)
1133 BT_INFO("HPS Client Read the value");
1138 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1141 int result = BLUETOOTH_ERROR_NONE;
1142 GVariantIter value_iter;
1143 const char *property = NULL;
1144 const char * char_path = NULL;
1145 const char * svc_handle = NULL;
1146 GVariant *var = NULL;
1147 GVariant *val = NULL;
1148 g_variant_iter_init(&value_iter, msg);
1150 while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &var))) {
1152 if (property == NULL) {
1153 BT_ERR("Property NULL");
1157 if (!g_strcmp0(property, "WriteValue")) {
1159 BT_INFO("WriteValue");
1160 BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1167 g_variant_get(var, "(&s&s&syq@ay)", &char_path,
1168 &svc_handle, &addr, &req_id, &offset, &val);
1170 len = g_variant_get_size(val);
1172 BT_DBG("Len = %d, Offset = %d", len, offset);
1174 value = (char *) g_variant_get_data(val);
1177 if (!g_strcmp0(char_path, http_uri_obj_path)) {
1179 result = _bt_hps_uri_write_cb(value, len, offset);;
1180 } else if (!g_strcmp0(char_path, http_hdr_obj_path)) {
1181 /* Retrive HEADER */
1182 result = _bt_hps_http_header_write_cb(value, len, offset);
1183 } else if (!g_strcmp0(char_path, http_entity_obj_path)) {
1184 /* Retrive ENTITY BODY */
1185 result = _bt_hps_entity_body_write_cb(value, len, offset);
1186 } else if (!g_strcmp0(char_path, http_cp_obj_path)) {
1187 result = _bt_hps_control_point_write_cb(value, len, addr);
1189 BT_ERR("Wrong Object Path %s", char_path);
1190 result = BLUETOOTH_ERROR_INTERNAL;
1192 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_WRITE, result, 0, NULL, 0);
1194 BT_ERR("Array Len 0");
1197 BT_ERR("var==NULL");
1199 } else if (!g_strcmp0(property, "ReadValue")) {
1205 int data_status = -1;
1206 BT_INFO("ReadValue");
1207 BT_INFO("Type '%s'\n", g_variant_get_type_string(var));
1209 g_variant_get(var, "(&s&s&syq)", &char_path, &svc_handle,
1210 &addr, &req_id, &offset);
1212 data_status = _bt_hps_read_cb(char_path, &value, &len);
1213 if (data_status >= DS_NONE) {
1214 struct hps_notify_read_info *notify_read_info = NULL;
1215 bluetooth_device_address_t addr_hex = { {0,} };
1216 _hps_convert_address_to_hex(&addr_hex, addr);
1217 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1218 BLUETOOTH_ERROR_NONE, offset, value, len);
1219 notify_read_info = _bt_hps_get_notify_read_status(char_path);
1220 if (notify_read_info) {
1221 _bt_hps_send_status_notification(notify_read_info->https_status,
1222 data_status, &addr_hex);
1224 if (data_status == DS_BODY_RECEIVED ||
1225 data_status == DS_HEADER_RECEIVED) {
1226 _bt_hps_set_char_value(char_path, NULL, 0, 0);
1232 BT_ERR("ReadValue failed %s", char_path);
1233 bluetooth_gatt_send_response(req_id, BLUETOOTH_GATT_ATT_REQUEST_TYPE_READ,
1234 BLUETOOTH_ERROR_INTERNAL, offset, NULL, 0);
1241 void _bt_hps_gatt_char_property_changed_event(GVariant *msg,
1244 GVariantIter value_iter;
1245 char *property = NULL;
1246 char * char_handle = NULL;
1247 GVariant *val = NULL;
1248 int result = BLUETOOTH_ERROR_NONE;
1249 GVariant *param = NULL;
1250 g_variant_iter_init(&value_iter, msg);
1251 char_handle = g_strdup(path);
1253 while ((g_variant_iter_loop(&value_iter, "{sv}", &property, &val))) {
1255 if (property == NULL) {
1256 BT_ERR("Property NULL");
1260 if (strcasecmp(property, "ChangedValue") == 0) {
1263 GByteArray *gp_byte_array = NULL;
1264 BT_INFO("Type '%s'\n", g_variant_get_type_string(val));
1267 gp_byte_array = g_byte_array_new();
1268 len = g_variant_get_size(val);
1269 BT_DBG("Len = %d", len);
1270 g_byte_array_append(gp_byte_array,
1271 (const guint8 *)g_variant_get_data(val), len);
1272 if (gp_byte_array->len != 0) {
1273 GVariant *byte_array = NULL;
1274 byte_array = g_variant_new_from_data(
1275 G_VARIANT_TYPE_BYTESTRING,
1276 gp_byte_array->data,
1279 param = g_variant_new("(is@ay)", result, char_handle,
1282 if (strcmp(path, http_uri_obj_path)) {
1284 _bt_hps_uri_write_cb(NULL, len);
1285 } else if (strcmp(path, http_hdr_obj_path)) {
1287 _bt_hps_http_header_write_cb(NULL, len);
1288 } else if (strcmp(path, http_entity_obj_path)) {
1289 //Retrive ENTITY BODY
1290 _bt_hps_entity_body_write_cb(NULL, len);
1291 } else if (strcmp(path, http_cp_obj_path)) {
1292 _bt_hps_control_point_write_cb(NULL, len);
1293 } else if (strcmp(path, http_security_obj_path)) {
1294 _bt_hps_security_read_cb(NULL, len);
1296 BT_ERR("Wrong Object Path %s", path);
1299 BT_ERR("Array Len 0");
1301 g_byte_array_free(gp_byte_array, TRUE);
1303 BT_ERR("val==NULL");
1307 g_free(char_handle);
1313 void _bt_hps_property_event_filter(GDBusConnection *connection,
1314 const gchar *sender_name,
1315 const gchar *object_path,
1316 const gchar *interface_name,
1317 const gchar *signal_name,
1318 GVariant *parameters,
1323 if (signal_name == NULL) {
1324 BT_ERR("Wrong Signal");
1329 if (g_strcmp0(signal_name, PROPERTIES_CHANGED) == 0) {
1331 g_variant_get(parameters, "(@a{sv}@as)", &value, NULL);
1333 _bt_hps_gatt_char_property_changed_event(value, object_path);
1335 if (g_strcmp0(interface_name, BT_HPS_PROPERTIES_INTERFACE) == 0) {
1337 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1339 _bt_hps_gatt_char_property_changed_event(value, object_path);
1342 //BT_ERR("Wrong Interface %s", interface_name);
1349 void _bt_hps_adapter_event_filter(GDBusConnection *connection,
1350 const gchar *sender_name,
1351 const gchar *object_path,
1352 const gchar *interface_name,
1353 const gchar *signal_name,
1354 GVariant *parameters,
1357 int result = BLUETOOTH_ERROR_NONE;
1360 if (signal_name == NULL) {
1361 BT_ERR("Wrong Signal");
1365 BT_INFO("Interface %s, Signal %s", interface_name, signal_name);
1367 if (g_strcmp0(interface_name, BT_HPS_INTERFACE_NAME) == 0) {
1369 g_variant_get(parameters, "(&s@a{sv}@as)", &interface_name, &value, NULL);
1371 if (strcasecmp(signal_name, BLE_ENABLED) == 0) {
1372 g_variant_get(parameters, "(i)", &result);
1374 if (_bt_hps_prepare_httpproxy() != BLUETOOTH_ERROR_NONE) {
1375 BT_ERR("Fail to prepare HTTP Proxy");
1379 if (_bt_hps_set_advertising_data() != BLUETOOTH_ERROR_NONE) {
1380 BT_ERR("Fail to set advertising data");
1385 BT_ERR("Wrong Signal %s", signal_name);
1392 int _bt_hps_init_event_receiver()
1394 GError *error = NULL;
1399 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
1400 if (error != NULL) {
1401 BT_ERR("ERROR: Can't get on system bus [%s]", error->message);
1402 g_clear_error(&error);
1406 property_sub_id = g_dbus_connection_signal_subscribe(conn,
1407 NULL, BT_HPS_INTERFACE_NAME,
1408 PROPERTIES_CHANGED, BT_HPS_OBJECT_PATH, NULL, 0,
1409 _bt_hps_property_event_filter,
1412 adapter_sub_id = g_dbus_connection_signal_subscribe(conn,
1413 NULL, BT_HPS_INTERFACE_NAME,
1414 BLE_ENABLED, BT_HPS_OBJECT_PATH, NULL, 0,
1415 _bt_hps_adapter_event_filter,
1421 void _bt_hps_deinit_event_receiver(void)
1424 g_dbus_connection_signal_unsubscribe(conn, property_sub_id);
1425 g_dbus_connection_signal_unsubscribe(conn, adapter_sub_id);
1430 int _bt_hps_set_advertising_data(void)
1435 guint8 data[4] = {0x03, 0x02, 0x23, 0x18};
1436 bluetooth_advertising_data_t adv;
1438 BT_DBG("%x %x %x %x", data[0], data[1], data[2], data[3]);
1439 memcpy(adv.data, data, sizeof(data));
1440 ret = bluetooth_set_advertising_data(0, &adv, sizeof(data));
1441 if (ret != BLUETOOTH_ERROR_NONE) {
1442 BT_ERR("Failed to set ADV data %d", ret);
1446 ret = bluetooth_set_advertising(0, TRUE);
1447 if (ret != BLUETOOTH_ERROR_NONE) {
1448 BT_ERR("Failed to set ADV %d", ret);
1455 int _bt_hps_prepare_httpproxy(void)
1457 int ret = BLUETOOTH_ERROR_NONE;
1461 bt_gatt_characteristic_property_t props;
1463 char value[MAX_URI_LENGTH] = { 0 };
1464 struct hps_char_info *char_info = NULL;
1466 char status[3] = { 0 };
1471 ret = bluetooth_gatt_init();
1472 if (ret != BLUETOOTH_ERROR_NONE) {
1473 BT_ERR("Failed to Init GATT %d", ret);
1477 service_uuid = __hps_convert_uuid_to_uuid128(HPS_UUID);
1478 ret = bluetooth_gatt_add_service(service_uuid, &hps_obj_path);
1479 if (ret != BLUETOOTH_ERROR_NONE) {
1480 BT_ERR("Failed to add service %d", ret);
1484 /* Characteristic URI */
1485 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1486 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_URI_UUID);
1487 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_uri_obj_path);
1488 if (ret != BLUETOOTH_ERROR_NONE) {
1489 BT_ERR("Failed to add new char %d", ret);
1494 ret = bluetooth_gatt_set_characteristic_value(http_uri_obj_path, value, MAX_URI_LENGTH);
1495 if (ret != BLUETOOTH_ERROR_NONE) {
1496 BT_ERR("Failed to add new char %d", ret);
1500 /* Store requets information */
1501 char_info = g_new0(struct hps_char_info, 1);
1502 char_info->char_path = g_strdup(http_uri_obj_path);
1503 hps_char_list = g_slist_append(hps_char_list, char_info);
1504 _bt_hps_set_char_value(http_uri_obj_path, value, MAX_URI_LENGTH, 0);
1507 /* Characteristic HTTP Headers */
1508 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1509 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1510 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_HDR_UUID);
1511 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_hdr_obj_path);
1512 if (ret != BLUETOOTH_ERROR_NONE) {
1513 BT_ERR("Failed to add new char %d", ret);
1517 ret = bluetooth_gatt_set_characteristic_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH);
1518 if (ret != BLUETOOTH_ERROR_NONE) {
1519 BT_ERR("Failed to add new char %d", ret);
1523 /* Store Characterisitc information */
1524 char_info = g_new0(struct hps_char_info, 1);
1525 char_info->char_path = g_strdup(http_hdr_obj_path);
1526 hps_char_list = g_slist_append(hps_char_list, char_info);
1527 _bt_hps_set_char_value(http_hdr_obj_path, value, MAX_HEADER_LENGTH, 0);
1530 /* Characteristic HTTP Entity Body */
1531 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ |
1532 BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1533 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_ENTITY_UUID);
1534 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_entity_obj_path);
1535 if (ret != BLUETOOTH_ERROR_NONE) {
1536 BT_ERR("Failed to add new char %d", ret);
1540 ret = bluetooth_gatt_set_characteristic_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH);
1541 if (ret != BLUETOOTH_ERROR_NONE) {
1542 BT_ERR("Failed to add new char %d", ret);
1546 /* Store Characterisitc information */
1547 char_info = g_new0(struct hps_char_info, 1);
1548 char_info->char_path = g_strdup(http_entity_obj_path);
1549 hps_char_list = g_slist_append(hps_char_list, char_info);
1550 _bt_hps_set_char_value(http_entity_obj_path, value, MAX_ENTITY_LENGTH, 0);
1553 /* Characteristic HTTP Control Point */
1554 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_WRITE;
1555 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_CP_UUID);
1556 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_cp_obj_path);
1557 if (ret != BLUETOOTH_ERROR_NONE) {
1558 BT_ERR("Failed to add new char %d", ret);
1562 ret = bluetooth_gatt_set_characteristic_value(http_cp_obj_path, &cp, 1);
1563 if (ret != BLUETOOTH_ERROR_NONE) {
1564 BT_ERR("Failed to add new char %d", ret);
1568 /* Store Characterisitc information */
1569 char_info = g_new0(struct hps_char_info, 1);
1570 char_info->char_path = g_strdup(http_cp_obj_path);
1571 hps_char_list = g_slist_append(hps_char_list, char_info);
1572 _bt_hps_set_char_value(http_cp_obj_path, &cp, 1, 0);
1575 /* Characteristic HTTP Status Code */
1576 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
1577 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_STATUS_UUID);
1578 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_status_obj_path);
1579 if (ret != BLUETOOTH_ERROR_NONE) {
1580 BT_ERR("Failed to add new char %d", ret);
1584 ret = bluetooth_gatt_set_characteristic_value(http_status_obj_path, status, 3);
1585 if (ret != BLUETOOTH_ERROR_NONE) {
1586 BT_ERR("Failed to add new char %d", ret);
1590 desc_uuid = __hps_convert_uuid_to_uuid128(HTTP_STATUS_CCC_DESC_UUID);
1591 ret = bluetooth_gatt_add_descriptor(http_status_obj_path, desc_uuid,
1592 (BLUETOOTH_GATT_PERMISSION_READ | BLUETOOTH_GATT_PERMISSION_WRITE),
1593 &http_status_desc_obj_path);
1594 if (ret != BLUETOOTH_ERROR_NONE) {
1595 BT_ERR("Failed to add new char descriptor %d", ret);
1599 /* Store Characterisitc information */
1600 char_info = g_new0(struct hps_char_info, 1);
1601 char_info->char_path = g_strdup(http_status_obj_path);
1602 hps_char_list = g_slist_append(hps_char_list, char_info);
1603 _bt_hps_set_char_value(http_status_obj_path, status, 3, 0);
1606 /* Characteristic HTTPS Security */
1607 props = BLUETOOTH_GATT_CHARACTERISTIC_PROPERTY_READ;
1608 char_uuid = __hps_convert_uuid_to_uuid128(HTTP_SECURITY_UUID);
1609 ret = bluetooth_gatt_add_new_characteristic(hps_obj_path, char_uuid, 0, props, &http_security_obj_path);
1610 if (ret != BLUETOOTH_ERROR_NONE) {
1611 BT_ERR("Failed to add new char %d", ret);
1615 ret = bluetooth_gatt_set_characteristic_value(http_security_obj_path, &cp, 1);
1616 if (ret != BLUETOOTH_ERROR_NONE) {
1617 BT_ERR("Failed to add new char %d", ret);
1621 /* Store Characterisitc information */
1622 char_info = g_new0(struct hps_char_info, 1);
1623 char_info->char_path = g_strdup(http_security_obj_path);
1624 hps_char_list = g_slist_append(hps_char_list, char_info);
1625 _bt_hps_set_char_value(http_security_obj_path, &cp, 1, 0);
1628 ret = bluetooth_gatt_register_service(hps_obj_path);
1629 if (ret != BLUETOOTH_ERROR_NONE) {
1630 BT_ERR("Failed to register service %d", ret);
1634 ret = bluetooth_gatt_register_application();
1635 if (ret != BLUETOOTH_ERROR_NONE) {
1636 BT_ERR("Failed to register application %d", ret);
1644 delete_all_characterisitc();
1645 delete_all_notify_read_status();
1651 static void _bt_hps_sig_handler(int sig)
1657 BT_DBG("caught signal - sigterm\n");
1660 BT_DBG("caught signal - sigint\n");
1663 BT_DBG("caught signal - sigkill\n");
1666 BT_DBG("caught signal %d and ignored\n", sig);
1671 void _bt_hps_exit(void)
1676 if (g_uri != NULL) {
1681 if (g_header != NULL) {
1686 if (g_entity != NULL) {
1691 soup_session_abort(hps_soup_session);
1692 g_assert_cmpint(G_OBJECT(hps_soup_session)->ref_count, ==, 1);
1693 g_object_unref(hps_soup_session);
1696 delete_all_characterisitc();
1699 ret = bluetooth_gatt_deinit();
1700 if (ret != BLUETOOTH_ERROR_NONE)
1701 BT_ERR("Failed to Deinit GATT %d", ret);
1703 ret = bluetooth_unregister_callback();
1704 if (ret != BLUETOOTH_ERROR_NONE)
1705 BT_ERR("Failed to Unregister callback %d", ret);
1707 _bt_hps_deinit_event_receiver();
1709 _bt_hps_unregister_interface();
1711 if (main_loop != NULL)
1712 g_main_loop_quit(main_loop);
1715 void bt_hps_event_callback(int event, bluetooth_event_param_t* param,
1718 BT_DBG("HPS event %d", event);
1722 /* HTTP Proxy Service Main loop */
1725 struct sigaction sa;
1727 BT_ERR("Starting the bt-httpproxy daemon");
1729 /* Values taken from http://www.browserscope.org/ following
1730 * the rule "Do What Every Other Modern Browser Is Doing". They seem
1731 * to significantly improve page loading time compared to soup's
1733 * Change MAX_CONNECTIONS_PER_HOST value 6 -> 12, and maxConnections is changed from 35 to 60.
1734 * Enhanced network loading speed apply tunning value. */
1735 static const int maxConnections = 60;
1736 static const int maxConnectionsPerHost = 12;
1738 memset(&sa, 0, sizeof(sa));
1739 sa.sa_handler = _bt_hps_sig_handler;
1740 sa.sa_flags = SA_SIGINFO;
1741 sigaction(SIGINT, &sa, NULL);
1742 sigaction(SIGTERM, &sa, NULL);
1743 sigaction(SIGKILL, &sa, NULL);
1746 if (bluetooth_register_callback(bt_hps_event_callback, NULL) != BLUETOOTH_ERROR_NONE) {
1747 BT_ERR("bluetooth_register_callback returned failiure");
1752 if (_bt_hps_register_interface() != BLUETOOTH_ERROR_NONE) {
1753 BT_ERR("Fail to register http proxy service");
1757 if (_bt_hps_init_event_receiver() != BLUETOOTH_ERROR_NONE) {
1758 BT_ERR("Fail to init event reciever");
1762 hps_soup_session = soup_session_async_new();
1763 if (hps_soup_session == NULL) {
1764 BT_ERR("Failed to soup_session_async_new");
1767 /* Set Soup Session Fetures */
1768 g_object_set(hps_soup_session,
1769 SOUP_SESSION_MAX_CONNS, maxConnections,
1770 SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
1771 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_DECODER,
1772 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_CONTENT_SNIFFER,
1773 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
1774 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
1777 main_loop = g_main_loop_new(NULL, FALSE);
1779 g_main_loop_run(main_loop);
1781 BT_DBG("g_main_loop_quit called!");
1783 if (main_loop != NULL)
1784 g_main_loop_unref(main_loop);