]> git.ipfire.org Git - people/ms/libloc.git/commitdiff
strings: Statically allocate all address/network strings
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 7 Mar 2022 13:21:29 +0000 (13:21 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 7 Mar 2022 13:21:29 +0000 (13:21 +0000)
This helps us to write less code and spend less time allocating and
freeing memory.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/address.c [new file with mode: 0644]
src/database.c
src/libloc/address.h
src/libloc/network.h
src/network-list.c
src/network.c
src/python/network.c
src/test-database.c
src/test-network.c

index e5197a56cacbe8d37ded38cb597795fdf51198fd..fac9e0141db3bf49aa2c69b6b8cc0d4336e16fc5 100644 (file)
@@ -111,6 +111,7 @@ lib_LTLIBRARIES = \
 
 src_libloc_la_SOURCES = \
        src/libloc.c \
+       src/address.c \
        src/as.c \
        src/as-list.c \
        src/country.c \
diff --git a/src/address.c b/src/address.c
new file mode 100644 (file)
index 0000000..a83fd6e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+       libloc - A library to determine the location of someone on the Internet
+
+       Copyright (C) 2022 IPFire Development Team <info@ipfire.org>
+
+       This library is free software; you can redistribute it and/or
+       modify it under the terms of the GNU Lesser General Public
+       License as published by the Free Software Foundation; either
+       version 2.1 of the License, or (at your option) any later version.
+
+       This library is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+       Lesser General Public License for more details.
+*/
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <stddef.h>
+
+#include <libloc/address.h>
+
+#define LOC_ADDRESS_BUFFERS                            6
+#define LOC_ADDRESS_BUFFER_LENGTH              INET6_ADDRSTRLEN
+
+static char __loc_address_buffers[LOC_ADDRESS_BUFFER_LENGTH + 1][LOC_ADDRESS_BUFFERS];
+static int  __loc_address_buffer_idx = 0;
+
+static const char* __loc_address6_str(const struct in6_addr* address, char* buffer, size_t length) {
+       return inet_ntop(AF_INET6, address, buffer, length);
+}
+
+static const char* __loc_address4_str(const struct in6_addr* address, char* buffer, size_t length) {
+       struct in_addr address4 = {
+               .s_addr = address->s6_addr32[3],
+       };
+
+       return inet_ntop(AF_INET, &address4, buffer, length);
+}
+
+const char* loc_address_str(const struct in6_addr* address) {
+       if (!address)
+               return NULL;
+
+       // Select buffer
+       char* buffer = __loc_address_buffers[__loc_address_buffer_idx++];
+
+       // Prevent index from overflow
+       __loc_address_buffer_idx %= LOC_ADDRESS_BUFFERS;
+
+       if (IN6_IS_ADDR_V4MAPPED(address))
+               return __loc_address4_str(address, buffer, LOC_ADDRESS_BUFFER_LENGTH);
+       else
+               return __loc_address6_str(address, buffer, LOC_ADDRESS_BUFFER_LENGTH);
+}
index 5951bcb347b5aa54c96e8510d19d9254c06ac5cb..dac7ebdecff9c6d0d477bdec6a5ea09b171c679b 100644 (file)
@@ -758,13 +758,8 @@ static int loc_database_fetch_network(struct loc_database* db, struct loc_networ
                        return -1;
        }
 
-#ifdef ENABLE_DEBUG
-       if (r == 0) {
-               char* string = loc_network_str(*network);
-               DEBUG(db->ctx, "Got network %s\n", string);
-               free(string);
-       }
-#endif
+       if (r == 0)
+               DEBUG(db->ctx, "Got network %s\n", loc_network_str(*network));
 
        return r;
 }
index 692ed12281984a4ed423dbea7d58c9d05cddd838..abb6fd0ac72b5e1ceb9eb829de565c89ebc767b9 100644 (file)
@@ -26,6 +26,8 @@
        All of these functions are private and for internal use only
 */
 
+const char* loc_address_str(const struct in6_addr* address);
+
 static inline int loc_address_family(const struct in6_addr* address) {
        if (IN6_IS_ADDR_V4MAPPED(address))
                return AF_INET;
index 8053ebe699f223b88f8fcfa01dd08cee43c34832..024a0f18ecd4a530bb1517b3ed50a66823af9ff6 100644 (file)
@@ -37,14 +37,14 @@ int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_network** networ
                const char* address_string);
 struct loc_network* loc_network_ref(struct loc_network* network);
 struct loc_network* loc_network_unref(struct loc_network* network);
-char* loc_network_str(struct loc_network* network);
+const char* loc_network_str(struct loc_network* network);
 int loc_network_address_family(struct loc_network* network);
 unsigned int loc_network_prefix(struct loc_network* network);
 
 const struct in6_addr* loc_network_get_first_address(struct loc_network* network);
-char* loc_network_format_first_address(struct loc_network* network);
+const char* loc_network_format_first_address(struct loc_network* network);
 const struct in6_addr* loc_network_get_last_address(struct loc_network* network);
-char* loc_network_format_last_address(struct loc_network* network);
+const char* loc_network_format_last_address(struct loc_network* network);
 int loc_network_matches_address(struct loc_network* network, const struct in6_addr* address);
 
 const char* loc_network_get_country_code(struct loc_network* network);
index 095d82f8988dbe98e43f2430af3b03d4daa364ab..4f4f14685a3810ff624dd116e275f6a2e09514ba 100644 (file)
@@ -113,15 +113,12 @@ LOC_EXPORT void loc_network_list_clear(struct loc_network_list* list) {
 
 LOC_EXPORT void loc_network_list_dump(struct loc_network_list* list) {
        struct loc_network* network;
-       char* s;
 
        for (unsigned int i = 0; i < list->size; i++) {
                network = list->elements[i];
 
-               s = loc_network_str(network);
-
-               INFO(list->ctx, "%4d: %s\n", i, s);
-               free(s);
+               INFO(list->ctx, "%4d: %s\n",
+                       i, loc_network_str(network));
        }
 }
 
@@ -308,6 +305,8 @@ int loc_network_list_summarize(struct loc_ctx* ctx,
                return 1;
        }
 
+       DEBUG(ctx, "Summarizing %s - %s\n", loc_address_str(first), loc_address_str(last));
+
        const int family1 = loc_address_family(first);
        const int family2 = loc_address_family(last);
 
@@ -357,16 +356,17 @@ int loc_network_list_summarize(struct loc_ctx* ctx,
                // Select the smaller one
                int bits = (bits1 > bits2) ? bits2 : bits1;
 
+               printf("prefix = %d, bits1 = %d, bits2 = %d\n", family_bit_length, bits1, bits2);
+
                // Create a network
                r = loc_network_new(ctx, &network, &start, family_bit_length - bits);
                if (r)
                        return r;
 
 #ifdef ENABLE_DEBUG
-               char* n = loc_network_str(network);
+               const char* n = loc_network_str(network);
                if (n) {
                        DEBUG(ctx, "Found network %s\n", n);
-                       free(n);
                }
 #endif
 
index 445f1efafd623b5d996982fd98d444309f254e5c..219cb2be6147410084353be133c31321dafbcee0 100644 (file)
@@ -45,6 +45,8 @@ struct loc_network {
        char country_code[3];
        uint32_t asn;
        enum loc_network_flags flags;
+
+       char string[INET6_ADDRSTRLEN + 4];
 };
 
 LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
@@ -158,61 +160,27 @@ LOC_EXPORT struct loc_network* loc_network_unref(struct loc_network* network) {
        return NULL;
 }
 
-static int format_ipv6_address(const struct in6_addr* address, char* string, size_t length) {
-       const char* ret = inet_ntop(AF_INET6, address, string, length);
-       if (!ret)
-               return -1;
-
-       return 0;
-}
-
-static int format_ipv4_address(const struct in6_addr* address, char* string, size_t length) {
-       struct in_addr ipv4_address;
-       ipv4_address.s_addr = address->s6_addr32[3];
-
-       const char* ret = inet_ntop(AF_INET, &ipv4_address, string, length);
-       if (!ret)
-               return -1;
-
-       return 0;
-}
-
-LOC_EXPORT char* loc_network_str(struct loc_network* network) {
-       int r;
-       const size_t length = INET6_ADDRSTRLEN + 4;
-
-       char* string = malloc(length);
-       if (!string)
-               return NULL;
-
-       unsigned int prefix = network->prefix;
-
-       switch (network->family) {
-               case AF_INET6:
-                       r = format_ipv6_address(&network->first_address, string, length);
-                       break;
-
-               case AF_INET:
-                       r = format_ipv4_address(&network->first_address, string, length);
-                       prefix -= 96;
-                       break;
-
-               default:
-                       r = -1;
-                       break;
-       }
+LOC_EXPORT const char* loc_network_str(struct loc_network* network) {
+       if (!*network->string) {
+               // Format the address
+               const char* address = loc_address_str(&network->first_address);
+               if (!address)
+                       return NULL;
 
-       if (r) {
-               ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
-               free(string);
+               // Fetch the prefix
+               unsigned int prefix = loc_network_prefix(network);
 
-               return NULL;
+               // Format the string
+               int r = snprintf(network->string, sizeof(network->string) - 1,
+                       "%s/%u", address, prefix);
+               if (r < 0) {
+                       ERROR(network->ctx, "Could not format network string: %m\n");
+                       *network->string = '\0';
+                       return NULL;
+               }
        }
 
-       // Append prefix
-       sprintf(string + strlen(string), "/%u", prefix);
-
-       return string;
+       return network->string;
 }
 
 LOC_EXPORT int loc_network_address_family(struct loc_network* network) {
@@ -231,53 +199,20 @@ LOC_EXPORT unsigned int loc_network_prefix(struct loc_network* network) {
        return 0;
 }
 
-static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) {
-       const size_t length = INET6_ADDRSTRLEN;
-
-       char* string = malloc(length);
-       if (!string)
-               return NULL;
-
-       int r = 0;
-
-       switch (network->family) {
-               case AF_INET6:
-                       r = format_ipv6_address(address, string, length);
-                       break;
-
-               case AF_INET:
-                       r = format_ipv4_address(address, string, length);
-                       break;
-
-               default:
-                       r = -1;
-                       break;
-       }
-
-       if (r) {
-               ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno));
-               free(string);
-
-               return NULL;
-       }
-
-       return string;
-}
-
 LOC_EXPORT const struct in6_addr* loc_network_get_first_address(struct loc_network* network) {
        return &network->first_address;
 }
 
-LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) {
-       return loc_network_format_address(network, &network->first_address);
+LOC_EXPORT const char* loc_network_format_first_address(struct loc_network* network) {
+       return loc_address_str(&network->first_address);
 }
 
 LOC_EXPORT const struct in6_addr* loc_network_get_last_address(struct loc_network* network) {
        return &network->last_address;
 }
 
-LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) {
-       return loc_network_format_address(network, &network->last_address);
+LOC_EXPORT const char* loc_network_format_last_address(struct loc_network* network) {
+       return loc_address_str(&network->last_address);
 }
 
 LOC_EXPORT int loc_network_matches_address(struct loc_network* network, const struct in6_addr* address) {
@@ -528,15 +463,8 @@ LOC_EXPORT struct loc_network_list* loc_network_exclude(
                struct loc_network* self, struct loc_network* other) {
        struct loc_network_list* list;
 
-#ifdef ENABLE_DEBUG
-       char* n1 = loc_network_str(self);
-       char* n2 = loc_network_str(other);
-
-       DEBUG(self->ctx, "Returning %s excluding %s...\n", n1, n2);
-
-       free(n1);
-       free(n2);
-#endif
+       DEBUG(self->ctx, "Returning %s excluding %s...\n",
+               loc_network_str(self), loc_network_str(other));
 
        // Create a new list with the result
        int r = loc_network_list_new(self->ctx, &list);
@@ -845,12 +773,11 @@ struct loc_network_tree* loc_network_tree_unref(struct loc_network_tree* tree) {
 static int __loc_network_tree_dump(struct loc_network* network, void* data) {
        DEBUG(network->ctx, "Dumping network at %p\n", network);
 
-       char* s = loc_network_str(network);
+       const char* s = loc_network_str(network);
        if (!s)
                return 1;
 
        INFO(network->ctx, "%s\n", s);
-       free(s);
 
        return 0;
 }
index 9dc6ab6e6ede05657220a32096f7dd6957763204..474b6de279969cbf875daf6157d12b0253bd16e8 100644 (file)
@@ -83,21 +83,15 @@ static int Network_init(NetworkObject* self, PyObject* args, PyObject* kwargs) {
 }
 
 static PyObject* Network_repr(NetworkObject* self) {
-       char* network = loc_network_str(self->network);
+       const char* network = loc_network_str(self->network);
 
-       PyObject* obj = PyUnicode_FromFormat("<location.Network %s>", network);
-       free(network);
-
-       return obj;
+       return PyUnicode_FromFormat("<location.Network %s>", network);
 }
 
 static PyObject* Network_str(NetworkObject* self) {
-       char* network = loc_network_str(self->network);
+       const char* network = loc_network_str(self->network);
 
-       PyObject* obj = PyUnicode_FromString(network);
-       free(network);
-
-       return obj;
+       return PyUnicode_FromString(network);
 }
 
 static PyObject* Network_get_country_code(NetworkObject* self) {
@@ -216,12 +210,9 @@ static PyObject* Network_get_family(NetworkObject* self) {
 }
 
 static PyObject* Network_get_first_address(NetworkObject* self) {
-       char* address = loc_network_format_first_address(self->network);
+       const char* address = loc_network_format_first_address(self->network);
 
-       PyObject* obj = PyUnicode_FromString(address);
-       free(address);
-
-       return obj;
+       return PyUnicode_FromString(address);
 }
 
 static PyObject* PyBytes_FromAddress(const struct in6_addr* address6) {
@@ -245,12 +236,9 @@ static PyObject* Network_get__first_address(NetworkObject* self) {
 }
 
 static PyObject* Network_get_last_address(NetworkObject* self) {
-       char* address = loc_network_format_last_address(self->network);
+       const char* address = loc_network_format_last_address(self->network);
 
-       PyObject* obj = PyUnicode_FromString(address);
-       free(address);
-
-       return obj;
+       return PyUnicode_FromString(address);
 }
 
 static PyObject* Network_get__last_address(NetworkObject* self) {
index 92a415fbfe73a172f4af2002714a6f4b27f47ad8..7037f6abe49a53fef607672119825332dafaf500 100644 (file)
@@ -215,9 +215,8 @@ int main(int argc, char** argv) {
                if (!network)
                        break;
 
-               char* s = loc_network_str(network);
+               const char* s = loc_network_str(network);
                printf("Got network: %s\n", s);
-               free(s);
        }
 
        // Free the enumerator
index 0d00a6e6287ff1574d97352452b094b1fa8c4c04..3230c7d6084409bd9033a491e2a5073d336b3b8d 100644 (file)
@@ -80,7 +80,7 @@ int main(int argc, char** argv) {
 #endif
 
        // Check if the first and last addresses are correct
-       char* string = loc_network_format_first_address(network1);
+       const char* string = loc_network_format_first_address(network1);
        if (!string) {
                fprintf(stderr, "Did get NULL instead of a string for the first address\n");
                exit(EXIT_FAILURE);
@@ -176,13 +176,11 @@ int main(int argc, char** argv) {
                exit(EXIT_FAILURE);
        }
 
-       char* s = loc_network_str(subnet1);
+       const char* s = loc_network_str(subnet1);
        printf("Received subnet1 = %s\n", s);
-       free(s);
 
        s = loc_network_str(subnet2);
        printf("Received subnet2 = %s\n", s);
-       free(s);
 
        if (!loc_network_is_subnet(network1, subnet1)) {
                fprintf(stderr, "Subnet1 is not a subnet\n");