diff options
Diffstat (limited to '')
-rw-r--r-- | ntp_sources.c | 1137 |
1 files changed, 1137 insertions, 0 deletions
diff --git a/ntp_sources.c b/ntp_sources.c new file mode 100644 index 0000000..fa21654 --- /dev/null +++ b/ntp_sources.c @@ -0,0 +1,1137 @@ +/* + chronyd/chronyc - Programs for keeping computer clocks accurate. + + ********************************************************************** + * Copyright (C) Richard P. Curnow 1997-2003 + * Copyright (C) Miroslav Lichvar 2011-2012, 2014, 2016 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ********************************************************************** + + ======================================================================= + + Functions which manage the pool of NTP sources that we are currently + a client of or peering with. + + */ + +#include "config.h" + +#include "sysincl.h" + +#include "array.h" +#include "ntp_sources.h" +#include "ntp_core.h" +#include "util.h" +#include "logging.h" +#include "local.h" +#include "memory.h" +#include "nameserv_async.h" +#include "privops.h" +#include "sched.h" + +/* ================================================== */ + +/* Record type private to this file, used to store information about + particular sources */ +typedef struct { + NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL + means this slot in table is in use */ + NCR_Instance data; /* Data for the protocol engine for this source */ + char *name; /* Name of the source, may be NULL */ + int pool; /* Number of the pool from which was this source + added or INVALID_POOL */ + int tentative; /* Flag indicating there was no valid response + received from the source yet */ +} SourceRecord; + +/* Hash table of SourceRecord, its size is a power of two and it's never + more than half full */ +static ARR_Instance records; + +/* Number of sources in the hash table */ +static int n_sources; + +/* Flag indicating new sources will be started automatically when added */ +static int auto_start_sources = 0; + +/* Source with unknown address (which may be resolved later) */ +struct UnresolvedSource { + char *name; + int port; + int random_order; + int replacement; + union { + struct { + NTP_Source_Type type; + SourceParameters params; + int pool; + int max_new_sources; + } new_source; + NTP_Remote_Address replace_source; + }; + struct UnresolvedSource *next; +}; + +#define RESOLVE_INTERVAL_UNIT 7 +#define MIN_RESOLVE_INTERVAL 2 +#define MAX_RESOLVE_INTERVAL 9 +#define MIN_REPLACEMENT_INTERVAL 8 + +static struct UnresolvedSource *unresolved_sources = NULL; +static int resolving_interval = 0; +static SCH_TimeoutID resolving_id; +static struct UnresolvedSource *resolving_source = NULL; +static NSR_SourceResolvingEndHandler resolving_end_handler = NULL; + +#define MAX_POOL_SOURCES 16 +#define INVALID_POOL (-1) + +/* Pool of sources with the same name */ +struct SourcePool { + /* Number of sources added from this pool (ignoring tentative sources) */ + int sources; + /* Maximum number of sources */ + int max_sources; +}; + +/* Array of SourcePool */ +static ARR_Instance pools; + +/* ================================================== */ +/* Forward prototypes */ + +static void resolve_sources(void *arg); +static void rehash_records(void); +static void clean_source_record(SourceRecord *record); + +static void +slew_sources(struct timespec *raw, + struct timespec *cooked, + double dfreq, + double doffset, + LCL_ChangeType change_type, + void *anything); + +/* ================================================== */ + +/* Flag indicating whether module is initialised */ +static int initialised = 0; + +/* ================================================== */ + +static SourceRecord * +get_record(unsigned index) +{ + return (SourceRecord *)ARR_GetElement(records, index); +} + +/* ================================================== */ + +void +NSR_Initialise(void) +{ + n_sources = 0; + initialised = 1; + + records = ARR_CreateInstance(sizeof (SourceRecord)); + rehash_records(); + + pools = ARR_CreateInstance(sizeof (struct SourcePool)); + + LCL_AddParameterChangeHandler(slew_sources, NULL); +} + +/* ================================================== */ + +void +NSR_Finalise(void) +{ + SourceRecord *record; + struct UnresolvedSource *us; + unsigned int i; + + ARR_DestroyInstance(pools); + + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (record->remote_addr) + clean_source_record(record); + } + + ARR_DestroyInstance(records); + + while (unresolved_sources) { + us = unresolved_sources; + unresolved_sources = us->next; + Free(us->name); + Free(us); + } + + initialised = 0; +} + +/* ================================================== */ +/* Return slot number and whether the IP address was matched or not. + found = 0 => Neither IP nor port matched, empty slot returned + found = 1 => Only IP matched, port doesn't match + found = 2 => Both IP and port matched. + + It is assumed that there can only ever be one record for a + particular IP address. (If a different port comes up, it probably + means someone is running ntpdate -d or something). Thus, if we + match the IP address we stop the search regardless of whether the + port number matches. + + */ + +static void +find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found) +{ + SourceRecord *record; + uint32_t hash; + unsigned int i, size; + unsigned short port; + + size = ARR_GetSize(records); + + *slot = 0; + *found = 0; + + if (remote_addr->ip_addr.family != IPADDR_INET4 && + remote_addr->ip_addr.family != IPADDR_INET6) + return; + + hash = UTI_IPToHash(&remote_addr->ip_addr); + port = remote_addr->port; + + for (i = 0; i < size / 2; i++) { + /* Use quadratic probing */ + *slot = (hash + (i + i * i) / 2) % size; + record = get_record(*slot); + + if (!record->remote_addr) + break; + + if (!UTI_CompareIPs(&record->remote_addr->ip_addr, + &remote_addr->ip_addr, NULL)) { + *found = record->remote_addr->port == port ? 2 : 1; + return; + } + } +} + +/* ================================================== */ +/* Check if hash table of given size is sufficient to contain sources */ + +static int +check_hashtable_size(unsigned int sources, unsigned int size) +{ + return sources * 2 <= size; +} + +/* ================================================== */ + +static void +rehash_records(void) +{ + SourceRecord *temp_records; + unsigned int i, old_size, new_size; + int slot, found; + + old_size = ARR_GetSize(records); + + temp_records = MallocArray(SourceRecord, old_size); + memcpy(temp_records, ARR_GetElements(records), old_size * sizeof (SourceRecord)); + + /* The size of the hash table is always a power of two */ + for (new_size = 1; !check_hashtable_size(n_sources, new_size); new_size *= 2) + ; + + ARR_SetSize(records, new_size); + + for (i = 0; i < new_size; i++) + get_record(i)->remote_addr = NULL; + + for (i = 0; i < old_size; i++) { + if (!temp_records[i].remote_addr) + continue; + + find_slot(temp_records[i].remote_addr, &slot, &found); + assert(!found); + + *get_record(slot) = temp_records[i]; + } + + Free(temp_records); +} + +/* ================================================== */ + +/* Procedure to add a new source */ +static NSR_Status +add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, SourceParameters *params, int pool) +{ + SourceRecord *record; + int slot, found; + + assert(initialised); + + /* Find empty bin & check that we don't have the address already */ + find_slot(remote_addr, &slot, &found); + if (found) { + return NSR_AlreadyInUse; + } else { + if (remote_addr->ip_addr.family != IPADDR_INET4 && + remote_addr->ip_addr.family != IPADDR_INET6) { + return NSR_InvalidAF; + } else { + n_sources++; + + if (!check_hashtable_size(n_sources, ARR_GetSize(records))) { + rehash_records(); + find_slot(remote_addr, &slot, &found); + } + + assert(!found); + record = get_record(slot); + record->data = NCR_GetInstance(remote_addr, type, params); + record->remote_addr = NCR_GetRemoteAddress(record->data); + record->name = name ? Strdup(name) : NULL; + record->pool = pool; + record->tentative = 1; + + if (auto_start_sources) + NCR_StartInstance(record->data); + + return NSR_Success; + } + } +} + +/* ================================================== */ + +static NSR_Status +replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr) +{ + int slot1, slot2, found; + SourceRecord *record; + struct SourcePool *pool; + + find_slot(old_addr, &slot1, &found); + if (!found) + return NSR_NoSuchSource; + + find_slot(new_addr, &slot2, &found); + if (found) + return NSR_AlreadyInUse; + + record = get_record(slot1); + NCR_ChangeRemoteAddress(record->data, new_addr); + record->remote_addr = NCR_GetRemoteAddress(record->data); + + if (!record->tentative) { + record->tentative = 1; + + if (record->pool != INVALID_POOL) { + pool = ARR_GetElement(pools, record->pool); + pool->sources--; + } + } + + /* The hash table must be rebuilt for the new address */ + rehash_records(); + + LOG(LOGS_INFO, "Source %s replaced with %s", + UTI_IPToString(&old_addr->ip_addr), + UTI_IPToString(&new_addr->ip_addr)); + + return NSR_Success; +} + +/* ================================================== */ + +static void +process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs) +{ + NTP_Remote_Address address; + int i, added; + unsigned short first = 0; + + if (us->random_order) + UTI_GetRandomBytes(&first, sizeof (first)); + + for (i = added = 0; i < n_addrs; i++) { + address.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs]; + address.port = us->port; + + DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&address.ip_addr)); + + if (us->replacement) { + if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse) + break; + } else { + if (add_source(&address, us->name, us->new_source.type, &us->new_source.params, + us->new_source.pool) == NSR_Success) + added++; + + if (added >= us->new_source.max_new_sources) + break; + } + } +} + +/* ================================================== */ + +static void +name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything) +{ + struct UnresolvedSource *us, **i, *next; + + us = (struct UnresolvedSource *)anything; + + assert(us == resolving_source); + + DEBUG_LOG("%s resolved to %d addrs", us->name, n_addrs); + + switch (status) { + case DNS_TryAgain: + break; + case DNS_Success: + process_resolved_name(us, ip_addrs, n_addrs); + break; + case DNS_Failure: + LOG(LOGS_WARN, "Invalid host %s", us->name); + break; + default: + assert(0); + } + + next = us->next; + + /* Remove the source from the list on success or failure, replacements + are removed on any status */ + if (us->replacement || status != DNS_TryAgain) { + for (i = &unresolved_sources; *i; i = &(*i)->next) { + if (*i == us) { + *i = us->next; + Free(us->name); + Free(us); + break; + } + } + } + + resolving_source = next; + + if (next) { + /* Continue with the next source in the list */ + DEBUG_LOG("resolving %s", next->name); + DNS_Name2IPAddressAsync(next->name, name_resolve_handler, next); + } else { + /* This was the last source in the list. If some sources couldn't + be resolved, try again in exponentially increasing interval. */ + if (unresolved_sources) { + if (resolving_interval < MIN_RESOLVE_INTERVAL) + resolving_interval = MIN_RESOLVE_INTERVAL; + else if (resolving_interval < MAX_RESOLVE_INTERVAL) + resolving_interval++; + resolving_id = SCH_AddTimeoutByDelay(RESOLVE_INTERVAL_UNIT * + (1 << resolving_interval), resolve_sources, NULL); + } else { + resolving_interval = 0; + } + + /* This round of resolving is done */ + if (resolving_end_handler) + (resolving_end_handler)(); + } +} + +/* ================================================== */ + +static void +resolve_sources(void *arg) +{ + struct UnresolvedSource *us; + + assert(!resolving_source); + + PRV_ReloadDNS(); + + /* Start with the first source in the list, name_resolve_handler + will iterate over the rest */ + us = unresolved_sources; + + resolving_source = us; + DEBUG_LOG("resolving %s", us->name); + DNS_Name2IPAddressAsync(us->name, name_resolve_handler, us); +} + +/* ================================================== */ + +static void +append_unresolved_source(struct UnresolvedSource *us) +{ + struct UnresolvedSource **i; + + for (i = &unresolved_sources; *i; i = &(*i)->next) + ; + *i = us; + us->next = NULL; +} + +/* ================================================== */ + +NSR_Status +NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params) +{ + return add_source(remote_addr, NULL, type, params, INVALID_POOL); +} + +/* ================================================== */ + +void +NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params) +{ + struct UnresolvedSource *us; + struct SourcePool *sp; + NTP_Remote_Address remote_addr; + + /* If the name is an IP address, don't bother with full resolving now + or later when trying to replace the source */ + if (UTI_StringToIP(name, &remote_addr.ip_addr)) { + remote_addr.port = port; + NSR_AddSource(&remote_addr, type, params); + return; + } + + us = MallocNew(struct UnresolvedSource); + us->name = Strdup(name); + us->port = port; + us->random_order = 0; + us->replacement = 0; + us->new_source.type = type; + us->new_source.params = *params; + + if (!pool) { + us->new_source.pool = INVALID_POOL; + us->new_source.max_new_sources = 1; + } else { + sp = (struct SourcePool *)ARR_GetNewElement(pools); + sp->sources = 0; + sp->max_sources = params->max_sources; + us->new_source.pool = ARR_GetSize(pools) - 1; + us->new_source.max_new_sources = MAX_POOL_SOURCES; + } + + append_unresolved_source(us); +} + +/* ================================================== */ + +void +NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler) +{ + resolving_end_handler = handler; +} + +/* ================================================== */ + +void +NSR_ResolveSources(void) +{ + /* Try to resolve unresolved sources now */ + if (unresolved_sources) { + /* Make sure no resolving is currently running */ + if (!resolving_source) { + if (resolving_interval) { + SCH_RemoveTimeout(resolving_id); + resolving_interval--; + } + resolve_sources(NULL); + } + } else { + /* No unresolved sources, we are done */ + if (resolving_end_handler) + (resolving_end_handler)(); + } +} + +/* ================================================== */ + +void NSR_StartSources(void) +{ + unsigned int i; + + for (i = 0; i < ARR_GetSize(records); i++) { + if (!get_record(i)->remote_addr) + continue; + NCR_StartInstance(get_record(i)->data); + } +} + +/* ================================================== */ + +void NSR_AutoStartSources(void) +{ + auto_start_sources = 1; +} + +/* ================================================== */ + +static void +clean_source_record(SourceRecord *record) +{ + assert(record->remote_addr); + record->remote_addr = NULL; + NCR_DestroyInstance(record->data); + if (record->name) + Free(record->name); + + n_sources--; +} + +/* ================================================== */ + +/* Procedure to remove a source. We don't bother whether the port + address is matched - we're only interested in removing a record for + the right IP address. Thus the caller can specify the port number + as zero if it wishes. */ +NSR_Status +NSR_RemoveSource(NTP_Remote_Address *remote_addr) +{ + int slot, found; + + assert(initialised); + + find_slot(remote_addr, &slot, &found); + if (!found) { + return NSR_NoSuchSource; + } + + clean_source_record(get_record(slot)); + + /* Rehash the table to make sure there are no broken probe sequences. + This is costly, but it's not expected to happen frequently. */ + + rehash_records(); + + return NSR_Success; +} + +/* ================================================== */ + +void +NSR_RemoveAllSources(void) +{ + SourceRecord *record; + unsigned int i; + + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (!record->remote_addr) + continue; + clean_source_record(record); + } + + rehash_records(); +} + +/* ================================================== */ + +static void +resolve_source_replacement(SourceRecord *record) +{ + struct UnresolvedSource *us; + + DEBUG_LOG("trying to replace %s", UTI_IPToString(&record->remote_addr->ip_addr)); + + us = MallocNew(struct UnresolvedSource); + us->name = Strdup(record->name); + us->port = record->remote_addr->port; + /* If there never was a valid reply from this source (e.g. it was a bad + replacement), ignore the order of addresses from the resolver to not get + stuck to a pair of addresses if the order doesn't change, or a group of + IPv4/IPv6 addresses if the resolver prefers inaccessible IP family */ + us->random_order = record->tentative; + us->replacement = 1; + us->replace_source = *record->remote_addr; + + append_unresolved_source(us); + NSR_ResolveSources(); +} + +/* ================================================== */ + +void +NSR_HandleBadSource(IPAddr *address) +{ + static struct timespec last_replacement; + struct timespec now; + NTP_Remote_Address remote_addr; + SourceRecord *record; + int slot, found; + double diff; + + remote_addr.ip_addr = *address; + remote_addr.port = 0; + + find_slot(&remote_addr, &slot, &found); + if (!found) + return; + + record = get_record(slot); + + /* Only sources with a name can be replaced */ + if (!record->name) + return; + + /* Don't resolve names too frequently */ + SCH_GetLastEventTime(NULL, NULL, &now); + diff = UTI_DiffTimespecsToDouble(&now, &last_replacement); + if (fabs(diff) < RESOLVE_INTERVAL_UNIT * (1 << MIN_REPLACEMENT_INTERVAL)) { + DEBUG_LOG("replacement postponed"); + return; + } + last_replacement = now; + + resolve_source_replacement(record); +} + +/* ================================================== */ + +void +NSR_RefreshAddresses(void) +{ + SourceRecord *record; + unsigned int i; + + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (!record->remote_addr || !record->name) + continue; + + resolve_source_replacement(record); + } +} + +/* ================================================== */ + +static void remove_tentative_pool_sources(int pool) +{ + SourceRecord *record; + unsigned int i, removed; + + for (i = removed = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + + if (!record->remote_addr || record->pool != pool || !record->tentative) + continue; + + DEBUG_LOG("removing tentative source %s", + UTI_IPToString(&record->remote_addr->ip_addr)); + + clean_source_record(record); + removed++; + } + + if (removed) + rehash_records(); +} + +/* ================================================== */ + +uint32_t +NSR_GetLocalRefid(IPAddr *address) +{ + NTP_Remote_Address remote_addr; + int slot, found; + + remote_addr.ip_addr = *address; + remote_addr.port = 0; + + find_slot(&remote_addr, &slot, &found); + if (!found) + return 0; + + return NCR_GetLocalRefid(get_record(slot)->data); +} + +/* ================================================== */ + +/* This routine is called by ntp_io when a new packet arrives off the network, + possibly with an authentication tail */ +void +NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, + NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length) +{ + SourceRecord *record; + struct SourcePool *pool; + int slot, found; + + assert(initialised); + + find_slot(remote_addr, &slot, &found); + if (found == 2) { /* Must match IP address AND port number */ + record = get_record(slot); + + if (!NCR_ProcessRxKnown(record->data, local_addr, rx_ts, message, length)) + return; + + if (record->tentative) { + /* This was the first good reply from the source */ + record->tentative = 0; + + if (record->pool != INVALID_POOL) { + pool = ARR_GetElement(pools, record->pool); + pool->sources++; + + DEBUG_LOG("pool %s has %d confirmed sources", record->name, pool->sources); + + /* If the number of sources from the pool reached the configured + maximum, remove the remaining tentative sources */ + if (pool->sources >= pool->max_sources) + remove_tentative_pool_sources(record->pool); + } + } + } else { + NCR_ProcessRxUnknown(remote_addr, local_addr, rx_ts, message, length); + } +} + +/* ================================================== */ + +void +NSR_ProcessTx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, + NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length) +{ + SourceRecord *record; + int slot, found; + + find_slot(remote_addr, &slot, &found); + + if (found == 2) { /* Must match IP address AND port number */ + record = get_record(slot); + NCR_ProcessTxKnown(record->data, local_addr, tx_ts, message, length); + } else { + NCR_ProcessTxUnknown(remote_addr, local_addr, tx_ts, message, length); + } +} + +/* ================================================== */ + +static void +slew_sources(struct timespec *raw, + struct timespec *cooked, + double dfreq, + double doffset, + LCL_ChangeType change_type, + void *anything) +{ + SourceRecord *record; + unsigned int i; + + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (record->remote_addr) { + if (change_type == LCL_ChangeUnknownStep) { + NCR_ResetInstance(record->data); + NCR_ResetPoll(record->data); + } else { + NCR_SlewTimes(record->data, cooked, dfreq, doffset); + } + } + } +} + +/* ================================================== */ + +int +NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity) +{ + SourceRecord *record, *syncpeer; + unsigned int i, any; + + if (connectivity != SRC_OFFLINE) + NSR_ResolveSources(); + + any = 0; + syncpeer = NULL; + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (record->remote_addr) { + if (address->family == IPADDR_UNSPEC || + !UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) { + any = 1; + if (NCR_IsSyncPeer(record->data)) { + syncpeer = record; + continue; + } + NCR_SetConnectivity(record->data, connectivity); + } + } + } + + /* Set the sync peer last to avoid unnecessary reference switching */ + if (syncpeer) + NCR_SetConnectivity(syncpeer->data, connectivity); + + if (address->family == IPADDR_UNSPEC) { + struct UnresolvedSource *us; + + for (us = unresolved_sources; us; us = us->next) { + if (us->replacement) + continue; + any = 1; + us->new_source.params.connectivity = connectivity; + } + } + + return any; +} + +/* ================================================== */ + +int +NSR_ModifyMinpoll(IPAddr *address, int new_minpoll) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMinpoll(get_record(slot)->data, new_minpoll); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyMaxpoll(IPAddr *address, int new_maxpoll) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMaxpoll(get_record(slot)->data, new_maxpoll); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyMaxdelay(IPAddr *address, double new_max_delay) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMaxdelay(get_record(slot)->data, new_max_delay); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyMaxdelayratio(IPAddr *address, double new_max_delay_ratio) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMaxdelayratio(get_record(slot)->data, new_max_delay_ratio); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyMaxdelaydevratio(IPAddr *address, double new_max_delay_dev_ratio) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMaxdelaydevratio(get_record(slot)->data, new_max_delay_dev_ratio); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyMinstratum(IPAddr *address, int new_min_stratum) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyMinstratum(get_record(slot)->data, new_min_stratum); + return 1; + } +} + +/* ================================================== */ + +int +NSR_ModifyPolltarget(IPAddr *address, int new_poll_target) +{ + int slot, found; + NTP_Remote_Address addr; + addr.ip_addr = *address; + addr.port = 0; + + find_slot(&addr, &slot, &found); + if (found == 0) { + return 0; + } else { + NCR_ModifyPolltarget(get_record(slot)->data, new_poll_target); + return 1; + } +} + +/* ================================================== */ + +int +NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, + IPAddr *mask, IPAddr *address) +{ + SourceRecord *record; + unsigned int i; + int any; + + any = 0; + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (record->remote_addr) { + if (address->family == IPADDR_UNSPEC || + !UTI_CompareIPs(&record->remote_addr->ip_addr, address, mask)) { + any = 1; + NCR_InitiateSampleBurst(record->data, n_good_samples, n_total_samples); + } + } + } + + return any; + +} + +/* ================================================== */ +/* The ip address is assumed to be completed on input, that is how we + identify the source record. */ + +void +NSR_ReportSource(RPT_SourceReport *report, struct timespec *now) +{ + NTP_Remote_Address rem_addr; + int slot, found; + + rem_addr.ip_addr = report->ip_addr; + rem_addr.port = 0; + find_slot(&rem_addr, &slot, &found); + if (found) { + NCR_ReportSource(get_record(slot)->data, report, now); + } else { + report->poll = 0; + report->latest_meas_ago = 0; + } +} + +/* ================================================== */ +/* The ip address is assumed to be completed on input, that is how we + identify the source record. */ + +int +NSR_GetNTPReport(RPT_NTPReport *report) +{ + NTP_Remote_Address rem_addr; + int slot, found; + + rem_addr.ip_addr = report->remote_addr; + rem_addr.port = 0; + find_slot(&rem_addr, &slot, &found); + if (!found) + return 0; + + NCR_GetNTPReport(get_record(slot)->data, report); + return 1; +} + +/* ================================================== */ + +void +NSR_GetActivityReport(RPT_ActivityReport *report) +{ + SourceRecord *record; + unsigned int i; + struct UnresolvedSource *us; + + report->online = 0; + report->offline = 0; + report->burst_online = 0; + report->burst_offline = 0; + + for (i = 0; i < ARR_GetSize(records); i++) { + record = get_record(i); + if (record->remote_addr) { + NCR_IncrementActivityCounters(record->data, &report->online, &report->offline, + &report->burst_online, &report->burst_offline); + } + } + + report->unresolved = 0; + + for (us = unresolved_sources; us; us = us->next) { + report->unresolved++; + } +} + + +/* ================================================== */ + |