1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
|
/* Copyright © 2012 Brandon L Black <blblack@gmail.com>
*
* This file is part of gdnsd.
*
* gdnsd-plugin-geoip is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* gdnsd-plugin-geoip 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gdnsd. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include "dcinfo.h"
#include <gdnsd/alloc.h>
#include <gdnsd/log.h>
#include <gdnsd/misc.h>
#include <math.h>
F_NONNULL
static unsigned dcinfo_init_auto(const dcinfo_t* info, const vscf_data_t* dc_auto_cfg, const char* map_name)
{
if (!vscf_is_hash(dc_auto_cfg))
log_fatal("plugin_geoip: map '%s': auto_dc_coords must be a key-value hash", map_name);
const unsigned num_auto = vscf_hash_get_len(dc_auto_cfg);
const unsigned num_dcs = info->num_dcs;
for (unsigned i = 0; i < num_dcs; i++) {
info->dcs[i].coords.lat = (double)NAN;
info->dcs[i].coords.lon = (double)NAN;
info->dcs[i].coords.cos_lat = (double)NAN;
}
for (unsigned i = 0; i < num_auto; i++) {
const char* dcname = vscf_hash_get_key_byindex(dc_auto_cfg, i, NULL);
unsigned dcidx;
for (dcidx = 0; dcidx < num_dcs; dcidx++) {
if (!strcmp(dcname, info->dcs[dcidx].name))
break;
}
if (dcidx == num_dcs)
log_fatal("plugin_geoip: map '%s': auto_dc_coords key '%s' not matched from 'datacenters' list", map_name, dcname);
GDNSD_DIAG_PUSH_IGNORED("-Wdouble-promotion")
if (!isnan(info->dcs[dcidx].coords.lat))
log_fatal("plugin_geoip: map '%s': auto_dc_coords key '%s' defined twice", map_name, dcname);
GDNSD_DIAG_POP
vscf_data_t* coord_cfg = vscf_hash_get_data_byindex(dc_auto_cfg, i);
if (!vscf_is_array(coord_cfg) || vscf_array_get_len(coord_cfg) != 2)
log_fatal("plugin_geoip: map '%s': auto_dc_coords value for datacenter '%s' must be an array of two values", map_name, dcname);
vscf_data_t* lat_cfg = vscf_array_get_data(coord_cfg, 0);
vscf_data_t* lon_cfg = vscf_array_get_data(coord_cfg, 1);
gdnsd_assert(lat_cfg);
gdnsd_assert(lon_cfg);
double lat;
double lon;
if (!vscf_is_simple(lat_cfg)
|| !vscf_is_simple(lon_cfg)
|| !vscf_simple_get_as_double(lat_cfg, &lat)
|| !vscf_simple_get_as_double(lon_cfg, &lon)
|| lat > 90.0 || lat < -90.0
|| lon > 180.0 || lon < -180.0
)
log_fatal("plugin_geoip: map '%s': auto_dc_coords value for datacenter '%s' must be a legal latitude and longitude in decimal degrees", map_name, dcname);
info->dcs[dcidx].coords.lat = lat * DEG2RAD;
info->dcs[dcidx].coords.lon = lon * DEG2RAD;
info->dcs[dcidx].coords.cos_lat = cos(lat * DEG2RAD);
}
return num_auto;
}
// Technically we could/should check for duplicates here. The plugin will
// still fail later though: when a resource is defined, the datacenter
// names go into a hash requiring uniqueness, and the count is required
// to match (ditto for auto_dc_coords never succeeding with dupes in the
// datacenters list).
void dcinfo_init(dcinfo_t* info, vscf_data_t* dc_cfg, const vscf_data_t* dc_auto_cfg, vscf_data_t* dc_auto_limit_cfg, const char* map_name, monreg_func_t mrf)
{
const unsigned num_dcs = vscf_array_get_len(dc_cfg);
unsigned num_auto = num_dcs;
if (!num_dcs)
log_fatal("plugin_geoip: map '%s': 'datacenters' must be an array of one or more strings", map_name);
if (num_dcs > MAX_NUM_DCS)
log_fatal("plugin_geoip: map '%s': %u datacenters is too many, this code only supports up to %i", map_name, num_dcs, MAX_NUM_DCS);
info->num_dcs = num_dcs;
info->dcs = xmalloc_n(num_dcs, sizeof(*info->dcs));
for (unsigned i = 0; i < num_dcs; i++) {
vscf_data_t* dcname_cfg = vscf_array_get_data(dc_cfg, i);
if (!dcname_cfg || !vscf_is_simple(dcname_cfg))
log_fatal("plugin_geoip: map '%s': 'datacenters' must be an array of one or more strings", map_name);
info->dcs[i].name = xstrdup(vscf_simple_get_data(dcname_cfg));
if (!strcmp(info->dcs[i].name, "auto"))
log_fatal("plugin_geoip: map '%s': datacenter name 'auto' is illegal", map_name);
char* map_mon_desc = gdnsd_str_combine_n(4, "geoip/", map_name, "/", info->dcs[i].name);
if (mrf)
info->dcs[i].mon_index = mrf(map_mon_desc);
free(map_mon_desc);
}
if (dc_auto_cfg)
num_auto = dcinfo_init_auto(info, dc_auto_cfg, map_name);
if (dc_auto_limit_cfg) {
unsigned long auto_limit_ul;
if (!vscf_is_simple(dc_auto_limit_cfg) || !vscf_simple_get_as_ulong(dc_auto_limit_cfg, &auto_limit_ul))
log_fatal("plugin_geoip: map '%s': auto_dc_limit must be a single unsigned integer value", map_name);
if (auto_limit_ul > num_auto || !auto_limit_ul)
auto_limit_ul = num_auto;
info->auto_limit = auto_limit_ul;
} else {
info->auto_limit = (num_auto > 3) ? 3 : num_auto;
}
}
unsigned dcinfo_get_count(const dcinfo_t* info)
{
return info->num_dcs;
}
unsigned dcinfo_get_limit(const dcinfo_t* info)
{
return info->auto_limit;
}
const dcinfo_coords_t* dcinfo_get_coords(const dcinfo_t* info, const unsigned dcnum)
{
gdnsd_assert(dcnum < info->num_dcs);
return &info->dcs[dcnum].coords;
}
unsigned dcinfo_name2num(const dcinfo_t* info, const char* dcname)
{
if (dcname)
for (unsigned i = 0; i < info->num_dcs; i++)
if (!strcmp(dcname, info->dcs[i].name))
return i + 1;
return 0;
}
const char* dcinfo_num2name(const dcinfo_t* info, const unsigned dcnum)
{
if (!dcnum || dcnum > info->num_dcs)
return NULL;
return info->dcs[dcnum - 1].name;
}
unsigned dcinfo_map_mon_idx(const dcinfo_t* info, const unsigned dcnum)
{
gdnsd_assert(dcnum && dcnum <= info->num_dcs);
return info->dcs[dcnum - 1].mon_index;
}
|