celix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rlenfer...@apache.org
Subject [celix] 01/03: Added support to specify a CIDR range in PSA_IP
Date Tue, 25 Jun 2019 18:04:52 GMT
This is an automated email from the ASF dual-hosted git repository.

rlenferink pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 342c5f84c83bd3160f476cdaa24f4c5440014f68
Author: Roy Lenferink <lenferinkroy@gmail.com>
AuthorDate: Mon Jun 24 14:14:14 2019 +0200

    Added support to specify a CIDR range in PSA_IP
---
 bundles/pubsub/mock/CMakeLists.txt                 |   3 +-
 bundles/pubsub/pubsub_admin_udp_mc/CMakeLists.txt  |   2 +-
 .../pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c   |  29 +++-
 bundles/pubsub/pubsub_admin_zmq/CMakeLists.txt     |   2 +-
 .../pubsub/pubsub_admin_zmq/src/pubsub_zmq_admin.c |  23 ++-
 libs/utils/CMakeLists.txt                          |   7 +
 libs/utils/README.md                               |   3 -
 libs/utils/include/ip_utils.h                      |  52 +++++++
 libs/utils/private/test/ip_utils_test.cpp          | 103 +++++++++++++
 libs/utils/src/ip_utils.c                          | 163 +++++++++++++++++++++
 10 files changed, 370 insertions(+), 17 deletions(-)

diff --git a/bundles/pubsub/mock/CMakeLists.txt b/bundles/pubsub/mock/CMakeLists.txt
index c310e1b..2a406d0 100644
--- a/bundles/pubsub/mock/CMakeLists.txt
+++ b/bundles/pubsub/mock/CMakeLists.txt
@@ -18,6 +18,7 @@
 #only install if CppuTest is available
 find_package(CppUTest QUIET)
 if (CPPUTEST_FOUND)
+    include_directories(SYSTEM ${CPPUTEST_INCLUDE_DIR})
 
     add_library(pubsub_mock STATIC
             src/publisher_mock.cc
@@ -34,7 +35,7 @@ if (CPPUTEST_FOUND)
             tst/run_tests.cc
         )
         target_include_directories(pubsubmock_test PRIVATE ${CMAKE_CURRENT_LIST_DIR}/api)
-	target_link_libraries(pubsubmock_test PRIVATE Celix::pubsub_api pubsub_mock ${CPPUTEST_LIBRARY}
${CPPUTEST_EXT_LIBRARY} Celix::framework)
+        target_link_libraries(pubsubmock_test PRIVATE Celix::pubsub_api pubsub_mock ${CPPUTEST_LIBRARY}
${CPPUTEST_EXT_LIBRARY} Celix::framework)
         add_test(NAME pubsubmock_test COMMAND pubsubmock_test)
     endif()
 endif()
diff --git a/bundles/pubsub/pubsub_admin_udp_mc/CMakeLists.txt b/bundles/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
index 0703ceb..e5ed16f 100644
--- a/bundles/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
+++ b/bundles/pubsub/pubsub_admin_udp_mc/CMakeLists.txt
@@ -34,7 +34,7 @@ target_include_directories(celix_pubsub_admin_udp_multicast PRIVATE
 		${JANSSON_INCLUDE_DIR}
 )
 set_target_properties(celix_pubsub_admin_udp_multicast PROPERTIES INSTALL_RPATH "$ORIGIN")
-target_link_libraries(celix_pubsub_admin_udp_multicast PRIVATE Celix::pubsub_spi Celix::framework
Celix::dfi Celix::log_helper)
+target_link_libraries(celix_pubsub_admin_udp_multicast PRIVATE Celix::pubsub_spi Celix::framework
Celix::dfi Celix::log_helper Celix::utils)
 
 install_celix_bundle(celix_pubsub_admin_udp_multicast EXPORT celix COMPONENT pubsub)
 
diff --git a/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c b/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
index 43602a4..b4c4cfe 100644
--- a/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
+++ b/bundles/pubsub/pubsub_admin_udp_mc/src/pubsub_udpmc_admin.c
@@ -25,6 +25,7 @@
 #include <ifaddrs.h>
 #include <pubsub_endpoint.h>
 #include <pubsub_serializer.h>
+#include <ip_utils.h>
 
 #include "pubsub_utils.h"
 #include "pubsub_udpmc_admin.h"
@@ -103,21 +104,37 @@ pubsub_udpmc_admin_t* pubsub_udpmcAdmin_create(celix_bundle_context_t
*ctx, log_
     char *if_ip = NULL;
     int sendSocket = -1;
 
-    const char *mcIpProp = celix_bundleContext_getProperty(ctx,PUBSUB_UDPMC_IP_KEY , NULL);
+    const char *mcIpProp = celix_bundleContext_getProperty(ctx, PUBSUB_UDPMC_IP_KEY, NULL);
     if(mcIpProp != NULL) {
-        mc_ip = strdup(mcIpProp);
+        if (strchr(mcIpProp, '/') != NULL) {
+            // IP with subnet prefix specified
+            char *found_if_ip = calloc(16, sizeof(char));
+            celix_status_t ip_status = ipUtils_findIpBySubnet(mcIpProp, &found_if_ip);
+            if (ip_status == CELIX_SUCCESS) {
+                if (found_if_ip != NULL)
+                    if_ip = strndup(found_if_ip, 16);
+                else
+                    L_WARN("Could not find interface for requested subnet %s", mcIpProp);
+            } else {
+                L_ERROR("Error while searching for available network interface for subnet
%s", mcIpProp);
+            }
+            free(found_if_ip);
+        } else {
+            // IP address specified
+            mc_ip = strndup(mcIpProp, 1024);
+        }
     }
 
 
     const char *mc_prefix = celix_bundleContext_getProperty(ctx, PUBSUB_UDPMC_MULTICAST_IP_PREFIX_KEY,
PUBSUB_UDPMC_MULTICAST_IP_PREFIX_DEFAULT);
     const char *interface = celix_bundleContext_getProperty(ctx, PUBSUB_UDPMC_ITF_KEY, NULL);
-    if (udpmc_getIpAddress(interface, &if_ip) != CELIX_SUCCESS) {
+    if (!if_ip && udpmc_getIpAddress(interface, &if_ip) != CELIX_SUCCESS) {
         L_WARN("[PSA_UDPMC] Could not retrieve IP address for interface %s", interface);
     } else if (psa->verbose) {
         L_INFO("[PSA_UDPMC] Using IP address %s", if_ip);
     }
 
-    if(if_ip && sscanf(if_ip, "%i.%i.%i.%i", &b0, &b1, &b2, &b3)
!= 4) {
+    if (if_ip && sscanf(if_ip, "%i.%i.%i.%i", &b0, &b1, &b2, &b3)
!= 4) {
         logHelper_log(psa->log, OSGI_LOGSERVICE_WARNING, "[PSA_UDPMC] Could not parse
IP address %s", if_ip);
         b2 = 1;
         b3 = 1;
@@ -126,12 +143,12 @@ pubsub_udpmc_admin_t* pubsub_udpmcAdmin_create(celix_bundle_context_t
*ctx, log_
     asprintf(&mc_ip, "%s.%d.%d",mc_prefix, b2, b3);
 
     sendSocket = socket(AF_INET, SOCK_DGRAM, 0);
-    if(sendSocket == -1) {
+    if (sendSocket == -1) {
         L_ERROR("[PSA_UDPMC] Error creating socket: %s", strerror(errno));
     } else {
         char loop = 1;
         int rc = setsockopt(sendSocket, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
-        if(rc != 0) {
+        if (rc != 0) {
             L_ERROR("[PSA_UDPMC] Error setsockopt(IP_MULTICAST_LOOP): %s", strerror(errno));
         }
         if (rc == 0) {
diff --git a/bundles/pubsub/pubsub_admin_zmq/CMakeLists.txt b/bundles/pubsub/pubsub_admin_zmq/CMakeLists.txt
index 2ef2001..e2d346b 100644
--- a/bundles/pubsub/pubsub_admin_zmq/CMakeLists.txt
+++ b/bundles/pubsub/pubsub_admin_zmq/CMakeLists.txt
@@ -53,7 +53,7 @@ if (BUILD_PUBSUB_PSA_ZMQ)
 	set_target_properties(celix_pubsub_admin_zmq PROPERTIES INSTALL_RPATH "$ORIGIN")
 	target_link_libraries(celix_pubsub_admin_zmq PRIVATE
 			Celix::pubsub_spi
-			Celix::framework Celix::dfi Celix::log_helper
+			Celix::framework Celix::dfi Celix::log_helper Celix::utils
 			${ZMQ_LIBRARIES} ${CZMQ_LIBRARIES} ${OPENSSL_CRYPTO_LIBRARY}
 	)
 	target_include_directories(celix_pubsub_admin_zmq PRIVATE
diff --git a/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_admin.c b/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_admin.c
index a61e533..ab19e79 100644
--- a/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_admin.c
+++ b/bundles/pubsub/pubsub_admin_zmq/src/pubsub_zmq_admin.c
@@ -26,6 +26,7 @@
 #include <pubsub_endpoint.h>
 #include <czmq.h>
 #include <pubsub_serializer.h>
+#include <ip_utils.h>
 
 #include "pubsub_utils.h"
 #include "pubsub_zmq_admin.h"
@@ -102,11 +103,23 @@ pubsub_zmq_admin_t* pubsub_zmqAdmin_create(celix_bundle_context_t *ctx,
log_help
     char *ip = NULL;
     const char *confIp = celix_bundleContext_getProperty(ctx, PUBSUB_ZMQ_PSA_IP_KEY , NULL);
     if (confIp != NULL) {
-        ip = strndup(confIp, 1024);
-    }
-
-    if (ip == NULL) {
-        //TODO try to get ip from subnet (CIDR)
+        if (strchr(confIp, '/') != NULL) {
+            // IP with subnet prefix specified
+            char *found_if_ip = calloc(16, sizeof(char));
+            celix_status_t ip_status = ipUtils_findIpBySubnet(confIp, &found_if_ip);
+            if (ip_status == CELIX_SUCCESS) {
+                if (found_if_ip != NULL)
+                    ip = strndup(found_if_ip, 16);
+                else
+                    L_WARN("Could not find interface for requested subnet %s", confIp);
+            } else {
+                L_ERROR("Error while searching for available network interface for subnet
%s", confIp);
+            }
+            free(found_if_ip);
+        } else {
+            // IP address specified
+            ip = strndup(confIp, 1024);
+        }
     }
 
     if (ip == NULL) {
diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt
index 9784a34..893c786 100644
--- a/libs/utils/CMakeLists.txt
+++ b/libs/utils/CMakeLists.txt
@@ -37,6 +37,7 @@ add_library(utils SHARED
     src/thpool.c
     src/properties.c
     src/utils.c
+    src/ip_utils.c
     src/filter.c
     ${MEMSTREAM_SOURCES}
 )
@@ -92,6 +93,7 @@ if (ENABLE_TESTING AND UTILS-TESTS)
 
     add_executable(celix_threads_test private/test/celix_threads_test.cpp)
     target_link_libraries(celix_threads_test Celix::utils ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY}
pthread)
+
     add_executable(linked_list_test private/test/linked_list_test.cpp)
     target_link_libraries(linked_list_test  Celix::utils ${CPPUTEST_LIBRARY} pthread)
 
@@ -105,6 +107,9 @@ if (ENABLE_TESTING AND UTILS-TESTS)
     add_executable(utils_test private/test/utils_test.cpp)
     target_link_libraries(utils_test ${CPPUTEST_LIBRARY}  Celix::utils pthread)
 
+    add_executable(ip_utils_test private/test/ip_utils_test.cpp)
+    target_link_libraries(ip_utils_test ${CPPUTEST_LIBRARY}  Celix::utils pthread)
+
     add_executable(filter_test private/test/filter_test.cpp)
     target_link_libraries(filter_test ${CPPUTEST_LIBRARY}  Celix::utils pthread)
 
@@ -117,6 +122,7 @@ if (ENABLE_TESTING AND UTILS-TESTS)
     add_test(NAME run_linked_list_test COMMAND linked_list_test)
     add_test(NAME run_properties_test COMMAND properties_test)
     add_test(NAME run_utils_test COMMAND utils_test)
+    add_test(NAME run_ip_utils_test COMMAND ip_utils_test)
     add_test(NAME filter_test COMMAND filter_test)
 
     SETUP_TARGET_FOR_COVERAGE(array_list_test array_list_test ${CMAKE_BINARY_DIR}/coverage/array_list_test/array_list_test)
@@ -126,5 +132,6 @@ if (ENABLE_TESTING AND UTILS-TESTS)
     SETUP_TARGET_FOR_COVERAGE(linked_list_test linked_list_test ${CMAKE_BINARY_DIR}/coverage/linked_list_test/linked_list_test)
     SETUP_TARGET_FOR_COVERAGE(properties_test properties_test ${CMAKE_BINARY_DIR}/coverage/properties_test/properties_test)
     SETUP_TARGET_FOR_COVERAGE(utils_test utils_test ${CMAKE_BINARY_DIR}/coverage/utils_test/utils_test)
+    SETUP_TARGET_FOR_COVERAGE(ip_utils_test ip_utils_test ${CMAKE_BINARY_DIR}/coverage/ip_utils_test/ip_utils_test)
 
 endif(ENABLE_TESTING AND UTILS-TESTS)
diff --git a/libs/utils/README.md b/libs/utils/README.md
index 90aaccc..1cf67d8 100644
--- a/libs/utils/README.md
+++ b/libs/utils/README.md
@@ -24,6 +24,3 @@ Celix Utils contains several useful containers/lists implementation used
with th
     Hash Map
     Linked List
     Thread Pool
-
-###### CMake option
-    BUILD_UTILS=ON
diff --git a/libs/utils/include/ip_utils.h b/libs/utils/include/ip_utils.h
new file mode 100644
index 0000000..d95a14a
--- /dev/null
+++ b/libs/utils/include/ip_utils.h
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * ip_utils.h
+ *
+ *  \date       Jun 24, 2019
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#ifndef IP_UTILS_H_
+#define IP_UTILS_H_
+
+#include <ctype.h>
+
+#include "celix_errno.h"
+#include "exports.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UTILS_EXPORT unsigned int ipUtils_ipToUnsignedInt(char *ip);
+
+UTILS_EXPORT char *ipUtils_unsignedIntToIp(unsigned int ip);
+
+UTILS_EXPORT unsigned int ipUtils_prefixToBitmask(unsigned int prefix);
+
+UTILS_EXPORT int ipUtils_netmaskToPrefix(const char *netmask);
+
+UTILS_EXPORT celix_status_t ipUtils_findIpBySubnet(const char *ipWithPrefix, char **ip);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* IP_UTILS_H_ */
diff --git a/libs/utils/private/test/ip_utils_test.cpp b/libs/utils/private/test/ip_utils_test.cpp
new file mode 100644
index 0000000..0a2629d
--- /dev/null
+++ b/libs/utils/private/test/ip_utils_test.cpp
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * ip_utils_test.cpp
+ *
+ *  \date       Jun 24, 2019
+ *  \author     <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright  Apache License, Version 2.0
+ */
+
+#include "string.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "CppUTest/TestHarness.h"
+#include "CppUTest/TestHarness_c.h"
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C"
+{
+#include "ip_utils.h"
+}
+
+int main(int argc, char** argv) {
+	return RUN_ALL_TESTS(argc, argv);
+}
+
+static char* my_strdup(const char* s){
+    if(s==NULL){
+        return NULL;
+    }
+
+    size_t len = strlen(s);
+
+    char *d = (char*) calloc (len + 1,sizeof(char));
+
+    if (d == NULL){
+        return NULL;
+    }
+
+    strncpy (d,s,len);
+    return d;
+}
+
+TEST_GROUP(ip_utils) {
+	void setup(void) {
+	}
+
+	void teardown() {
+	}
+};
+
+TEST(ip_utils, ipToUnsignedInt){
+	char *ip = my_strdup("192.168.1.64");
+
+	unsigned int expected = 3232235840;
+    unsigned int actual = ipUtils_ipToUnsignedInt(ip);
+    UNSIGNED_LONGS_EQUAL(expected, actual);
+
+    free(ip);
+}
+
+TEST(ip_utils, unsignedIntToIp){
+    unsigned int ipAsUint = 3232235840;
+
+    const char *expected = "192.168.1.64";
+    char *actual = ipUtils_unsignedIntToIp(ipAsUint);
+    STRCMP_EQUAL(expected, actual);
+    free(actual);
+}
+
+TEST(ip_utils, prefixToBitmask){
+    unsigned int expected = 4294967264;
+    unsigned int actual = ipUtils_prefixToBitmask(27);
+
+    UNSIGNED_LONGS_EQUAL(expected, actual);
+}
+
+TEST(ip_utils, netmaskToPrefix){
+    char *netmask = my_strdup("255.255.255.0");
+
+    int expected = 24;
+    int actual = ipUtils_netmaskToPrefix(netmask);
+    LONGS_EQUAL(expected, actual);
+
+    free(netmask);
+}
diff --git a/libs/utils/src/ip_utils.c b/libs/utils/src/ip_utils.c
new file mode 100644
index 0000000..633ee79
--- /dev/null
+++ b/libs/utils/src/ip_utils.c
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * ip_utils.c
+ *
+ *  \date       Jun 24, 2019
+ *  \author    	<a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
+ *  \copyright	Apache License, Version 2.0
+ */
+
+#include "ip_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <math.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+#include <unistd.h>
+
+unsigned int ipUtils_ipToUnsignedInt(char *ip) {
+    unsigned int ipAsUint = 0;
+
+    char *partOfIp, *savePtr;
+    char *input = strdup(ip); // Make a copy because otherwise strtok_r manipulates the input
string
+    partOfIp = strtok_r(input, ".\0", &savePtr); ipAsUint += strtoul(partOfIp, NULL,
10) * (unsigned int) pow(256, 3);
+    partOfIp = strtok_r(NULL, ".\0", &savePtr);  ipAsUint += strtoul(partOfIp, NULL,
10) * (unsigned int) pow(256, 2);
+    partOfIp = strtok_r(NULL, ".\0", &savePtr);  ipAsUint += strtoul(partOfIp, NULL,
10) * (unsigned int) pow(256, 1);
+    partOfIp = strtok_r(NULL, ".\0", &savePtr);  ipAsUint += strtoul(partOfIp, NULL,
10) * (unsigned int) pow(256, 0);
+    free(input);
+
+    return ipAsUint;
+}
+
+char *ipUtils_unsignedIntToIp(unsigned int ip) {
+    char *ipStr = calloc(16, sizeof(char));
+
+    int ipPart1 = ip / (int) pow(256, 3); ip -= ipPart1 * (int) pow(256, 3);
+    int ipPart2 = ip / (int) pow(256, 2); ip -= ipPart2 * (int) pow(256, 2);
+    int ipPart3 = ip / (int) pow(256, 1); ip -= ipPart3 * (int) pow(256, 1);
+    int ipPart4 = ip / (int) pow(256, 0);
+
+    snprintf(ipStr, 16, "%d.%d.%d.%d", ipPart1, ipPart2, ipPart3, ipPart4);
+
+    return ipStr;
+}
+
+unsigned int ipUtils_prefixToBitmask(unsigned int prefix) {
+    return (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF;
+}
+
+int ipUtils_netmaskToPrefix(const char *netmask) {
+    // Convert netmask to in_addr object
+    struct in_addr in;
+    int ret = inet_pton(AF_INET, netmask, &in);
+    if (ret == 0)
+        return -1;
+
+    // Now convert the mask to a prefix
+    int prefix = 0;
+    bool processed_one = false;
+    unsigned int i = ntohl(in.s_addr);
+
+    while (i > 0) {
+        if (i & 1) {
+            prefix++;
+            processed_one = true;
+        } else {
+            if (processed_one) return -1;
+        }
+
+        i >>= 1;
+    }
+
+    return prefix;
+}
+
+/** Finds an IP of the available network interfaces of the machine by specifying an CIDR
subnet.
+ *
+ * @param ipWithPrefix  [in] IP with prefix, e.g. 192.168.1.0/24
+ * @param ip            [out] In case a matching interface could be found, an allocated string
containing the IP of the
+ *                      interface will be set, e.g. 192.168.1.16. Memory for the new string
can be freed with free().
+ *                      When no matching interface is found NULL will be set.
+ * @return              CELIX_SUCCESS for success. Otherwise an error status from celix_errno.h
will be set.
+ */
+celix_status_t ipUtils_findIpBySubnet(const char *ipWithPrefix, char **ip) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    char *input = strndup(ipWithPrefix, 19); // Make a copy as otherwise strtok_r manipulates
the input string
+
+    char *savePtr;
+    char *inputIp = strtok_r(input, "/", &savePtr);
+    char *inputPrefixStr = strtok_r(NULL, "\0", &savePtr);
+    unsigned int inputPrefix = (unsigned int) strtoul(inputPrefixStr, NULL, 10);
+
+    unsigned int ipAsUint = ipUtils_ipToUnsignedInt(inputIp);
+    unsigned int bitmask = ipUtils_prefixToBitmask(inputPrefix);
+
+    unsigned int ipRangeStart = ipAsUint & bitmask;
+    unsigned int ipRangeStop = ipAsUint | ~bitmask;
+
+    // Requested IP range is known now, now loop through network interfaces
+    struct ifaddrs *ifap, *ifa;
+
+    getifaddrs (&ifap);
+    for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+        if (ifa->ifa_addr == NULL)
+            continue;
+
+        if (ifa->ifa_addr->sa_family != AF_INET)
+            continue;
+
+        // Retrieve IP address for interface
+        char if_addr[NI_MAXHOST];
+        int rv = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
+                             if_addr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+
+        if (rv != 0) {
+            printf("getnameinfo() failed: %s\n", gai_strerror(rv));
+            continue;
+        }
+
+        // Retrieve netmask
+        struct sockaddr_in *sa = (struct sockaddr_in *) ifa->ifa_netmask;
+        char *if_netmask = inet_ntoa(sa->sin_addr);
+
+        unsigned int ifIpAsUint = ipUtils_ipToUnsignedInt(if_addr);
+        int ifPrefix = ipUtils_netmaskToPrefix(if_netmask);
+        if (ifPrefix == -1) {
+            status = CELIX_ILLEGAL_ARGUMENT;
+            break;
+        }
+
+        if (ifIpAsUint >= ipRangeStart && ifIpAsUint <= ipRangeStop &&
inputPrefix >= ifPrefix) {
+            *ip = strndup(if_addr, 1024);
+            break;
+        }
+    }
+    freeifaddrs(ifap);
+    free(input);
+
+    return status;
+}


Mime
View raw message