Annotation of embedaddon/ntp/ntpsnmpd/ntpSnmpSubagentObject.c, revision 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>