Commit 0a0a289a authored by Michael Tremer's avatar Michael Tremer

strings: Statically allocate all address/network strings

This helps us to write less code and spend less time allocating and
freeing memory.
Signed-off-by: default avatarMichael Tremer <michael.tremer@ipfire.org>
parent 1fd09d0b
......@@ -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 \
......
/*
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);
}
......@@ -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;
}
......
......@@ -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;
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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) {
......
......@@ -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
......
......@@ -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");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment