various: split functions to IPv4 and IPv6 versions

The code selection will be set with function pointer, which avoids
numerous IP version checks.  As a result with some inputs the analysis
runs quicker.  Most users will not notice much of difference.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Sami Kerola 2013-09-21 11:38:24 +01:00
parent 97c6f0292f
commit 8da98bbc89
5 changed files with 215 additions and 89 deletions

View file

@ -55,36 +55,90 @@
#include <unistd.h>
#include <limits.h>
/*! \brief Set function pointers depending on IP version.
* \param ip IP version.
*/
void set_ipv_functions(int version)
{
switch (version) {
case VERSION_4:
config.dhcp_version = version;
add_lease = add_lease_v4;
copy_ipaddr = copy_ipaddr_v4;
find_lease = find_lease_v4;
get_range_size = get_range_size_v4;
ipcomp = ipcomp_v4;
ntop_ipaddr = ntop_ipaddr_v4;
parse_ipaddr = parse_ipaddr_v4;
xstrstr = xstrstr_v4;
break;
case VERSION_6:
config.dhcp_version = version;
add_lease = add_lease_v6;
copy_ipaddr = copy_ipaddr_v6;
find_lease = find_lease_v6;
get_range_size = get_range_size_v6;
ipcomp = ipcomp_v6;
ntop_ipaddr = ntop_ipaddr_v6;
parse_ipaddr = parse_ipaddr_v6;
xstrstr = xstrstr_v6;
break;
case VERSION_UNKNOWN:
config.dhcp_version = version;
add_lease = add_lease_init;
copy_ipaddr = copy_ipaddr_init;
find_lease = find_lease_init;
get_range_size = get_range_size_init;
ipcomp = ipcomp_init;
ntop_ipaddr = ntop_ipaddr_init;
parse_ipaddr = parse_ipaddr_init;
xstrstr = xstrstr_init;
break;
default:
abort();
}
return;
}
/*! \brief Convert text string IP address from either IPv4 or IPv6 to an integer.
* \param src An IP string in either format.
* \param dst An union which will hold conversion result.
* \return Was parsing successful.
*/
int parse_ipaddr(const char *restrict src, union ipaddr_t *restrict dst)
int parse_ipaddr_init(const char *restrict src, union ipaddr_t *restrict dst)
{
struct in_addr addr;
struct in6_addr addr6;
if (inet_aton(src, &addr) == 1) {
set_ipv_functions(VERSION_4);
} else if (inet_pton(AF_INET6, src, &addr6) == 1) {
set_ipv_functions(VERSION_6);
} else {
return 0;
}
return parse_ipaddr(src, dst);
}
int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst)
{
int rv;
if (config.dhcp_version == VERSION_UNKNOWN) {
struct in_addr addr;
struct in6_addr addr6;
if (inet_aton(src, &addr) == 1) {
config.dhcp_version = VERSION_4;
xstrstr = xstrstr_v4;
} else if (inet_pton(AF_INET6, src, &addr6) == 1) {
config.dhcp_version = VERSION_6;
xstrstr = xstrstr_v6;
} else {
return 0;
}
}
if (config.dhcp_version == VERSION_6) {
struct in6_addr addr;
rv = inet_pton(AF_INET6, src, &addr);
memcpy(&dst->v6, addr.s6_addr, sizeof(addr.s6_addr));
} else {
struct in_addr addr;
rv = inet_aton(src, &addr);
dst->v4 = ntohl(addr.s_addr);
}
struct in_addr addr;
rv = inet_aton(src, &addr);
dst->v4 = ntohl(addr.s_addr);
return rv == 1;
}
int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst)
{
int rv;
struct in6_addr addr;
rv = inet_pton(AF_INET6, src, &addr);
memcpy(&dst->v6, addr.s6_addr, sizeof(addr.s6_addr));
return rv == 1;
}
@ -92,14 +146,21 @@ int parse_ipaddr(const char *restrict src, union ipaddr_t *restrict dst)
*
* \param dst Destination for a binary IP address.
* \param src Sourse of an IP address. */
void copy_ipaddr(union ipaddr_t *restrict dst,
void copy_ipaddr_init(union ipaddr_t *restrict dst __attribute__((unused)),
const union ipaddr_t *restrict src __attribute__((unused)))
{
}
void copy_ipaddr_v4(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src)
{
dst->v4 = src->v4;
}
void copy_ipaddr_v6(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src)
{
if (config.dhcp_version == VERSION_6) {
memcpy(&dst->v6, &src->v6, sizeof(src->v6));
} else {
dst->v4 = src->v4;
}
memcpy(&dst->v6, &src->v6, sizeof(src->v6));
}
/*! \brief Convert an address to string. This function will convert the
@ -110,19 +171,27 @@ void copy_ipaddr(union ipaddr_t *restrict dst,
* \param ip Binary IP address.
* \return Printable address.
*/
const char *ntop_ipaddr(const union ipaddr_t *ip)
const char *ntop_ipaddr_init(const union ipaddr_t *ip __attribute__((unused)))
{
static char buffer = '\0';
return &buffer;
}
const char *ntop_ipaddr_v4(const union ipaddr_t *ip)
{
static char buffer[sizeof("255.255.255.255")];
struct in_addr addr;
addr.s_addr = htonl(ip->v4);
return inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));
}
const char *ntop_ipaddr_v6(const union ipaddr_t *ip)
{
static char
buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
if (config.dhcp_version == VERSION_6) {
struct in6_addr addr;
memcpy(addr.s6_addr, ip->v6, sizeof(addr.s6_addr));
return inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
} else {
struct in_addr addr;
addr.s_addr = htonl(ip->v4);
return inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));
}
struct in6_addr addr;
memcpy(addr.s6_addr, ip->v6, sizeof(addr.s6_addr));
return inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
}
/*! \brief Calculate how many addresses there are in a range.
@ -131,23 +200,28 @@ const char *ntop_ipaddr(const union ipaddr_t *ip)
* and last IP in the range.
* \return Size of a range.
*/
double get_range_size(const struct range_t *r)
double get_range_size_init(const struct range_t *r __attribute__((unused)))
{
if (config.dhcp_version == VERSION_6) {
double size = 0;
int i;
/* When calculating the size of an IPv6 range overflow may
* occur. In that case only the last LONG_BIT bits are
* preserved, thus we just skip the first (16 - LONG_BIT)
* bits... */
for (i = 0; i < 16; i++) {
size *= 256;
size += (int)r->last_ip.v6[i] - (int)r->first_ip.v6[i];
}
return size + 1;
} else {
return r->last_ip.v4 - r->first_ip.v4 + 1;
return 0;
}
double get_range_size_v4(const struct range_t *r)
{
return r->last_ip.v4 - r->first_ip.v4 + 1;
}
double get_range_size_v6(const struct range_t *r)
{
double size = 0;
int i;
/* When calculating the size of an IPv6 range overflow may occur.
* In that case only the last LONG_BIT bits are preserved, thus
* we just skip the first (16 - LONG_BIT) bits... */
for (i = 0; i < 16; i++) {
size *= 256;
size += (int)r->last_ip.v6[i] - (int)r->first_ip.v6[i];
}
return size + 1;
}
/*! \fn xstrstr_init(const char *restrict str)
@ -164,12 +238,10 @@ int
xstrstr_init(const char *restrict str)
{
if (memcmp("lease ", str, 6)) {
config.dhcp_version = VERSION_4;
xstrstr = xstrstr_v4;
set_ipv_functions(VERSION_4);
return PREFIX_LEASE;
} else if (memcmp(" iaaddr ", str, 9)) {
config.dhcp_version = VERSION_6;
xstrstr = xstrstr_v6;
set_ipv_functions(VERSION_6);
return PREFIX_LEASE;
}
return NUM_OF_PREFIX;