tools.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:25k
源码类别:

SNMP编程

开发平台:

Unix_Linux

  1. /*
  2.  * tools.c
  3.  */
  4. #define NETSNMP_TOOLS_C 1 /* dont re-define malloc wrappers here */
  5. #include <net-snmp/net-snmp-config.h>
  6. #include <ctype.h>
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #if TIME_WITH_SYS_TIME
  10. # ifdef WIN32
  11. #  include <sys/timeb.h>
  12. # else
  13. #  include <sys/time.h>
  14. # endif
  15. # include <time.h>
  16. #else
  17. # if HAVE_SYS_TIME_H
  18. #  include <sys/time.h>
  19. # else
  20. #  include <time.h>
  21. # endif
  22. #endif
  23. #ifdef HAVE_SYS_SOCKET_H
  24. #include <sys/socket.h>
  25. #endif
  26. #if HAVE_WINSOCK_H
  27. #include <winsock.h>
  28. #endif
  29. #ifdef HAVE_STDLIB_H
  30. #include <stdlib.h>
  31. #endif
  32. #if HAVE_STRING_H
  33. #include <string.h>
  34. #else
  35. #include <strings.h>
  36. #endif
  37. #ifdef HAVE_NETINET_IN_H
  38. #include <netinet/in.h>
  39. #endif
  40. #ifdef HAVE_ARPA_INET_H
  41. #include <arpa/inet.h>
  42. #endif
  43. #ifdef cygwin
  44. #include <windows.h>
  45. #endif
  46. #if HAVE_DMALLOC_H
  47. #include <dmalloc.h>
  48. #endif
  49. #include <net-snmp/types.h>
  50. #include <net-snmp/output_api.h>
  51. #include <net-snmp/utilities.h>
  52. #include <net-snmp/library/tools.h>     /* for "internal" definitions */
  53. #include <net-snmp/library/snmp_api.h>
  54. #include <net-snmp/library/mib.h>
  55. #include <net-snmp/library/scapi.h>
  56. #ifdef WIN32
  57. /**
  58.  * This function is a wrapper for the strdup function.
  59.  */
  60. char * netsnmp_strdup( const char * ptr)
  61. {
  62.     return strdup(ptr);
  63. }
  64. /**
  65.  * This function is a wrapper for the calloc function.
  66.  */
  67. void * netsnmp_calloc(size_t nmemb, size_t size)
  68. {
  69.     return calloc(nmemb, size);
  70. }
  71. /**
  72.  * This function is a wrapper for the malloc function.
  73.  */
  74. void * netsnmp_malloc(size_t size)
  75. {
  76.     return malloc(size);
  77. }
  78. /**
  79.  * This function is a wrapper for the realloc function.
  80.  */
  81. void * netsnmp_realloc( void * ptr, size_t size)
  82. {
  83.     return realloc(ptr, size);
  84. }
  85. /**
  86.  * This function is a wrapper for the free function.
  87.  * It calls free only if the calling parameter has a non-zero value.
  88.  */
  89. void netsnmp_free( void * ptr)
  90. {
  91.     if (ptr)
  92.         free(ptr);
  93. }
  94. #endif /* WIN32 */
  95. /**
  96.  * This function increase the size of the buffer pointed at by *buf, which is
  97.  * initially of size *buf_len.  Contents are preserved **AT THE BOTTOM END OF
  98.  * THE BUFFER**.  If memory can be (re-)allocated then it returns 1, else it
  99.  * returns 0.
  100.  * 
  101.  * @param buf  pointer to a buffer pointer
  102.  * @param buf_len      pointer to current size of buffer in bytes
  103.  * 
  104.  * @note
  105.  * The current re-allocation algorithm is to increase the buffer size by
  106.  * whichever is the greater of 256 bytes or the current buffer size, up to
  107.  * a maximum increase of 8192 bytes.  
  108.  */
  109. int
  110. snmp_realloc(u_char ** buf, size_t * buf_len)
  111. {
  112.     u_char         *new_buf = NULL;
  113.     size_t          new_buf_len = 0;
  114.     if (buf == NULL) {
  115.         return 0;
  116.     }
  117.     if (*buf_len <= 255) {
  118.         new_buf_len = *buf_len + 256;
  119.     } else if (*buf_len > 255 && *buf_len <= 8191) {
  120.         new_buf_len = *buf_len * 2;
  121.     } else if (*buf_len > 8191) {
  122.         new_buf_len = *buf_len + 8192;
  123.     }
  124.     if (*buf == NULL) {
  125.         new_buf = (u_char *) malloc(new_buf_len);
  126.     } else {
  127.         new_buf = (u_char *) realloc(*buf, new_buf_len);
  128.     }
  129.     if (new_buf != NULL) {
  130.         *buf = new_buf;
  131.         *buf_len = new_buf_len;
  132.         return 1;
  133.     } else {
  134.         return 0;
  135.     }
  136. }
  137. int
  138. snmp_strcat(u_char ** buf, size_t * buf_len, size_t * out_len,
  139.             int allow_realloc, const u_char * s)
  140. {
  141.     if (buf == NULL || buf_len == NULL || out_len == NULL) {
  142.         return 0;
  143.     }
  144.     if (s == NULL) {
  145.         /*
  146.          * Appending a NULL string always succeeds since it is a NOP.  
  147.          */
  148.         return 1;
  149.     }
  150.     while ((*out_len + strlen((const char *) s) + 1) >= *buf_len) {
  151.         if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
  152.             return 0;
  153.         }
  154.     }
  155.     strcpy((char *) (*buf + *out_len), (const char *) s);
  156.     *out_len += strlen((char *) (*buf + *out_len));
  157.     return 1;
  158. }
  159. /** zeros memory before freeing it.
  160.  *
  161.  * @param *buf Pointer at bytes to free.
  162.  * @param size Number of bytes in buf.
  163.  */
  164. void
  165. free_zero(void *buf, size_t size)
  166. {
  167.     if (buf) {
  168.         memset(buf, 0, size);
  169.         free(buf);
  170.     }
  171. }                               /* end free_zero() */
  172. /**
  173.  * Returns pointer to allocaed & set buffer on success, size contains
  174.  * number of random bytes filled.  buf is NULL and *size set to KMT
  175.  * error value upon failure.
  176.  *
  177.  * @param size Number of bytes to malloc() and fill with random bytes.
  178.  *
  179.  * @return a malloced buffer
  180.  *
  181.  */
  182. u_char         *
  183. malloc_random(size_t * size)
  184. {
  185.     int             rval = SNMPERR_SUCCESS;
  186.     u_char         *buf = (u_char *) calloc(1, *size);
  187.     if (buf) {
  188.         rval = sc_random(buf, size);
  189.         if (rval < 0) {
  190.             free_zero(buf, *size);
  191.             buf = NULL;
  192.         } else {
  193.             *size = rval;
  194.         }
  195.     }
  196.     return buf;
  197. }                               /* end malloc_random() */
  198. /** Duplicates a memory block.
  199.  *  Copies a existing memory location from a pointer to another, newly
  200.     malloced, pointer.
  201.  * @param to       Pointer to allocate and copy memory to.
  202.  *      @param from     Pointer to copy memory from.
  203.  *      @param size     Size of the data to be copied.
  204.  *      
  205.  * @return SNMPERR_SUCCESS on success, SNMPERR_GENERR on failure.
  206.  */
  207. int
  208. memdup(u_char ** to, const u_char * from, size_t size)
  209. {
  210.     if (to == NULL)
  211.         return SNMPERR_GENERR;
  212.     if (from == NULL) {
  213.         *to = NULL;
  214.         return SNMPERR_SUCCESS;
  215.     }
  216.     if ((*to = (u_char *) malloc(size)) == NULL)
  217.         return SNMPERR_GENERR;
  218.     memcpy(*to, from, size);
  219.     return SNMPERR_SUCCESS;
  220. }                               /* end memdup() */
  221. /** copies a (possible) unterminated string of a given length into a
  222.  *  new buffer and null terminates it as well (new buffer MAY be one
  223.  *  byte longer to account for this */
  224. char           *
  225. netsnmp_strdup_and_null(const u_char * from, size_t from_len)
  226. {
  227.     u_char         *ret;
  228.     if (from_len == 0 || from[from_len - 1] != '') {
  229.         ret = malloc(from_len + 1);
  230.         if (!ret)
  231.             return NULL;
  232.         ret[from_len] = '';
  233.     } else {
  234.         ret = malloc(from_len);
  235.         if (!ret)
  236.             return NULL;
  237.         ret[from_len - 1] = '';
  238.     }
  239.     memcpy(ret, from, from_len);
  240.     return ret;
  241. }
  242. /** converts binary to hexidecimal
  243.  *
  244.  * @param *input Binary data.
  245.  * @param len Length of binary data.
  246.  * @param **output NULL terminated string equivalent in hex.
  247.  *      
  248.  * @return olen Length of output string not including NULL terminator.
  249.  *
  250.  * FIX Is there already one of these in the UCD SNMP codebase?
  251.  * The old one should be used, or this one should be moved to
  252.  * snmplib/snmp_api.c.
  253.  */
  254. u_int
  255. binary_to_hex(const u_char * input, size_t len, char **output)
  256. {
  257.     u_int           olen = (len * 2) + 1;
  258.     char           *s = (char *) calloc(1, olen), *op = s;
  259.     const u_char   *ip = input;
  260.     while (ip - input < (int) len) {
  261.         *op++ = VAL2HEX((*ip >> 4) & 0xf);
  262.         *op++ = VAL2HEX(*ip & 0xf);
  263.         ip++;
  264.     }
  265.     *op = '';
  266.     *output = s;
  267.     return olen;
  268. }                               /* end binary_to_hex() */
  269. /**
  270.  * hex_to_binary2
  271.  * @param *input Printable data in base16.
  272.  * @param len Length in bytes of data.
  273.  * @param **output Binary data equivalent to input.
  274.  *      
  275.  * @return SNMPERR_GENERR on failure, otherwise length of allocated string.
  276.  *
  277.  * Input of an odd length is right aligned.
  278.  *
  279.  * FIX Another version of "hex-to-binary" which takes odd length input
  280.  * strings.  It also allocates the memory to hold the binary data.
  281.  * Should be integrated with the official hex_to_binary() function.
  282.  */
  283. int
  284. hex_to_binary2(const u_char * input, size_t len, char **output)
  285. {
  286.     u_int           olen = (len / 2) + (len % 2);
  287.     char           *s = (char *) calloc(1, (olen) ? olen : 1), *op = s;
  288.     const u_char   *ip = input;
  289.     *output = NULL;
  290.     *op = 0;
  291.     if (len % 2) {
  292.         if (!isxdigit(*ip))
  293.             goto hex_to_binary2_quit;
  294.         *op++ = HEX2VAL(*ip);
  295.         ip++;
  296.     }
  297.     while (ip - input < (int) len) {
  298.         if (!isxdigit(*ip))
  299.             goto hex_to_binary2_quit;
  300.         *op = HEX2VAL(*ip) << 4;
  301.         ip++;
  302.         if (!isxdigit(*ip))
  303.             goto hex_to_binary2_quit;
  304.         *op++ += HEX2VAL(*ip);
  305.         ip++;
  306.     }
  307.     *output = s;
  308.     return olen;
  309.   hex_to_binary2_quit:
  310.     free_zero(s, olen);
  311.     return -1;
  312. }                               /* end hex_to_binary2() */
  313. int
  314. snmp_decimal_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
  315.                        int allow_realloc, const char *decimal)
  316. {
  317.     int             subid = 0;
  318.     const char     *cp = decimal;
  319.     if (buf == NULL || buf_len == NULL || out_len == NULL
  320.         || decimal == NULL) {
  321.         return 0;
  322.     }
  323.     while (*cp != '') {
  324.         if (isspace((int) *cp) || *cp == '.') {
  325.             cp++;
  326.             continue;
  327.         }
  328.         if (!isdigit((int) *cp)) {
  329.             return 0;
  330.         }
  331.         if ((subid = atoi(cp)) > 255) {
  332.             return 0;
  333.         }
  334.         if ((*out_len >= *buf_len) &&
  335.             !(allow_realloc && snmp_realloc(buf, buf_len))) {
  336.             return 0;
  337.         }
  338.         *(*buf + *out_len) = (u_char) subid;
  339.         (*out_len)++;
  340.         while (isdigit((int) *cp)) {
  341.             cp++;
  342.         }
  343.     }
  344.     return 1;
  345. }
  346. /**
  347.  * convert an ASCII hex string (with specified delimiters) to binary
  348.  *
  349.  * @param buf     address of a pointer (pointer to pointer) for the output buffer.
  350.  *                If allow_realloc is set, the buffer may be grown via snmp_realloc
  351.  *                to accomodate the data.
  352.  *
  353.  * @param buf_len pointer to a size_t containing the initial size of buf.
  354.  *
  355.  * @param out_len On input, a pointer to a size_t indicating an offset into buf.
  356.  *                The  binary data will be stored at this offset.
  357.  *                On output, this pointer will have updated the offset to be
  358.  *                the first byte after the converted data.
  359.  *
  360.  * @param allow_realloc If true, the buffer can be reallocated. If false, and
  361.  *                      the buffer is not large enough to contain the string,
  362.  *                      an error will be returned.
  363.  *
  364.  * @param hex     pointer to hex string to be converted. May be prefixed by
  365.  *                "0x" or "0X".
  366.  *
  367.  * @param delim   point to a string of allowed delimiters between bytes.
  368.  *                If not specified, any non-hex characters will be an error.
  369.  *
  370.  * @retval 1  success
  371.  * @retval 0  error
  372.  */
  373. int
  374. netsnmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
  375.                       int allow_realloc, const char *hex, const char *delim)
  376. {
  377.     int             subid = 0;
  378.     const char     *cp = hex;
  379.     if (buf == NULL || buf_len == NULL || out_len == NULL || hex == NULL) {
  380.         return 0;
  381.     }
  382.     if ((*cp == '0') && ((*(cp + 1) == 'x') || (*(cp + 1) == 'X'))) {
  383.         cp += 2;
  384.     }
  385.     while (*cp != '') {
  386.         if (!isxdigit((int) *cp)) {
  387.             if ((NULL != delim) && (NULL != strchr(delim, *cp))) {
  388.                 cp++;
  389.                 continue;
  390.             }
  391.             return 0;
  392.         }
  393.         if (sscanf(cp, "%2x", &subid) == 0) {
  394.             return 0;
  395.         }
  396.         /*
  397.          * if we dont' have enough space, realloc.
  398.          * (snmp_realloc will adjust buf_len to new size)
  399.          */
  400.         if ((*out_len >= *buf_len) &&
  401.             !(allow_realloc && snmp_realloc(buf, buf_len))) {
  402.             return 0;
  403.         }
  404.         *(*buf + *out_len) = (u_char) subid;
  405.         (*out_len)++;
  406.         if (*++cp == '') {
  407.             /*
  408.              * Odd number of hex digits is an error.  
  409.              */
  410.             return 0;
  411.         } else {
  412.             cp++;
  413.         }
  414.     }
  415.     return 1;
  416. }
  417. /**
  418.  * convert an ASCII hex string to binary
  419.  *
  420.  * @note This is a wrapper which calls netsnmp_hex_to_binary with a
  421.  * delimiter string of " ".
  422.  *
  423.  * See netsnmp_hex_to_binary for parameter descriptions.
  424.  *
  425.  * @retval 1  success
  426.  * @retval 0  error
  427.  */
  428. int
  429. snmp_hex_to_binary(u_char ** buf, size_t * buf_len, size_t * out_len,
  430.                    int allow_realloc, const char *hex)
  431. {
  432.     return netsnmp_hex_to_binary(buf, buf_len, out_len, allow_realloc, hex, " ");
  433. }
  434. /*******************************************************************-o-******
  435.  * dump_chunk
  436.  *
  437.  * Parameters:
  438.  * *title (May be NULL.)
  439.  * *buf
  440.  *  size
  441.  */
  442. void
  443. dump_chunk(const char *debugtoken, const char *title, const u_char * buf,
  444.            int size)
  445. {
  446.     u_int           printunit = 64;     /* XXX  Make global. */
  447.     char            chunk[SNMP_MAXBUF], *s, *sp;
  448.     if (title && (*title != '')) {
  449.         DEBUGMSGTL((debugtoken, "%sn", title));
  450.     }
  451.     memset(chunk, 0, SNMP_MAXBUF);
  452.     size = binary_to_hex(buf, size, &s);
  453.     sp = s;
  454.     while (size > 0) {
  455.         if (size > (int) printunit) {
  456.             strncpy(chunk, sp, printunit);
  457.             chunk[printunit] = '';
  458.             DEBUGMSGTL((debugtoken, "t%sn", chunk));
  459.         } else {
  460.             DEBUGMSGTL((debugtoken, "t%sn", sp));
  461.         }
  462.         sp += printunit;
  463.         size -= printunit;
  464.     }
  465.     SNMP_FREE(s);
  466. }                               /* end dump_chunk() */
  467. /*******************************************************************-o-******
  468.  * dump_snmpEngineID
  469.  *
  470.  * Parameters:
  471.  * *estring
  472.  * *estring_len
  473.  *      
  474.  * Returns:
  475.  * Allocated memory pointing to a string of buflen char representing
  476.  * a printf'able form of the snmpEngineID.
  477.  *
  478.  * -OR- NULL on error.
  479.  *
  480.  *
  481.  * Translates the snmpEngineID TC into a printable string.  From RFC 2271,
  482.  * Section 5 (pp. 36-37):
  483.  *
  484.  * First bit: 0 Bit string structured by means non-SNMPv3.
  485.  *   1 Structure described by SNMPv3 SnmpEngineID TC.
  486.  *  
  487.  * Bytes 1-4: Enterprise ID.  (High bit of first byte is ignored.)
  488.  *  
  489.  * Byte 5: 0 (RESERVED by IANA.)
  490.  *   1 IPv4 address. (   4 octets)
  491.  *   2 IPv6 address. (  16 octets)
  492.  *   3 MAC address. (   6 octets)
  493.  *   4 Locally defined text. (0-27 octets)
  494.  *   5 Locally defined octets. (0-27 octets)
  495.  *   6-127 (RESERVED for enterprise.)
  496.  *  
  497.  * Bytes 6-32: (Determined by byte 5.)
  498.  *  
  499.  *
  500.  * Non-printable characters are given in hex.  Text is given in quotes.
  501.  * IP and MAC addresses are given in standard (UN*X) conventions.  Sections
  502.  * are comma separated.
  503.  *
  504.  * esp, remaining_len and s trace the state of the constructed buffer.
  505.  * s will be defined if there is something to return, and it will point
  506.  * to the end of the constructed buffer.
  507.  *
  508.  *
  509.  * ASSUME  "Text" means printable characters.
  510.  *
  511.  * XXX Must the snmpEngineID always have a minimum length of 12?
  512.  * (Cf. part 2 of the TC definition.)
  513.  * XXX Does not enforce upper-bound of 32 bytes.
  514.  * XXX Need a switch to decide whether to use DNS name instead of a simple
  515.  * IP address.
  516.  *
  517.  * FIX Use something other than snprint_hexstring which doesn't add 
  518.  * trailing spaces and (sometimes embedded) newlines...
  519.  */
  520. #ifdef SNMP_TESTING_CODE
  521. char           *
  522. dump_snmpEngineID(const u_char * estring, size_t * estring_len)
  523. {
  524. #define eb(b) ( *(esp+b) & 0xff )
  525.     int             rval = SNMPERR_SUCCESS, gotviolation = 0, slen = 0;
  526.     u_int           remaining_len;
  527.     char            buf[SNMP_MAXBUF], *s = NULL, *t;
  528.     const u_char   *esp = estring;
  529.     struct in_addr  iaddr;
  530.     /*
  531.      * Sanity check.
  532.      */
  533.     if (!estring || (*estring_len <= 0)) {
  534.         QUITFUN(SNMPERR_GENERR, dump_snmpEngineID_quit);
  535.     }
  536.     remaining_len = *estring_len;
  537.     memset(buf, 0, SNMP_MAXBUF);
  538.     /*
  539.      * Test first bit.  Return immediately with a hex string, or
  540.      * begin by formatting the enterprise ID.
  541.      */
  542.     if (!(*esp & 0x80)) {
  543.         snprint_hexstring(buf, SNMP_MAXBUF, esp, remaining_len);
  544.         s = strchr(buf, '');
  545.         s -= 1;
  546.         goto dump_snmpEngineID_quit;
  547.     }
  548.     s = buf;
  549.     s += sprintf(s, "enterprise %d, ", ((*(esp + 0) & 0x7f) << 24) |
  550.                  ((*(esp + 1) & 0xff) << 16) |
  551.                  ((*(esp + 2) & 0xff) << 8) | ((*(esp + 3) & 0xff)));
  552.     /*
  553.      * XXX  Ick. 
  554.      */
  555.     if (remaining_len < 5) {    /* XXX  Violating string. */
  556.         goto dump_snmpEngineID_quit;
  557.     }
  558.     esp += 4;                   /* Incremented one more in the switch below. */
  559.     remaining_len -= 5;
  560.     /*
  561.      * Act on the fifth byte.
  562.      */
  563.     switch ((int) *esp++) {
  564.     case 1:                    /* IPv4 address. */
  565.         if (remaining_len < 4)
  566.             goto dump_snmpEngineID_violation;
  567.         memcpy(&iaddr.s_addr, esp, 4);
  568.         if (!(t = inet_ntoa(iaddr)))
  569.             goto dump_snmpEngineID_violation;
  570.         s += sprintf(s, "%s", t);
  571.         esp += 4;
  572.         remaining_len -= 4;
  573.         break;
  574.     case 2:                    /* IPv6 address. */
  575.         if (remaining_len < 16)
  576.             goto dump_snmpEngineID_violation;
  577.         s += sprintf(s,
  578.                      "%02X%02X %02X%02X %02X%02X %02X%02X::"
  579.                      "%02X%02X %02X%02X %02X%02X %02X%02X",
  580.                      eb(0), eb(1), eb(2), eb(3),
  581.                      eb(4), eb(5), eb(6), eb(7),
  582.                      eb(8), eb(9), eb(10), eb(11),
  583.                      eb(12), eb(13), eb(14), eb(15));
  584.         esp += 16;
  585.         remaining_len -= 16;
  586.         break;
  587.     case 3:                    /* MAC address. */
  588.         if (remaining_len < 6)
  589.             goto dump_snmpEngineID_violation;
  590.         s += sprintf(s, "%02X:%02X:%02X:%02X:%02X:%02X",
  591.                      eb(0), eb(1), eb(2), eb(3), eb(4), eb(5));
  592.         esp += 6;
  593.         remaining_len -= 6;
  594.         break;
  595.     case 4:                    /* Text. */
  596.         /*
  597.          * Doesn't exist on all (many) architectures 
  598.          */
  599.         /*
  600.          * s += snprintf(s, remaining_len+3, ""%s"", esp); 
  601.          */
  602.         s += sprintf(s, ""%s"", esp);
  603.         goto dump_snmpEngineID_quit;
  604.         break;
  605.      /*NOTREACHED*/ case 5:    /* Octets. */
  606.         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
  607.                           esp, remaining_len);
  608.         s = strchr(buf, '');
  609.         s -= 1;
  610.         goto dump_snmpEngineID_quit;
  611.         break;
  612.        /*NOTREACHED*/ dump_snmpEngineID_violation:
  613.     case 0:                    /* Violation of RESERVED, 
  614.                                  * *   -OR- of expected length.
  615.                                  */
  616.         gotviolation = 1;
  617.         s += sprintf(s, "!!! ");
  618.     default:                   /* Unknown encoding. */
  619.         if (!gotviolation) {
  620.             s += sprintf(s, "??? ");
  621.         }
  622.         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
  623.                           esp, remaining_len);
  624.         s = strchr(buf, '');
  625.         s -= 1;
  626.         goto dump_snmpEngineID_quit;
  627.     }                           /* endswitch */
  628.     /*
  629.      * Cases 1-3 (IP and MAC addresses) should not have trailing
  630.      * octets, but perhaps they do.  Throw them in too.  XXX
  631.      */
  632.     if (remaining_len > 0) {
  633.         s += sprintf(s, " (??? ");
  634.         snprint_hexstring(s, (SNMP_MAXBUF - (s-buf)),
  635.                           esp, remaining_len);
  636.         s = strchr(buf, '');
  637.         s -= 1;
  638.         s += sprintf(s, ")");
  639.     }
  640.   dump_snmpEngineID_quit:
  641.     if (s) {
  642.         slen = s - buf + 1;
  643.         s = calloc(1, slen);
  644.         memcpy(s, buf, (slen) - 1);
  645.     }
  646.     memset(buf, 0, SNMP_MAXBUF);        /* XXX -- Overkill? XXX: Yes! */
  647.     return s;
  648. #undef eb
  649. }                               /* end dump_snmpEngineID() */
  650. #endif                          /* SNMP_TESTING_CODE */
  651. /**
  652.  * create a new time marker.
  653.  * NOTE: Caller must free time marker when no longer needed.
  654.  */
  655. marker_t
  656. atime_newMarker(void)
  657. {
  658.     marker_t        pm = (marker_t) calloc(1, sizeof(struct timeval));
  659.     gettimeofday((struct timeval *) pm, 0);
  660.     return pm;
  661. }
  662. /**
  663.  * set a time marker.
  664.  */
  665. void
  666. atime_setMarker(marker_t pm)
  667. {
  668.     if (!pm)
  669.         return;
  670.     gettimeofday((struct timeval *) pm, 0);
  671. }
  672. /**
  673.  * Returns the difference (in msec) between the two markers
  674.  */
  675. long
  676. atime_diff(marker_t first, marker_t second)
  677. {
  678.     struct timeval *tv1, *tv2, diff;
  679.     tv1 = (struct timeval *) first;
  680.     tv2 = (struct timeval *) second;
  681.     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
  682.     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
  683.     return (diff.tv_sec * 1000 + diff.tv_usec / 1000);
  684. }
  685. /**
  686.  * Returns the difference (in u_long msec) between the two markers
  687.  */
  688. u_long
  689. uatime_diff(marker_t first, marker_t second)
  690. {
  691.     struct timeval *tv1, *tv2, diff;
  692.     tv1 = (struct timeval *) first;
  693.     tv2 = (struct timeval *) second;
  694.     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
  695.     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
  696.     return (((u_long) diff.tv_sec) * 1000 + diff.tv_usec / 1000);
  697. }
  698. /**
  699.  * Returns the difference (in u_long 1/100th secs) between the two markers
  700.  * (functionally this is what sysUpTime needs)
  701.  */
  702. u_long
  703. uatime_hdiff(marker_t first, marker_t second)
  704. {
  705.     struct timeval *tv1, *tv2, diff;
  706.     u_long          res;
  707.     tv1 = (struct timeval *) first;
  708.     tv2 = (struct timeval *) second;
  709.     diff.tv_sec = tv2->tv_sec - tv1->tv_sec - 1;
  710.     diff.tv_usec = tv2->tv_usec - tv1->tv_usec + 1000000;
  711.     res = ((u_long) diff.tv_sec) * 100 + diff.tv_usec / 10000;
  712.     return res;
  713. }
  714. /**
  715.  * Test: Has (marked time plus delta) exceeded current time (in msec) ?
  716.  * Returns 0 if test fails or cannot be tested (no marker).
  717.  */
  718. int
  719. atime_ready(marker_t pm, int deltaT)
  720. {
  721.     marker_t        now;
  722.     long            diff;
  723.     if (!pm)
  724.         return 0;
  725.     now = atime_newMarker();
  726.     diff = atime_diff(pm, now);
  727.     free(now);
  728.     if (diff < deltaT)
  729.         return 0;
  730.     return 1;
  731. }
  732. /**
  733.  * Test: Has (marked time plus delta) exceeded current time (in msec) ?
  734.  * Returns 0 if test fails or cannot be tested (no marker).
  735.  */
  736. int
  737. uatime_ready(marker_t pm, unsigned int deltaT)
  738. {
  739.     marker_t        now;
  740.     u_long          diff;
  741.     if (!pm)
  742.         return 0;
  743.     now = atime_newMarker();
  744.     diff = uatime_diff(pm, now);
  745.     free(now);
  746.     if (diff < deltaT)
  747.         return 0;
  748.     return 1;
  749. }
  750.         /*
  751.          * Time-related utility functions
  752.          */
  753. /**
  754.  * Return the number of timeTicks since the given marker 
  755.  */
  756. int
  757. marker_tticks(marker_t pm)
  758. {
  759.     int             res;
  760.     marker_t        now = atime_newMarker();
  761.     res = atime_diff(pm, now);
  762.     free(now);
  763.     return res / 10;            /* atime_diff works in msec, not csec */
  764. }
  765. int
  766. timeval_tticks(struct timeval *tv)
  767. {
  768.     return marker_tticks((marker_t) tv);
  769. }
  770. /**
  771.  * Non Windows:  Returns a pointer to the desired environment variable  
  772.  *               or NULL if the environment variable does not exist.  
  773.  *               
  774.  * Windows:      Returns a pointer to the desired environment variable  
  775.  *               if it exists.  If it does not, the variable is looked up
  776.  *               in the registry in HKCUNet-SNMP or HKLMNet-SNMP
  777.  *               (whichever it finds first) and stores the result in the 
  778.  *               environment variable.  It then returns a pointer to 
  779.  *               environment variable.
  780.  */
  781. char *netsnmp_getenv(const char *name)
  782. {
  783. #if !defined (WIN32) && !defined (cygwin)
  784.   return (getenv(name));
  785. #else
  786.   char *temp = NULL;  
  787.   HKEY hKey;
  788.   unsigned char * key_value = NULL;
  789.   DWORD key_value_size = 0;
  790.   DWORD key_value_type = 0;
  791.   DWORD getenv_worked = 0;
  792.   DEBUGMSGTL(("read_config", "netsnmp_getenv called with name: %sn",name));
  793.   if (!(name))
  794.     return NULL;
  795.   
  796.   /* Try environment variable first */ 
  797.   temp = getenv(name);
  798.   if (temp) {
  799.     getenv_worked = 1;
  800.     DEBUGMSGTL(("read_config", "netsnmp_getenv will return from ENV: %sn",temp));
  801.   }
  802.   
  803.   /* Next try HKCU */
  804.   if (temp == NULL)
  805.   {
  806.     if (RegOpenKeyExA(
  807.           HKEY_CURRENT_USER, 
  808.           "SOFTWARE\Net-SNMP", 
  809.           0, 
  810.           KEY_QUERY_VALUE, 
  811.           &hKey) == ERROR_SUCCESS) {   
  812.       
  813.       if (RegQueryValueExA(
  814.             hKey, 
  815.             name, 
  816.             NULL, 
  817.             &key_value_type, 
  818.             NULL,               /* Just get the size */
  819.             &key_value_size) == ERROR_SUCCESS) {
  820.         if (key_value)
  821.           SNMP_FREE(key_value);
  822.         /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
  823.          * string data in registry is missing one (which is unlikely).
  824.          */
  825.         key_value = (char *) malloc((sizeof(char) * key_value_size)+sizeof(char));
  826.         
  827.         if (RegQueryValueExA(
  828.               hKey, 
  829.               name, 
  830.               NULL, 
  831.               &key_value_type, 
  832.               key_value, 
  833.               &key_value_size) == ERROR_SUCCESS) {
  834.         }
  835.         temp = key_value;
  836.       }
  837.       RegCloseKey(hKey);
  838.       if (temp)
  839.         DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKCU: %sn",temp));
  840.     }
  841.   }
  842.   /* Next try HKLM */
  843.   if (temp == NULL)
  844.   {
  845.     if (RegOpenKeyExA(
  846.           HKEY_LOCAL_MACHINE, 
  847.           "SOFTWARE\Net-SNMP", 
  848.           0, 
  849.           KEY_QUERY_VALUE, 
  850.           &hKey) == ERROR_SUCCESS) {   
  851.       
  852.       if (RegQueryValueExA(
  853.             hKey, 
  854.             name, 
  855.             NULL, 
  856.             &key_value_type, 
  857.             NULL,               /* Just get the size */
  858.             &key_value_size) == ERROR_SUCCESS) {
  859.         if (key_value)
  860.           SNMP_FREE(key_value);
  861.         /* Allocate memory needed +1 to allow RegQueryValueExA to NULL terminate the
  862.          * string data in registry is missing one (which is unlikely).
  863.          */
  864.         key_value = (char *) malloc((sizeof(char) * key_value_size)+sizeof(char));
  865.         
  866.         if (RegQueryValueExA(
  867.               hKey, 
  868.               name, 
  869.               NULL, 
  870.               &key_value_type, 
  871.               key_value, 
  872.               &key_value_size) == ERROR_SUCCESS) {
  873.         }
  874.         temp = key_value;
  875.       }
  876.       RegCloseKey(hKey);
  877.       if (temp)
  878.         DEBUGMSGTL(("read_config", "netsnmp_getenv will return from HKLM: %sn",temp));
  879.     }
  880.   }
  881.   
  882.   if (temp && !getenv_worked) {
  883.     setenv(name, temp, 1);
  884.     SNMP_FREE(temp);
  885.   }
  886.   DEBUGMSGTL(("read_config", "netsnmp_getenv returning: %sn",getenv(name)));
  887.   return(getenv(name));
  888. #endif
  889. }