1 /* chrony plugin for collectd
2 (c) 2015 by Claudius M Zingerli, ZSeng
3 Internas roughly based on the ntpd plugin
9 #include <sys/socket.h>
13 #include "common.h" /* auxiliary functions */
14 #include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
16 static const char *g_config_keys[] =
22 static int g_config_keys_num = STATIC_ARRAY_SIZE (g_config_keys);
24 # define CHRONY_DEFAULT_HOST "localhost"
25 # define CHRONY_DEFAULT_PORT "323"
27 /* Copied from chrony/candm.h */
28 #define PROTO_VERSION_NUMBER 6
30 #define REQ_N_SOURCES 14
31 #define REQ_SOURCE_DATA 15
33 #define PKT_TYPE_CMD_REQUEST 1
34 #define PKT_TYPE_CMD_REPLY 2
37 static int g_is_connected = 0;
38 static int g_chrony_socket = -1;
39 static char *g_chrony_host = NULL;
40 static char *g_chrony_port = NULL;
41 static uint32_t g_chrony_seq = 0;
42 //static char ntpd_port[16];
48 } tChrony_Req_N_Sources;
67 tChrony_Req_N_Sources n_sources;
95 /*****************************************************************************/
96 /* Internal functions */
97 /*****************************************************************************/
98 /* Code from: http://long.ccaba.upc.edu/long/045Guidelines/eva/ipv6.html#daytimeClient6 */
100 connect_client (const char *hostname,
105 struct addrinfo hints, *res, *ressave;
108 memset(&hints, 0, sizeof(struct addrinfo));
110 hints.ai_family = family;
111 hints.ai_socktype = socktype;
113 n = getaddrinfo(hostname, service, &hints, &res);
117 ERROR ("chrony plugin: getaddrinfo error:: [%s]", gai_strerror(n));
126 sockfd = socket(res->ai_family,
132 if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
143 freeaddrinfo(ressave);
147 static int chrony_connect()
149 int socket = connect_client(g_chrony_host, g_chrony_port, AF_UNSPEC, SOCK_DGRAM);
152 ERROR ("chrony plugin: Error connecting to daemon. Errno = %d", errno);
155 g_chrony_socket = socket;
159 static int chrony_send_request(const tChrony_Request *p_req, size_t p_req_size)
161 if (send(g_chrony_socket,p_req,p_req_size,0) < 0)
163 ERROR ("chrony plugin: Error sending packet. Errno = %d", errno);
170 static int chrony_recv_response(tChrony_Response *p_resp, size_t p_resp_max_size, size_t *p_resp_size)
172 ssize_t rc = recv(g_chrony_socket,p_resp,p_resp_max_size,0);
175 ERROR ("chrony plugin: Error receiving packet. Errno = %d", errno);
183 static int chrony_query(int p_command, tChrony_Request *p_req, tChrony_Response *p_resp, size_t *p_resp_size)
185 /* Check connection. We simply perform one try as collectd already handles retries */
189 if (g_is_connected == 0)
191 if (chrony_connect() == 0)
195 ERROR ("chrony plugin: Unable to connect. Errno = %d", errno);
203 int valid_command = 0;
204 size_t req_size = sizeof(p_req->header);
205 size_t resp_size = sizeof(p_resp->header);
209 req_size += sizeof(p_req->body.n_sources);
216 if (valid_command == 0)
221 p_req->header.f_cmd = p_command;
222 p_req->header.f_cmd_try = 0;
223 p_req->header.f_seq = g_chrony_seq++;
225 if (chrony_send_request(p_req,req_size) != 0)
229 if (chrony_recv_response(p_resp,resp_size,p_resp_size) != 0)
239 static void chrony_init_req(tChrony_Request *p_req)
241 p_req->header.f_version = PROTO_VERSION_NUMBER;
242 p_req->header.f_type = PKT_TYPE_CMD_REQUEST;
243 p_req->header.f_dummy0 = 0;
244 p_req->header.f_dummy1 = 0;
245 p_req->header.f_dummy2 = 0;
246 p_req->header.f_dummy3 = 0;
250 /*****************************************************************************/
251 /* Exported functions */
252 /*****************************************************************************/
253 static int chrony_config(const char *p_key, const char *p_value)
255 //Parse config variables
256 if (strcasecmp(p_key, "Host") == 0)
258 if (g_chrony_host != NULL)
260 free (g_chrony_host);
262 if ((g_chrony_host = strdup (p_value)) == NULL)
264 ERROR ("chrony plugin: Error duplicating host name");
267 } else if (strcasecmp(p_key, "Port") == 0)
269 if (g_chrony_port != NULL)
271 free (g_chrony_port);
273 if ((g_chrony_port = strdup (p_value)) == NULL)
275 ERROR ("chrony plugin: Error duplicating port name");
282 static int chrony_read (void)
284 //plugin_dispatch_values (&vl);
286 tChrony_Request chrony_req;
287 tChrony_Response chrony_resp;
288 size_t chrony_resp_size;
290 chrony_init_req(&chrony_req);
291 status = chrony_query (REQ_N_SOURCES, &chrony_req, &chrony_resp, &chrony_resp_size);
294 ERROR ("chrony plugin: chrony_query (REQ_N_SOURCES) failed with status %i", status);
300 static int chrony_shutdown()
305 void module_register (void)
307 plugin_register_config ("chrony", chrony_config, g_config_keys, g_config_keys_num);
308 plugin_register_read ("chrony", chrony_read);
309 plugin_register_shutdown ("chrony", chrony_shutdown);