#include #include #include #include #include #include #include #include "memcached.h" static char *uriencode_map[256]; static char uriencode_str[768]; void uriencode_init(void) { int x; char *str = uriencode_str; for (x = 0; x < 256; x++) { if (isalnum(x) || x == '-' || x == '.' || x == '_' || x == '~') { uriencode_map[x] = NULL; } else { snprintf(str, 4, "%%%02hhX", (unsigned char)x); uriencode_map[x] = str; str += 3; /* lobbing off the \0 is fine */ } } } bool uriencode(const char *src, char *dst, const size_t srclen, const size_t dstlen) { int x; size_t d = 0; for (x = 0; x < srclen; x++) { if (d + 4 > dstlen) return false; if (uriencode_map[(unsigned char) src[x]] != NULL) { memcpy(&dst[d], uriencode_map[(unsigned char) src[x]], 3); d += 3; } else { dst[d] = src[x]; d++; } } dst[d] = '\0'; return true; } /* Avoid warnings on solaris, where isspace() is an index into an array, and gcc uses signed chars */ #define xisspace(c) isspace((unsigned char)c) bool safe_strtoull(const char *str, uint64_t *out) { assert(out != NULL); errno = 0; *out = 0; char *endptr; unsigned long long ull = strtoull(str, &endptr, 10); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { if ((long long) ull < 0) { /* only check for negative signs in the uncommon case when * the unsigned number is so big that it's negative as a * signed number. */ if (strchr(str, '-') != NULL) { return false; } } *out = ull; return true; } return false; } /* Could macro this. Decided to keep this unrolled for safety rather than add * the base parameter to all callers. Very few places need to parse a number * outside of base 10, currently exactly once, so splitting this up should * help avoid typo bugs. */ bool safe_strtoull_hex(const char *str, uint64_t *out) { assert(out != NULL); errno = 0; *out = 0; char *endptr; unsigned long long ull = strtoull(str, &endptr, 16); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { if ((long long) ull < 0) { /* only check for negative signs in the uncommon case when * the unsigned number is so big that it's negative as a * signed number. */ if (strchr(str, '-') != NULL) { return false; } } *out = ull; return true; } return false; } bool safe_strtoll(const char *str, int64_t *out) { assert(out != NULL); errno = 0; *out = 0; char *endptr; long long ll = strtoll(str, &endptr, 10); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { *out = ll; return true; } return false; } bool safe_strtoul(const char *str, uint32_t *out) { char *endptr = NULL; unsigned long l = 0; assert(out); assert(str); *out = 0; errno = 0; l = strtoul(str, &endptr, 10); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { if ((long) l < 0) { /* only check for negative signs in the uncommon case when * the unsigned number is so big that it's negative as a * signed number. */ if (strchr(str, '-') != NULL) { return false; } } *out = l; return true; } return false; } bool safe_strtol(const char *str, int32_t *out) { assert(out != NULL); errno = 0; *out = 0; char *endptr; long l = strtol(str, &endptr, 10); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { *out = l; return true; } return false; } bool safe_strtod(const char *str, double *out) { assert(out != NULL); errno = 0; *out = 0; char *endptr; double d = strtod(str, &endptr); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { *out = d; return true; } return false; } // slow, safe function for copying null terminated buffers. // ensures null terminator set on destination buffer. copies at most dstmax-1 // non-null bytes. // Explicitly avoids over-reading src while looking for the null byte. // returns true if src was fully copied. // returns false if src was truncated into dst. bool safe_strcpy(char *dst, const char *src, const size_t dstmax) { size_t x; for (x = 0; x < dstmax - 1 && src[x] != '\0'; x++) { dst[x] = src[x]; } dst[x] = '\0'; if (src[x] == '\0') { return true; } else { return false; } } bool safe_memcmp(const void *a, const void *b, size_t len) { const volatile unsigned char *ua = (const volatile unsigned char *)a; const volatile unsigned char *ub = (const volatile unsigned char *)b; int delta = 0; size_t x; for (x = 0; x < len; x++) { delta |= ua[x] ^ ub[x]; } if (delta == 0) { return true; } else { return false; } } void vperror(const char *fmt, ...) { int old_errno = errno; char buf[1024]; va_list ap; va_start(ap, fmt); if (vsnprintf(buf, sizeof(buf), fmt, ap) == -1) { buf[sizeof(buf) - 1] = '\0'; } va_end(ap); errno = old_errno; perror(buf); } #ifndef HAVE_HTONLL static uint64_t mc_swap64(uint64_t in) { #ifdef ENDIAN_LITTLE /* Little endian, flip the bytes around until someone makes a faster/better * way to do this. */ int64_t rv = 0; int i = 0; for(i = 0; i<8; i++) { rv = (rv << 8) | (in & 0xff); in >>= 8; } return rv; #else /* big-endian machines don't need byte swapping */ return in; #endif } uint64_t ntohll(uint64_t val) { return mc_swap64(val); } uint64_t htonll(uint64_t val) { return mc_swap64(val); } #endif