This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/509-remove-cpputests
in repository https://gitbox.apache.org/repos/asf/celix.git

commit d1f7d10abe3ce23006d1007d1a16100b8af1b8c2
Author: Pepijn Noltes <[email protected]>
AuthorDate: Sat Dec 30 17:31:22 2023 +0100

    Refactor ip utils and ip utils tests
    
    Also improves error handling
---
 libs/utils/gtest/CMakeLists.txt                    |   1 +
 .../gtest/src/IpUtilsErrorInjectionTestSuite.cc    |  16 +-
 libs/utils/gtest/src/IpUtilsTestSuite.cc           | 125 ++++++++++++++
 libs/utils/include/celix_ip_utils.h                | 108 ++++++++++++
 libs/utils/include_deprecated/ip_utils.h           |  52 ------
 libs/utils/private/test/ip_utils_test.cpp          | 108 ------------
 libs/utils/src/ip_utils.c                          | 192 +++++++++++++--------
 7 files changed, 361 insertions(+), 241 deletions(-)

diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index b492009f..44a4aa42 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -34,6 +34,7 @@ add_executable(test_utils
         src/ThreadsTestSuite.cc
         src/CelixErrnoTestSuite.cc
         src/CelixUtilsAutoCleanupTestSuite.cc
+        src/IpUtilsTestSuite.cc
         src/DeprecatedHashmapTestSuite.cc
 )
 
diff --git a/libs/utils/gtest/src/IpUtilsErrorInjectionTestSuite.cc 
b/libs/utils/gtest/src/IpUtilsErrorInjectionTestSuite.cc
index 57a4c83c..93bd5626 100644
--- a/libs/utils/gtest/src/IpUtilsErrorInjectionTestSuite.cc
+++ b/libs/utils/gtest/src/IpUtilsErrorInjectionTestSuite.cc
@@ -17,10 +17,12 @@
   under the License.
  */
 
-#include <errno.h>
 #include <gtest/gtest.h>
+
+#include <errno.h>
+
 #include "ifaddrs_ei.h"
-#include "ip_utils.h"
+#include "celix_ip_utils.h"
 #include "celix_utils_ei.h"
 
 class IpUtilsWithErrorInjectionTestSuite : public ::testing::Test {
@@ -28,20 +30,20 @@ public:
     IpUtilsWithErrorInjectionTestSuite() = default;
     ~IpUtilsWithErrorInjectionTestSuite() override {
         celix_ei_expect_getifaddrs(nullptr, 0, 0);
-        celix_ei_expect_celix_utils_strdup(nullptr, 0, 0);
+        celix_ei_expect_celix_utils_strdup(nullptr, 0, nullptr);
     }
 };
 
 TEST_F(IpUtilsWithErrorInjectionTestSuite, failToGetInterfaceAddresses) {
-    celix_ei_expect_getifaddrs((void *)&ipUtils_findIpBySubnet, 0, -1);
-    auto ipAddresses = ipUtils_findIpBySubnet("192.168.1.0/24");
+    celix_ei_expect_getifaddrs((void *)&celix_utils_findIpInSubnet, 0, -1);
+    auto ipAddresses = celix_utils_findIpInSubnet("192.168.1.0/24");
     EXPECT_EQ(ipAddresses, nullptr);
     EXPECT_EQ(errno, EMFILE);
 }
 
 TEST_F(IpUtilsWithErrorInjectionTestSuite, failToDuplicateString) {
-    celix_ei_expect_celix_utils_strdup((void *) &ipUtils_findIpBySubnet, 0, 
nullptr);
-    auto ipAddresses = ipUtils_findIpBySubnet("192.168.1.0/24");
+    celix_ei_expect_celix_utils_strdup((void *) &celix_utils_findIpInSubnet, 
0, nullptr);
+    auto ipAddresses = celix_utils_findIpInSubnet("192.168.1.0/24");
     EXPECT_EQ(ipAddresses, nullptr);
     EXPECT_EQ(errno, ENOMEM);
 }
\ No newline at end of file
diff --git a/libs/utils/gtest/src/IpUtilsTestSuite.cc 
b/libs/utils/gtest/src/IpUtilsTestSuite.cc
new file mode 100644
index 00000000..5a2d1aa4
--- /dev/null
+++ b/libs/utils/gtest/src/IpUtilsTestSuite.cc
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "celix_err.h"
+#include "celix_ip_utils.h"
+#include "celix_stdlib_cleanup.h"
+
+class IpUtilsTestSuite : public ::testing::Test {
+public:
+    IpUtilsTestSuite() {
+        celix_err_resetErrors();
+    }
+    ~IpUtilsTestSuite() override {
+        celix_err_printErrors(stderr, nullptr, nullptr);
+    }
+};
+
+TEST_F(IpUtilsTestSuite, ipToUnsignedIntTest) {
+    const char *ip = "192.168.1.64";
+    uint32_t expected = 3232235840;
+    uint32_t actual = celix_utils_convertIpToUint(ip, nullptr);
+    EXPECT_EQ(expected, actual);
+
+    bool converted;
+    actual = celix_utils_convertIpToUint(ip, &converted);
+    EXPECT_TRUE(converted);
+    EXPECT_EQ(expected, actual);
+
+    EXPECT_EQ(0, celix_utils_convertIpToUint("a.b.c.d", &converted));
+    EXPECT_FALSE(converted);
+    EXPECT_EQ(1, celix_err_getErrorCount());
+
+    EXPECT_EQ(0, celix_utils_convertIpToUint("273.168.1.64", &converted));
+    EXPECT_FALSE(converted);
+    EXPECT_EQ(2, celix_err_getErrorCount());
+
+    EXPECT_EQ(0, celix_utils_convertIpToUint("10.1.1.1.1", &converted));
+    EXPECT_FALSE(converted);
+    EXPECT_EQ(3, celix_err_getErrorCount());
+}
+
+TEST_F(IpUtilsTestSuite, unsignedIntToIpTest) {
+    uint32_t ipAsUint = 3232235840;
+    const char *expected = "192.168.1.64";
+    char* ip = celix_utils_convertUintToIp(ipAsUint);
+    EXPECT_STREQ(expected, ip);
+    free(ip);
+
+    ip = celix_utils_convertUintToIp(0);
+    EXPECT_STREQ("0.0.0.0", ip);
+    free(ip);
+
+    ip = celix_utils_convertUintToIp(UINT32_MAX);
+    EXPECT_STREQ("255.255.255.255", ip);
+    free(ip);
+}
+
+TEST_F(IpUtilsTestSuite, prefixToBitmaskTest) {
+    uint32_t bitmask = celix_utils_ipPrefixLengthToBitmask(27);
+    EXPECT_EQ(4294967264, bitmask);
+
+    bitmask = celix_utils_ipPrefixLengthToBitmask(0);
+    EXPECT_EQ(0, bitmask);
+
+    bitmask = celix_utils_ipPrefixLengthToBitmask(32);
+    EXPECT_EQ(UINT32_MAX, bitmask);
+
+    bitmask = celix_utils_ipPrefixLengthToBitmask(-1);
+    EXPECT_EQ(0, bitmask);
+
+    bitmask = celix_utils_ipPrefixLengthToBitmask(33);
+    EXPECT_EQ(0, bitmask);
+}
+
+TEST_F(IpUtilsTestSuite, NetmaskToPrefixTest) {
+    int prefix = celix_utils_ipNetmaskToPrefixLength("255.255.255.0");
+    EXPECT_EQ(24, prefix);
+
+    prefix = celix_utils_ipNetmaskToPrefixLength("0.0.0.0");
+    EXPECT_EQ(0, prefix);
+
+    prefix = celix_utils_ipNetmaskToPrefixLength("255.255.255.255");
+    EXPECT_EQ(32, prefix);
+
+    prefix = celix_utils_ipNetmaskToPrefixLength("255.0.0.0");
+    EXPECT_EQ(8, prefix);
+
+    EXPECT_EQ(-1, celix_utils_ipNetmaskToPrefixLength("a.b.c.d"));
+    EXPECT_EQ(1, celix_err_getErrorCount());
+}
+
+TEST_F(IpUtilsTestSuite, FindIpInSubnetWithInvalidInputTest) {
+    EXPECT_EQ(nullptr, celix_utils_findIpInSubnet("198.168.0.1")); // missing 
subnet
+    EXPECT_EQ(1, celix_err_getErrorCount());
+
+    EXPECT_EQ(nullptr, celix_utils_findIpInSubnet("198.168.0.1/abc")); // 
invalid subnet
+    EXPECT_EQ(2, celix_err_getErrorCount());
+
+    EXPECT_EQ(nullptr, celix_utils_findIpInSubnet("198.168.0.1/40")); // out 
of range subnet
+    EXPECT_EQ(3, celix_err_getErrorCount());
+
+    EXPECT_EQ(nullptr, celix_utils_findIpInSubnet("198.168.0.1/-1")); // out 
of range subnet
+    EXPECT_EQ(4, celix_err_getErrorCount());
+
+    EXPECT_EQ(nullptr, celix_utils_findIpInSubnet("a.b.c.d/8")); // invalid ip
+    EXPECT_EQ(5, celix_err_getErrorCount());
+}
diff --git a/libs/utils/include/celix_ip_utils.h 
b/libs/utils/include/celix_ip_utils.h
new file mode 100644
index 00000000..3e487476
--- /dev/null
+++ b/libs/utils/include/celix_ip_utils.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+/**
+ * @file celix_ip_utils.h
+ * @brief Utility functions for IP address manipulation.
+ *
+ * This header file contains declarations of utility functions for
+ * converting IP addresses and manipulating IP address data.
+ */
+
+#ifndef CELIX_IP_UTILS_H
+#define CELIX_IP_UTILS_H
+
+#include "celix_utils_export.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Converts an IP address in string format to an unsigned integer.
+ *
+ * This function takes an IP address as a string and converts it to
+ * its corresponding unsigned integer representation.
+ *
+ * @param[in] ip The IP address in string format (e.g., "192.168.0.1").
+ * @param[out] converted A boolean indicating whether the conversion was 
successful. Can be NULL.
+ * @return The IP address as an uint32_t. Returns 0 if the conversion fails.
+ */
+uint32_t celix_utils_convertIpToUint(const char* ip, bool* converted);
+
+/**
+ * @brief Converts an unsigned integer to its corresponding IP address in 
string format.
+ *
+ * This function converts an unsigned integer representing an IP address
+ * to a string format.
+ *
+ * @param[in] ip The IP address as an uint32_t.
+ * @return The IP address in string format (e.g., "192.168.0.1").
+ */
+char* celix_utils_convertUintToIp(uint32_t ip);
+
+/**
+ * @brief Converts a subnet prefix length to a bitmask.
+ *
+ * This function takes a subnet prefix length and converts it into
+ * a bitmask in unsigned integer format.
+ *
+ * @param[in] prefix The subnet prefix length.
+ * @return The corresponding bitmask as an unsigned integer. Returns 0 if the 
prefix is invalid or 0.
+ */
+uint32_t celix_utils_ipPrefixLengthToBitmask(int prefix);
+
+/**
+ * @brief Converts a netmask string to a prefix length.
+ *
+ * This function converts a netmask in string format (e.g., "255.255.255.0")
+ * to its corresponding prefix length.
+ *
+ * @param[in] netmask The netmask in string format.
+ * @return The prefix length or -1 if the conversion fails.
+ */
+int celix_utils_ipNetmaskToPrefixLength(const char* netmask);
+
+/**
+ * @brief Finds an IP address within a given subnet on the host's network 
interfaces.
+ *
+ * This function searches through the network interfaces of the host to find
+ * an IP address that falls within the specified subnet. It analyzes the IP 
addresses
+ * assigned to each network interface and checks if any of them match the 
given subnet criteria.
+ * The function returns the first IP address that is within the specified 
subnet range.
+ *
+ * The input parameter is expected to be in CIDR notation.
+ * CIDR notation is a concise format for specifying IP addresses ranges using 
IP address and subnet prefix length.
+ * It takes the form of 'IP_ADDRESS/PREFIX_LENGTH' (e.g., "192.168.0.1/24").
+ *
+ * @param[in] subnetCidrNotation The IP address with subnet prefix.
+ * @return A string containing an IP address within the specified subnet that 
is also
+ * assigned to a network interface on the host, or NULL if no matching IP 
address is found. The caller is owner of the
+ * returned string.
+ */
+char* celix_utils_findIpInSubnet(const char* subnetCidrNotation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELIX_IP_UTILS_H */
diff --git a/libs/utils/include_deprecated/ip_utils.h 
b/libs/utils/include_deprecated/ip_utils.h
deleted file mode 100644
index 75adcb59..00000000
--- a/libs/utils/include_deprecated/ip_utils.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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:[email protected]";>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 "celix_utils_export.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-CELIX_UTILS_DEPRECATED_EXPORT unsigned int ipUtils_ipToUnsignedInt(char *ip);
-
-CELIX_UTILS_DEPRECATED_EXPORT char *ipUtils_unsignedIntToIp(unsigned int ip);
-
-CELIX_UTILS_DEPRECATED_EXPORT unsigned int ipUtils_prefixToBitmask(unsigned 
int prefix);
-
-CELIX_UTILS_DEPRECATED_EXPORT int ipUtils_netmaskToPrefix(const char *netmask);
-
-CELIX_UTILS_DEPRECATED_EXPORT char *ipUtils_findIpBySubnet(const char 
*ipWithPrefix);
-
-#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
deleted file mode 100644
index 7b576b3a..00000000
--- a/libs/utils/private/test/ip_utils_test.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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:[email protected]";>Apache Celix Project 
Team</a>
- *  \copyright  Apache License, Version 2.0
- */
-
-#include <errno.h>
-#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) {
-    MemoryLeakWarningPlugin::turnOffNewDeleteOverloads();
-    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);
-
-    actual = ipUtils_netmaskToPrefix("a.b.c.d");
-    LONGS_EQUAL(-1, actual);
-}
diff --git a/libs/utils/src/ip_utils.c b/libs/utils/src/ip_utils.c
index d168fa36..833bd203 100644
--- a/libs/utils/src/ip_utils.c
+++ b/libs/utils/src/ip_utils.c
@@ -16,110 +16,151 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-/**
- * ip_utils.c
- *
- *  \date       Jun 24, 2019
- *  \author     <a href="mailto:[email protected]";>Apache Celix Project 
Team</a>
- *  \copyright  Apache License, Version 2.0
- */
 
-#include "ip_utils.h"
+#include "celix_ip_utils.h"
+
+#include "celix_err.h"
+#include "celix_stdlib_cleanup.h"
 #include "celix_utils.h"
+#include "celix_convert_utils.h"
 
+#include <arpa/inet.h>
 #include <errno.h>
+#include <ifaddrs.h>
+#include <limits.h>
+#include <math.h>
+#include <netdb.h>
+#include <stdbool.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;
+uint32_t celix_utils_convertIpToUint(const char* ip, bool* converted) {
+    if (converted) {
+        *converted = false;
+    }
+
+    // copy for strtok_r
+    celix_autofree char* input = strdup(ip);
+    if (!input) {
+        celix_err_push("Failed to duplicate input string for IP conversion");
+        return 0;
+    }
 
-    char *partOfIp = NULL, *savePtr = NULL;
-    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);
+    uint32_t ipAsUint = 0;
+    char* partOfIp = NULL;
+    char* savePtr = NULL;
+    int count = 0;
+    while ((partOfIp = strtok_r(partOfIp == NULL ? input : NULL, ".\0", 
&savePtr)) != NULL) {
+        if (count > 3) {
+            celix_err_pushf("Failed to convert IP address %s to unsigned int, 
to many parts", ip);
+            return 0;
+        }
+        bool longConverted = false;
+        long partAsLong = celix_utils_convertStringToLong(partOfIp, ULONG_MAX, 
&longConverted);
+        if (!longConverted) {
+            celix_err_pushf("Failed to convert IP address %s to unsigned int, 
part `%s` is not a number", ip, partOfIp);
+            return 0;
+        } else if (partAsLong > 255 || partAsLong < 0) {
+            celix_err_pushf("Failed to convert IP address %s to unsigned int, 
part `%s` is out of range", ip, partOfIp);
+            return 0;
+        }
+        ipAsUint += (uint32_t)(partAsLong * powl(256, 3 - count++));
+    }
 
+    if (converted) {
+        *converted = true;
+    }
     return ipAsUint;
 }
 
-char *ipUtils_unsignedIntToIp(unsigned int ip) {
-    char *ipStr = calloc(16, sizeof(char));
+char* celix_utils_convertUintToIp(uint32_t ip) {
+    char* ipStr = calloc(16, sizeof(char));
+    if (!ipStr) {
+        celix_err_push("Failed to allocate memory for IP address string");
+        return NULL;
+    }
 
-    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);
+    int64_t ipPart1 = ip / (int64_t)pow(256, 3);
+    ip -= ipPart1 * (int64_t)pow(256, 3);
+    int64_t ipPart2 = ip / (int64_t)pow(256, 2);
+    ip -= ipPart2 * (int64_t)pow(256, 2);
+    int64_t ipPart3 = ip / (int64_t)pow(256, 1);
+    ip -= ipPart3 * (int64_t)pow(256, 1);
+    int64_t ipPart4 = ip / (int64_t)pow(256, 0);
 
-    snprintf(ipStr, 16, "%d.%d.%d.%d", ipPart1, ipPart2, ipPart3, ipPart4);
+    snprintf(ipStr, 16, "%li.%li.%li.%li", ipPart1, ipPart2, ipPart3, ipPart4);
 
     return ipStr;
 }
 
-unsigned int ipUtils_prefixToBitmask(unsigned int prefix) {
-    return (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF;
+uint32_t celix_utils_ipPrefixLengthToBitmask(int prefix) {
+    if (prefix > 32 || prefix <= 0) {
+        return 0;
+    }
+    return (uint32_t )((0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF);
 }
 
-int ipUtils_netmaskToPrefix(const char *netmask) {
+int celix_utils_ipNetmaskToPrefixLength(const char* netmask) {
     // Convert netmask to in_addr object
     struct in_addr in;
     int ret = inet_pton(AF_INET, netmask, &in);
     if (ret != 1) {
+        celix_err_pushf("Failed to convert netmask %s to in_addr object", 
netmask);
         return -1;
     }
 
     // Now convert the mask to a prefix
     int prefix = 0;
-    bool processed_one = false;
-    unsigned int i = ntohl(in.s_addr);
+    uint32_t 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  IP with prefix, e.g. 192.168.1.0/24
- * @return ip           In case a matching interface could be found, an 
allocated string containing the IP of the
- *                      interface will be returned, 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 
returned.
- */
-char *ipUtils_findIpBySubnet(const char *ipWithPrefix) {
-    char *ip = NULL;
+char* celix_utils_findIpInSubnet(const char* subnetCidrNotation) {
+    char* ip = NULL;
 
-    char *input = celix_utils_strdup(ipWithPrefix); // Make a copy as 
otherwise strtok_r manipulates the input string
-    if (input == NULL) {
-        goto strdup_failed;
+    //create copy for strtok_r
+    celix_autofree char* input = celix_utils_strdup(subnetCidrNotation);
+    if (!input) {
+        celix_err_push("Failed to duplicate input string for subnet search");
+        return NULL;
     }
 
-    char *savePtr;
-    char *inputIp = strtok_r(input, "/", &savePtr);
-    char *inputPrefixStr = strtok_r(NULL, "\0", &savePtr);
-    unsigned int inputPrefix = (unsigned int) strtoul(inputPrefixStr, NULL, 
10);
+    char* savePtr;
+    char* inputIp = strtok_r(input, "/", &savePtr);
+    char* inputPrefixStr = strtok_r(NULL, "\0", &savePtr);
 
-    unsigned int ipAsUint = ipUtils_ipToUnsignedInt(inputIp);
-    unsigned int bitmask = ipUtils_prefixToBitmask(inputPrefix);
+    if (!inputPrefixStr) {
+        celix_err_pushf("Failed to parse IP address with prefix %s. Missing a 
'/'", subnetCidrNotation);
+        return NULL;
+    }
+
+    bool convertedLong = false;
+    int inputPrefix = (int)celix_utils_convertStringToLong(inputPrefixStr, 
INT_MAX, &convertedLong);
+    if (!convertedLong) {
+        celix_err_pushf("Failed to parse prefix in IP address with prefix %s", 
subnetCidrNotation);
+        return NULL;
+    } else if (inputPrefix > 32 || inputPrefix < 0) {
+        celix_err_pushf(
+            "Failed to parse IP address with prefix %s. Prefix %s is out of 
range", subnetCidrNotation, inputPrefixStr);
+        return NULL;
+    }
+
+    bool converted;
+    uint32_t ipAsUint = celix_utils_convertIpToUint(inputIp, &converted);
+    if (!converted) {
+        return NULL;
+    }
+    uint32_t bitmask = celix_utils_ipPrefixLengthToBitmask(inputPrefix);
 
     unsigned int ipRangeStart = ipAsUint & bitmask;
     unsigned int ipRangeStop = ipAsUint | ~bitmask;
@@ -127,44 +168,47 @@ char *ipUtils_findIpBySubnet(const char *ipWithPrefix) {
     // Requested IP range is known now, now loop through network interfaces
     struct ifaddrs *ifap, *ifa;
 
-    if(getifaddrs (&ifap) == -1) {
-        goto getifaddrs_failed;
+    if (getifaddrs(&ifap) == -1) {
+        celix_err_push("Failed to get network interfaces");
+        return NULL;
     }
+
     for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-        if (ifa->ifa_addr == NULL)
+        if (ifa->ifa_addr == NULL) {
             continue;
+        }
 
-        if (ifa->ifa_addr->sa_family != AF_INET)
+        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);
+        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));
+            celix_err_pushf("Failed to get IP address for interface %s: %s", 
ifa->ifa_name, gai_strerror(rv));
             continue;
         }
 
         // Retrieve netmask
-        struct sockaddr_in *sa = (struct sockaddr_in *) ifa->ifa_netmask;
-        char *if_netmask = inet_ntoa(sa->sin_addr);
+        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);
+        uint32_t ifIpAsUint = celix_utils_convertIpToUint(if_addr, NULL);
+        int ifPrefix = celix_utils_ipNetmaskToPrefixLength(if_netmask);
         if (ifPrefix == -1) {
             break;
         }
 
         if (ifIpAsUint >= ipRangeStart && ifIpAsUint <= ipRangeStop && 
inputPrefix >= ifPrefix) {
-            ip = strndup(if_addr, 1024);
+            ip = celix_utils_strdup(if_addr);
+            if (!ip) {
+                celix_err_push("Failed to duplicate IP address");
+                break;
+            }
             break;
         }
     }
-    freeifaddrs(ifap);
-getifaddrs_failed:
-    free(input);
-strdup_failed:
     return ip;
 }

Reply via email to