static double stratum_weight;
static double combine_limit;
+/* Identifier of the dump file */
+#define DUMP_IDENTIFIER "SRC0\n"
+
/* ================================================== */
/* Forward prototype */
/* ================================================== */
-static
-FILE *open_dumpfile(SRC_Instance inst, char mode)
+static int
+get_dumpfile(SRC_Instance inst, char *filename, size_t len)
+{
+ /* Use the IP address, or reference ID with reference clocks */
+ switch (inst->type) {
+ case SRC_NTP:
+ if (!UTI_IsIPReal(inst->ip_addr) ||
+ snprintf(filename, len, "%s", source_to_string(inst)) >= len)
+ return 0;
+ break;
+ case SRC_REFCLOCK:
+ if (snprintf(filename, len, "refid:%08"PRIx32, inst->ref_id) >= len)
+ return 0;
+ break;
+ default:
+ assert(0);
+ }
+
+ return 1;
+}
+
+/* ================================================== */
+
+static void
+save_source(SRC_Instance inst)
{
- char filename[64], *dumpdir;
+ char filename[64], *dumpdir, *ntp_name;
+ FILE *f;
dumpdir = CNF_GetDumpDir();
if (!dumpdir)
- return NULL;
+ return;
- /* Include IP address in the name for NTP sources, or reference ID in hex */
- if (inst->type == SRC_NTP && UTI_IsIPReal(inst->ip_addr))
- snprintf(filename, sizeof (filename), "%s", source_to_string(inst));
- else if (inst->type == SRC_REFCLOCK)
- snprintf(filename, sizeof (filename), "refid:%08"PRIx32, inst->ref_id);
- else
- return NULL;
+ if (!get_dumpfile(inst, filename, sizeof (filename)))
+ return;
+
+ f = UTI_OpenFile(dumpdir, filename, ".dat", 'w', 0644);
+ if (!f)
+ return;
+
+ ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
+
+ if (fprintf(f, "%s%s\n%d %o %d %d %d\n",
+ DUMP_IDENTIFIER, ntp_name, inst->authenticated,
+ (unsigned int)inst->reachability, inst->reachability_size,
+ inst->stratum, (int)inst->leap) < 0 ||
+ !SST_SaveToFile(inst->stats, f)) {
+ fclose(f);
+ if (!UTI_RemoveFile(dumpdir, filename, ".dat"))
+ ;
+ return;
+ }
- return UTI_OpenFile(dumpdir, filename, ".dat", mode, 0644);
+ fclose(f);
}
/* ================================================== */
void
SRC_DumpSources(void)
{
- FILE *out;
int i;
- for (i = 0; i < n_sources; i++) {
- out = open_dumpfile(sources[i], 'w');
- if (!out)
- continue;
- SST_SaveToFile(sources[i]->stats, out);
- fclose(out);
+ for (i = 0; i < n_sources; i++)
+ save_source(sources[i]);
+}
+
+/* ================================================== */
+
+#define MAX_WORDS 1
+
+static void
+load_source(SRC_Instance inst)
+{
+ char filename[64], line[256], *dumpdir, *ntp_name, *words[MAX_WORDS];
+ int auth, leap, reach_size, stratum;
+ unsigned int reach;
+ FILE *f;
+
+ dumpdir = CNF_GetDumpDir();
+ if (!dumpdir)
+ return;
+
+ if (!get_dumpfile(inst, filename, sizeof (filename)))
+ return;
+
+ f = UTI_OpenFile(dumpdir, filename, ".dat", 'r', 0);
+ if (!f)
+ return;
+
+ ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
+
+ if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
+ !fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 1 ||
+ (inst->type == SRC_NTP && (!ntp_name || strcmp(words[0], ntp_name) != 0)) ||
+ !fgets(line, sizeof (line), f) ||
+ sscanf(words[0], "%d %o %d %d %d",
+ &auth, &reach, &reach_size, &stratum, &leap) != 5 ||
+ (!auth && inst->authenticated) ||
+ stratum < 1 || stratum >= NTP_MAX_STRATUM ||
+ leap < LEAP_Normal || leap >= LEAP_Unsynchronised ||
+ !SST_LoadFromFile(inst->stats, f)) {
+ LOG(LOGS_WARN, "Could not load dump file for %s", source_to_string(inst));
+ fclose(f);
+ return;
}
+
+ inst->reachability = reach & ((1U << SOURCE_REACH_BITS) - 1);
+ inst->reachability_size = CLAMP(0, reach_size, SOURCE_REACH_BITS);
+ inst->stratum = stratum;
+ inst->leap = leap;
+
+ LOG(LOGS_INFO, "Loaded dump file for %s", source_to_string(inst));
+
+ fclose(f);
}
/* ================================================== */
void
SRC_ReloadSources(void)
{
- FILE *in;
int i;
for (i = 0; i < n_sources; i++) {
- in = open_dumpfile(sources[i], 'r');
- if (!in)
- continue;
- if (!SST_LoadFromFile(sources[i]->stats, in))
- LOG(LOGS_WARN, "Could not load dump file for %s",
- source_to_string(sources[i]));
- else
- LOG(LOGS_INFO, "Loaded dump file for %s",
- source_to_string(sources[i]));
- fclose(in);
+ load_source(sources[i]);
}
}
/* This is used to save the register to a file, so that we can reload
it after restarting the daemon */
-void
+int
SST_SaveToFile(SST_Stats inst, FILE *out)
{
int m, i, j;
- fprintf(out, "%d\n", inst->n_samples);
+ if (inst->n_samples < 1)
+ return 0;
+
+ if (fprintf(out, "%d %d\n", inst->n_samples, inst->asymmetry_run) < 0)
+ return 0;
for(m = 0; m < inst->n_samples; m++) {
i = get_runsbuf_index(inst, m);
j = get_buf_index(inst, m);
- fprintf(out,
-#ifdef HAVE_LONG_TIME_T
- "%08"PRIx64" %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
- (uint64_t)inst->sample_times[i].tv_sec,
-#else
- "%08lx %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
- (unsigned long)inst->sample_times[i].tv_sec,
-#endif
- (unsigned long)inst->sample_times[i].tv_nsec / 1000,
- inst->offsets[i],
- inst->orig_offsets[j],
- inst->peer_delays[i],
- inst->peer_dispersions[j],
- inst->root_delays[j],
- inst->root_dispersions[j],
- 1.0, /* used to be inst->weights[i] */
- 0 /* used to be an array of strata */);
-
+ if (fprintf(out, "%s %.6e %.6e %.6e %.6e %.6e %.6e\n",
+ UTI_TimespecToString(&inst->sample_times[i]),
+ inst->offsets[i], inst->orig_offsets[j],
+ inst->peer_delays[i], inst->peer_dispersions[j],
+ inst->root_delays[j], inst->root_dispersions[j]) < 0)
+ return 0;
}
- fprintf(out, "%d\n", inst->asymmetry_run);
+ return 1;
}
/* ================================================== */
int
SST_LoadFromFile(SST_Stats inst, FILE *in)
{
-#ifdef HAVE_LONG_TIME_T
- uint64_t sec;
-#else
- unsigned long sec;
-#endif
- unsigned long usec;
- int i;
- char line[1024];
- double weight;
- int stratum;
+ int i, n_samples, arun;
+ double sample_time;
+ char line[256];
- SST_ResetInstance(inst);
+ if (!fgets(line, sizeof (line), in) ||
+ sscanf(line, "%d %d", &n_samples, &arun) != 2 ||
+ n_samples < 1 || n_samples > MAX_SAMPLES)
+ return 0;
- if (fgets(line, sizeof(line), in) &&
- sscanf(line, "%d", &inst->n_samples) == 1 &&
- inst->n_samples >= 0 && inst->n_samples <= MAX_SAMPLES) {
+ SST_ResetInstance(inst);
- for (i=0; i<inst->n_samples; i++) {
- if (!fgets(line, sizeof(line), in) ||
- (sscanf(line,
-#ifdef HAVE_LONG_TIME_T
- "%"SCNx64"%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
-#else
- "%lx%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
-#endif
- &(sec), &(usec),
- &(inst->offsets[i]),
- &(inst->orig_offsets[i]),
- &(inst->peer_delays[i]),
- &(inst->peer_dispersions[i]),
- &(inst->root_delays[i]),
- &(inst->root_dispersions[i]),
- &weight, /* not used anymore */
- &stratum /* not used anymore */) != 10)) {
-
- /* This is the branch taken if the read FAILED */
-
- inst->n_samples = 0; /* Load abandoned if any sign of corruption */
- return 0;
- } else {
-
- /* This is the branch taken if the read is SUCCESSFUL */
- inst->sample_times[i].tv_sec = sec;
- inst->sample_times[i].tv_nsec = 1000 * usec;
- UTI_NormaliseTimespec(&inst->sample_times[i]);
- }
- }
+ for (i = 0; i < n_samples; i++) {
+ if (!fgets(line, sizeof (line), in) ||
+ sscanf(line, "%lf %lf %lf %lf %lf %lf %lf",
+ &sample_time, &inst->offsets[i], &inst->orig_offsets[i],
+ &inst->peer_delays[i], &inst->peer_dispersions[i],
+ &inst->root_delays[i], &inst->root_dispersions[i]) != 7)
+ return 0;
- /* This field was not saved in older versions */
- if (!fgets(line, sizeof(line), in) || sscanf(line, "%d\n", &inst->asymmetry_run) != 1)
- inst->asymmetry_run = 0;
- } else {
- inst->n_samples = 0; /* Load abandoned if any sign of corruption */
- return 0;
+ /* Some resolution is lost in the double format, but that's ok */
+ UTI_DoubleToTimespec(sample_time, &inst->sample_times[i]);
}
- if (!inst->n_samples)
- return 1;
-
+ inst->n_samples = n_samples;
inst->last_sample = inst->n_samples - 1;
+ inst->asymmetry_run = CLAMP(-MAX_ASYMMETRY_RUN, arun, MAX_ASYMMETRY_RUN);
find_min_delay_sample(inst);
SST_DoNewRegression(inst);