Annotation of embedaddon/ntp/ntpsnmpd/ntpSnmpSubagentObject.c, revision 1.1.1.1
1.1 misho 1: /*****************************************************************************
2: *
3: * ntpSnmpSubAgentObject.c
4: *
5: * This file provides the callback functions for net-snmp and registers the
6: * serviced MIB objects with the master agent.
7: *
8: * Each object has its own callback function that is called by the
9: * master agent process whenever someone queries the corresponding MIB
10: * object.
11: *
12: * At the moment this triggers a full send/receive procedure for each
13: * queried MIB object, one of the things that are still on my todo list:
14: * a caching mechanism that reduces the number of requests sent to the
15: * ntpd process.
16: *
17: ****************************************************************************/
18: #include <ntp_snmp.h>
19: #include <ctype.h>
20: #include <ntp.h>
21: #include <libntpq.h>
22:
23: /* general purpose buffer length definition */
24: #define NTPQ_BUFLEN 2048
25:
26: char ntpvalue[NTPQ_BUFLEN];
27:
28:
29: /*****************************************************************************
30: *
31: * ntpsnmpd_parse_string
32: *
33: * This function will parse a given NULL terminated string and cut it
34: * into a fieldname and a value part (using the '=' as the delimiter.
35: * The fieldname will be converted to uppercase and all whitespace
36: * characters are removed from it.
37: * The value part is stripped, e.g. all whitespace characters are removed
38: * from the beginning and end of the string.
39: * If the value is started and ended with quotes ("), they will be removed
40: * and everything between the quotes is left untouched (including
41: * whitespace)
42: * Example:
43: * server host name = hello world!
44: * will result in a field string "SERVERHOSTNAME" and a value
45: * of "hello world!".
46: * My first Parameter = " is this! "
47: * results in a field string "MYFIRSTPARAMETER" and a value " is this! "
48: ****************************************************************************
49: * Parameters:
50: * string const char * The source string to parse.
51: * NOTE: must be NULL terminated!
52: * field char * The buffer for the field name.
53: * fieldsize size_t The size of the field buffer.
54: * value char * The buffer for the value.
55: * valuesize size_t The size of the value buffer.
56: *
57: * Returns:
58: * size_t length of value string
59: ****************************************************************************/
60:
61: size_t
62: ntpsnmpd_parse_string(
63: const char * string,
64: char * field,
65: size_t fieldsize,
66: char * value,
67: size_t valuesize
68: )
69: {
70: int i;
71: int j;
72: int loop;
73: size_t str_cnt;
74: size_t val_cnt;
75:
76: /* we need at least one byte to work with to simplify */
77: if (fieldsize < 1 || valuesize < 1)
78: return 0;
79:
80: str_cnt = strlen(string);
81:
82: /* Parsing the field name */
83: j = 0;
84: loop = TRUE;
85: for (i = 0; loop && i <= str_cnt; i++) {
86: switch (string[i]) {
87:
88: case '\t': /* Tab */
89: case '\n': /* LF */
90: case '\r': /* CR */
91: case ' ': /* Space */
92: break;
93:
94: case '=':
95: loop = FALSE;
96: break;
97:
98: default:
99: if (j < fieldsize)
100: field[j++] = toupper(string[i]);
101: }
102: }
103:
104: j = min(j, fieldsize - 1);
105: field[j] = '\0';
106:
107: /* Now parsing the value */
108: value[0] = '\0';
109: j = 0;
110: for (val_cnt = 0; i < str_cnt; i++) {
111: if (string[i] > 0x0D && string[i] != ' ')
112: val_cnt = min(j + 1, valuesize - 1);
113:
114: if (value[0] != '\0' ||
115: (string[i] > 0x0D && string[i] != ' ')) {
116: if (j < valuesize)
117: value[j++] = string[i];
118: }
119: }
120: value[val_cnt] = '\0';
121:
122: if (value[0] == '"') {
123: val_cnt--;
124: strncpy(value, &value[1], valuesize);
125: if (val_cnt > 0 && value[val_cnt - 1] == '"') {
126: val_cnt--;
127: value[val_cnt] = '\0';
128: }
129: }
130:
131: return val_cnt;
132: }
133:
134:
135: /*****************************************************************************
136: *
137: * ntpsnmpd_cut_string
138: *
139: * This function will parse a given NULL terminated string and cut it
140: * into fields using the specified delimiter character.
141: * It will then copy the requested field into a destination buffer
142: * Example:
143: * ntpsnmpd_cut_string(read:my:lips:fool, RESULT, ':', 2, sizeof(RESULT))
144: * will copy "lips" to RESULT.
145: ****************************************************************************
146: * Parameters:
147: * src const char * The name of the source string variable
148: * NOTE: must be NULL terminated!
149: * dest char * The name of the string which takes the
150: * requested field content
151: * delim char The delimiter character
152: * fieldnumber int The number of the required field
153: * (start counting with 0)
154: * maxsize size_t The maximum size of dest
155: *
156: * Returns:
157: * size_t length of resulting dest string
158: ****************************************************************************/
159:
160: size_t
161: ntpsnmpd_cut_string(
162: const char * string,
163: char * dest,
164: char delim,
165: int fieldnumber,
166: size_t maxsize
167: )
168: {
169: size_t i;
170: size_t j;
171: int l;
172: size_t str_cnt;
173:
174: if (maxsize < 1)
175: return 0;
176:
177: str_cnt = strlen(string);
178: j = 0;
179: memset(dest, 0, maxsize);
180:
181: /* Parsing the field name */
182: for (i = 0, l = 0; i < str_cnt && l <= fieldnumber; i++) {
183: if (string[i] == delim)
184: l++; /* next field */
185: else if (l == fieldnumber && j < maxsize)
186: dest[j++] = string[i];
187: }
188: j = min(j, maxsize - 1);
189: dest[j] = '\0';
190:
191: return j;
192: }
193:
194:
195: /*****************************************************************************
196: *
197: * read_ntp_value
198: *
199: * This function retrieves the value for a given variable, currently
200: * this only supports sysvars. It starts a full mode 6 send/receive/parse
201: * iteration and needs to be optimized, e.g. by using a caching mechanism
202: *
203: ****************************************************************************
204: * Parameters:
205: * variable char* The name of the required variable
206: * rbuffer char* The buffer where the value goes
207: * maxlength int Max. number of bytes for resultbuf
208: *
209: * Returns:
210: * u_int number of chars that have been copied to
211: * rbuffer
212: ****************************************************************************/
213:
214: size_t
215: read_ntp_value(
216: const char * variable,
217: char * value,
218: size_t valuesize
219: )
220: {
221: size_t sv_len;
222: char sv_data[NTPQ_BUFLEN];
223:
224: memset(sv_data, 0, sizeof(sv_data));
225: sv_len = ntpq_read_sysvars(sv_data, sizeof(sv_data));
226:
227: if (0 == sv_len)
228: return 0;
229: else
230: return ntpq_getvar(sv_data, sv_len, variable, value,
231: valuesize);
232: }
233:
234:
235: /*****************************************************************************
236: *
237: * The get_xxx functions
238: *
239: * The following function calls are callback functions that will be
240: * used by the master agent process to retrieve a value for a requested
241: * MIB object.
242: *
243: ****************************************************************************/
244:
245:
246: int get_ntpEntSoftwareName (netsnmp_mib_handler *handler,
247: netsnmp_handler_registration *reginfo,
248: netsnmp_agent_request_info *reqinfo,
249: netsnmp_request_info *requests)
250: {
251: char ntp_softwarename[NTPQ_BUFLEN];
252:
253: memset (ntp_softwarename, 0, NTPQ_BUFLEN);
254:
255: switch (reqinfo->mode) {
256: case MODE_GET:
257: {
258: if ( read_ntp_value("product", ntpvalue, NTPQ_BUFLEN) )
259: {
260: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
261: (u_char *)ntpvalue,
262: strlen(ntpvalue)
263: );
264: }
265: else if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
266: {
267: ntpsnmpd_cut_string(ntpvalue, ntp_softwarename, ' ', 0, sizeof(ntp_softwarename)-1);
268: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
269: (u_char *)ntp_softwarename,
270: strlen(ntp_softwarename)
271: );
272: } else {
273: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
274: (u_char *)"N/A",
275: 3
276: );
277: }
278: break;
279:
280: }
281:
282:
283: default:
284: /* If we cannot get the information we need, we will return a generic error to the SNMP client */
285: return SNMP_ERR_GENERR;
286: }
287:
288: return SNMP_ERR_NOERROR;
289: }
290:
291:
292: int get_ntpEntSoftwareVersion (netsnmp_mib_handler *handler,
293: netsnmp_handler_registration *reginfo,
294: netsnmp_agent_request_info *reqinfo,
295: netsnmp_request_info *requests)
296: {
297:
298: switch (reqinfo->mode) {
299: case MODE_GET:
300: {
301:
302: if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
303: {
304: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
305: (u_char *)ntpvalue,
306: strlen(ntpvalue)
307: );
308: } else {
309: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
310: (u_char *)"N/A",
311: 3
312: );
313: }
314: break;
315:
316: }
317:
318:
319: default:
320: /* If we cannot get the information we need, we will return a generic error to the SNMP client */
321: return SNMP_ERR_GENERR;
322: }
323:
324: return SNMP_ERR_NOERROR;
325: }
326:
327:
328: int get_ntpEntSoftwareVendor (netsnmp_mib_handler *handler,
329: netsnmp_handler_registration *reginfo,
330: netsnmp_agent_request_info *reqinfo,
331: netsnmp_request_info *requests)
332: {
333:
334: switch (reqinfo->mode) {
335: case MODE_GET:
336: {
337:
338: if ( read_ntp_value("vendor", ntpvalue, NTPQ_BUFLEN) )
339: {
340: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
341: (u_char *)ntpvalue,
342: strlen(ntpvalue)
343: );
344: } else {
345: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
346: (u_char *)"N/A",
347: 3
348: );
349: }
350: break;
351:
352: default:
353: /* If we cannot get the information we need, we will return a generic error to the SNMP client */
354: return SNMP_ERR_GENERR;
355: }
356: }
357: return SNMP_ERR_NOERROR;
358: }
359:
360:
361: int get_ntpEntSystemType (netsnmp_mib_handler *handler,
362: netsnmp_handler_registration *reginfo,
363: netsnmp_agent_request_info *reqinfo,
364: netsnmp_request_info *requests)
365: {
366:
367: switch (reqinfo->mode) {
368: case MODE_GET:
369: {
370:
371: if ( read_ntp_value("systemtype", ntpvalue, NTPQ_BUFLEN) )
372: {
373: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
374: (u_char *)ntpvalue,
375: strlen(ntpvalue)
376: );
377: }
378:
379: if ( read_ntp_value("system", ntpvalue, NTPQ_BUFLEN) )
380: {
381: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
382: (u_char *)ntpvalue,
383: strlen(ntpvalue)
384: );
385: } else {
386: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
387: (u_char *)"N/A",
388: 3
389: );
390: }
391: break;
392:
393: }
394:
395:
396: default:
397: /* If we cannot get the information we need, we will return a generic error to the SNMP client */
398: return SNMP_ERR_GENERR;
399: }
400:
401: return SNMP_ERR_NOERROR;
402: }
403:
404:
405: /*
406: * ntpEntTimeResolution
407: * "The time resolution in integer format, where the resolution
408: * is represented as divisions of a second, e.g., a value of 1000
409: * translates to 1.0 ms."
410: *
411: * ntpEntTimeResolution is a challenge for ntpd, as the resolution is
412: * not known nor exposed by ntpd, only the measured precision (time to
413: * read the clock).
414: *
415: * Logically the resolution must be at least the precision, so report
416: * it as our best approximation of resolution until/unless ntpd provides
417: * better.
418: */
419: int
420: get_ntpEntTimeResolution(
421: netsnmp_mib_handler * handler,
422: netsnmp_handler_registration * reginfo,
423: netsnmp_agent_request_info * reqinfo,
424: netsnmp_request_info * requests
425: )
426: {
427: int precision;
428: u_int32 resolution;
429:
430: switch (reqinfo->mode) {
431:
432: case MODE_GET:
433: if (!read_ntp_value("precision", ntpvalue,
434: sizeof(ntpvalue)))
435: return SNMP_ERR_GENERR;
436: if (1 != sscanf(ntpvalue, "%d", &precision))
437: return SNMP_ERR_GENERR;
438: if (precision >= 0)
439: return SNMP_ERR_GENERR;
440: precision = max(precision, -31);
441: resolution = 1 << -precision;
442: snmp_set_var_typed_value(
443: requests->requestvb,
444: ASN_UNSIGNED,
445: (void *)&resolution,
446: sizeof(resolution));
447: break;
448:
449: default:
450: return SNMP_ERR_GENERR;
451: }
452:
453: return SNMP_ERR_NOERROR;
454: }
455:
456:
457: /*
458: * ntpEntTimePrecision
459: * "The entity's precision in integer format, shows the precision.
460: * A value of -5 would mean 2^-5 = 31.25 ms."
461: */
462: int
463: get_ntpEntTimePrecision(
464: netsnmp_mib_handler * handler,
465: netsnmp_handler_registration * reginfo,
466: netsnmp_agent_request_info * reqinfo,
467: netsnmp_request_info * requests
468: )
469: {
470: int precision;
471: int32 precision32;
472:
473: switch (reqinfo->mode) {
474:
475: case MODE_GET:
476: if (!read_ntp_value("precision", ntpvalue,
477: sizeof(ntpvalue)))
478: return SNMP_ERR_GENERR;
479: if (1 != sscanf(ntpvalue, "%d", &precision))
480: return SNMP_ERR_GENERR;
481: precision32 = (int32)precision;
482: snmp_set_var_typed_value(
483: requests->requestvb,
484: ASN_INTEGER,
485: (void *)&precision32,
486: sizeof(precision32));
487: break;
488:
489: default:
490: return SNMP_ERR_GENERR;
491: }
492:
493: return SNMP_ERR_NOERROR;
494: }
495:
496:
497: int get_ntpEntTimeDistance (netsnmp_mib_handler *handler,
498: netsnmp_handler_registration *reginfo,
499: netsnmp_agent_request_info *reqinfo,
500: netsnmp_request_info *requests)
501: {
502: switch (reqinfo->mode) {
503: case MODE_GET:
504: {
505:
506: if ( read_ntp_value("rootdelay", ntpvalue, NTPQ_BUFLEN) )
507: {
508: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
509: (u_char *)ntpvalue,
510: strlen(ntpvalue)
511: );
512: } else {
513: snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
514: (u_char *)"N/A",
515: 3
516: );
517: }
518: break;
519:
520: }
521:
522:
523: default:
524: /* If we cannot get the information we need, we will return a generic error to the SNMP client */
525: return SNMP_ERR_GENERR;
526: }
527:
528: return SNMP_ERR_NOERROR;
529: }
530:
531:
532: /*
533: *
534: * Initialize sub agent
535: */
536:
537: void
538: init_ntpSnmpSubagentObject(void)
539: {
540: /* Register all MIB objects with the agentx master */
541: NTP_OID_RO( ntpEntSoftwareName, 1, 1, 1, 0);
542: NTP_OID_RO( ntpEntSoftwareVersion, 1, 1, 2, 0);
543: NTP_OID_RO( ntpEntSoftwareVendor, 1, 1, 3, 0);
544: NTP_OID_RO( ntpEntSystemType, 1, 1, 4, 0);
545: NTP_OID_RO( ntpEntTimeResolution, 1, 1, 5, 0);
546: NTP_OID_RO( ntpEntTimePrecision, 1, 1, 6, 0);
547: NTP_OID_RO( ntpEntTimeDistance, 1, 1, 7, 0);
548: }
549:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>