From b06685c8ea3a5a257ff4496ee0772c387b2cb726 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 12 Aug 2022 14:29:05 +0200 Subject: [PATCH] Add new CAPI for registering SRP service with TXT records Change-Id: I8e9e861ac0b8e4579ebd0fbdeccc9404b578d025 --- include/thread-private.h | 11 +++++++++++ include/thread-type.h | 13 +++++++++++++ include/thread.h | 24 ++++++++++++++++++++++++ src/thread-srp.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/thread-util.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+) diff --git a/include/thread-private.h b/include/thread-private.h index 8017556..0329763 100755 --- a/include/thread-private.h +++ b/include/thread-private.h @@ -383,6 +383,17 @@ void _thread_route_free(gpointer data); */ void _thread_onmesh_prefix_free(gpointer data); +/** + * @brief Encode TXT entries as a null-terminated hex-string. + * @since_tizen 7.0 + * + * @exception + * @pre + * @post + */ +int _thread_encode_txt_entries(const thread_dns_txt_entry_s *txt_entries, + uint8_t num_txt_entries, char *buffer, size_t buffer_size); + #ifdef __cplusplus } #endif diff --git a/include/thread-type.h b/include/thread-type.h index 5dd11f4..6aa15ed 100755 --- a/include/thread-type.h +++ b/include/thread-type.h @@ -198,6 +198,19 @@ typedef void (*thread_joiner_result_cb)(int result, void *user_data); */ typedef void *thread_network_h; +/** + * @ingroup CAPI_NETWORK_THREAD_MODULE + * @brief Structure which holds single DNS TXT entry. + * @since_tizen 7.0 + * + * @note The total length of the TXT entry, which is "key + '=' + value" or + * "key" for boolean key, must not exceed 255 bytes. + */ +typedef struct { + const char *key; /** The TXT record null-terminated key string */ + const uint8_t *value; /** The TXT record value, or NULL for boolean key */ + uint8_t value_len; /** The length of the TXT record value */ +} thread_dns_txt_entry_s; /** * @ingroup CAPI_NETWORK_THREAD_MODULE diff --git a/include/thread.h b/include/thread.h index 2f93623..01ace89 100644 --- a/include/thread.h +++ b/include/thread.h @@ -1473,12 +1473,36 @@ int thread_srp_client_set_host_address(thread_instance_h instance, const char *i * @pre thread API must be initialized with thread_initialize(). * @see thread_srp_client_start() * @see thread_srp_client_set_host_address() + * @see thread_srp_client_register_service_full() */ int thread_srp_client_register_service(thread_instance_h instance, const char *service_name, const char *service_type, uint64_t port); /** * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE + * @brief Register Service to SRP server + * @since_tizen 7.0 + * + * This is an extended version of thread_srp_client_register_service() + * which allows to set priority, weight and TXT entries. + * + * @return 0 on success, otherwise a negative error value. + * @retval #THREAD_ERROR_NONE Successful + * @retval #THREAD_ERROR_NOT_INITIALIZED Not initialized + * @retval #THREAD_ERROR_OPERATION_FAILED Operation failed + * @retval #THREAD_ERROR_NOT_SUPPORTED Not supported + * + * @pre thread API must be initialized with thread_initialize(). + * @see thread_srp_client_start() + * @see thread_srp_client_set_host_address() + * @see thread_srp_client_register_service() + */ +int thread_srp_client_register_service_full(thread_instance_h instance, + const char *service_name, const char *service_type, uint16_t port, uint16_t priority, + uint16_t weight, const thread_dns_txt_entry_s *txt_entries, uint8_t num_txt_entries); + +/** + * @ingroup CAPI_NETWORK_THREAD_SRP_MODULE * @brief Remove Service from SRP server * @since_tizen 7.0 * diff --git a/src/thread-srp.c b/src/thread-srp.c index 063649a..8667c75 100644 --- a/src/thread-srp.c +++ b/src/thread-srp.c @@ -175,6 +175,51 @@ int thread_srp_client_register_service(thread_instance_h instance, return ret; } +int thread_srp_client_register_service_full(thread_instance_h instance, + const char *service_name, const char *service_type, uint16_t port, uint16_t priority, + uint16_t weight, const thread_dns_txt_entry_s *txt_entries, uint8_t num_txt_entries) +{ + FUNC_ENTRY; + THREAD_CHECK_SUPPORTED_FEATURE(THREAD_FEATURE_COMMON); + THREAD_VALIDATE_INPUT_PARAMETER(service_name); + THREAD_VALIDATE_INPUT_PARAMETER(txt_entries); + THREAD_CHECK_INIT_STATUS(); + THREAD_VALIDATE_INPUT_PARAMETER(instance); + int ret = THREAD_ERROR_NONE; + + /* Register SRP service */ + const char *msg = THREAD_SRP_CLIENT_REGISTER_SERVICE_CMD; + + char buffer[THREAD_MAX_BUFFER_SIZE] = {0}; + char txt[THREAD_MAX_BUFFER_SIZE] = ""; + + ret = _thread_encode_txt_entries(txt_entries, num_txt_entries, txt, sizeof(txt)); + if (ret != THREAD_ERROR_NONE) { + THREAD_DBG("socket srp_client_register_service_full encode txt entries failed"); + return ret; + } + + int len = snprintf(buffer, sizeof(buffer), "%s %s %s %u %u %u %s", msg, + service_name, service_type, (int)port, (int)priority, (int)weight, txt); + /* Make sure that the socket command was not truncated. It might + * happen if the TXT record is too long. */ + if (len > sizeof(buffer) - 1) { + THREAD_DBG("socket srp_client_register_service_full buffer overflow"); + return THREAD_ERROR_INVALID_PARAMETER; + } + + ret = _thread_socket_client_execute(_thread_get_socket_fd(), + buffer, strlen(buffer)); + if (ret != THREAD_ERROR_NONE && ret != THREAD_ERROR_ALREADY_DONE) { + THREAD_DBG("socket srp_client_register_service_full execute failed"); + return ret; + } + THREAD_DBG("socket srp_client_register_service_full execute successful"); + + FUNC_EXIT; + return ret; +} + int thread_srp_client_remove_service(thread_instance_h instance, const char *service_name, const char *service_type) { diff --git a/src/thread-util.c b/src/thread-util.c index a5b41bd..1265ee2 100644 --- a/src/thread-util.c +++ b/src/thread-util.c @@ -238,3 +238,52 @@ void _thread_dbus_method_cb(gboolean res, const char* method, FUNC_EXIT; } + +int _thread_encode_txt_entries(const thread_dns_txt_entry_s *txt_entries, + uint8_t num_txt_entries, char *buffer, size_t buffer_size) +{ + FUNC_ENTRY; + int ret = THREAD_ERROR_NONE; + + for (size_t i = 0; i < num_txt_entries; i++) { + + /* calculate data length for DNS TXT entry as "key=value" */ + size_t key_len = strlen(txt_entries[i].key); + size_t entry_len = key_len; + if (txt_entries[i].value != NULL) + entry_len += 1 + txt_entries[i].value_len; + if (entry_len > 255) { + THREAD_DBG("Invalid DNS TXT entry length: %zu > 255", entry_len); + return THREAD_ERROR_INVALID_PARAMETER; + } + + /* check if buffer is big enough to hold hex-encoded + * entry record and string null-terminator */ + if (buffer_size < 2 * (entry_len + 1) + 1) { + THREAD_DBG("Not enough space in buffer for hex-encoded TXT entries"); + return THREAD_ERROR_OUT_OF_MEMORY; + } + + sprintf(&buffer[0], "%.2x", (int)entry_len); + for (size_t n = 0; n < key_len; n++) + sprintf(&buffer[2 + 2 * n], "%.2x", txt_entries[i].key[n]); + + buffer += 2 * (1 + key_len); + buffer_size -= 2 * (1 + key_len); + + if (txt_entries[i].value != NULL) { + + sprintf(&buffer[0], "%.2x", (int)'='); + for (size_t n = 0; n < txt_entries[i].value_len; n++) + sprintf(&buffer[2 + 2 * n], "%.2x", txt_entries[i].value[n]); + + buffer += 2 * (1 + txt_entries[i].value_len); + buffer_size -= 2 * (1 + txt_entries[i].value_len); + + } + + } + + FUNC_EXIT; + return ret; +} -- 2.7.4