#include "collectd.h"
-#include "common.h" /* auxiliary functions */
-#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+#include "utils/common/common.h" /* auxiliary functions */
#if HAVE_NETDB_H
#include <netdb.h> /* struct addrinfo */
#include <arpa/inet.h> /* ntohs/ntohl */
#endif
+/* AIX doesn't have MSG_DONTWAIT */
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT MSG_NONBLOCK
+#endif
+
#define CONFIG_KEY_HOST "Host"
#define CONFIG_KEY_PORT "Port"
#define CONFIG_KEY_TIMEOUT "Timeout"
#define IPADDR_INET4 1
#define IPADDR_INET6 2
#define IPV6_STR_MAX_SIZE (8 * 4 + 7 + 1)
+#define MODE_REFCLOCK 2
typedef enum { PKT_TYPE_CMD_REQUEST = 1, PKT_TYPE_CMD_REPLY = 2 } ePacketType;
uint8_t ip6[16];
} addr;
uint16_t f_family;
+ uint16_t padding;
} tChrony_IPAddr;
typedef struct ATTRIB_PACKED {
tChrony_IPAddr addr;
- uint16_t
- dummy; /* FIXME: Strange dummy space. Needed on gcc 4.8.3/clang 3.4.1 on
- x86_64 */
int16_t f_poll; /* 2^f_poll = Time between polls (s) */
uint16_t f_stratum; /* Remote clock stratum */
uint16_t f_state; /* 0 = RPY_SD_ST_SYNC, 1 = RPY_SD_ST_UNREACH, 2 =
typedef struct ATTRIB_PACKED {
uint32_t f_ref_id;
tChrony_IPAddr addr;
- uint16_t
- dummy; /* FIXME: Strange dummy space. Needed on gcc 4.8.3/clang 3.4.1 on
- x86_64 */
uint32_t f_n_samples; /* Number of measurements done */
uint32_t f_n_runs; /* How many measurements to come */
uint32_t f_span_seconds; /* For how long we're measuring */
typedef struct ATTRIB_PACKED {
uint32_t f_ref_id;
tChrony_IPAddr addr;
- uint16_t
- dummy; /* FIXME: Strange dummy space. Needed on gcc 4.8.3/clang 3.4.1 on
- x86_64 */
uint16_t f_stratum;
uint16_t f_leap_status;
tTimeval f_ref_time;
return p_buf;
}
+static void nreftostr(uint32_t nrefid, char *p_buf, size_t p_buf_size) {
+ size_t j = 0;
+
+ for (int i = 0; i < 4; i++) {
+ int c = ntohl(nrefid) << i * 8 >> 24;
+ if (!isalnum(c) || j + 1 >= p_buf_size)
+ continue;
+ p_buf[j++] = c;
+ }
+ if (j < p_buf_size)
+ p_buf[j] = '\0';
+}
+
static int chrony_set_timeout(void) {
/* Set the socket's timeout to g_chrony_timeout; a value of 0 signals
* infinite timeout */
}
}
+static void chrony_flush_recv_queue(void) {
+ char buf[1];
+
+ if (g_chrony_is_connected) {
+ while (recv(g_chrony_socket, buf, sizeof(buf), MSG_DONTWAIT) > 0)
+ ;
+ }
+}
+
static int chrony_query(const int p_command, tChrony_Request *p_req,
tChrony_Response *p_resp, size_t *p_resp_size) {
/* Check connection. We simply perform one try as collectd already handles
uint32_t uval;
uval = ntohl(p_float.value);
- exp = (uval >> FLOAT_COEF_BITS) - FLOAT_COEF_BITS;
+ exp = (uval >> FLOAT_COEF_BITS);
if (exp >= 1 << (FLOAT_EXP_BITS - 1))
exp -= 1 << FLOAT_EXP_BITS;
+ exp -= FLOAT_COEF_BITS;
/* coef = (x << FLOAT_EXP_BITS) >> FLOAT_EXP_BITS; */
coef = uval % (1U << FLOAT_COEF_BITS);
static void chrony_push_data(const char *p_type, const char *p_type_inst,
double p_value) {
- value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge =
- p_value; /* TODO: Check type??? (counter, gauge, derive, absolute) */
-
- vl.values = values;
+ vl.values = &(value_t){.gauge = p_value};
vl.values_len = 1;
/* XXX: Shall g_chrony_host/g_chrony_port be reflected in the plugin's output?
*/
- /* hostname_g is set in daemon/collectd.c (from config, via gethostname or by
- * resolving localhost) */
- /* defined as: char hostname_g[DATA_MAX_NAME_LEN]; (never NULL) */
- sstrncpy(vl.host, hostname_g, sizeof(vl.host));
sstrncpy(vl.plugin, PLUGIN_NAME_SHORT, sizeof(vl.plugin));
if (g_chrony_plugin_instance != NULL) {
sstrncpy(vl.plugin_instance, g_chrony_plugin_instance,
chrony_push_data("time_ref", DAEMON_NAME, time_ref); /* unit: s */
chrony_push_data(
"time_offset_ntp", DAEMON_NAME,
- ntohf(
- chrony_resp.body.tracking.f_current_correction)); /* Offset between
- system time and
- NTP, unit: s */
+ ntohf(chrony_resp.body.tracking.f_current_correction)); /* Offset between
+ system time and
+ NTP, unit: s */
chrony_push_data(
"time_offset", DAEMON_NAME,
ntohf(
ntohf(chrony_resp.body.tracking.f_skew_ppm));
chrony_push_data(
"root_delay", DAEMON_NAME,
- ntohf(
- chrony_resp.body.tracking.f_root_delay)); /* Network latency between
- local daemon and the
- current source */
+ ntohf(chrony_resp.body.tracking.f_root_delay)); /* Network latency between
+ local daemon and the
+ current source */
chrony_push_data("root_dispersion", DAEMON_NAME,
ntohf(chrony_resp.body.tracking.f_root_dispersion));
chrony_push_data("clock_last_update", DAEMON_NAME,
return CHRONY_RC_OK;
}
-static int chrony_request_source_data(int p_src_idx, int *p_is_reachable) {
+static int chrony_request_source_data(int p_src_idx, char *src_addr,
+ size_t addr_size, int *p_is_reachable) {
/* Perform Source data request for source #p_src_idx */
int rc;
size_t chrony_resp_size;
tChrony_Request chrony_req;
tChrony_Response chrony_resp;
- char src_addr[IPV6_STR_MAX_SIZE] = {0};
-
chrony_init_req(&chrony_req);
chrony_req.body.source_data.f_index = htonl(p_src_idx);
rc = chrony_query(REQ_SOURCE_DATA, &chrony_req, &chrony_resp,
return rc;
}
- niptoha(&chrony_resp.body.source_data.addr, src_addr, sizeof(src_addr));
+ if (ntohs(chrony_resp.body.source_data.f_mode) == MODE_REFCLOCK)
+ nreftostr(chrony_resp.body.source_data.addr.addr.ip4, src_addr, addr_size);
+ else
+ niptoha(&chrony_resp.body.source_data.addr, src_addr, addr_size);
+
DEBUG(PLUGIN_NAME ": Source[%d] data: .addr = %s, .poll = %u, .stratum = %u, "
".state = %u, .mode = %u, .flags = %u, .reach = %u, "
".latest_meas_ago = %u, .orig_latest_meas = %f, "
chrony_push_data_valid("clock_reachability", src_addr, is_reachable,
ntohs(chrony_resp.body.source_data.f_reachability));
chrony_push_data_valid("clock_last_meas", src_addr, is_reachable,
- ntohs(chrony_resp.body.source_data.f_since_sample));
+ ntohl(chrony_resp.body.source_data.f_since_sample));
+ chrony_push_data_valid(
+ "time_offset", src_addr, is_reachable,
+ ntohf(chrony_resp.body.source_data.f_origin_latest_meas));
return CHRONY_RC_OK;
}
-static int chrony_request_source_stats(int p_src_idx,
+static int chrony_request_source_stats(int p_src_idx, const char *src_addr,
const int *p_is_reachable) {
/* Perform Source stats request for source #p_src_idx */
int rc;
size_t chrony_resp_size;
tChrony_Request chrony_req;
tChrony_Response chrony_resp;
- double skew_ppm, frequency_error, time_offset;
-
- char src_addr[IPV6_STR_MAX_SIZE] = {0};
+ double skew_ppm, frequency_error;
if (*p_is_reachable == 0) {
skew_ppm = 0;
frequency_error = 0;
- time_offset = 0;
} else {
chrony_init_req(&chrony_req);
chrony_req.body.source_stats.f_index = htonl(p_src_idx);
skew_ppm = ntohf(chrony_resp.body.source_stats.f_skew_ppm);
frequency_error = ntohf(chrony_resp.body.source_stats.f_rtc_gain_rate_ppm);
- time_offset = ntohf(chrony_resp.body.source_stats.f_est_offset);
- niptoha(&chrony_resp.body.source_stats.addr, src_addr, sizeof(src_addr));
DEBUG(PLUGIN_NAME
": Source[%d] stat: .addr = %s, .ref_id= %u, .n_samples = %u, "
".n_runs = %u, .span_seconds = %u, .rtc_seconds_fast = %f, "
ntohl(chrony_resp.body.source_stats.f_n_runs),
ntohl(chrony_resp.body.source_stats.f_span_seconds),
ntohf(chrony_resp.body.source_stats.f_rtc_seconds_fast),
- frequency_error, skew_ppm, time_offset,
+ frequency_error, skew_ppm,
+ ntohf(chrony_resp.body.source_stats.f_est_offset),
ntohf(chrony_resp.body.source_stats.f_est_offset_err));
} /* if (*is_reachable) */
chrony_push_data_valid("clock_skew_ppm", src_addr, *p_is_reachable, skew_ppm);
chrony_push_data_valid("frequency_error", src_addr, *p_is_reachable,
frequency_error); /* unit: ppm */
- chrony_push_data_valid("time_offset", src_addr, *p_is_reachable,
- time_offset); /* unit: s */
return CHRONY_RC_OK;
}
g_chrony_seq_is_initialized = 1;
}
+ /* Ignore late responses that may have been received */
+ chrony_flush_recv_queue();
+
/* Get daemon stats */
rc = chrony_request_daemon_stats();
if (rc != CHRONY_RC_OK)
return rc;
for (unsigned int now_src = 0; now_src < n_sources; ++now_src) {
+ char src_addr[IPV6_STR_MAX_SIZE] = {0};
int is_reachable;
- rc = chrony_request_source_data(now_src, &is_reachable);
+ rc = chrony_request_source_data(now_src, src_addr, sizeof(src_addr),
+ &is_reachable);
if (rc != CHRONY_RC_OK)
return rc;
- rc = chrony_request_source_stats(now_src, &is_reachable);
+ rc = chrony_request_source_stats(now_src, src_addr, &is_reachable);
if (rc != CHRONY_RC_OK)
return rc;
}