1 #include <stdio.h>
2 #include <assert.h>
3 #include <ctype.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdarg.h>
8
9 #include "memcached.h"
10
11 static char *uriencode_map[256];
12 static char uriencode_str[768];
13
uriencode_init(void)14 void uriencode_init(void) {
15 int x;
16 char *str = uriencode_str;
17 for (x = 0; x < 256; x++) {
18 if (isalnum(x) || x == '-' || x == '.' || x == '_' || x == '~') {
19 uriencode_map[x] = NULL;
20 } else {
21 snprintf(str, 4, "%%%02hhX", (unsigned char)x);
22 uriencode_map[x] = str;
23 str += 3; /* lobbing off the \0 is fine */
24 }
25 }
26 }
27
uriencode(const char * src,char * dst,const size_t srclen,const size_t dstlen)28 bool uriencode(const char *src, char *dst, const size_t srclen, const size_t dstlen) {
29 int x;
30 size_t d = 0;
31 for (x = 0; x < srclen; x++) {
32 if (d + 4 > dstlen)
33 return false;
34 if (uriencode_map[(unsigned char) src[x]] != NULL) {
35 memcpy(&dst[d], uriencode_map[(unsigned char) src[x]], 3);
36 d += 3;
37 } else {
38 dst[d] = src[x];
39 d++;
40 }
41 }
42 dst[d] = '\0';
43 return true;
44 }
45
46 /* Avoid warnings on solaris, where isspace() is an index into an array, and gcc uses signed chars */
47 #define xisspace(c) isspace((unsigned char)c)
48
safe_strtoull(const char * str,uint64_t * out)49 bool safe_strtoull(const char *str, uint64_t *out) {
50 assert(out != NULL);
51 errno = 0;
52 *out = 0;
53 char *endptr;
54 unsigned long long ull = strtoull(str, &endptr, 10);
55 if ((errno == ERANGE) || (str == endptr)) {
56 return false;
57 }
58
59 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
60 if ((long long) ull < 0) {
61 /* only check for negative signs in the uncommon case when
62 * the unsigned number is so big that it's negative as a
63 * signed number. */
64 if (memchr(str, '-', endptr - str) != NULL) {
65 return false;
66 }
67 }
68 *out = ull;
69 return true;
70 }
71 return false;
72 }
73
74 /* Could macro this. Decided to keep this unrolled for safety rather than add
75 * the base parameter to all callers. Very few places need to parse a number
76 * outside of base 10, currently exactly once, so splitting this up should
77 * help avoid typo bugs.
78 */
safe_strtoull_hex(const char * str,uint64_t * out)79 bool safe_strtoull_hex(const char *str, uint64_t *out) {
80 assert(out != NULL);
81 errno = 0;
82 *out = 0;
83 char *endptr;
84 unsigned long long ull = strtoull(str, &endptr, 16);
85 if ((errno == ERANGE) || (str == endptr)) {
86 return false;
87 }
88
89 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
90 if ((long long) ull < 0) {
91 /* only check for negative signs in the uncommon case when
92 * the unsigned number is so big that it's negative as a
93 * signed number. */
94 if (memchr(str, '-', endptr - str) != NULL) {
95 return false;
96 }
97 }
98 *out = ull;
99 return true;
100 }
101 return false;
102 }
103
safe_strtoll(const char * str,int64_t * out)104 bool safe_strtoll(const char *str, int64_t *out) {
105 assert(out != NULL);
106 errno = 0;
107 *out = 0;
108 char *endptr;
109 long long ll = strtoll(str, &endptr, 10);
110 if ((errno == ERANGE) || (str == endptr)) {
111 return false;
112 }
113
114 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
115 *out = ll;
116 return true;
117 }
118 return false;
119 }
120
safe_strtoul(const char * str,uint32_t * out)121 bool safe_strtoul(const char *str, uint32_t *out) {
122 char *endptr = NULL;
123 unsigned long l = 0;
124 assert(out);
125 assert(str);
126 *out = 0;
127 errno = 0;
128
129 l = strtoul(str, &endptr, 10);
130 if ((errno == ERANGE) || (str == endptr)) {
131 return false;
132 }
133
134 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
135 if ((long) l < 0) {
136 /* only check for negative signs in the uncommon case when
137 * the unsigned number is so big that it's negative as a
138 * signed number. */
139 if (memchr(str, '-', endptr - str) != NULL) {
140 return false;
141 }
142 }
143 *out = l;
144 return true;
145 }
146
147 return false;
148 }
149
safe_strtol(const char * str,int32_t * out)150 bool safe_strtol(const char *str, int32_t *out) {
151 assert(out != NULL);
152 errno = 0;
153 *out = 0;
154 char *endptr;
155 long l = strtol(str, &endptr, 10);
156 if ((errno == ERANGE) || (str == endptr)) {
157 return false;
158 }
159
160 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
161 *out = l;
162 return true;
163 }
164 return false;
165 }
166
safe_strtod(const char * str,double * out)167 bool safe_strtod(const char *str, double *out) {
168 assert(out != NULL);
169 errno = 0;
170 *out = 0;
171 char *endptr;
172 double d = strtod(str, &endptr);
173 if ((errno == ERANGE) || (str == endptr)) {
174 return false;
175 }
176
177 if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) {
178 *out = d;
179 return true;
180 }
181 return false;
182 }
183
184 // slow, safe function for copying null terminated buffers.
185 // ensures null terminator set on destination buffer. copies at most dstmax-1
186 // non-null bytes.
187 // Explicitly avoids over-reading src while looking for the null byte.
188 // returns true if src was fully copied.
189 // returns false if src was truncated into dst.
safe_strcpy(char * dst,const char * src,const size_t dstmax)190 bool safe_strcpy(char *dst, const char *src, const size_t dstmax) {
191 size_t x;
192
193 for (x = 0; x < dstmax - 1 && src[x] != '\0'; x++) {
194 dst[x] = src[x];
195 }
196
197 dst[x] = '\0';
198
199 if (src[x] == '\0') {
200 return true;
201 } else {
202 return false;
203 }
204 }
205
safe_memcmp(const void * a,const void * b,size_t len)206 bool safe_memcmp(const void *a, const void *b, size_t len) {
207 const volatile unsigned char *ua = (const volatile unsigned char *)a;
208 const volatile unsigned char *ub = (const volatile unsigned char *)b;
209 int delta = 0;
210 size_t x;
211
212 for (x = 0; x < len; x++) {
213 delta |= ua[x] ^ ub[x];
214 }
215
216 if (delta == 0) {
217 return true;
218 } else {
219 return false;
220 }
221 }
222
vperror(const char * fmt,...)223 void vperror(const char *fmt, ...) {
224 int old_errno = errno;
225 char buf[1024];
226 va_list ap;
227
228 va_start(ap, fmt);
229 if (vsnprintf(buf, sizeof(buf), fmt, ap) == -1) {
230 buf[sizeof(buf) - 1] = '\0';
231 }
232 va_end(ap);
233
234 errno = old_errno;
235
236 perror(buf);
237 }
238
239 #ifndef HAVE_HTONLL
mc_swap64(uint64_t in)240 static uint64_t mc_swap64(uint64_t in) {
241 #ifdef ENDIAN_LITTLE
242 /* Little endian, flip the bytes around until someone makes a faster/better
243 * way to do this. */
244 int64_t rv = 0;
245 int i = 0;
246 for(i = 0; i<8; i++) {
247 rv = (rv << 8) | (in & 0xff);
248 in >>= 8;
249 }
250 return rv;
251 #else
252 /* big-endian machines don't need byte swapping */
253 return in;
254 #endif
255 }
256
ntohll(uint64_t val)257 uint64_t ntohll(uint64_t val) {
258 return mc_swap64(val);
259 }
260
htonll(uint64_t val)261 uint64_t htonll(uint64_t val) {
262 return mc_swap64(val);
263 }
264 #endif
265
266