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); }
int NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address) { SourceRecord *record; unsigned int i; int any; NSR_ResolveSources(); 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_TakeSourceOnline(record->data); } } } 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.online = 1; } } return any; }
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; }
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++; } }
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_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); } }
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(); }
int NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address) { SourceRecord *record, *syncpeer; unsigned int i, any; 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_TakeSourceOffline(record->data); } } } /* Take sync peer offline as last to avoid reference switching */ if (syncpeer) { NCR_TakeSourceOffline(syncpeer->data); } 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.online = 0; } } return any; }
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(LOGF_NtpSources, "removing tentative source %s", UTI_IPToString(&record->remote_addr->ip_addr)); clean_source_record(record); removed++; } if (removed) rehash_records(); }
static void slew_sources(struct timeval *raw, struct timeval *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); } else { NCR_SlewTimes(record->data, cooked, dfreq, doffset); } } } }
/* 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; } } }
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; }
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); }
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); if (remote_addr->ip_addr.family != IPADDR_INET4 && remote_addr->ip_addr.family != IPADDR_INET6) { *found = *slot = 0; 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; } } *found = 0; }
void test_unit(void) { int i, j, index; struct timespec ts; IPAddr ip; char conf[][100] = { "clientloglimit 10000", "ratelimit interval 3 burst 4 leak 3", "cmdratelimit interval 3 burst 4 leak 3", }; CNF_Initialise(0, 0); for (i = 0; i < sizeof conf / sizeof conf[0]; i++) CNF_ParseLine(NULL, i + 1, conf[i]); CLG_Initialise(); TEST_CHECK(ARR_GetSize(records) == 16); for (i = 0; i < 500; i++) { DEBUG_LOG("iteration %d", i); ts.tv_sec = (time_t)random() & 0x0fffffff; ts.tv_nsec = 0; for (j = 0; j < 1000; j++) { TST_GetRandomAddress(&ip, IPADDR_UNSPEC, i % 8 ? -1 : i / 8 % 9); DEBUG_LOG("address %s", UTI_IPToString(&ip)); if (random() % 2) { index = CLG_LogNTPAccess(&ip, &ts); TEST_CHECK(index >= 0); CLG_LimitNTPResponseRate(index); } else { index = CLG_LogCommandAccess(&ip, &ts); TEST_CHECK(index >= 0); CLG_LimitCommandResponseRate(index); } UTI_AddDoubleToTimespec(&ts, (1 << random() % 14) / 100.0, &ts); } } DEBUG_LOG("records %u", ARR_GetSize(records)); TEST_CHECK(ARR_GetSize(records) == 64); for (i = j = 0; i < 10000; i++) { ts.tv_sec += 1; index = CLG_LogNTPAccess(&ip, &ts); TEST_CHECK(index >= 0); if (!CLG_LimitNTPResponseRate(index)) j++; } DEBUG_LOG("requests %d responses %d", i, j); TEST_CHECK(j * 4 < i && j * 6 > i); CLG_Finalise(); CNF_Finalise(); }