File: dcinfo.c

package info (click to toggle)
gdnsd 3.8.3-2.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,584 kB
  • sloc: ansic: 30,669; sh: 4,872; perl: 1,047; makefile: 401; pascal: 108
file content (164 lines) | stat: -rw-r--r-- 6,487 bytes parent folder | download | duplicates (4)
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;
}