diff --git a/broker/include/broker/extension.h b/broker/include/broker/extension.h index 6a6e61be..f568d95e 100644 --- a/broker/include/broker/extension.h +++ b/broker/include/broker/extension.h @@ -9,7 +9,7 @@ extern "C" { #endif struct ExtensionConfig { - char* brokerUrl; + const char* brokerUrl; uv_loop_t* loop; }; diff --git a/broker/include/broker/utils.h b/broker/include/broker/utils.h index 0fd07fc8..962e6807 100644 --- a/broker/include/broker/utils.h +++ b/broker/include/broker/utils.h @@ -15,6 +15,8 @@ void broker_utils_send_static_list_resp(RemoteDSLink *link, json_t *req); void broker_utils_send_disconnected_list_resp(RemoteDSLink *link, json_t *req); +const char* setHostFrom(const char* protocol,const char* address, const char* port); + #ifdef __cplusplus } #endif diff --git a/broker/src/broker.c b/broker/src/broker.c index ada621d4..779da6f5 100644 --- a/broker/src/broker.c +++ b/broker/src/broker.c @@ -471,17 +471,10 @@ void broker_stop(Broker* broker) { dslink_free(extension); } } - dslink_free(broker->extensionConfig.brokerUrl); + dslink_free((void*)broker->extensionConfig.brokerUrl); dslink_list_free_all_nodes(&broker->extensions); } -static int isipv6address(const char* host) -{ - int i = 0; - for(; host[i]; host[i]==':' ? i++ : *host++); - return i>0; -} - int broker_init_extensions(Broker* broker, json_t* config) { list_init(&broker->extensions); @@ -571,26 +564,14 @@ int broker_init_extensions(Broker* broker, json_t* config) { return -1; } - int len = strlen(httpsHost)+strlen(httpsPort)+16+1; - broker->extensionConfig.brokerUrl = dslink_malloc(len); - if(isipv6address(httpsHost)) { - snprintf(broker->extensionConfig.brokerUrl, len, "https://[%s]:%s/conn", httpsHost, httpsPort); - } else { - snprintf(broker->extensionConfig.brokerUrl, len, "https://%s:%s/conn", httpsHost, httpsPort); - } + broker->extensionConfig.brokerUrl = setHostFrom("https", httpsHost, httpsPort); } else { if(!httpEnabled) { log_err("Cannot load extensions. At least http has to be enabled."); return -1; } - int len = strlen(httpHost)+strlen(httpPort)+15+1; - broker->extensionConfig.brokerUrl = dslink_malloc(len); - if(isipv6address(httpHost)) { - snprintf(broker->extensionConfig.brokerUrl, len, "http://[%s]:%s/conn", httpHost, httpPort); - } else { - snprintf(broker->extensionConfig.brokerUrl, len, "http://%s:%s/conn", httpHost, httpPort); - } + broker->extensionConfig.brokerUrl = setHostFrom("http", httpHost, httpPort); } broker->extensionConfig.loop = mainLoop; diff --git a/broker/src/utils.c b/broker/src/utils.c index 2558dee6..f43843d6 100644 --- a/broker/src/utils.c +++ b/broker/src/utils.c @@ -2,6 +2,8 @@ #include "broker/net/ws.h" #include "broker/utils.h" +#include + void broker_free_handle(uv_handle_t *handle) { dslink_free(handle); } @@ -108,3 +110,24 @@ void broker_utils_send_disconnected_list_resp(RemoteDSLink *link, json_t *req) { broker_ws_send_obj(link, top); json_decref(top); } + +const char* setHostFrom(const char* protocol,const char* address, const char* port) +{ + char* host = NULL; + + if(dslink_isipv6address(address)) { + const char* temp = dslink_checkIpv6Address(address); + int len = strlen(temp)+strlen(port)+16+1; + host = dslink_malloc(len); + snprintf(host, len, "%s://[%s]:%s/conn", protocol, temp, port); + } else { + const char* temp = dslink_checkIpv4Address(address); + int len = strlen(temp)+strlen(port)+16+1; + host = dslink_malloc(len); + snprintf(host, len, "%s://%s:%s/conn", protocol, temp, port); + } + + return host; +} + + diff --git a/sdk/include/dslink/utils.h b/sdk/include/dslink/utils.h index a98eb835..f2305cb1 100644 --- a/sdk/include/dslink/utils.h +++ b/sdk/include/dslink/utils.h @@ -25,6 +25,10 @@ size_t dslink_create_ts(char *buf, size_t bufLen); int dslink_sleep(long ms); +const char* dslink_checkIpv4Address(const char* address); +const char* dslink_checkIpv6Address(const char* address); +int dslink_isipv6address(const char* host); + #ifdef __cplusplus } #endif diff --git a/sdk/src/utils.c b/sdk/src/utils.c index 044c684a..2da156a7 100644 --- a/sdk/src/utils.c +++ b/sdk/src/utils.c @@ -242,3 +242,39 @@ int dslink_sleep(long ms) { return nanosleep(&req, NULL); } + +const char* dslink_checkIpv4Address(const char* address) +{ + const char* host = address; + if(strcmp("0.0.0.0", address) == 0) { + static char* localhost = "127.0.0.1"; + host = localhost; + } + + return host; +} + +const char* dslink_checkIpv6Address(const char* address) +{ + const char* host = address; + static char* localhost = "::1"; + + if(strcmp("::/128", address) == 0 || strcmp("::/0", address) == 0) { + host = localhost; + } else { + size_t span = strspn(address, "0:"); + if(address[span] == '\0') { + host = localhost; + } + } + + return host; +} + +int dslink_isipv6address(const char* host) +{ + int i = 0; + for(; host[i]; host[i]==':' ? i++ : *host++); + return i>0; +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f4a8b0d4..6dfbfe1e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,6 +19,7 @@ set(SDK_TEST_SET set(BROKER_TEST_SET "node_test" + "utils_test" ) function(add_memcheck_test name) diff --git a/test/broker/utils_test.c b/test/broker/utils_test.c new file mode 100644 index 00000000..7f736771 --- /dev/null +++ b/test/broker/utils_test.c @@ -0,0 +1,37 @@ +#include "cmocka_init.h" + +#include + +static +void setHostFrom_test(void** state) +{ + (void) state; + + assert_string_equal(setHostFrom("http", "localhost", "12345"), "http://localhost:12345/conn" ); + assert_string_equal(setHostFrom("http", "anyhost.de", "12345"), "http://anyhost.de:12345/conn" ); + assert_string_equal(setHostFrom("http", "1.2.3.4", "12345"), "http://1.2.3.4:12345/conn" ); + assert_string_equal(setHostFrom("http", "0:1:2:3:4:5:6:7", "8888"), "http://[0:1:2:3:4:5:6:7]:8888/conn" ); + assert_string_equal(setHostFrom("http", "0:1:2::7:8", "8888"), "http://[0:1:2::7:8]:8888/conn" ); + + // Special case IPv4 unspecified address + assert_string_equal(setHostFrom("http", "0.0.0.0", "12345"), "http://127.0.0.1:12345/conn" ); + + // Special case IPv6 unspecified address + assert_string_equal(setHostFrom("http", "::/0", "12345"), "http://[::1]:12345/conn" ); + assert_string_equal(setHostFrom("http", "::/128", "23456"), "http://[::1]:23456/conn" ); + assert_string_equal(setHostFrom("http", "::1", "1234"), "http://[::1]:1234/conn" ); + assert_string_equal(setHostFrom("http", "0:0:0::0", "12345"), "http://[::1]:12345/conn" ); + assert_string_equal(setHostFrom("http", "0:0::0:0", "12345"), "http://[::1]:12345/conn" ); + assert_string_equal(setHostFrom("http", "0:0:0:0:0:0:0:0", "12345"), "http://[::1]:12345/conn" ); + + +} + + +int main() { + const struct CMUnitTest tests[] = { + cmocka_unit_test(setHostFrom_test) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/sdk/utils_test.c b/test/sdk/utils_test.c index d4e41e76..d99a4cde 100644 --- a/test/sdk/utils_test.c +++ b/test/sdk/utils_test.c @@ -69,12 +69,90 @@ void url_parse_test(void **state) assert_true(8463u == url->port); assert_string_equal("/conn", url->uri); } + { + const char address[] = "http://[::/128]:8100/conn"; + + Url* url = dslink_url_parse(address); + assert_non_null(url); + assert_string_equal("::/128", url->host); + assert_string_equal("http", url->scheme); + assert_false(url->secure); + assert_true(8100u == url->port); + assert_string_equal("/conn", url->uri); + } +} + +static +void ipv6_test(void** state) +{ + (void)state; + + const char* ipv6 = "::1"; + assert_true(dslink_isipv6address(ipv6)); + ipv6 = "2001:420:44e7:1300:b039:6611:2e10:e963"; + assert_true(dslink_isipv6address(ipv6)); + ipv6 = "2001:db8::ff00:42:8329"; + assert_true(dslink_isipv6address(ipv6)); + ipv6 = "::192.0.2.128"; + assert_true(dslink_isipv6address(ipv6)); + ipv6 = "::1/128"; + assert_true(dslink_isipv6address(ipv6)); + + const char* ipv4 = "127.0.0.1"; + assert_false(dslink_isipv6address(ipv4)); + ipv4 = "0.0.0.0"; + assert_false(dslink_isipv6address(ipv4)); + ipv4 = "127.0.0.1"; + assert_false(dslink_isipv6address(ipv4)); +} + +static +void checkIpv4Address_test(void** state) +{ + (void)state; + + const char* ipv4 = "127.0.0.1"; + const char* host = dslink_checkIpv4Address(ipv4); + assert_string_equal("127.0.0.1", host); + + ipv4 = "0.0.0.0"; + host = dslink_checkIpv4Address(ipv4); + assert_string_equal("127.0.0.1", host); +} + +static +void checkIpv6Address_test(void** state) +{ + (void)state; + + const char* ipv6 = "2001:420:44e7:1300:b039:6611:2e10:e963"; + const char* host = dslink_checkIpv6Address(ipv6); + assert_string_equal("2001:420:44e7:1300:b039:6611:2e10:e963", host); + + ipv6 = "::1"; + host = dslink_checkIpv6Address(ipv6); + assert_string_equal("::1", host); + + ipv6 = "0:0:0:0:0:0:0:0"; + host = dslink_checkIpv6Address(ipv6); + assert_string_equal("::1", host); + + ipv6 = "::/128"; + host = dslink_checkIpv6Address(ipv6); + assert_string_equal("::1", host); + + ipv6 = "::/0"; + host = dslink_checkIpv6Address(ipv6); + assert_string_equal("::1", host); } int main() { const struct CMUnitTest tests[] = { cmocka_unit_test(utils_str_replace_all_test), - cmocka_unit_test(url_parse_test) + cmocka_unit_test(url_parse_test), + cmocka_unit_test(ipv6_test), + cmocka_unit_test(checkIpv4Address_test), + cmocka_unit_test(checkIpv6Address_test) }; return cmocka_run_group_tests(tests, NULL, NULL);