1 /*
2  * Copyright (c) 2004-2005 Sean Chittenden <sean@chittenden.org>
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 /* The crc32 functions and data was originally written by Spencer
26  * Garrett <srg@quick.com> and was cleaned from the PostgreSQL source
27  * tree via the files contrib/ltree/crc32.[ch].  No license was
28  * included, therefore it is assumed that this code is public
29  * domain.  Attribution still noted. */
30 
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34 #include <ctype.h>
35 #include <string.h>
36 #include <strings.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <sysexits.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #ifdef __linux
43 # ifndef __USE_POSIX
44 #  define __USE_POSIX
45 #warning "Working around busted-ass Linux header include problems: use FreeBSD instead"
46 #warning "http://www.FreeBSD.org/ - you won't regret it"
47 # endif
48 #endif
49 #include <sys/time.h>
50 #include <sys/socket.h>
51 #include <sys/uio.h>
52 #include <netdb.h>
53 #include <netinet/in.h>
54 #include <netinet/tcp.h>
55 #include <unistd.h>
56 #include <fcntl.h>
57 #include <arpa/inet.h>
58 
59 #define __MEMCACHE__
60 # include "memcache.h"
61 # include "memcache/buffer.h"
62 #undef __MEMCACHE__
63 
64 #ifdef MAX
65 # undef MAX
66 #endif
67 #define MAX(a,b) (((a)>(b))?(a):(b))
68 
69 #ifdef MIN
70 # undef MIN
71 #endif
72 #define MIN(a,b) (((a)<(b))?(a):(b))
73 
74 
75 /* Prototypes for static functions that are mcm_*() safe, but don't
76  * require a memory context. */
77 static void			 mcm_server_init(const struct memcache_ctxt *ctxt, struct memcache_server *ms);
78 
79 /* Prototypes for static functions that require a memory context */
80 static u_int32_t		 mcm_atomic_cmd(struct memcache_ctxt *ctxt, struct memcache *mc,
81 						const char *cmd, const size_t cmd_len,
82 						char *key, const size_t key_len, const u_int32_t val);
83 static int32_t			 mcm_err_func(MCM_ERR_FUNC_SIG);
84 static void			 mcm_fetch_cmd(struct memcache_ctxt *ctxt, struct memcache *mc,
85 					       struct memcache_req *req, const char *cmd, const size_t cmd_len);
86 static char			*mcm_get_line(struct memcache_ctxt *ctxt, struct memcache *mc,
87 					      struct memcache_server *ms);
88 static u_int32_t		 mcm_hash_key_func(MCM_HASH_SIG);
89 static size_t			 mcm_read_fd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms, char *buf, size_t bytes);
90 static void			 mcm_res_cb_free(struct memcache_req *req, struct memcache_res_cb *cb);
91 static struct memcache_res	*mcm_res_new(const struct memcache_ctxt *ctxt);
92 static int			 mcm_server_connect(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms);
93 static struct memcache_server	*mcm_server_connect_next_avail(struct memcache_ctxt *ctxt, struct memcache *mc, const u_int32_t hash);
94 static void			*mcm_server_find_func(const void *ctxt, void *mc, const u_int32_t hash);
95 static int			 mcm_server_readable(struct memcache_ctxt *ctxt, struct memcache_server *ms, struct timeval *tv);
96 static int			 mcm_server_resolve(struct memcache_ctxt *ctxt, struct memcache_server *ms);
97 static size_t			 mcm_server_send_cmd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms);
98 inline static ssize_t		 mcm_server_send_last_cmd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms);
99 static struct memcache_server_stats	*mcm_server_stats_new(const struct memcache_ctxt *ctxt);
100 static int			 mcm_server_writable(struct memcache_ctxt *ctxt, struct memcache_server *ms, struct timeval *tv);
101 static int			 mcm_storage_cmd(struct memcache_ctxt *ctxt, struct memcache *mc,
102 						 const char *cmd, const size_t cmd_len,
103 						 char *key, const size_t key_len,
104 						 const void *val, const size_t bytes,
105 						 const time_t expire, const u_int16_t flags);
106 inline static int32_t		 mcm_validate_key(const struct memcache_ctxt *ctxt, char *key, size_t len);
107 static int32_t			 mcm_validate_key_func(MCM_KEY_VALID_FUNC_SIG);
108 
109 /* Simple macro to test the input of keys. */
110 #define MCM_VALIDATE_KEY(_key, _len)	do { int32_t _validate_ret; \
111 	_validate_ret = mcm_validate_key(ctxt, _key, _len); \
112 	if (_validate_ret != 0) return _validate_ret; \
113 } while(0);
114 
115 #define MCM_VALIDATE_KEY_RET(_key, _len, _ret)	do { int32_t _validate_ret; \
116 	_validate_ret = mcm_validate_key(ctxt, _key, _len); \
117 	if (_validate_ret != 0) return _ret; \
118 } while(0);
119 
120 #define MCM_CLEAN_BUFS(ctxt, ms) do { \
121 	if (ms->rbuf->off == ms->rbuf->len) \
122 		mcm_buf_reset(ctxt, ms->rbuf); \
123 	if (ms->wbuf->off == ms->wbuf->len) \
124 		mcm_buf_reset(ctxt, ms->wbuf); \
125 } while(0)
126 
127 
128 /* This is kinda ugly, but, it saves on some warnings and a tad of
129  * stack space across the library. Note, remember strlen(3) does not
130  * include the trailing null character, but sizeoof() does, so when
131  * computing the sizeof() commands, subtract one from its return. */
132 static const char	str_add_cmd[] = "add ";
133 static const size_t	str_add_len = MCM_CSTRLEN(str_add_cmd);
134 static const char	str_decr_cmd[] = "decr ";
135 static const size_t	str_decr_len = MCM_CSTRLEN(str_decr_cmd);
136 static const char	str_delete_cmd[] = "delete ";
137 static const size_t	str_delete_len = MCM_CSTRLEN(str_delete_cmd);
138 static const char	str_endl[] = "\r\n";
139 static const size_t	str_endl_len = MCM_CSTRLEN(str_endl);
140 static const char	str_get_cmd[] = "get ";
141 static const size_t	str_get_len = MCM_CSTRLEN(str_get_cmd);
142 static const char	str_incr_cmd[] = "incr ";
143 static const size_t	str_incr_len = MCM_CSTRLEN(str_incr_cmd);
144 #ifdef SEAN_HACKS
145 static const char	str_listen_cmd[] = "listen ";
146 static const size_t	str_listen_len = MCM_CSTRLEN(str_listen_cmd);
147 static const char	str_refresh_cmd[] = "refresh ";
148 static const size_t	str_refresh_len = MCM_CSTRLEN(str_refresh_cmd);
149 #endif
150 static const char	str_replace_cmd[] = "replace ";
151 static const size_t	str_replace_len = MCM_CSTRLEN(str_replace_cmd);
152 static const char	str_set_cmd[] = "set ";
153 static const size_t	str_set_len = MCM_CSTRLEN(str_set_cmd);
154 static const char	str_space[] = " ";
155 static const size_t	str_space_len = MCM_CSTRLEN(str_space);
156 
157 
158 /* Set the default error handling context. */
159 static struct memcache_err_ctxt mcGlobalECtxt;
160 
161 /* Set the default memory handling routines to be system defaults. */
162 static struct memcache_ctxt mcGlobalCtxt = {
163   (mcFreeFunc)free,
164   (mcMallocFunc)malloc,
165   (mcMallocFunc)malloc,
166   (mcReallocFunc)realloc,
167   (mcErrFunc)mcm_err_func,
168   (mcKeyValidFunc)mcm_validate_key_func,
169   (mcHashKeyFunc)mcm_hash_key_func,
170   (mcServerFindFunc)mcm_server_find_func,
171   (u_int32_t)0,
172   (struct memcache_buf *)NULL,
173   (struct memcache_buf *)NULL,
174   (u_int32_t)0,
175   (struct memcache_err_ctxt *)&mcGlobalECtxt,
176   (u_int32_t)0
177 };
178 
179 
180 int
mc_add(struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)181 mc_add(struct memcache *mc,
182        char *key, const size_t key_len,
183        const void *val, const size_t bytes,
184        const time_t expire, const u_int16_t flags) {
185   return mcm_storage_cmd(&mcGlobalCtxt, mc, str_add_cmd, str_add_len, key, key_len, val, bytes, expire, flags);
186 }
187 
188 
189 void *
mc_aget(struct memcache * mc,char * key,const size_t len)190 mc_aget(struct memcache *mc, char *key, const size_t len) {
191   return mcm_aget(&mcGlobalCtxt, mc, key, len);
192 }
193 
194 
195 void *
mc_aget2(struct memcache * mc,char * key,const size_t len,size_t * retlen)196 mc_aget2(struct memcache *mc, char *key, const size_t len, size_t *retlen) {
197   return mcm_aget2(&mcGlobalCtxt, mc, key, len, retlen);
198 }
199 
200 
201 #ifdef SEAN_HACKS
202 void *
mc_alisten(struct memcache * mc,char * key,const size_t len)203 mc_alisten(struct memcache *mc, char *key, const size_t len) {
204   return mcm_alisten(&mcGlobalCtxt, mc, key, len);
205 }
206 
207 
208 void *
mc_arefresh(struct memcache * mc,char * key,const size_t len)209 mc_arefresh(struct memcache *mc, char *key, const size_t len) {
210   return mcm_arefresh(&mcGlobalCtxt, mc, key, len);
211 }
212 #endif
213 
214 
215 u_int32_t
mc_decr(struct memcache * mc,char * key,const size_t key_len,const u_int32_t val)216 mc_decr(struct memcache *mc, char *key, const size_t key_len, const u_int32_t val) {
217   return mcm_atomic_cmd(&mcGlobalCtxt, mc, str_decr_cmd, str_decr_len, key, key_len, val);
218 }
219 
220 
221 int
mc_delete(struct memcache * mc,char * key,const size_t key_len,const time_t hold)222 mc_delete(struct memcache *mc, char *key, const size_t key_len, const time_t hold) {
223   return mcm_delete(&mcGlobalCtxt, mc, key, key_len, hold);
224 }
225 
226 
227 int
mc_err_filter_add(const u_int32_t err_mask)228 mc_err_filter_add(const u_int32_t err_mask) {
229   return mcm_err_filter_add(&mcGlobalCtxt, err_mask);
230 }
231 
232 
233 int
mc_err_filter_del(const u_int32_t err_mask)234 mc_err_filter_del(const u_int32_t err_mask) {
235   return mcm_err_filter_del(&mcGlobalCtxt, err_mask);
236 }
237 
238 
239 u_int32_t
mc_err_filter_get(void)240 mc_err_filter_get(void) {
241   return mcm_err_filter_get(&mcGlobalCtxt);
242 }
243 
244 
245 int
mc_err_filter_test(const u_int32_t err_lvl)246 mc_err_filter_test(const u_int32_t err_lvl) {
247   return mcm_err_filter_test(&mcGlobalCtxt, err_lvl);
248 }
249 
250 
251 void
mc_err_test(void)252 mc_err_test(void) {
253   mcm_err_test(&mcGlobalCtxt);
254 }
255 
256 
257 int
mc_flush(struct memcache * mc,struct memcache_server * ms)258 mc_flush(struct memcache *mc, struct memcache_server *ms) {
259   return mcm_flush(&mcGlobalCtxt, mc, ms);
260 }
261 
262 
263 int
mc_flush_all(struct memcache * mc)264 mc_flush_all(struct memcache *mc) {
265   return mcm_flush_all(&mcGlobalCtxt, mc);
266 }
267 
268 
269 void
mc_free(struct memcache * mc)270 mc_free(struct memcache *mc) {
271   mcm_free(&mcGlobalCtxt, mc);
272 }
273 
274 
275 void
mc_get(struct memcache * mc,struct memcache_req * req)276 mc_get(struct memcache *mc, struct memcache_req *req) {
277   mcm_get(&mcGlobalCtxt, mc, req);
278 }
279 
280 
281 struct memcache_ctxt *
mc_global_ctxt(void)282 mc_global_ctxt(void) {
283   return &mcGlobalCtxt;
284 }
285 
286 
287 u_int32_t
mc_hash(const struct memcache * mc,const char * key,const size_t len)288 mc_hash(const struct memcache *mc, const char *key, const size_t len) {
289   return mcGlobalCtxt.mcHashKey(&mcGlobalCtxt, mc, key, len);
290 }
291 
292 
293 u_int32_t
mc_hash_key(const char * key,const size_t len)294 mc_hash_key(const char *key, const size_t len) {
295   return mcGlobalCtxt.mcHashKey(&mcGlobalCtxt, NULL, key, len);
296 }
297 
298 
299 u_int32_t
mc_incr(struct memcache * mc,char * key,const size_t key_len,const u_int32_t val)300 mc_incr(struct memcache *mc, char *key, const size_t key_len, const u_int32_t val) {
301   return mcm_atomic_cmd(&mcGlobalCtxt, mc, str_incr_cmd, str_incr_len, key, key_len, val);
302 }
303 
304 
305 struct memcache *
mc_new(void)306 mc_new(void) {
307   return mcm_new(&mcGlobalCtxt);
308 }
309 
310 
311 #ifdef SEAN_HACKS
312 void
mc_listen(struct memcache * mc,struct memcache_req * req)313 mc_listen(struct memcache *mc, struct memcache_req *req) {
314   mcm_fetch_cmd(&mcGlobalCtxt, mc, req, str_listen_cmd, str_listen_len);
315 }
316 
317 
318 void
mc_refresh(struct memcache * mc,struct memcache_req * req)319 mc_refresh(struct memcache *mc, struct memcache_req *req) {
320   mcm_fetch_cmd(&mcGlobalCtxt, mc, req, str_refresh_cmd, str_refresh_len);
321 }
322 #endif
323 
324 
325 u_int32_t
mc_reldate(void)326 mc_reldate(void) {
327   return MEMCACHE_RELDATE;
328 }
329 
330 
331 int
mc_replace(struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)332 mc_replace(struct memcache *mc,
333 	   char *key, const size_t key_len,
334 	   const void *val, const size_t bytes,
335 	   const time_t expire, const u_int16_t flags) {
336   return mcm_storage_cmd(&mcGlobalCtxt, mc, str_replace_cmd, str_replace_len, key, key_len, val, bytes, expire, flags);
337 }
338 
339 
340 struct memcache_res *
mc_req_add(struct memcache_req * req,char * key,const size_t len)341 mc_req_add(struct memcache_req *req, char *key, const size_t len) {
342   return mcm_req_add(&mcGlobalCtxt, req, key, len);
343 }
344 
345 
346 struct memcache_res *
mc_req_add_ref(struct memcache_req * req,char * key,const size_t len)347 mc_req_add_ref(struct memcache_req *req, char *key, const size_t len) {
348   return mcm_req_add_ref(&mcGlobalCtxt, req, key, len);
349 }
350 
351 
352 void
mc_req_free(struct memcache_req * req)353 mc_req_free(struct memcache_req *req) {
354   mcm_req_free(&mcGlobalCtxt, req);
355 }
356 
357 
358 struct memcache_req *
mc_req_new(void)359 mc_req_new(void) {
360   return mcm_req_new(&mcGlobalCtxt);
361 }
362 
363 
364 int
mc_res_attempted(const struct memcache_res * res)365 mc_res_attempted(const struct memcache_res *res) {
366   return mcm_res_attempted(&mcGlobalCtxt, res);
367 }
368 
369 
370 int
mc_res_found(const struct memcache_res * res)371 mc_res_found(const struct memcache_res *res) {
372   return mcm_res_found(&mcGlobalCtxt, res);
373 }
374 
375 
376 void
mc_res_free(struct memcache_req * req,struct memcache_res * res)377 mc_res_free(struct memcache_req *req, struct memcache_res *res) {
378   mcm_res_free(&mcGlobalCtxt, req, res);
379 }
380 
381 
382 void
mc_res_free_on_delete(struct memcache_res * res,const int fod)383 mc_res_free_on_delete(struct memcache_res *res, const int fod) {
384   mcm_res_free_on_delete(&mcGlobalCtxt, res, fod);
385 }
386 
387 
388 int
mc_res_register_fetch_cb(struct memcache_req * req,struct memcache_res * res,mcResCallback cb,void * misc)389 mc_res_register_fetch_cb(struct memcache_req *req, struct memcache_res *res,
390 			 mcResCallback cb, void *misc) {
391   return mcm_res_register_fetch_cb(&mcGlobalCtxt, req, res, cb, misc);
392 }
393 
394 
395 int
mc_server_activate(struct memcache * mc,struct memcache_server * ms)396 mc_server_activate(struct memcache *mc, struct memcache_server *ms) {
397   return mcm_server_activate(&mcGlobalCtxt, mc, ms);
398 }
399 
400 
401 int
mc_server_activate_all(struct memcache * mc)402 mc_server_activate_all(struct memcache *mc) {
403   return mcm_server_activate_all(&mcGlobalCtxt, mc);
404 }
405 
406 
407 int
mc_server_add(struct memcache * mc,const char * hostname,const char * port)408 mc_server_add(struct memcache *mc, const char *hostname, const char *port) {
409   return mcm_server_add2(&mcGlobalCtxt, mc, hostname, (hostname != NULL ? strlen(hostname) : 0), port, (port != NULL ? strlen(port) : 0));
410 }
411 
412 
413 int
mc_server_add2(struct memcache * mc,const char * hostname,const size_t hostname_len,const char * port,const size_t port_len)414 mc_server_add2(struct memcache *mc, const char *hostname, const size_t hostname_len,
415 	       const char *port, const size_t port_len) {
416   return mcm_server_add2(&mcGlobalCtxt, mc, hostname, hostname_len, port, port_len);
417 }
418 
419 
420 int
mc_server_add3(struct memcache * mc,struct memcache_server * ms)421 mc_server_add3(struct memcache *mc, struct memcache_server *ms) {
422   return mcm_server_add3(&mcGlobalCtxt, mc, ms);
423 }
424 
425 
426 int
mc_server_add4(struct memcache * mc,mc_const char * hostport)427 mc_server_add4(struct memcache *mc, mc_const char *hostport) {
428   return mcm_server_add5(&mcGlobalCtxt, mc, hostport, (hostport != NULL ? strlen(hostport) : 0));
429 }
430 
431 
432 int
mc_server_add5(struct memcache * mc,mc_const char * hostport,const size_t hostlen)433 mc_server_add5(struct memcache *mc, mc_const char *hostport, const size_t hostlen) {
434   return mcm_server_add5(&mcGlobalCtxt, mc, hostport, hostlen);
435 }
436 
437 
438 void
mc_server_deactivate(struct memcache * mc,struct memcache_server * ms)439 mc_server_deactivate(struct memcache *mc, struct memcache_server *ms) {
440   mcm_server_deactivate(&mcGlobalCtxt, mc, ms);
441 }
442 
443 
444 void
mc_server_disconnect(struct memcache_server * ms)445 mc_server_disconnect(struct memcache_server *ms) {
446   mcm_server_disconnect(&mcGlobalCtxt, ms);
447 }
448 
449 
450 void
mc_server_disconnect_all(const struct memcache * mc)451 mc_server_disconnect_all(const struct memcache *mc) {
452   mcm_server_disconnect_all(&mcGlobalCtxt, mc);
453 }
454 
455 
456 struct memcache_server *
mc_server_find(struct memcache * mc,const u_int32_t hash)457 mc_server_find(struct memcache *mc, const u_int32_t hash) {
458   return (struct memcache_server *)mcGlobalCtxt.mcServerFind(&mcGlobalCtxt, mc, hash);
459 }
460 
461 
462 void
mc_server_free(struct memcache_server * ms)463 mc_server_free(struct memcache_server *ms) {
464   mcm_server_free(&mcGlobalCtxt, ms);
465 }
466 
467 
468 struct memcache_server *
mc_server_new(void)469 mc_server_new(void) {
470   return mcm_server_new(&mcGlobalCtxt);
471 }
472 
473 
474 struct memcache_server_stats *
mc_server_stats(struct memcache * mc,struct memcache_server * ms)475 mc_server_stats(struct memcache *mc, struct memcache_server *ms) {
476   return mcm_server_stats(&mcGlobalCtxt, mc, ms);
477 }
478 
479 
480 int
mc_server_timeout(struct memcache_server * ms,const int sec,const int msec)481 mc_server_timeout(struct memcache_server *ms, const int sec, const int msec) {
482   return mcm_server_timeout(&mcGlobalCtxt, ms, sec, msec);
483 }
484 
485 
486 void
mc_server_stats_free(struct memcache_server_stats * s)487 mc_server_stats_free(struct memcache_server_stats *s) {
488   mcm_server_stats_free(&mcGlobalCtxt, s);
489 }
490 
491 
492 int
mc_set(struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)493 mc_set(struct memcache *mc,
494        char *key, const size_t key_len,
495        const void *val, const size_t bytes,
496        const time_t expire, const u_int16_t flags) {
497   return mcm_storage_cmd(&mcGlobalCtxt, mc, str_set_cmd, str_set_len, key, key_len, val, bytes, expire, flags);
498 }
499 
500 
501 struct memcache_server_stats *
mc_stats(struct memcache * mc)502 mc_stats(struct memcache *mc) {
503   return mcm_stats(&mcGlobalCtxt, mc);
504 }
505 
506 
507 char *
mc_strdup(const char * str)508 mc_strdup(const char *str) {
509   return mcm_strndup(&mcGlobalCtxt, str, strlen(str));
510 }
511 
512 
513 char *
mc_strnchr(mc_const char * str,const int c,const size_t len)514 mc_strnchr(mc_const char *str, const int c, const size_t len) {
515   return mcm_strnchr(&mcGlobalCtxt, str, c, len);
516 }
517 
518 
519 char *
mc_strndup(const char * str,const size_t len)520 mc_strndup(const char *str, const size_t len) {
521   return mcm_strndup(&mcGlobalCtxt, str, len);
522 }
523 
524 
525 void
mc_timeout(struct memcache * mc,const int sec,const int msec)526 mc_timeout(struct memcache *mc, const int sec, const int msec) {
527   mcm_timeout(&mcGlobalCtxt, mc, sec, msec);
528 }
529 
530 
531 u_int32_t
mc_vernum(void)532 mc_vernum(void) {
533   return MEMCACHE_VERNUM;
534 }
535 
536 
537 const char *
mc_version(void)538 mc_version(void) {
539   return MEMCACHE_VER;
540 }
541 /* END OF THE SINGLE MEMORY CONTEXT API CALLS (ie: mc_*()) */
542 
543 
544 /* BEGIN MEMORY CONTEXT API (ie: mcm_*())  */
545 int
mcm_add(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)546 mcm_add(struct memcache_ctxt *ctxt, struct memcache *mc,
547 	char *key, const size_t key_len,
548 	const void *val, const size_t bytes,
549 	const time_t expire, const u_int16_t flags) {
550   return mcm_storage_cmd(ctxt, mc, str_add_cmd, str_add_len, key, key_len, val, bytes, expire, flags);
551 }
552 
553 
554 /* Issues a "get" command to the memcache server that should contain
555  * the key.  The result is mcMalloc(3)'ed and it is assumed that the
556  * caller is required to mcFree(3) the memory. */
557 void *
mcm_aget(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t len)558 mcm_aget(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len) {
559   return mcm_aget2(ctxt, mc, key, len, NULL);
560 }
561 
562 
563 /* Issues a "get" command to the memcache server that should contain
564  * the key.  The result is mcMalloc(3)'ed and it is assumed that the
565  * caller is required to mcFree(3) the memory. */
566 void *
mcm_aget2(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t len,size_t * retlen)567 mcm_aget2(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len, size_t *retlen) {
568   struct memcache_req *req;
569   struct memcache_res *res;
570   void *ret;
571 
572   MCM_VALIDATE_KEY_RET(key, len, NULL);
573   req = mcm_req_new(ctxt);
574   res = mcm_req_add_ref(ctxt, req, key, len);
575   mcm_res_free_on_delete(ctxt, res, 0);
576   mcm_get(ctxt, mc, req);
577   if (retlen != NULL)
578     *retlen = res->bytes;
579   ret = res->val;
580   mcm_req_free(ctxt, req);
581   return ret;
582 }
583 
584 
585 #ifdef SEAN_HACKS
586 void *
mcm_alisten(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t len)587 mcm_alisten(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len) {
588   struct memcache_req *req;
589   struct memcache_res *res;
590   void *ret;
591 
592   MCM_VALIDATE_KEY(key, len);
593   req = mcm_req_new(ctxt);
594   res = mcm_req_add_ref(ctxt, req, key, len);
595   mcm_res_free_on_delete(ctxt, res, 0);
596   mcm_listen(ctxt, mc, req);
597   ret = res->val;
598   mcm_req_free(ctxt, req);
599   return ret;
600 }
601 
602 
603 /* Issues a "refresh" command to the memcache server that should
604  * contain the key.  The result is mcMalloc(3)'ed and it is assumed
605  * that the caller is required to mcFree(3) the memory. */
606 void *
mcm_arefresh(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t len)607 mcm_arefresh(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t len) {
608   struct memcache_req *req;
609   struct memcache_res *res;
610   void *ret;
611 
612   MCM_VALIDATE_KEY(key, len);
613   req = mcm_req_new(ctxt);
614   res = mcm_req_add_ref(ctxt, req, key, len);
615   mcm_res_free_on_delete(ctxt, res, 0);
616   mcm_refresh(ctxt, mc, req);
617   ret = res->val;
618   mcm_req_free(ctxt, req);
619   return ret;
620 }
621 #endif
622 
623 
624 static u_int32_t
mcm_atomic_cmd(struct memcache_ctxt * ctxt,struct memcache * mc,const char * cmd,const size_t cmd_len,char * key,const size_t key_len,const u_int32_t val)625 mcm_atomic_cmd(struct memcache_ctxt *ctxt, struct memcache *mc,
626 	       const char *cmd, const size_t cmd_len,
627 	       char *key, const size_t key_len, const u_int32_t val) {
628   struct memcache_server *ms;
629   u_int32_t hash;
630   char *cp, *cur;
631   size_t i;
632   u_int32_t ret;
633   char numbuf[11]; /* 10 == (2 ** 32).to_s.length + '\0'.length */
634 
635   /* Reset errnum on re-entry into memcache(3). */
636   ctxt->errnum = 0;
637 
638   MCM_VALIDATE_KEY(key, key_len);
639 
640   hash = ctxt->mcHashKey(ctxt, mc, key, key_len);
641 
642   ms = mcm_server_connect_next_avail(ctxt, mc, hash);
643   if (ms == NULL) {
644     MCM_ERRX(MCM_ERR_MC_VALID_SERVER);
645     return (u_int32_t)MCM_RET_CODE(0);
646   }
647 
648   mcm_buf_append(ctxt, ms->wbuf, cmd, cmd_len);
649   mcm_buf_append(ctxt, ms->wbuf, key, key_len);
650   mcm_buf_append_char(ctxt, ms->wbuf, ' ');
651 
652   /* Convert the value to a string */
653   i = (size_t)snprintf(numbuf, sizeof(numbuf), "%u", val);
654   if (i < 1) {
655     MCM_ERR(MCM_ERR_LIB_SNPRINTF);
656     MCM_CLEAN_BUFS(ctxt, ms);
657     return (u_int32_t)MCM_RET_CODE(0);
658   }
659 
660   mcm_buf_append(ctxt, ms->wbuf, numbuf, i);
661   mcm_buf_append(ctxt, ms->wbuf, str_endl, str_endl_len);
662 
663   /* Send the command */
664   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
665     MCM_CLEAN_BUFS(ctxt, ms);
666     return 0;
667   }
668 
669   cur = mcm_get_line(ctxt, mc, ms);
670   if (cur != NULL && memcmp(cur, "NOT_FOUND", MCM_CSTRLEN("NOT_FOUND")) == 0) {
671     ctxt->errnum = ENOENT;
672     MCM_CLEAN_BUFS(ctxt, ms);
673     return (u_int32_t)MCM_RET_CODE(0);
674   } else if (cur == NULL) {
675     MCM_CLEAN_BUFS(ctxt, ms);
676     return (u_int32_t)MCM_RET_CODE(0);
677   }
678 
679 
680   /* Try converting the value to an integer. If it succeeds, we've got
681    * a winner. */
682   ret = (u_int32_t)strtol(cur, &cp, 10);
683   if (ret == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
684     MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "strtol(3) failed");
685     MCM_CLEAN_BUFS(ctxt, ms);
686     return (u_int32_t)MCM_RET_CODE(0);
687   }
688 
689 #ifdef DEBUG_MC_PROTO_ASSERT
690   if (*cp != '\r') {
691     MCM_ERRX(MCM_ERR_PROTO);
692     MCM_CLEAN_BUFS(ctxt, ms);
693     return (u_int32_t)MCM_RET_CODE(0);
694   }
695 #endif
696 
697   MCM_CLEAN_BUFS(ctxt, ms);
698   return ret;
699 }
700 
701 
702 u_int32_t
mcm_decr(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const u_int32_t val)703 mcm_decr(struct memcache_ctxt *ctxt, struct memcache *mc, char *key, const size_t key_len, const u_int32_t val) {
704   return mcm_atomic_cmd(ctxt, mc, str_decr_cmd, str_decr_len, key, key_len, val);
705 }
706 
707 
708 int
mcm_delete(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const time_t hold)709 mcm_delete(struct memcache_ctxt *ctxt, struct memcache *mc,
710 	   char *key, const size_t key_len, const time_t hold) {
711   struct memcache_server *ms;
712   u_int32_t hash;
713   char *cp;
714   size_t i;
715   char numbuf[11]; /* 10 == (2 ** 32).to_s.length + '\0'.length */
716 
717   MCM_VALIDATE_KEY(key, key_len);
718 
719   /* Reset ctxt->errnum upon entry into memcache(3). */
720   ctxt->errnum = 0;
721 
722   hash = ctxt->mcHashKey(ctxt, mc, key, key_len);
723 
724   ms = mcm_server_connect_next_avail(ctxt, mc, hash);
725   if (ms == NULL)
726     return (int)MCM_RET_CODE(-1);
727 
728   mcm_buf_append(ctxt, ms->wbuf, str_delete_cmd, str_delete_len);
729   mcm_buf_append(ctxt, ms->wbuf, key, key_len);
730 
731   /* Only send the hold timer if the value is greater than zero */
732   if (hold != 0) {
733     mcm_buf_append_char(ctxt, ms->wbuf, ' ');
734     /* Convert the value to a string */
735     i = (size_t)snprintf(numbuf, sizeof(numbuf), "%u", (u_int32_t)hold);
736     if (i < 1) {
737       MCM_ERR(MCM_ERR_LIB_SNPRINTF);
738       MCM_CLEAN_BUFS(ctxt, ms);
739       return (int)MCM_RET_CODE(-4);
740     }
741 
742     mcm_buf_append(ctxt, ms->wbuf, numbuf, i);
743   }
744 
745   mcm_buf_append(ctxt, ms->wbuf, str_endl, str_endl_len);
746 
747   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
748     MCM_CLEAN_BUFS(ctxt, ms);
749     return (int)MCM_RET_CODE(-3);
750   }
751 
752   cp = mcm_get_line(ctxt, mc, ms);
753   if (cp != NULL && memcmp(cp, "DELETED", MCM_CSTRLEN("DELETED")) == 0) {
754     MCM_CLEAN_BUFS(ctxt, ms);
755     return 0;
756   } else if (cp != NULL && memcmp(cp, "NOT_FOUND", MCM_CSTRLEN("NOT_FOUND")) == 0) {
757     MCM_CLEAN_BUFS(ctxt, ms);
758     return 1;
759   } else {
760     MCM_ERRX_MSG(MCM_ERR_PROTO, cp);
761     MCM_CLEAN_BUFS(ctxt, ms);
762     return (int)MCM_RET_CODE(-5);
763   }
764 }
765 
766 
767 void
mcm_err(const struct memcache_ctxt * ctxt,const u_int32_t flags,const char * funcname,const u_int32_t lineno,const u_int32_t errcode,const char * msg,const u_int32_t msglen,const u_int32_t errlvl)768 mcm_err(const struct memcache_ctxt *ctxt, const u_int32_t flags, const char *funcname, const u_int32_t lineno,
769 	const u_int32_t errcode, const char *msg, const u_int32_t msglen, const u_int32_t errlvl) {
770   struct memcache_err_ctxt *ectxt;
771 
772   bzero(ctxt->ectxt, sizeof(struct memcache_err_ctxt));
773   ectxt = ctxt->ectxt;
774 
775   ectxt->ctxt = ctxt;
776   ectxt->funcname = funcname;
777   ectxt->lineno = lineno;
778   ectxt->errnum = ((flags & NO_ERRNO_FLAG) ? 0 : errno);
779   ectxt->errcode = errcode;
780   ectxt->errmsg = msg;
781   ectxt->errlen = msglen;
782 
783   /* Collect all error handling into one place and dispatch handlers
784    * from here. */
785   switch(errcode) {
786   case MCM_ERR_NONE:
787     ectxt->errstr = "no error";
788     ectxt->severity = MCM_ERR_LVL_NONE;
789     ectxt->sysexit = EX_OK;
790     break;
791   case MCM_ERR_ASSERT:
792     ectxt->errstr = "internal memcache(3) assertion";
793     ectxt->severity = MCM_ERR_LVL_FATAL;
794     ectxt->sysexit = EX_SOFTWARE;
795     break;
796   case MCM_ERR_LIB_SNPRINTF:
797     ectxt->errstr = "snprintf(3) failed to convert the value to a string";
798     ectxt->severity = MCM_ERR_LVL_ERR;
799     ectxt->sysexit = EX_DATAERR;
800     break;
801   case MCM_ERR_LIB_STRTOL:
802     ectxt->errstr = "strtol(3) failed";
803     ectxt->severity = MCM_ERR_LVL_ERR;
804     ectxt->sysexit = EX_DATAERR;
805     break;
806   case MCM_ERR_LIB_STRTOLL:
807     ectxt->errstr = "strtoll(3) failed";
808     ectxt->severity = MCM_ERR_LVL_ERR;
809     ectxt->sysexit = EX_DATAERR;
810     break;
811   case MCM_ERR_MC_RECONN:
812     ectxt->errstr = "connection re-established with server";
813     ectxt->severity = MCM_ERR_LVL_INFO;
814     ectxt->sysexit = EX_OK;
815     break;
816   case MCM_ERR_MC_SEND_CMD:
817     ectxt->errstr = "failed to send command to the memcache server";
818     ectxt->severity = MCM_ERR_LVL_NOTICE;
819     ectxt->sysexit = EX_IOERR;
820     break;
821   case MCM_ERR_MC_SERV_LIST:
822     ectxt->errstr = "no available servers in server list";
823     ectxt->severity = MCM_ERR_LVL_WARN;
824     ectxt->sysexit = EX_DATAERR;
825     break;
826   case MCM_ERR_MC_STORE:
827     ectxt->errstr = "unable to store value";
828     ectxt->severity = MCM_ERR_LVL_NOTICE;
829     ectxt->sysexit = EX_CANTCREAT;
830     break;
831   case MCM_ERR_MC_VALID_SERVER:
832     ectxt->errstr = "unable to find a server to connect to";
833     ectxt->severity = MCM_ERR_LVL_NOTICE;
834     ectxt->sysexit = EX_UNAVAILABLE;
835     break;
836   case MCM_ERR_MEM_MALLOC:
837     ectxt->errstr = "mcMalloc(3) failed";
838     ectxt->severity = MCM_ERR_LVL_ERR;
839     ectxt->sysexit = EX_OSERR;
840     break;
841   case MCM_ERR_MEM_REALLOC:
842     ectxt->errstr = "mcRealloc(3) failed";
843     ectxt->severity = MCM_ERR_LVL_ERR;
844     ectxt->sysexit = EX_OSERR;
845     break;
846   case MCM_ERR_NET_CONNECT:
847     ectxt->errstr = "unable to connect to a server";
848     ectxt->severity = MCM_ERR_LVL_NOTICE;
849     ectxt->sysexit = EX_TEMPFAIL;
850     break;
851   case MCM_ERR_NET_HOST:
852     ectxt->errstr = "unable to lookup/resolve host";
853     ectxt->severity = MCM_ERR_LVL_WARN;
854     ectxt->sysexit = EX_NOHOST;
855     break;
856   case MCM_ERR_PROTO:
857     ectxt->errstr = "memcache(4) protocol error";
858     ectxt->severity = MCM_ERR_LVL_FATAL;
859     ectxt->sysexit = EX_PROTOCOL;
860     break;
861   case MCM_ERR_SYS_CLOSE:
862     ectxt->errstr = "close(2) failed";
863     ectxt->severity = MCM_ERR_LVL_ERR;
864     ectxt->sysexit = EX_OSERR;
865     break;
866   case MCM_ERR_SYS_CONNECT:
867     ectxt->errstr = "connect(2) failed";
868     ectxt->severity = MCM_ERR_LVL_NOTICE;
869     ectxt->sysexit = EX_OSERR;
870     break;
871   case MCM_ERR_SYS_FCNTL:
872     ectxt->errstr = "unable to get or set file descriptor status";
873     ectxt->severity = MCM_ERR_LVL_ERR;
874     ectxt->sysexit = EX_OSERR;
875     break;
876   case MCM_ERR_SYS_READ:
877     ectxt->errstr = "read(2) failed";
878     ectxt->severity = MCM_ERR_LVL_ERR;
879     ectxt->sysexit = EX_OSERR;
880     break;
881   case MCM_ERR_SYS_SELECT:
882     ectxt->errstr = "select(2) failed";
883     ectxt->severity = MCM_ERR_LVL_ERR;
884     ectxt->sysexit = EX_OSERR;
885     break;
886   case MCM_ERR_SYS_SETSOCKOPT:
887     ectxt->errstr = "setsockopt(2) failed";
888     ectxt->severity = MCM_ERR_LVL_ERR;
889     ectxt->sysexit = EX_OSERR;
890     break;
891   case MCM_ERR_SYS_SOCKET:
892     ectxt->errstr = "socket(2) failed";
893     ectxt->severity = MCM_ERR_LVL_ERR;
894     ectxt->sysexit = EX_OSERR;
895     break;
896   case MCM_ERR_SYS_WRITEV:
897     ectxt->errstr = "writev(2) failed";
898     ectxt->severity = MCM_ERR_LVL_ERR;
899     ectxt->sysexit = EX_OSERR;
900   case MCM_ERR_TEST:
901     ectxt->errstr = "internal memcache(3) test message";
902     ectxt->severity = MCM_ERR_LVL_WARN;
903     ectxt->sysexit = EX_OK;
904     break;
905   case MCM_ERR_TIMEOUT:
906     ectxt->errstr = "timeout";
907     ectxt->severity = MCM_ERR_LVL_WARN;
908     ectxt->sysexit = EX_UNAVAILABLE;
909     break;
910   case MCM_ERR_TRACE:
911     ectxt->errstr = "memcache(3) trace";
912     ectxt->severity = MCM_ERR_LVL_INFO;
913     ectxt->sysexit = EX_OK;
914     break;
915   case MCM_ERR_UNKNOWN_STAT:
916     ectxt->errstr = "unknown stat variable";
917     ectxt->severity = MCM_ERR_LVL_WARN;
918     ectxt->sysexit = EX_PROTOCOL;
919     break;
920   default:
921     ectxt->errstr = "unknown error code";
922     ectxt->severity = MCM_ERR_LVL_FATAL;
923     ectxt->sysexit = EX_SOFTWARE;
924   }
925 
926   /* If we were passed in an error level, override the default
927    * severity. */
928   if (errlvl != 0)
929     ectxt->severity = errlvl;
930 
931   /* Apply the error filter and ignore errors from levels that are
932    * ignored. */
933   if ((ctxt->MCM_ERR_MASK & ectxt->severity) != 0)
934     return;
935 
936   /* Determine whether or not we continue running depending on the severity */
937   switch (ectxt->severity) {
938   case MCM_ERR_LVL_INFO:
939   case MCM_ERR_LVL_NOTICE:
940   case MCM_ERR_LVL_WARN:
941     ectxt->cont = 'y';
942     break;
943   case MCM_ERR_LVL_ERR:
944     ectxt->cont = 'n';
945     break;
946   case MCM_ERR_LVL_FATAL:
947   default:
948     ectxt->cont = 'a';
949   }
950 
951   /* Call the user's handler.  Disregard the return value for now, but
952    * have it there for future use.  *shrug* */
953   if (ctxt->mcErr != NULL)
954     (void)ctxt->mcErr(ctxt, ctxt->ectxt);
955 
956   /* There are a few error codes that require special cases for */
957   switch (errcode) {
958   case MCM_ERR_MC_SERV_LIST:
959     if (ectxt->cont == 'n')
960       ectxt->cont = 'y';
961     break;
962   }
963 
964   switch (ectxt->cont) {
965   case 'y':
966     /* Yes: do nothing */
967     break;
968   case 'n':
969     /* No: exit with an error code */
970     exit(ectxt->sysexit);
971   case 'a':
972     /* Abort: do just that, abort(3) */
973   default:
974     abort();
975   }
976 }
977 
978 
979 int
mcm_err_filter_add(struct memcache_ctxt * ctxt,const u_int32_t err_mask)980 mcm_err_filter_add(struct memcache_ctxt *ctxt, const u_int32_t err_mask) {
981   if ((ctxt->MCM_ERR_MASK & err_mask) == ctxt->MCM_ERR_MASK)
982     return 0;
983 
984   ctxt->MCM_ERR_MASK &= err_mask;
985   return 1;
986 }
987 
988 
989 int
mcm_err_filter_del(struct memcache_ctxt * ctxt,const u_int32_t err_mask)990 mcm_err_filter_del(struct memcache_ctxt *ctxt, const u_int32_t err_mask) {
991   if ((ctxt->MCM_ERR_MASK & err_mask) == ctxt->MCM_ERR_MASK)
992     return 0;
993 
994   ctxt->MCM_ERR_MASK &= ~err_mask;
995   return 1;
996 }
997 
998 
999 u_int32_t
mcm_err_filter_get(const struct memcache_ctxt * ctxt)1000 mcm_err_filter_get(const struct memcache_ctxt *ctxt) {
1001   return ctxt->MCM_ERR_MASK;
1002 }
1003 
1004 
1005 int
mcm_err_filter_test(const struct memcache_ctxt * ctxt,const u_int32_t err_lvl)1006 mcm_err_filter_test(const struct memcache_ctxt *ctxt, const u_int32_t err_lvl) {
1007   return(((ctxt->MCM_ERR_MASK & err_lvl) != 0) ? 1 : 0);
1008 }
1009 
1010 
1011 static int32_t
mcm_err_func(MCM_ERR_FUNC_ARGS)1012 mcm_err_func(MCM_ERR_FUNC_ARGS) {
1013   const struct memcache_ctxt *ctxt;
1014   struct memcache_err_ctxt *ectxt;
1015   const char *errno_str, *severity;
1016   struct timeval tv;
1017 
1018   MCM_ERR_INIT_CTXT(ctxt, ectxt);
1019 
1020   if (ectxt->errnum != 0)
1021     errno_str = strerror(ectxt->errnum);
1022   else
1023     errno_str = NULL;
1024 
1025   switch (ectxt->severity) {
1026   case MCM_ERR_LVL_INFO:
1027     severity = "INFO";
1028     break;
1029   case MCM_ERR_LVL_NOTICE:
1030     severity = "NOTICE";
1031     break;
1032   case MCM_ERR_LVL_WARN:
1033     severity = "WARN";
1034     break;
1035   case MCM_ERR_LVL_ERR:
1036     severity = "ERROR";
1037     break;
1038   case MCM_ERR_LVL_FATAL:
1039     severity = "FATAL";
1040     break;
1041   default:
1042 #ifdef DEBUG_MC_PROTO
1043     do {
1044       char *tm;
1045       size_t tml;
1046       tml = asprintf(&tm, "Unknown error severity: %d", ectxt->severity);
1047       if (tml > 0 && tm != NULL) {
1048 	MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
1049 	free(tm);
1050       }
1051     } while(0);
1052 #endif
1053     severity = "UNKNOWN";
1054   }
1055 
1056   /*
1057    * Quick explaination of the various bits of text:
1058    *
1059    * ectxt->errmsg - per error message passed along via one of the MCM_*_MSG() macros (optional)
1060    * ectxt->errstr - memcache(3) error string (optional, though almost always set)
1061    * errno_str - errno error string (optional)
1062    */
1063 
1064   if (gettimeofday(&tv, NULL) != 0) {
1065     tv.tv_sec = 0;
1066     tv.tv_usec = 0;
1067   }
1068 
1069   if (ectxt->errmsg != NULL && errno_str != NULL && ectxt->errmsg != NULL)
1070     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s: %s: %.*s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, ectxt->errstr, errno_str, (int)ectxt->errlen, ectxt->errmsg);
1071   else if (ectxt->errmsg == NULL && errno_str != NULL && ectxt->errmsg != NULL)
1072     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s: %.*s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, errno_str, (int)ectxt->errlen, ectxt->errmsg);
1073   else if (ectxt->errmsg != NULL && errno_str == NULL && ectxt->errmsg != NULL)
1074     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s: %.*s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, ectxt->errstr, (int)ectxt->errlen, ectxt->errmsg);
1075   else if (ectxt->errmsg != NULL && errno_str != NULL && ectxt->errmsg == NULL)
1076     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s: %s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, errno_str, ectxt->errstr);
1077   else if (ectxt->errmsg == NULL && errno_str == NULL && ectxt->errmsg != NULL)
1078     fprintf(stderr, "[%s@%d.%06d] %s():%u: %.*s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, (int)ectxt->errlen, ectxt->errmsg);
1079   else if (ectxt->errmsg == NULL && errno_str != NULL && ectxt->errmsg == NULL)
1080     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, errno_str);
1081   else if (ectxt->errmsg != NULL && errno_str == NULL && ectxt->errmsg == NULL)
1082     fprintf(stderr, "[%s@%d.%06d] %s():%u: %s\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno, ectxt->errmsg);
1083   else
1084     fprintf(stderr, "[%s@%d.%06d] %s():%u\n", severity, (int)tv.tv_sec, (int)tv.tv_usec, ectxt->funcname, ectxt->lineno);
1085 
1086   return 0;
1087 }
1088 
1089 
1090 void
mcm_err_test(const struct memcache_ctxt * ctxt)1091 mcm_err_test(const struct memcache_ctxt *ctxt) {
1092   MCM_WARNX(MCM_ERR_TEST, "per-error message specific to this line of code");
1093 }
1094 
1095 
1096 static void
mcm_fetch_cmd(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_req * req,const char * cmd,const size_t cmd_len)1097 mcm_fetch_cmd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req,
1098 	      const char *cmd, const size_t cmd_len) {
1099   struct memcache_res *res;
1100   struct memcache_res_cb *cb;
1101   struct memcache_server *ms;
1102   size_t bytes, len, remain;
1103   u_int16_t flags, retry;
1104   char *cp, *end;
1105 
1106   if (req->num_keys == 0)
1107     return;
1108 
1109   /* mcm_fetch_cmd() is now wrapped by mcm_get() so that a serial list
1110    * of fetch cmds are run and all keys are guaranteed to goto the
1111    * correct server. */
1112   res = TAILQ_FIRST(&req->query);
1113   if (res->hash == 0)
1114     res->hash = ctxt->mcHashKey(ctxt, mc, res->key, res->len);
1115 
1116   ms = mcm_server_connect_next_avail(ctxt, mc, res->hash);
1117   if (ms == NULL)
1118     return;
1119 
1120   mcm_buf_append(ctxt, ms->wbuf, cmd, cmd_len);
1121 
1122   TAILQ_FOREACH(res, &req->query, entries) {
1123     if (res->hash == 0)
1124       res->hash = ctxt->mcHashKey(ctxt, mc, res->key, res->len);
1125 
1126     mcm_buf_append(ctxt, ms->wbuf, res->key, res->len);
1127 
1128     if (res->entries.tqe_next != NULL)
1129       mcm_buf_append_char(ctxt, ms->wbuf, ' ');
1130 
1131     /* Even though we haven't sent the request, mark the response as
1132      * having been attempted. */
1133     res->_flags |= MCM_RES_ATTEMPTED;
1134 
1135     /* While we're looping, might as well see if we should be auto
1136      * deleting any of these keys. */
1137     if ((res->_flags & (MCM_RES_FREE_ON_DELETE | MCM_RES_NO_FREE_ON_DELETE)) ==
1138 	(MCM_RES_FREE_ON_DELETE | MCM_RES_NO_FREE_ON_DELETE))
1139       mcm_res_free_on_delete(ctxt, res, (res->size > 0 ? 0 : 1));
1140   }
1141   mcm_buf_append(ctxt, ms->wbuf, str_endl, str_endl_len);
1142 
1143   /* Send the command to the server */
1144   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
1145     MCM_CLEAN_BUFS(ctxt, ms);
1146     MCM_ERRX_MSG(MCM_ERR_ASSERT, "unable to send command");
1147     return;
1148   }
1149 
1150   while(1) {
1151     /* Grab a line of input from the server */
1152     cp = mcm_get_line(ctxt, mc, ms);
1153     if (cp == NULL) {
1154       MCM_ERRX_MSG(MCM_ERR_PROTO, "protocol, expected a response");
1155       return;
1156     }
1157 
1158     if (strncmp(cp, "VALUE ", MCM_CSTRLEN("VALUE ")) == 0) {
1159       cp += MCM_CSTRLEN("VALUE ");
1160 
1161       /* Find the length of the key */
1162       for (len = 0; cp[len] && cp[len] != ' ';len++);
1163 
1164       /* Find the response for this key */
1165       TAILQ_FOREACH(res, &req->query, entries) {
1166 	if ((res->_flags & MCM_RES_FOUND) == 0 &&
1167 	    len == res->len && memcmp(cp, res->key, res->len) == 0) {
1168 	  res->_flags |= MCM_RES_FOUND;
1169 	  break;
1170 	}
1171       }
1172 
1173       /* Bail if we run across a situation where a VALUE comes back
1174        * for a key that we don't have a request for. */
1175       if (res == NULL) {
1176 	MCM_ERR_MSG(MCM_ERR_PROTO, "server sent data for key not in request");
1177 	goto cleanup;
1178       }
1179 
1180       cp += res->len + MCM_CSTRLEN(" ");
1181 
1182       /* Parse the flags */
1183       flags = (u_int16_t)strtol(cp, &end, 10);
1184       if (flags == 0 && ((errno == EINVAL && end == mcm_buf_off_ptr(ctxt, ms->rbuf)) || errno == ERANGE)) {
1185 	MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid flags");
1186 	mcm_server_deactivate(ctxt, mc, ms);
1187 	goto cleanup;
1188       }
1189       res->flags = flags;
1190       cp += end - cp + MCM_CSTRLEN(" ");
1191 
1192       /* Parse the bytes */
1193       bytes = (size_t)strtol(cp, &end, 10);
1194       if (bytes == 0 && ((errno == EINVAL && end == mcm_buf_off_ptr(ctxt, ms->rbuf)) || errno == ERANGE)) {
1195 	MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid bytes");
1196 	mcm_server_deactivate(ctxt, mc, ms);
1197 	goto cleanup;
1198       }
1199       res->bytes = bytes;
1200       cp += end - cp + MCM_CSTRLEN("\r\n");
1201 
1202       /* If necessary, allocate memory for the response */
1203       if (res->size == 0) {
1204 	res->val = ctxt->mcMallocAtomic(res->bytes + MCM_CSTRLEN("\0"));
1205 	if (res->val == NULL) {
1206 	  MCM_ERRX_MSG(MCM_ERR_ASSERT, "memory was not allocated for res->val");
1207 	  goto cleanup;
1208 	}
1209 	((char *)res->val)[res->bytes] = '\0';
1210 	res->size = res->bytes;
1211       }
1212 
1213       /* Copy what data we can from the end of the buffer (potentially
1214        * all of it) into the value.  If we need to read(2) more data,
1215        * do so directly into the response object. */
1216       remain = mcm_buf_remain_off(ctxt, ms->rbuf);
1217       if (remain >= res->bytes && res->size >= res->bytes) {
1218 	/* Response for key fully read(2).  We can copy the remaining
1219 	 * data without having to read(2) it off the wire. */
1220 	memcpy(res->val, cp, res->bytes);
1221 
1222 	ms->rbuf->off += res->bytes;
1223 	cp = mcm_get_line(ctxt, mc, ms);
1224 	if (cp == NULL) {
1225 	  MCM_ERRX(MCM_ERR_PROTO);
1226 	  goto cleanup;
1227 	}
1228       } else if (res->bytes >= res->size && remain >= res->bytes) {
1229 	/* Response for key fully read(2).  We can only copy part of
1230 	 * the data due to the response object's size limitation, but
1231 	 * we still read(2) in everything off the wire for this given
1232 	 * response. */
1233 	memcpy(res->val, cp, res->size);
1234 
1235 	/* Set the offset that way mcm_get_line() doesn't incorrectly
1236 	 * scan through most of the response looking for a newline. */
1237 	ms->rbuf->off += res->bytes;
1238 	ms->rbuf->flags |= MCM_BUF_OFF_USED;
1239 
1240 	/* Suck in the \r\n */
1241 	cp = mcm_get_line(ctxt, mc, ms);
1242 	if (cp == NULL) {
1243 	  MCM_ERRX(MCM_ERR_PROTO);
1244 	  goto cleanup;
1245 	}
1246       } else if (res->size >= res->bytes && remain < res->bytes) {
1247 	/* Response for key partially read(2).  We need to read(2) the
1248 	 * remaining data off the wire and into the response object's
1249 	 * value ptr. */
1250 	memcpy(res->val, cp, remain);
1251 
1252 	/* Need to read(2) the remaining data for a response */
1253 	mcm_read_fd(ctxt, mc, ms, &((char *)res->val)[remain], res->bytes - remain);
1254 
1255 	/* Suck in the "next" line that way we can scan past "\r\n" */
1256 	mcm_buf_reset(ctxt, ms->rbuf);
1257 	cp = mcm_get_line(ctxt, mc, ms);
1258 	if (cp == NULL) {
1259 	  MCM_ERRX_MSG(MCM_ERR_PROTO, "unable to read another line");
1260 	  goto cleanup;
1261 	}
1262 
1263 #ifdef DEBUG_MC_PROTO_ASSERT
1264 	if (memcmp(cp, "\r\n", MCM_CSTRLEN("\r\n")) != 0) {
1265 	  MCM_ERRX(MCM_ERR_PROTO);
1266 	  goto cleanup;
1267 	}
1268 #endif
1269       } else if (res->size < res->bytes && remain < res->size) {
1270 	/* Response for key partially read(2).  We can only copy part
1271 	 * of the data, and the remaining part of data is already in
1272 	 * buffer.  Unwanted data needs to be read(2) off the fd, but
1273 	 * needs to be discarded. */
1274 	memcpy(res->val, cp, remain);
1275 
1276 	/* Need to read(2) the remaining data for a response */
1277 	mcm_read_fd(ctxt, mc, ms, &((char *)res->val)[remain], res->size - remain);
1278 
1279 	/* Suck in remaining data and make it disappear */
1280 	bytes = res->bytes - (res->size - remain);
1281 	retry = 0;
1282 	do {
1283 	  bytes = mcm_read_fd(ctxt, mc, ms, mcm_buf_to_cstr(ctxt, ms->rbuf), mcm_buf_size(ctxt, ms->rbuf));
1284 	  if (retry > 3)
1285 	    break;
1286 	  else
1287 	    retry++;
1288 	} while (bytes > 0);
1289 
1290 	/* Suck in the "next" line that way we can scan past "\r\n" */
1291 	mcm_buf_reset(ctxt, ms->rbuf);
1292 	cp = mcm_get_line(ctxt, mc, ms);
1293 	if (cp == NULL) {
1294 	  MCM_ERRX_MSG(MCM_ERR_PROTO, "unable to read another line");
1295 	  goto cleanup;
1296 	}
1297       } else {
1298 	MCM_ERRX(MCM_ERR_ASSERT);
1299 	goto cleanup;
1300       }
1301     } else if (strncmp(cp, "END", MCM_CSTRLEN("END")) == 0) {
1302       /* This END is the result of no matches found from the request */
1303       goto cleanup;
1304     } else {
1305       MCM_ERRX_MSG(MCM_ERR_PROTO, cp);
1306       goto cleanup;
1307     }
1308   }
1309 
1310   /* This should never happen as we exit above while(1) via cleanup
1311    * goto code */
1312   cp = mcm_get_line(ctxt, mc, ms);
1313 #ifdef DEBUG_MC_PROTO_ASSERT
1314   if (strncmp(cp, "END", MCM_CSTRLEN("END")) != 0) {
1315     MCM_ERRX(MCM_ERR_PROTO);
1316     goto cleanup;
1317   }
1318 #endif
1319 
1320   cleanup:
1321   /* Now that we've finished the IO, fire off any callbacks that are
1322    * registered. */
1323   /* This is only for "shortcut" calls as the other ones don't get cb */
1324   TAILQ_FOREACH(cb, &req->cb, entries) {
1325     (*cb->cb)(cb->ctxt, cb->res, cb->misc);
1326   }
1327 
1328   MCM_CLEAN_BUFS(ctxt, ms);
1329   return;
1330 }
1331 
1332 
1333 int
mcm_flush(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)1334 mcm_flush(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
1335   char *cur;
1336 
1337   if (mcm_server_connect(ctxt, mc, ms) == -1)
1338     return (int)MCM_RET_CODE(-1);
1339 
1340   mcm_buf_append(ctxt, ms->wbuf, "flush_all\r\n", MCM_CSTRLEN("flush_all\r\n"));
1341 
1342   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
1343     MCM_CLEAN_BUFS(ctxt, ms);
1344     return (int)MCM_RET_CODE(-2);
1345   }
1346 
1347   cur = mcm_get_line(ctxt, mc, ms);
1348   if (cur != NULL && memcmp(cur, "OK", MCM_CSTRLEN("OK")) == 0) {
1349     MCM_CLEAN_BUFS(ctxt, ms);
1350     return 0;
1351   } else {
1352     MCM_ERRX(MCM_ERR_PROTO);
1353     MCM_CLEAN_BUFS(ctxt, ms);
1354     return (int)MCM_RET_CODE(-3);
1355   }
1356 }
1357 
1358 
1359 int
mcm_flush_all(struct memcache_ctxt * ctxt,struct memcache * mc)1360 mcm_flush_all(struct memcache_ctxt *ctxt, struct memcache *mc) {
1361   struct memcache_server *ms;
1362   int ret = 0,
1363     tret;
1364 
1365   for (ms = mc->server_list.tqh_first; ms != NULL; ms = ms->entries.tqe_next) {
1366     tret = mcm_flush(ctxt, mc, ms);
1367 
1368     /* Return the error code of the first non-zero value if there is
1369      * one.  Not sure if this is correct, but I don't have a better
1370      * idea right now. XXX */
1371     if (tret != 0 && ret == 0)
1372       ret = tret;
1373   }
1374 
1375   return ret;
1376 }
1377 
1378 
1379 void
mcm_free(struct memcache_ctxt * ctxt,struct memcache * mc)1380 mcm_free(struct memcache_ctxt *ctxt, struct memcache *mc) {
1381   struct memcache_server *ms, *tms;
1382 
1383   if (mc == NULL)
1384     return;
1385 
1386   tms = mc->server_list.tqh_first;
1387   while(tms != NULL) {
1388     ms = tms;
1389     tms = ms->entries.tqe_next;
1390 
1391     mcm_server_free(ctxt, ms);
1392   }
1393 
1394   if (mc->servers != NULL) {
1395     ctxt->mcFree(mc->servers);
1396   }
1397 
1398   ctxt->mcFree(mc);
1399 }
1400 
1401 
1402 void
mcm_get(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_req * req)1403 mcm_get(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req) {
1404   /* At this point, we can safely assume we're performing a multi-get.
1405    * Pre-calculate what keys map up with which servers in order to
1406    * group requests where possible. Assume the worst/best case
1407    * scenario in that all keys will go to one server.*/
1408   struct memcache_req	**psq, *tsq;	/* Per-Server-reQuest */
1409   struct memcache_res	*psr, *trs;	/* Per-Server-Response */
1410   struct memcache_res_cb *cb;
1411   u_int16_t		 i;
1412 
1413   /* Reset ctxt->errnum upon entry into memcache(3), even though
1414    * mcm_get() and its call graph doesn't make use of ctxt->errnum. */
1415   ctxt->errnum = 0;
1416 
1417   /* Perform some trickery and call mcm_fetch_cmd() once for every
1418    * server that needs to be queried.  Short-circuit execution where
1419    * possible by invoking mcm_fetch_cmd() immediately if there is only
1420    * one key being queried. */
1421   switch (req->num_keys) {
1422   case 0:
1423     return;
1424   case 1:
1425     mcm_fetch_cmd(ctxt, mc, req, str_get_cmd, str_get_len);
1426     return;
1427   }
1428 
1429   /* If we're a multi-get but there is only one server, don't bother
1430    * with splitting out the keys to their appropriate server. */
1431   if (mc->num_servers == 0) {
1432     return;
1433   } else if (mc->num_servers == 1) {
1434     mcm_fetch_cmd(ctxt, mc, req, str_get_cmd, str_get_len);
1435     return;
1436   }
1437 
1438   /* Create an array of pointers to the per-server request objects.
1439    * Allocate one extra request object as a terminator of the pointer
1440    * array. */
1441   psq = (struct memcache_req**)ctxt->mcMalloc(sizeof(struct memcache_req*) * (mc->num_servers + 1));
1442   if (psq == NULL) {
1443     MCM_ERRX_MSG(MCM_ERR_ASSERT, "memory was not allocated for psq");
1444     return;
1445   }
1446   bzero(psq, sizeof(struct memcache_req*) * (mc->num_servers + 1));
1447 
1448   /* Make a first pass through the keys to determine which server they
1449    * belong to. */
1450   for (trs = req->query.tqh_first; trs != NULL; trs = trs->entries.tqe_next) {
1451     psr = mcm_res_new(ctxt);
1452 
1453     /* Shallow copy of trs into psr */
1454     psr->key = trs->key;
1455     psr->len = trs->len;
1456     psr->hash = trs->hash;
1457     psr->val = trs->val;
1458     psr->bytes = trs->bytes;
1459     psr->size = trs->size;
1460     psr->flags = trs->flags;
1461 
1462     /* No flags for shadow structure: we don't want the key or value
1463      * to be reaped when we cleanup. */
1464     psr->_flags = 0;
1465 
1466     mcm_res_free_on_delete(ctxt, psr, 0);
1467 
1468     if (psr->hash == 0) {
1469       psr->hash = trs->hash = ctxt->mcHashKey(ctxt, mc, psr->key, psr->len);
1470     }
1471 
1472     /* Store a pointer to the original object. */
1473     psr->misc = trs;
1474 
1475     /* Append onto the correct request chain for a server. */
1476     tsq = psq[psr->hash % mc->num_servers];
1477     if (tsq == NULL)
1478       tsq = psq[psr->hash % mc->num_servers] = mcm_req_new(ctxt);
1479     TAILQ_INSERT_TAIL(&tsq->query, psr, entries);
1480     tsq->num_keys++;
1481   }
1482 
1483   /* Make a second pass through the list of requests and execute the
1484    * fetch command where appropriate. */
1485   for (i = 0; i < mc->num_servers; i++) {
1486     if (psq[i] == NULL || psq[i]->num_keys == 0)
1487       continue;
1488 
1489     mcm_fetch_cmd(ctxt, mc, psq[i], str_get_cmd, str_get_len);
1490 
1491     /* Copy the important bits back. */
1492     for (psr = psq[i]->query.tqh_first; psr != NULL; psr = psr->entries.tqe_next) {
1493       trs = (struct memcache_res*)psr->misc;
1494       trs->val = psr->val;
1495       trs->bytes = psr->bytes;
1496       trs->size = psr->size;
1497       trs->flags = psr->flags;
1498       trs->_flags |= psr->_flags;
1499     }
1500   }
1501 
1502   /* Cleanup */
1503   for (i = 0; i < mc->num_servers; i++) {
1504     if (psq[i] != NULL)
1505       mcm_req_free(ctxt, psq[i]);
1506   }
1507 
1508   ctxt->mcFree(psq);
1509 
1510   /* Now that we've finished the IO, fire off any callbacks that are
1511    * registered. */
1512   /* This is for "non-shortcut" calls */
1513   TAILQ_FOREACH(cb, &req->cb, entries) {
1514     (*cb->cb)(cb->ctxt, cb->res, cb->misc);
1515   }
1516 }
1517 
1518 
1519 static char *
mcm_get_line(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)1520 mcm_get_line(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
1521   size_t bytes_read = 0, bytes_scan = 0;
1522   char *end, *line;
1523   int ret;
1524 
1525   /* If we haven't initialized an offset, do so. */
1526   if ((ms->rbuf->flags & MCM_BUF_OFF_USED) != MCM_BUF_OFF_USED) {
1527     ms->rbuf->off = 0;
1528     ms->rbuf->flags |= MCM_BUF_OFF_USED;
1529   } else {
1530     bytes_read = mcm_buf_remain_off(ctxt, ms->rbuf);
1531   }
1532 
1533   /* Search for a newline starting at the offset */
1534   scan_for_line:
1535   end = memchr(mcm_buf_off_ptr(ctxt, ms->rbuf) + bytes_scan, (int)'\n', bytes_read);
1536   if (end == NULL) {
1537     /* Prevent rescanning of the buffer */
1538     bytes_scan += bytes_read;
1539   } else {
1540 #ifdef DEBUG_MC_PROTO_ASSERT
1541     if (*(end - 1) != '\r') {
1542       MCM_ERRX_MSG(MCM_ERR_PROTO, "no \\r before \\n");
1543       return NULL;
1544     }
1545 #endif
1546 
1547     line = mcm_buf_off_ptr(ctxt, ms->rbuf);
1548     ms->rbuf->off += end - line + 1;
1549     return line;
1550   }
1551 
1552   /* We were unable to scan for any bytes in our given buffer.  Need
1553    * to read(2) in some data. */
1554   read_more:
1555   if (mcm_server_readable(ctxt, ms, &ms->tv)) {
1556     bytes_read = mcm_buf_read(ctxt, ms->rbuf, ms->fd);
1557   } else {
1558     goto resend;
1559   }
1560 
1561   if (bytes_read == 0) {
1562     switch (errno) {
1563     case EAGAIN:
1564     case EINTR:
1565 
1566       /* Assume a file descriptor can be read(2), but if it can't
1567        * block until we can read(2) from the fd. */
1568       ret = mcm_server_readable(ctxt, ms, &ms->tv);
1569       if (ret < 0) {
1570 	mcm_server_deactivate(ctxt, mc, ms);
1571 	MCM_ERR_MSG(MCM_ERR_SYS_SELECT, "select returned bogus value");
1572 	return NULL;
1573       } else if (ret == 0) {
1574 	goto resend;
1575       } else {
1576 	goto read_more;
1577       }
1578     case ECONNRESET:
1579     case EINVAL:
1580       resend:
1581       mcm_server_disconnect(ctxt, ms);
1582 
1583       /* Reconnect to the same server.  If this fails, get the next
1584        * available server. */
1585       if (mcm_server_connect(ctxt, mc, ms) == -1) {
1586 	mcm_server_deactivate(ctxt, mc, ms);
1587 	ms = mcm_server_connect_next_avail(ctxt, mc, ms->_last_hash);
1588 
1589 	if (ms == NULL)
1590 	  return NULL;
1591       } else {
1592 	MCM_ERRX(MCM_ERR_MC_RECONN);
1593       }
1594 
1595       mcm_server_send_last_cmd(ctxt, mc, ms);
1596       goto read_more;
1597     default:
1598       /* This shouldn't happen and if it does, we're pooched: better
1599        * dump. */
1600       MCM_ERRX_MSG(MCM_ERR_ASSERT, strerror(errno));
1601       return NULL;
1602     }
1603   }
1604 
1605   goto scan_for_line;
1606 }
1607 
1608 
1609 #ifdef USE_CRC32_HASH
1610 #include "crc32_table.h"
1611 #endif /* USE_CRC32_HASH */
1612 
1613 
1614 u_int32_t
mcm_hash(const struct memcache_ctxt * ctxt,const struct memcache * mc,const char * key,const size_t len)1615 mcm_hash(const struct memcache_ctxt *ctxt, const struct memcache *mc, const char *key, const size_t len) {
1616   return ctxt->mcHashKey(ctxt, mc, key, len);
1617 }
1618 
1619 
1620 u_int32_t
mcm_hash_key(const struct memcache_ctxt * ctxt,const char * key,const size_t len)1621 mcm_hash_key(const struct memcache_ctxt *ctxt, const char *key, const size_t len) {
1622   return ctxt->mcHashKey(ctxt, NULL, key, len);
1623 }
1624 
1625 
1626 static u_int32_t
mcm_hash_key_func(MCM_HASH_FUNC)1627 mcm_hash_key_func(MCM_HASH_FUNC) {
1628 #ifdef USE_CRC32_HASH
1629   const struct memcache_ctxt *ctxt;
1630   const struct memcache *mc;
1631   const char *key;
1632   u_int32_t crc;
1633   size_t len;
1634   size_t i;
1635 
1636   MCM_HASH_INIT(ctxt, mc, key, len);
1637   if (mc != NULL && mc->num_servers <= 1)
1638     return 1;
1639 
1640   crc = ~0;
1641 
1642   for (i = 0; i < len; i++)
1643     crc = (crc >> 8) ^ crc32tab[(crc ^ (key[i])) & 0xff];
1644 
1645   crc = (~crc >> 16) & 0x7fff;
1646 
1647   return crc == 0 ? 1 : crc;
1648 #else
1649 # ifdef USE_PERL_HASH
1650   const struct memcache_ctxt *ctxt;
1651   const struct memcache *mc;
1652   const char *key;
1653   u_int32_t h, i;
1654   size_t len;
1655   char *p;
1656 
1657   MCM_HASH_INIT(ctxt, mc, key, len);
1658   if (mc != NULL && mc->num_servers <= 1)
1659     return 1;
1660 
1661   i = len;	/* Work back through the key length */
1662   p = key;	/* Character pointer */
1663   h = 0;	/* The hash value */
1664 
1665   while (i--) {
1666     h += *p++;
1667     h += (h << 10);
1668     h ^= (h >> 6);
1669   }
1670   h += (h << 3);
1671   h ^= (h >> 11);
1672   h += (h << 15);
1673 
1674   return h == 0 ? 1 : h;
1675 # else
1676 #  ifdef USE_ELF_HASH
1677   const struct memcache_ctxt *ctxt;
1678   const struct memcache *mc;
1679   u_int32_t g, h, i;
1680   const char *key;
1681   size_t len;
1682   char *p;
1683 
1684   MCM_HASH_INIT(ctxt, mc, key, len);
1685   if (mc != NULL && mc->num_servers <= 1)
1686     return 1;
1687 
1688   i = len;	/* Work back through the key length */
1689   p = key;	/* Character pointer */
1690   h = 0;	/* The hash value */
1691 
1692   while (i--) {
1693     h = (h << 4) + *p++;
1694     if (g = h & 0xF0000000)
1695       h ^= g >> 24;
1696     h &= ~g;
1697   }
1698 
1699   return h == 0 ? 1 : h;
1700 #  else
1701 #   error "Please choose USE_CRC32_HASH, USE_ELF_HASH, or USE_PERL_HASH as a hashing scheme when compiling memcache"
1702 #  endif
1703 # endif
1704 #endif
1705 }
1706 
1707 
1708 u_int32_t
mcm_incr(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const u_int32_t val)1709 mcm_incr(struct memcache_ctxt *ctxt, struct memcache *mc,
1710 	 char *key, const size_t key_len, const u_int32_t val) {
1711   return mcm_atomic_cmd(ctxt, mc, str_incr_cmd, str_incr_len, key, key_len, val);
1712 }
1713 
1714 
1715 struct memcache *
mcm_new(struct memcache_ctxt * ctxt)1716 mcm_new(struct memcache_ctxt *ctxt) {
1717   struct memcache *mc;
1718 
1719   mc = (struct memcache *)ctxt->mcMalloc(sizeof(struct memcache));
1720   if (mc != NULL) {
1721     bzero(mc, sizeof(struct memcache));
1722 
1723     TAILQ_INIT(&mc->server_list);
1724 
1725     /* Set any default values */
1726     mc->tv.tv_sec = 2;
1727     mc->tv.tv_usec = 600;
1728   }
1729 
1730   return mc;
1731 }
1732 
1733 
1734 static size_t
mcm_read_fd(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms,char * buf,size_t bytes)1735 mcm_read_fd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms, char *buf, size_t bytes) {
1736   size_t bytes_read = 0;
1737   ssize_t rb;
1738   int ret;
1739 
1740   read_more:
1741   rb = read(ms->fd, buf, bytes);
1742   if (rb < 1) {
1743     switch (errno) {
1744     case EAGAIN:
1745     case EINTR:
1746 
1747       /* Assume a file descriptor can be read(2), but if it can't
1748        * block until we can read(2) from the fd. */
1749       ret = mcm_server_readable(ctxt, ms, &ms->tv);
1750       if (ret < 0) {
1751 	mcm_server_deactivate(ctxt, mc, ms);
1752 	MCM_ERR_MSG(MCM_ERR_SYS_SELECT, "select returned bogus value");
1753 	return 0;
1754       } else if (ret == 0) {
1755 	mcm_server_disconnect(ctxt, ms);
1756 
1757 	/* Reconnect to the same server.  If this fails, get the next
1758 	 * available server. */
1759 	if (mcm_server_connect(ctxt, mc, ms) == -1) {
1760 	  mcm_server_deactivate(ctxt, mc, ms);
1761 	  ms = mcm_server_connect_next_avail(ctxt, mc, ms->_last_hash);
1762 
1763 	  if (ms == NULL)
1764 	    return 0;
1765 	} else {
1766 	  MCM_ERRX(MCM_ERR_MC_RECONN);
1767 	}
1768 
1769 	mcm_server_send_last_cmd(ctxt, mc, ms);
1770       } else {
1771 	goto read_more;
1772       }
1773     default:
1774       /* This shouldn't happen and if it does, we're pooched: better
1775        * dump. */
1776       MCM_ERRX_MSG(MCM_ERR_ASSERT, strerror(errno));
1777       mcm_server_disconnect(ctxt, ms);
1778       return 0;
1779     }
1780   } else {
1781     bytes_read += rb;
1782     buf += rb;
1783   }
1784 
1785   /* Need to read(2) more data */
1786   if ((size_t)rb < bytes) {
1787     bytes -= rb;
1788     goto read_more;
1789   } else {
1790     return bytes_read;
1791   }
1792 }
1793 
1794 
1795 #ifdef SEAN_HACKS
1796 void
mcm_listen(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_req * req)1797 mcm_listen(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req) {
1798   mcm_fetch_cmd(ctxt, mc, req, str_listen_cmd, str_listen_len);
1799 }
1800 
1801 
1802 void
mcm_refresh(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_req * req)1803 mcm_refresh(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_req *req) {
1804   mcm_fetch_cmd(ctxt, mc, req, str_refresh_cmd, str_refresh_len);
1805 }
1806 #endif
1807 
1808 
1809 u_int32_t
mcm_reldate(const struct memcache_ctxt * ctxt)1810 mcm_reldate(const struct memcache_ctxt *ctxt) {
1811   return MEMCACHE_RELDATE;
1812 }
1813 
1814 
1815 int
mcm_replace(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)1816 mcm_replace(struct memcache_ctxt *ctxt, struct memcache *mc,
1817 	    char *key, const size_t key_len,
1818 	    const void *val, const size_t bytes,
1819 	    const time_t expire, const u_int16_t flags) {
1820   return mcm_storage_cmd(ctxt, mc, str_replace_cmd, str_replace_len, key, key_len, val, bytes, expire, flags);
1821 }
1822 
1823 
1824 struct memcache_res *
mcm_req_add(const struct memcache_ctxt * ctxt,struct memcache_req * req,char * key,const size_t len)1825 mcm_req_add(const struct memcache_ctxt *ctxt, struct memcache_req *req, char *key, const size_t len) {
1826   struct memcache_res *res;
1827   res = mcm_res_new(ctxt);
1828 
1829   MCM_VALIDATE_KEY_RET(key, len, NULL);
1830 
1831   res->key = mcm_strdup(ctxt, key);
1832   res->_flags |= MCM_RES_NEED_FREE_KEY;
1833   res->len = len;
1834 
1835   TAILQ_INSERT_TAIL(&req->query, res, entries);
1836   req->num_keys++;
1837 
1838   return res;
1839 }
1840 
1841 
1842 struct memcache_res *
mcm_req_add_ref(const struct memcache_ctxt * ctxt,struct memcache_req * req,char * key,const size_t len)1843 mcm_req_add_ref(const struct memcache_ctxt *ctxt, struct memcache_req *req, char *key, const size_t len) {
1844   struct memcache_res *res;
1845   res = mcm_res_new(ctxt);
1846 
1847   MCM_VALIDATE_KEY_RET(key, len, NULL);
1848 
1849   res->key = key;
1850   res->len = len;
1851 
1852   TAILQ_INSERT_TAIL(&req->query, res, entries);
1853   req->num_keys++;
1854 
1855   return res;
1856 }
1857 
1858 
1859 void
mcm_req_free(const struct memcache_ctxt * ctxt,struct memcache_req * req)1860 mcm_req_free(const struct memcache_ctxt *ctxt, struct memcache_req *req) {
1861   while (req->query.tqh_first != NULL)
1862     mcm_res_free(ctxt, req, req->query.tqh_first);
1863 
1864   while (req->cb.tqh_first != NULL)
1865     mcm_res_cb_free(req, req->cb.tqh_first);
1866 
1867   ctxt->mcFree(req);
1868 }
1869 
1870 
1871 struct memcache_req *
mcm_req_new(const struct memcache_ctxt * ctxt)1872 mcm_req_new(const struct memcache_ctxt *ctxt) {
1873   struct memcache_req *req;
1874 
1875   req = (struct memcache_req *)ctxt->mcMalloc(sizeof(struct memcache_req));
1876   if (req != NULL) {
1877     bzero(req, sizeof(struct memcache_req));
1878 
1879     TAILQ_INIT(&req->query);
1880     TAILQ_INIT(&req->cb);
1881   }
1882 
1883   return req;
1884 }
1885 
1886 
1887 int
mcm_res_attempted(const struct memcache_ctxt * ctxt,const struct memcache_res * res)1888 mcm_res_attempted(const struct memcache_ctxt *ctxt,
1889 		  const struct memcache_res *res) {
1890   return res->_flags & MCM_RES_ATTEMPTED ? 1 : 0;
1891 }
1892 
1893 
1894 int
mcm_res_found(const struct memcache_ctxt * ctxt,const struct memcache_res * res)1895 mcm_res_found(const struct memcache_ctxt *ctxt,
1896 	      const struct memcache_res *res) {
1897   return ((res->_flags & (MCM_RES_ATTEMPTED | MCM_RES_FOUND)) == (MCM_RES_ATTEMPTED | MCM_RES_FOUND) ? 1 : 0);
1898 }
1899 
1900 
1901 void
mcm_res_free(const struct memcache_ctxt * ctxt,struct memcache_req * req,struct memcache_res * res)1902 mcm_res_free(const struct memcache_ctxt *ctxt, struct memcache_req *req, struct memcache_res *res) {
1903   TAILQ_REMOVE(&req->query, res, entries);
1904   if ((res->_flags & MCM_RES_NEED_FREE_KEY) == MCM_RES_NEED_FREE_KEY)
1905     ctxt->mcFree((void *)res->key);
1906 
1907   if (((res->_flags & (MCM_RES_FREE_ON_DELETE | MCM_RES_NO_FREE_ON_DELETE)) ==
1908        (MCM_RES_FREE_ON_DELETE | MCM_RES_NO_FREE_ON_DELETE)) ||
1909       res->_flags & MCM_RES_FREE_ON_DELETE) {
1910     if (res->size > 0)
1911       ctxt->mcFree(res->val);
1912   }
1913 
1914   ctxt->mcFree(res);
1915 }
1916 
1917 
1918 void
mcm_res_free_on_delete(const struct memcache_ctxt * ctxt,struct memcache_res * res,const int fod)1919 mcm_res_free_on_delete(const struct memcache_ctxt *ctxt, struct memcache_res *res, const int fod) {
1920   if (fod) {
1921     res->_flags &= ~MCM_RES_NO_FREE_ON_DELETE;
1922     res->_flags |= MCM_RES_FREE_ON_DELETE;
1923   } else {
1924     res->_flags &= ~MCM_RES_FREE_ON_DELETE;
1925     res->_flags |= MCM_RES_NO_FREE_ON_DELETE;
1926   }
1927 }
1928 
1929 
1930 static struct memcache_res *
mcm_res_new(const struct memcache_ctxt * ctxt)1931 mcm_res_new(const struct memcache_ctxt *ctxt) {
1932   struct memcache_res *res;
1933 
1934   res = (struct memcache_res *)ctxt->mcMalloc(sizeof(struct memcache_res));
1935   if (res != NULL) {
1936     bzero(res, sizeof(struct memcache_res));
1937 
1938     /* Default values */
1939     res->_flags = MCM_RES_FREE_ON_DELETE | MCM_RES_NO_FREE_ON_DELETE; /* unset */
1940   }
1941 
1942   return res;
1943 }
1944 
1945 
1946 static void
mcm_res_cb_free(struct memcache_req * req,struct memcache_res_cb * cb)1947 mcm_res_cb_free(struct memcache_req *req, struct memcache_res_cb *cb) {
1948   mcFreeFunc freeFunc;
1949 
1950   if (cb == NULL || cb->ctxt == NULL)
1951     return;
1952 
1953   TAILQ_REMOVE(&req->cb, cb, entries);
1954   freeFunc = cb->ctxt->mcFree;
1955   (freeFunc)(cb);
1956 }
1957 
1958 
1959 static struct memcache_res_cb *
mcm_res_cb_new(const struct memcache_ctxt * ctxt)1960 mcm_res_cb_new(const struct memcache_ctxt *ctxt) {
1961   struct memcache_res_cb *cb;
1962 
1963   cb = (struct memcache_res_cb *)ctxt->mcMalloc(sizeof(struct memcache_res_cb));
1964   if (cb != NULL) {
1965     bzero(cb, sizeof(struct memcache_res_cb));
1966   }
1967 
1968   return cb;
1969 }
1970 
1971 
1972 int
mcm_res_register_fetch_cb(struct memcache_ctxt * ctxt,struct memcache_req * req,struct memcache_res * res,mcResCallback callback,void * misc)1973 mcm_res_register_fetch_cb(struct memcache_ctxt *ctxt, struct memcache_req *req,
1974 			  struct memcache_res *res, mcResCallback callback, void *misc) {
1975   struct memcache_res_cb *cb;
1976 
1977   if (callback == NULL || req == NULL || res == NULL || ctxt == NULL)
1978     return (int)MCM_RET_CODE(-1);
1979 
1980   cb = mcm_res_cb_new(ctxt);
1981   if (cb == NULL)
1982     return (int)MCM_RET_CODE(-2);
1983 
1984   cb->ctxt = ctxt;
1985   cb->req = req;
1986   cb->cb = callback;
1987   cb->res = res;
1988   cb->misc = misc;
1989 
1990   TAILQ_INSERT_TAIL(&req->cb, cb, entries);
1991 
1992   return 0;
1993 }
1994 
1995 
1996 int
mcm_server_activate(const struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)1997 mcm_server_activate(const struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
1998   switch (ms->active) {
1999   case 'd':
2000     ms->active = 'u';
2001     return 0;
2002   case 'n':
2003     MCM_ERRX_MSG(MCM_ERR_ASSERT, "unable to activate a server that does not exist");
2004     return (int)MCM_RET_CODE(-1);
2005   case 't':
2006     MCM_ERRX_MSG_LVL(MCM_ERR_ASSERT, "unable to activate a server that hasn't been added to the server list", MCM_ERR_LVL_INFO);
2007     return (int)MCM_RET_CODE(-2);
2008   case 'u':
2009     MCM_ERRX_MSG_LVL(MCM_ERR_ASSERT, "unable to activate a server that is active", MCM_ERR_LVL_INFO);
2010     return (int)MCM_RET_CODE(-3);
2011   default:
2012     MCM_ERRX(MCM_ERR_ASSERT);
2013   }
2014 
2015   MCM_ERRX(MCM_ERR_ASSERT);
2016   return 0;
2017 }
2018 
2019 
2020 int
mcm_server_activate_all(const struct memcache_ctxt * ctxt,struct memcache * mc)2021 mcm_server_activate_all(const struct memcache_ctxt *ctxt, struct memcache *mc) {
2022   struct memcache_server *ms;
2023 
2024   for (ms = mc->server_list.tqh_first; ms != NULL; ms = ms->entries.tqe_next) {
2025     if (ms->active == 'd')
2026       mcm_server_activate(ctxt, mc, ms);
2027   }
2028 
2029   return 0;
2030 }
2031 
2032 
2033 int
mcm_server_add(struct memcache_ctxt * ctxt,struct memcache * mc,const char * hostname,const char * port)2034 mcm_server_add(struct memcache_ctxt *ctxt, struct memcache *mc, const char *hostname, const char *port) {
2035   return mcm_server_add2(ctxt, mc, hostname, (hostname != NULL ? strlen(hostname) : 0), port, (port != NULL ? strlen(port) : 0));
2036 }
2037 
2038 
2039 int
mcm_server_add2(struct memcache_ctxt * ctxt,struct memcache * mc,const char * hostname,const size_t hostname_len,const char * port,const size_t port_len)2040 mcm_server_add2(struct memcache_ctxt *ctxt, struct memcache *mc, const char *hostname,
2041 		const size_t hostname_len, const char *port, const size_t port_len) {
2042   struct memcache_server *ms;
2043 
2044   ms = mcm_server_new(ctxt);
2045   if (ms == NULL)
2046     return (int)MCM_RET_CODE(-1);
2047 
2048   if (hostname == NULL || hostname_len == 0) {
2049     ms->hostname = mcm_strdup(ctxt, "localhost");
2050   } else {
2051     ms->hostname = mcm_strndup(ctxt, hostname, hostname_len);
2052   }
2053 
2054   if (ms->hostname == NULL) {
2055     mcm_server_free(ctxt, ms);
2056     return (int)MCM_RET_CODE(-2);
2057   }
2058 
2059 
2060   if (port == NULL || port_len == 0) {
2061     ms->port = mcm_strdup(ctxt, "11211");
2062   } else {
2063     ms->port = mcm_strndup(ctxt, port, port_len);
2064   }
2065 
2066   if (ms->port == NULL) {
2067     mcm_server_free(ctxt, ms);
2068     return (int)MCM_RET_CODE(-3);
2069   }
2070 
2071   return mcm_server_add3(ctxt, mc, ms);
2072 }
2073 
2074 
2075 int
mcm_server_add3(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2076 mcm_server_add3(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2077   int ret;
2078   struct memcache_server **ts;
2079 
2080   ret = mcm_server_resolve(ctxt, ms);
2081   if (ret != 0) {
2082     MCM_ERR_MSG(MCM_ERR_NET_HOST, gai_strerror(ret));
2083     mcm_server_free(ctxt, ms);
2084     return (int)MCM_RET_CODE(-4);
2085   }
2086 
2087   /* Defaults from mc */
2088   if (ms->tv.tv_sec == 0 && ms->tv.tv_usec == 0) {
2089     ms->tv.tv_sec = mc->tv.tv_sec;
2090     ms->tv.tv_usec = mc->tv.tv_usec;
2091   }
2092 
2093   TAILQ_INSERT_TAIL(&mc->server_list, ms, entries);
2094 
2095   /* Add ms to the array of servers to try */
2096   if (mc->servers == NULL) {
2097     mc->num_servers = 1;
2098     mc->servers = (struct memcache_server**)ctxt->mcMalloc(sizeof(struct memcache_server*) * (mc->num_servers + 1));
2099     mc->servers[0] = ms;
2100     mc->servers[1] = NULL;
2101   } else {
2102     /* Reallocate mc->servers to fit the number of struct
2103      * memcache_servers entries. 2 == the new memcache server plus an
2104      * additional slot for a NULL server entry. */
2105     ts = (struct memcache_server**)ctxt->mcRealloc(mc->servers, sizeof(struct memcache_server*) * (mc->num_servers + 2));
2106     if (ts == NULL) {
2107       MCM_ERR(MCM_ERR_MEM_REALLOC);
2108       mcm_server_free(ctxt, ms);
2109       return (int)MCM_RET_CODE(-5);
2110     }
2111     mc->servers = ts;
2112 
2113     /* Add the new server to the end of the list */
2114     mc->servers[mc->num_servers] = ms;
2115     mc->num_servers++;
2116     mc->servers[mc->num_servers] = NULL;
2117   }
2118 
2119   return 0;
2120 }
2121 
2122 
2123 int
mcm_server_add4(struct memcache_ctxt * ctxt,struct memcache * mc,mc_const char * hostport)2124 mcm_server_add4(struct memcache_ctxt *ctxt, struct memcache *mc, mc_const char *hostport) {
2125   return mcm_server_add5(ctxt, mc, hostport, (hostport != NULL ? strlen(hostport) : 0));
2126 }
2127 
2128 
2129 int
mcm_server_add5(struct memcache_ctxt * ctxt,struct memcache * mc,mc_const char * hostport,const size_t hostlen)2130 mcm_server_add5(struct memcache_ctxt *ctxt, struct memcache *mc,
2131 		mc_const char *hostport, const size_t hostlen) {
2132   struct memcache_server *ms;
2133   char *cp;
2134 
2135   ms = mcm_server_new(ctxt);
2136   if (ms == NULL)
2137     return (int)MCM_RET_CODE(-1);
2138 
2139   /* Tease out the hostname and portname from a string that we expect
2140    * to look like "host:port". */
2141   if (hostport == NULL || hostlen == 0) {
2142     ms->hostname = mcm_strdup(ctxt, "localhost");
2143     if (ms->hostname == NULL) {
2144       mcm_server_free(ctxt, ms);
2145       return (int)MCM_RET_CODE(-2);
2146     }
2147 
2148     ms->port = mcm_strdup(ctxt, "11211");
2149     if (ms->port == NULL) {
2150       mcm_server_free(ctxt, ms);
2151       return (int)MCM_RET_CODE(-3);
2152     }
2153   } else {
2154     cp = mcm_strnchr(ctxt, hostport, ':', hostlen);
2155     if (*cp == '\0') {
2156       ms->hostname = mcm_strndup(ctxt, hostport, hostlen);
2157       if (ms->hostname == NULL) {
2158 	mcm_server_free(ctxt, ms);
2159 	return (int)MCM_RET_CODE(-2);
2160       }
2161 
2162       ms->port = mcm_strdup(ctxt, "11211");
2163       if (ms->port == NULL) {
2164 	mcm_server_free(ctxt, ms);
2165 	return (int)MCM_RET_CODE(-3);
2166       }
2167     } else {
2168       ms->hostname = mcm_strndup(ctxt, hostport, (size_t)(cp - hostport));
2169       if (ms->hostname == NULL) {
2170 	mcm_server_free(ctxt, ms);
2171 	return (int)MCM_RET_CODE(-2);
2172       }
2173 
2174       /* advance past the ':' and copy whatever is left as the port */
2175       cp++;
2176       ms->port = mcm_strndup(ctxt, cp, hostlen - (size_t)(cp - hostport));
2177       if (ms->port == NULL) {
2178 	mcm_server_free(ctxt, ms);
2179 	return (int)MCM_RET_CODE(-3);
2180       }
2181     }
2182   }
2183 
2184   return mcm_server_add3(ctxt, mc, ms);
2185 }
2186 
2187 
2188 static int
mcm_server_connect(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2189 mcm_server_connect(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2190   struct addrinfo *res;
2191   int flags, i;
2192 #ifdef TCP_NODELAY
2193   int val;
2194 #endif
2195 #ifdef HAVE_SELECT
2196   int ret;
2197 #endif
2198 
2199   if (ms->fd != -1)
2200     return ms->fd;
2201 
2202 #ifdef DEBUG_MC_PROTO
2203   MCM_WARNX_MSG(MCM_ERR_TRACE, "Begin connect(2)");
2204 #endif
2205 
2206   if (ms->active == 'd' || ms->active == 'n')
2207     return (int)MCM_RET_CODE(-1);
2208 
2209   if (ms->hostinfo == NULL || ms->hostinfo->ai_addrlen == 0) {
2210     i = mcm_server_resolve(ctxt, ms);
2211     if (i != 0) {
2212       MCM_ERR_MSG(MCM_ERR_NET_HOST, gai_strerror(i));
2213       ms->active = 'n';
2214       return (int)MCM_RET_CODE(-1);
2215     }
2216   }
2217 
2218   for (i = 0, res = ms->hostinfo; res != NULL; res = res->ai_next, i++) {
2219     ms->fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2220     if (ms->fd < 0) {
2221 #ifdef AF_INET6
2222       if (errno == EPROTONOSUPPORT && res->ai_family == AF_INET6)
2223 	continue;
2224 #endif
2225       MCM_ERR(MCM_ERR_SYS_SOCKET);
2226       continue;
2227     }
2228 
2229 #ifdef TCP_NODELAY
2230     val = 1;
2231     if (setsockopt(ms->fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)) != 0) {
2232       MCM_WARN_MSG(MCM_ERR_SYS_SETSOCKOPT, "setsockopt(TCP_NODELAY) failed");
2233     }
2234 #endif
2235 
2236     if (mcm_server_timeout(ctxt, ms, ms->tv.tv_sec, ms->tv.tv_usec) == 0) {
2237       mcm_server_disconnect(ctxt, ms);
2238       continue;
2239     }
2240 
2241     flags = fcntl(ms->fd, F_GETFL, 0);
2242     if (flags == -1) {
2243       MCM_ERR_MSG(MCM_ERR_SYS_FCNTL, "fcntl(F_GETFL)");
2244       return (int)MCM_RET_CODE(-1);
2245     }
2246 
2247     if (fcntl(ms->fd, F_SETFL, flags | O_NONBLOCK) < 0) {
2248       MCM_ERR_MSG(MCM_ERR_SYS_FCNTL, "fcntl(F_SETFL)");
2249       return (int)MCM_RET_CODE(-1);
2250     }
2251 
2252   get_conn_status:
2253     ret = connect(ms->fd, res->ai_addr, (socklen_t)res->ai_addrlen);
2254 #ifdef DEBUG_MC_PROTO
2255     do {
2256       char *tm;
2257       size_t tml;
2258       char ch[256], cs[256];
2259 
2260       tml = getnameinfo(res->ai_addr, res->ai_addr->sa_len, ch, sizeof(ch), cs, sizeof(cs), NI_NUMERICHOST | NI_NUMERICSERV);
2261       if (tml != 0) {
2262 	MCM_WARNX_MSG(MCM_ERR_TRACE, "Unable to get address");
2263 	return (int)MCM_RET_CODE(-1);
2264       }
2265 
2266       tml = asprintf(&tm, "connect(2) return status for %s:%s: %d", ch, cs, ret);
2267       if (tml > 0 && tm != NULL) {
2268 	MCM_WARN_MSG(MCM_ERR_TRACE, tm);
2269 	free(tm);
2270       }
2271     } while (0);
2272 #endif
2273     if (ret == 0) {
2274       return ms->fd;
2275     } else {
2276       /* Leave error handling in the event I figure out why connect(2)
2277        * and select(2) weren't returning when polling for a writable
2278        * file descriptor. */
2279       switch (errno) {
2280       case EISCONN:
2281 	return ms->fd;
2282         /* Call again, if interrupted */
2283       case EINTR:
2284         goto get_conn_status;
2285       case EINPROGRESS:
2286 	ret = mcm_server_writable(ctxt, ms, &ms->tv);
2287 	if (ret == -1) {
2288 	  MCM_ERR_MSG_LVL(MCM_ERR_SYS_SELECT, "select(2) failed for writable status", MCM_ERR_LVL_WARN);
2289 	} else if (ret == 0) {
2290 	  MCM_ERR_MSG_LVL(MCM_ERR_SYS_SELECT, "select(2) timed out on establishing connection", MCM_ERR_LVL_WARN);
2291 	  printf("connect(): %d\n", connect(ms->fd, res->ai_addr, (socklen_t)res->ai_addrlen));
2292 	} else {
2293 	  goto get_conn_status;
2294 	}
2295 	/* Fall through */
2296       default:
2297 	MCM_ERR(MCM_ERR_SYS_CONNECT);
2298 	mcm_server_disconnect(ctxt, ms);
2299 	continue;
2300       }
2301     }
2302   }
2303 
2304   /* If none of the IP addresses for this hostname work, remove the
2305    * server from the **server list (we assume they're live by default)
2306    * and return -1. */
2307   mcm_server_deactivate(ctxt, mc, ms);
2308   return (int)MCM_RET_CODE(-1);
2309 }
2310 
2311 
2312 static struct memcache_server *
mcm_server_connect_next_avail(struct memcache_ctxt * ctxt,struct memcache * mc,const u_int32_t hash)2313 mcm_server_connect_next_avail(struct memcache_ctxt *ctxt, struct memcache *mc, const u_int32_t hash) {
2314   struct memcache_server *ms, *nms;
2315 
2316   if (mc->num_servers == 0) {
2317     MCM_ERRX(MCM_ERR_MC_SERV_LIST);
2318     return NULL;
2319   }
2320 
2321   ms = ctxt->mcServerFind(ctxt, mc, hash);
2322   if (ms == NULL) {
2323     MCM_ERRX(MCM_ERR_MC_VALID_SERVER);
2324     return NULL;
2325   }
2326 
2327   while (mcm_server_connect(ctxt, mc, ms) == -1) {
2328     MCM_ERR(MCM_ERR_NET_CONNECT);
2329     mcm_server_deactivate(ctxt, mc, ms);
2330 
2331     nms = ctxt->mcServerFind(ctxt, mc, hash);
2332     if (nms == NULL) {
2333       MCM_ERRX(MCM_ERR_MC_SERV_LIST);
2334       return NULL;
2335     }
2336 
2337     nms->rbuf= ms->rbuf;
2338     nms->wbuf = ms->wbuf;
2339     ms->rbuf = ms->wbuf = NULL;
2340     ms = nms;
2341   }
2342 
2343   ms->_last_hash = ctxt->_last_hash = hash;
2344 
2345   /* If there was a present left behind by the last memcache_server,
2346    * assume ownership of the command. */
2347   if (ctxt->_rbuf != NULL || ctxt->_wbuf != NULL) {
2348     ms->rbuf = ctxt->_rbuf;
2349     ms->wbuf = ctxt->_wbuf;
2350   }
2351 
2352   return ms;
2353 }
2354 
2355 
2356 void
mcm_server_deactivate(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2357 mcm_server_deactivate(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2358   /* Stash this server's command in the context */
2359   ctxt->_rbuf = ms->rbuf;
2360   ctxt->_wbuf = ms->wbuf;
2361   ctxt->_last_hash = ms->_last_hash;
2362 
2363   if (ms->active == 'u' || ms->active == 't')
2364     ms->active = 'd';
2365 
2366   mcm_server_disconnect(ctxt, ms);
2367 }
2368 
2369 
2370 void
mcm_server_disconnect(const struct memcache_ctxt * ctxt,struct memcache_server * ms)2371 mcm_server_disconnect(const struct memcache_ctxt *ctxt, struct memcache_server *ms) {
2372 #ifdef DEBUG_MC_PROTO
2373     MCM_WARNX_MSG(MCM_ERR_TRACE, "Attempting to disconnect");
2374 #endif
2375   if (ms->fd != -1) {
2376 #ifdef DEBUG_MC_PROTO
2377     MCM_WARNX_MSG(MCM_ERR_TRACE, "Closing file descriptor");
2378 #endif
2379     if (close(ms->fd) != 0)
2380       MCM_ERR(MCM_ERR_SYS_CLOSE);
2381     mcm_server_init(ctxt, ms);
2382   }
2383 }
2384 
2385 
2386 void
mcm_server_disconnect_all(const struct memcache_ctxt * ctxt,const struct memcache * mc)2387 mcm_server_disconnect_all(const struct memcache_ctxt *ctxt, const struct memcache *mc) {
2388   struct memcache_server *ms;
2389 
2390   for (ms = mc->server_list.tqh_first; ms != NULL; ms = ms->entries.tqe_next)
2391     mcm_server_disconnect(ctxt, ms);
2392 }
2393 
2394 
2395 struct memcache_server *
mcm_server_find(const struct memcache_ctxt * ctxt,struct memcache * mc,const u_int32_t hash)2396 mcm_server_find(const struct memcache_ctxt *ctxt, struct memcache *mc, const u_int32_t hash) {
2397   return ((struct memcache_server *)ctxt->mcServerFind(ctxt, mc, hash));
2398 }
2399 
2400 
2401 static void *
mcm_server_find_func(const void * void_ctxt,void * void_mc,const u_int32_t hash)2402 mcm_server_find_func(const void *void_ctxt, void *void_mc, const u_int32_t hash) {
2403   const struct memcache_ctxt *ctxt;
2404   struct memcache_server *ms = NULL;
2405   struct memcache *mc;
2406   u_int32_t idx, i;
2407 
2408   ctxt = (const struct memcache_ctxt *)void_ctxt;
2409   mc = (struct memcache *)void_mc;
2410 
2411   if (mc->num_servers < 1)
2412     return NULL;
2413 
2414   idx = hash % mc->num_servers;
2415 
2416   for (i = 0; i < mc->num_servers; i++) {
2417     /* Grab the correct server from the list. */
2418     ms = mc->servers[idx];
2419 
2420     if (ms->active == 'u' || ms->active == 't') {
2421       /* Store the last hash value used to find this server.  In the
2422        * event that this server dies, we use this value to
2423        * automatically fall back to the next server. */
2424       ms->_last_hash = hash;
2425 
2426       return ms;
2427     } else if (ms->active == 'd') {
2428       /* Try searching for the next server in this list.  Remember:
2429        * idx is zero based, but num_servers is one based. */
2430       if (idx + 1 == mc->num_servers)
2431 	idx = 0;
2432       else
2433 	idx++;
2434 
2435       continue;
2436     } else {
2437       MCM_ERRX(MCM_ERR_ASSERT);
2438       return NULL;
2439     }
2440   }
2441 
2442   return NULL;
2443 }
2444 
2445 
2446 void
mcm_server_free(struct memcache_ctxt * ctxt,struct memcache_server * ms)2447 mcm_server_free(struct memcache_ctxt *ctxt, struct memcache_server *ms) {
2448   if (ms == NULL)
2449     return;
2450 
2451   if (ms->hostinfo != NULL)
2452     freeaddrinfo(ms->hostinfo);
2453 
2454   if (ms->hostname != NULL)
2455     ctxt->mcFree(ms->hostname);
2456 
2457   if (ms->port != NULL)
2458     ctxt->mcFree(ms->port);
2459 
2460   if (ms->rbuf != NULL)
2461     mcm_buf_free(ctxt, &ms->rbuf);
2462 
2463   if (ms->wbuf != NULL)
2464     mcm_buf_free(ctxt, &ms->wbuf);
2465 
2466   mcm_server_disconnect(ctxt, ms);
2467 
2468   ctxt->mcFree(ms);
2469 }
2470 
2471 
2472 static void
mcm_server_init(const struct memcache_ctxt * ctxt,struct memcache_server * ms)2473 mcm_server_init(const struct memcache_ctxt *ctxt, struct memcache_server *ms) {
2474   ms->active = 't';
2475   ms->fd = -1;
2476   ms->startoff = ms->soff = 0;
2477 }
2478 
2479 
2480 struct memcache_server *
mcm_server_new(struct memcache_ctxt * ctxt)2481 mcm_server_new(struct memcache_ctxt *ctxt) {
2482   struct memcache_server *ms;
2483 
2484   ms = (struct memcache_server *)ctxt->mcMalloc(sizeof(struct memcache_server));
2485   if (ms != NULL) {
2486     bzero(ms, sizeof(struct memcache_server));
2487 
2488     ms->rbuf = mcm_buf_new(ctxt);
2489     if (ms->rbuf == NULL) {
2490       mcm_server_free(ctxt, ms);
2491       return NULL;
2492     }
2493 
2494     ms->wbuf = mcm_buf_new(ctxt);
2495     if (ms->wbuf == NULL) {
2496       mcm_server_free(ctxt, ms);
2497       return NULL;
2498     }
2499 
2500     /* Set default values */
2501     mcm_server_init(ctxt, ms);
2502   }
2503 
2504   return ms;
2505 }
2506 
2507 
2508 static int
mcm_server_readable(struct memcache_ctxt * ctxt,struct memcache_server * ms,struct timeval * tv)2509 mcm_server_readable(struct memcache_ctxt *ctxt, struct memcache_server *ms, struct timeval *tv) {
2510 #ifndef HAVE_SELECT
2511   return 1;
2512 #else
2513   struct timeval local_tv;
2514   socklen_t so_err_length;
2515   int ret, so_err;
2516 
2517   retry_check_readable:
2518 
2519   FD_ZERO(&ms->fds);
2520   FD_SET(ms->fd, &ms->fds);
2521 
2522 #ifdef DEBUG_MC_PROTO_ASSERT
2523   if (FD_ISSET(ms->fd, &ms->fds) == 0) {
2524     MCM_ERRX(MCM_ERR_ASSERT);
2525     return -1;
2526   }
2527 #endif
2528 
2529   memcpy(&local_tv, tv, sizeof(struct timeval));
2530 
2531 #ifdef DEBUG_MC_PROTO
2532   do {
2533     char *tm;
2534     size_t tml;
2535     tml = asprintf(&tm, "Begin select(2)'ing to see if fd %d is read(2)able.  Timeout %llu.%llu", ms->fd, (u_int64_t)local_tv.tv_sec, (u_int64_t)local_tv.tv_usec);
2536     if (tml > 0 && tm != NULL) {
2537       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2538       free(tm);
2539     }
2540   } while (0);
2541 #endif
2542 
2543   /* Before we read(2) anything, check to make sure there is data
2544    * available to be read(2).  No sense in wastefully calling read(2)
2545    * constantly in a loop. */
2546   ret = select(ms->fd + 1, &ms->fds, NULL, NULL, &local_tv);
2547 #ifdef DEBUG_MC_PROTO
2548   do {
2549     char *tm;
2550     size_t tml;
2551     tml = asprintf(&tm, "fd's ready to be read(2): %d/%d", ret, FD_SETSIZE);
2552     if (tml > 0 && tm != NULL) {
2553       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2554       free(tm);
2555     }
2556   } while (0);
2557 #endif
2558   if (ret > 0) {
2559     /* Check where readable flag is set */
2560     if (!FD_ISSET(ms->fd, &ms->fds)) {
2561       MCM_ERR(MCM_ERR_SYS_SELECT);
2562       return 0;
2563     }
2564 
2565     /* Check for the socket errors */
2566     so_err_length = sizeof(so_err);
2567     if (getsockopt(ms->fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &so_err_length) == -1) {
2568       MCM_ERR(MCM_ERR_SYS_SELECT); /* Socket error */
2569       return 0;
2570     } else {
2571       return ret;
2572     }
2573   } else if (ret == -1) {
2574     switch (errno) {
2575     case EINTR: /* retry this check again */
2576       goto retry_check_readable;
2577     default:
2578       MCM_ERR(MCM_ERR_SYS_SELECT);
2579       return 0;
2580     }
2581   } else if (ret == 0) {
2582     MCM_ERR_MSG(MCM_ERR_TIMEOUT, "select(2) call timed out for read(2)able fds");
2583     return 0;
2584   }
2585 
2586 #ifdef DEBUG_MC_PROTO
2587   MCM_WARNX_MSG(MCM_ERR_TRACE, "End select(2)'ing to see if fd is read(2)able");
2588 #endif
2589 
2590   return ret;
2591 #endif
2592 }
2593 
2594 
2595 static int
mcm_server_resolve(struct memcache_ctxt * ctxt,struct memcache_server * ms)2596 mcm_server_resolve(struct memcache_ctxt *ctxt, struct memcache_server *ms) {
2597   struct addrinfo hints, *res;
2598   int ret;
2599 
2600 #ifdef DEBUG_MC_PROTO
2601   do {
2602     char *tm;
2603     size_t tml;
2604     tml = asprintf(&tm, "Resolving the host %s:%s", ms->hostname, ms->port);
2605     if (tml > 0 && tm != NULL) {
2606       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2607       free(tm);
2608     }
2609   } while (0);
2610 #endif
2611 
2612   /* Resolve the hostname ahead of time */
2613   bzero(&hints, sizeof(struct addrinfo));
2614   hints.ai_family = PF_UNSPEC;
2615   hints.ai_socktype = SOCK_STREAM;
2616   hints.ai_protocol = IPPROTO_TCP;
2617   ret = getaddrinfo(ms->hostname, ms->port, &hints, &ms->hostinfo);
2618   if (ret != 0) {
2619 #ifdef DEBUG_MC_PROTO
2620     do {
2621       char *tm;
2622       size_t tml;
2623       tml = asprintf(&tm, "getaddrinfo(): %s", gai_strerror(ret));
2624       if (tml > 0 && tm != NULL) {
2625 	MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2626 	free(tm);
2627       }
2628     } while (0);
2629 #endif
2630 
2631     return ret;
2632   }
2633 
2634   for (res = ms->hostinfo; res != NULL; res = res->ai_next) {
2635     ms->num_addrs++;
2636 #ifdef DEBUG_MC_PROTO
2637     do {
2638       char *tm, ch[256], cs[256];
2639       size_t tml;
2640       tml = getnameinfo(res->ai_addr, res->ai_addr->sa_len, ch, sizeof(ch), cs, sizeof(cs), NI_NUMERICHOST | NI_NUMERICSERV);
2641       if (tml != 0) {
2642 	MCM_WARNX_MSG(MCM_ERR_TRACE, "Unable to get address");
2643 	return tml;
2644       }
2645 
2646       tml = asprintf(&tm, "Resolved host to \"%s:%s\"", ch, cs);
2647       if (tml > 0 && tm != NULL) {
2648 	MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2649 	free(tm);
2650       }
2651     } while (0);
2652 #endif
2653 
2654   }
2655 
2656   return 0;
2657 }
2658 
2659 
2660 static size_t
mcm_server_send_cmd(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2661 mcm_server_send_cmd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2662   ssize_t ret;
2663 
2664   ms->wbuf->off = 0;
2665 
2666 #ifdef DEBUG_MC_PROTO
2667   MCM_WARNX_MSG(MCM_ERR_TRACE, "Sending the following data to the server:");
2668   write(fileno(stderr), mcm_buf_to_cstr(ctxt, ms->wbuf), mcm_buf_len(ctxt, ms->wbuf) - ms->wbuf->off);
2669 #endif
2670 
2671   write_again:
2672   ret = write(ms->fd, mcm_buf_off_ptr(ctxt, ms->wbuf), mcm_buf_len(ctxt, ms->wbuf) - ms->wbuf->off);
2673 #ifdef DEBUG_MC_PROTO
2674   do {
2675     char *tm;
2676     size_t tml;
2677     tml = asprintf(&tm, "%d = write(2), errno = %d", (int)ret, errno);
2678     if (tml > 0 && tm != NULL) {
2679       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
2680       free(tm);
2681     }
2682   } while (0);
2683 #endif
2684   if (ret < 1) {
2685     switch (errno) {
2686     case EAGAIN:
2687     case EINTR:
2688     case ENOBUFS:
2689       goto write_again;
2690     case EBADF:
2691     case EDESTADDRREQ:
2692       /* Need to reconnect */
2693       MCM_ERR_MSG_LVL(MCM_ERR_MC_SEND_CMD, strerror(errno), MCM_ERR_LVL_INFO);
2694       mcm_server_disconnect(ctxt, ms);
2695 
2696       ms = mcm_server_connect_next_avail(ctxt, mc, ms->_last_hash);
2697       goto write_again;
2698     case EDQUOT:
2699     case EFAULT:
2700     case EFBIG:
2701     case EINVAL:
2702     case EIO:
2703     case ENOSPC:
2704     case EPIPE:
2705     default:
2706       MCM_ERR_MSG_LVL(MCM_ERR_MC_SEND_CMD, strerror(errno), MCM_ERR_LVL_FATAL);
2707       mcm_server_deactivate(ctxt, mc, ms);
2708       /* If we're here, the game's up and we can't continue. */
2709       return 0;
2710     }
2711   } else if ((size_t)ret == mcm_buf_len(ctxt, ms->wbuf) - ms->wbuf->off) {
2712     ms->wbuf->off += ret;
2713     return ret;
2714   } else {
2715     ms->wbuf->off += ret;
2716     goto write_again;
2717   }
2718 }
2719 
2720 
2721 inline static ssize_t
mcm_server_send_last_cmd(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2722 mcm_server_send_last_cmd(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2723   mcm_buf_reset(ctxt, ms->rbuf);
2724 
2725   return mcm_server_send_cmd(ctxt, mc, ms);
2726 }
2727 
2728 
2729 struct memcache_server_stats *
mcm_server_stats(struct memcache_ctxt * ctxt,struct memcache * mc,struct memcache_server * ms)2730 mcm_server_stats(struct memcache_ctxt *ctxt, struct memcache *mc, struct memcache_server *ms) {
2731   struct memcache_server_stats *s;
2732   char *cp, *cur;
2733 
2734   if (mcm_server_connect(ctxt, mc, ms) == -1)
2735     return NULL;
2736 
2737   mcm_buf_append(ctxt, ms->wbuf, "stats\r\n", MCM_CSTRLEN("stats\r\n"));
2738   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
2739     MCM_CLEAN_BUFS(ctxt, ms);
2740     return NULL;
2741   }
2742 
2743   s = mcm_server_stats_new(ctxt);
2744   if (s == NULL) {
2745     MCM_CLEAN_BUFS(ctxt, ms);
2746     return NULL;
2747   }
2748 
2749   for(;;) {
2750     cur = mcm_get_line(ctxt, mc, ms);
2751 
2752     if (cur != NULL && memcmp(cur, "STAT ", MCM_CSTRLEN("STAT ")) == 0) {
2753       cur = &cur[MCM_CSTRLEN("STAT ")];
2754 
2755       /* Time to loop through the potential stats keys.  Joy.  This is
2756        * going to complete in O(1 + 2 + 3 ... N) operations (currently
2757        * 190).  Ugh.  Don't know of a better way to handle this
2758        * without a hash.  Besides, this is just stats. */
2759       if (memcmp(cur, "pid ", MCM_CSTRLEN("pid ")) == 0) {
2760 	cur = &cur[MCM_CSTRLEN("pid ")];
2761 	s->pid = (pid_t)strtol(cur, &cp, 10);
2762 	if (s->pid == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2763 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid pid");
2764 	  MCM_CLEAN_BUFS(ctxt, ms);
2765 	  return NULL;
2766 	} else {
2767 	  cur = cp;
2768 	}
2769       } else if (memcmp(cur, "uptime ", MCM_CSTRLEN("uptime ")) == 0) {
2770 	cur = &cur[MCM_CSTRLEN("uptime ")];
2771 	s->uptime = (time_t)strtol(cur, &cp, 10);
2772 	if (s->uptime == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2773 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid uptime");
2774 	  MCM_CLEAN_BUFS(ctxt, ms);
2775 	  return NULL;
2776 	} else {
2777 	  cur = cp;
2778 	}
2779       } else if (memcmp(cur, "time ", MCM_CSTRLEN("time ")) == 0) {
2780 	cur = &cur[MCM_CSTRLEN("time ")];
2781 	s->time = (time_t)strtol(cur, &cp, 10);
2782 	if (s->time == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2783 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid time");
2784 	  MCM_CLEAN_BUFS(ctxt, ms);
2785 	  return NULL;
2786 	} else {
2787 	  cur = cp;
2788 	}
2789       } else if (memcmp(cur, "version ", MCM_CSTRLEN("version ")) == 0) {
2790 	cur = &cur[MCM_CSTRLEN("version ")];
2791 	for (cp = cur; !isspace(*cp); cp++);
2792 	s->version = (char *)ctxt->mcMallocAtomic((size_t)(cp - cur + 1));
2793 	if (s->version == NULL) {
2794 	  MCM_ERR(MCM_ERR_MEM_MALLOC);
2795 	} else {
2796 	  memcpy(s->version, cur, (size_t)(cp - cur));
2797 	  s->version[(size_t)(cp - cur)] = '\0';
2798 	}
2799       } else if (memcmp(cur, "rusage_user ", MCM_CSTRLEN("rusage_user ")) == 0) {
2800 	cur = &cur[MCM_CSTRLEN("rusage_user ")];
2801 	s->rusage_user.tv_sec = (int32_t)strtol(cur, &cp, 10);
2802 	if (s->rusage_user.tv_sec == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2803 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid rusage_user seconds");
2804 	  MCM_CLEAN_BUFS(ctxt, ms);
2805 	  return NULL;
2806 	} else {
2807 	  cur = cp;
2808 #ifdef DEBUG_MC_PROTO_ASSERT
2809 	  if (!(*cur == '.' || *cur == ':'))
2810 	    MCM_WARNX_MSG(MCM_ERR_PROTO, "invalid separator");
2811 	  else {
2812 #endif
2813 	    cur += 1; /* advance past colon */
2814 	    s->rusage_user.tv_usec = (int32_t)strtol(cur, &cp, 10);
2815 	    if (s->rusage_user.tv_usec == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2816 	      MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid rusage_user microseconds");
2817 	      MCM_CLEAN_BUFS(ctxt, ms);
2818 	      return NULL;
2819 	    } else {
2820 	      cur = cp;
2821 	    }
2822 #ifdef DEBUG_MC_PROTO_ASSERT
2823 	  }
2824 #endif
2825 	}
2826 
2827       } else if (memcmp(cur, "rusage_system ", MCM_CSTRLEN("rusage_system ")) == 0) {
2828 	cur = &cur[MCM_CSTRLEN("rusage_system ")];
2829 	s->rusage_system.tv_sec = (int32_t)strtol(cur, &cp, 10);
2830 	if (s->rusage_system.tv_sec == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2831 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid rusage_system seconds");
2832 	  MCM_CLEAN_BUFS(ctxt, ms);
2833 	  return NULL;
2834 	} else {
2835 	  cur = cp;
2836 #ifdef DEBUG_MC_PROTO_ASSERT
2837 	  if (!(*cur == '.' || *cur == ':')) {
2838 	    MCM_ERR_MSG(MCM_ERR_PROTO, "invalid separator");
2839 	    MCM_CLEAN_BUFS(ctxt, ms);
2840 	    return NULL;
2841 	  } else {
2842 #endif
2843 	    cur += 1; /* advance past colon */
2844 	    s->rusage_system.tv_usec = (int32_t)strtol(cur, &cp, 10);
2845 	    if (s->rusage_system.tv_usec == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2846 	      MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid rusage_system microseconds");
2847 	      MCM_CLEAN_BUFS(ctxt, ms);
2848 	      return NULL;
2849 	    } else {
2850 	      cur = cp;
2851 	    }
2852 #ifdef DEBUG_MC_PROTO_ASSERT
2853 	  }
2854 #endif
2855 	}
2856       } else if (memcmp(cur, "curr_items ", MCM_CSTRLEN("curr_items ")) == 0) {
2857 	cur = &cur[MCM_CSTRLEN("curr_items ")];
2858 	s->curr_items = (u_int32_t)strtol(cur, &cp, 10);
2859 	if (s->curr_items == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2860 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid curr_items");
2861 	  MCM_CLEAN_BUFS(ctxt, ms);
2862 	  return NULL;
2863 	} else {
2864 	  cur = cp;
2865 	}
2866       } else if (memcmp(cur, "total_items ", MCM_CSTRLEN("total_items ")) == 0) {
2867 	cur = &cur[MCM_CSTRLEN("total_items ")];
2868 	s->total_items = (u_int64_t)strtoll(cur, &cp, 10);
2869 	if (s->total_items == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2870 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid total_items");
2871 	  MCM_CLEAN_BUFS(ctxt, ms);
2872 	  return NULL;
2873 	} else {
2874 	  cur = cp;
2875 	}
2876       } else if (memcmp(cur, "bytes ", MCM_CSTRLEN("bytes ")) == 0) {
2877 	cur = &cur[MCM_CSTRLEN("bytes")];
2878 	s->bytes = (u_int64_t)strtoll(cur, &cp, 10);
2879 	if (s->bytes == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2880 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid bytes");
2881 	  MCM_CLEAN_BUFS(ctxt, ms);
2882 	  return NULL;
2883 	} else {
2884 	  cur = cp;
2885 	}
2886       } else if (memcmp(cur, "curr_connections ", MCM_CSTRLEN("curr_connections ")) == 0) {
2887 	cur = &cur[MCM_CSTRLEN("curr_connections ")];
2888 	s->curr_connections = (u_int32_t)strtol(cur, &cp, 10);
2889 	if (s->curr_connections == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2890 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid curr_connections");
2891 	  MCM_CLEAN_BUFS(ctxt, ms);
2892 	  return NULL;
2893 	} else {
2894 	  cur = cp;
2895 	}
2896       } else if (memcmp(cur, "total_connections ", MCM_CSTRLEN("total_connections ")) == 0) {
2897 	cur = &cur[MCM_CSTRLEN("total_connections ")];
2898 	s->total_connections = (u_int64_t)strtoll(cur, &cp, 10);
2899 	if (s->total_connections == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2900 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid total_connections");
2901 	  MCM_CLEAN_BUFS(ctxt, ms);
2902 	  return NULL;
2903 	} else {
2904 	  cur = cp;
2905 	}
2906       } else if (memcmp(cur, "connection_structures ", MCM_CSTRLEN("connection_structures ")) == 0) {
2907 	cur = &cur[MCM_CSTRLEN("connection_structures ")];
2908 	s->connection_structures = (u_int32_t)strtol(cur, &cp, 10);
2909 	if (s->connection_structures == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2910 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid connection_structures");
2911 	  MCM_CLEAN_BUFS(ctxt, ms);
2912 	  return NULL;
2913 	} else {
2914 	  cur = cp;
2915 	}
2916       } else if (memcmp(cur, "cmd_get ", MCM_CSTRLEN("cmd_get ")) == 0) {
2917 	cur = &cur[MCM_CSTRLEN("cmd_get ")];
2918 	s->cmd_get = (u_int64_t)strtoll(cur, &cp, 10);
2919 	if (s->cmd_get == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2920 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid cmd_get");
2921 	  MCM_CLEAN_BUFS(ctxt, ms);
2922 	  return NULL;
2923 	} else {
2924 	  cur = cp;
2925 	}
2926 #ifdef SEAN_HACKS
2927       } else if (memcmp(cur, "cmd_refresh ", MCM_CSTRLEN("cmd_refresh ")) == 0) {
2928 	cur = &cur[MCM_CSTRLEN("cmd_refresh ")];
2929 	s->cmd_refresh = (u_int64_t)strtoll(cur, &cp, 10);
2930 	if (s->cmd_refresh == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2931 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid cmd_refresh");
2932 	  MCM_CLEAN_BUFS(ctxt, ms);
2933 	  return NULL;
2934 	} else {
2935 	  cur = cp;
2936 	}
2937 #endif
2938       } else if (memcmp(cur, "cmd_set ", MCM_CSTRLEN("cmd_set ")) == 0) {
2939 	cur = &cur[MCM_CSTRLEN("cmd_set ")];
2940 	s->cmd_set = (u_int64_t)strtoll(cur, &cp, 10);
2941 	if (s->cmd_set == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2942 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid cmd_set");
2943 	  MCM_CLEAN_BUFS(ctxt, ms);
2944 	  return NULL;
2945 	} else {
2946 	  cur = cp;
2947 	}
2948       } else if (memcmp(cur, "get_hits ", MCM_CSTRLEN("get_hits ")) == 0) {
2949 	cur = &cur[MCM_CSTRLEN("get_hits ")];
2950 	s->get_hits = (u_int64_t)strtoll(cur, &cp, 10);
2951 	if (s->get_hits == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2952 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid get_hits");
2953 	  MCM_CLEAN_BUFS(ctxt, ms);
2954 	  return NULL;
2955 	} else {
2956 	  cur = cp;
2957 	}
2958       } else if (memcmp(cur, "get_misses ", MCM_CSTRLEN("get_misses ")) == 0) {
2959 	cur = &cur[MCM_CSTRLEN("get_misses ")];
2960 	s->get_misses = (u_int64_t)strtoll(cur, &cp, 10);
2961 	if (s->get_misses == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2962 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid get_misses");
2963 	  MCM_CLEAN_BUFS(ctxt, ms);
2964 	  return NULL;
2965 	} else {
2966 	  cur = cp;
2967 	}
2968 #ifdef SEAN_HACKS
2969       } else if (memcmp(cur, "refresh_hits ", MCM_CSTRLEN("refresh_hits ")) == 0) {
2970 	cur = &cur[MCM_CSTRLEN("refresh_hits ")];
2971 	s->refresh_hits = (u_int64_t)strtoll(cur, &cp, 10);
2972 	if (s->refresh_hits == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2973 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid refresh_hits");
2974 	  MCM_CLEAN_BUFS(ctxt, ms);
2975 	  return NULL;
2976 	} else {
2977 	  cur = cp;
2978 	}
2979       } else if (memcmp(cur, "refresh_misses ", MCM_CSTRLEN("refresh_misses ")) == 0) {
2980 	cur = &cur[MCM_CSTRLEN("refresh_misses ")];
2981 	s->refresh_misses = (u_int64_t)strtoll(cur, &cp, 10);
2982 	if (s->refresh_misses == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2983 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid refresh_misses");
2984 	  MCM_CLEAN_BUFS(ctxt, ms);
2985 	  return NULL;
2986 	} else {
2987 	  cur = cp;
2988 	}
2989 #endif
2990       } else if (memcmp(cur, "bytes_read ", MCM_CSTRLEN("bytes_read ")) == 0) {
2991 	cur = &cur[MCM_CSTRLEN("bytes_read ")];
2992 	s->bytes_read = (u_int64_t)strtoll(cur, &cp, 10);
2993 	if (s->bytes_read == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
2994 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid bytes_read");
2995 	  MCM_CLEAN_BUFS(ctxt, ms);
2996 	  return NULL;
2997 	} else {
2998 	  cur = cp;
2999 	}
3000       } else if (memcmp(cur, "bytes_written ", MCM_CSTRLEN("bytes_written ")) == 0) {
3001 	cur = &cur[MCM_CSTRLEN("bytes_written ")];
3002 	s->bytes_written = (u_int64_t)strtoll(cur, &cp, 10);
3003 	if (s->bytes_written == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
3004 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid bytes_written");
3005 	  MCM_CLEAN_BUFS(ctxt, ms);
3006 	  return NULL;
3007 	} else {
3008 	  cur = cp;
3009 	}
3010       } else if (memcmp(cur, "limit_maxbytes ", MCM_CSTRLEN("limit_maxbytes ")) == 0) {
3011 	cur = &cur[MCM_CSTRLEN("limit_maxbytes ")];
3012 	s->limit_maxbytes = (u_int64_t)strtoll(cur, &cp, 10);
3013 	if (s->limit_maxbytes == 0 && ((errno == EINVAL && cp == cur) || errno == ERANGE)) {
3014 	  MCM_ERR_MSG(MCM_ERR_LIB_STRTOL, "invalid limit_maxbytes");
3015 	  MCM_CLEAN_BUFS(ctxt, ms);
3016 	  return NULL;
3017 	} else {
3018 	  cur = cp;
3019 	}
3020       } else {
3021 	for (cp = cur; !isspace(*cp); cp++);
3022 	MCM_WARNX_MSGLEN(MCM_ERR_UNKNOWN_STAT, cur, (int)(cp - cur));
3023 	MCM_CLEAN_BUFS(ctxt, ms);
3024 	return NULL;
3025       }
3026 
3027       /* Now that we've sucked in our stats value, set our cursor to
3028        * the end of the value. */
3029       if (!mcm_buf_end(ctxt, ms->rbuf, "\r\n", MCM_CSTRLEN("\r\n"))) {
3030 	MCM_ERR_MSG(MCM_ERR_PROTO, "anticipated end of stats value: not at end of stats value");
3031 	mcm_server_stats_free(ctxt, s);
3032 	mcm_server_deactivate(ctxt, mc, ms);
3033 	MCM_CLEAN_BUFS(ctxt, ms);
3034 	return NULL;
3035       }
3036     } else if (cur != NULL && memcmp(cur, "END", MCM_CSTRLEN("END")) == 0) {
3037       /* We're done reading in stats. */
3038       break;
3039     } else {
3040       MCM_ERRX_MSG(MCM_ERR_PROTO, "unable to handle response");
3041       MCM_CLEAN_BUFS(ctxt, ms);
3042       return NULL;
3043     }
3044   }
3045 
3046   MCM_CLEAN_BUFS(ctxt, ms);
3047   return s;
3048 }
3049 
3050 
3051 int
mcm_server_timeout(const struct memcache_ctxt * ctxt,struct memcache_server * ms,const int sec,const int msec)3052 mcm_server_timeout(const struct memcache_ctxt *ctxt, struct memcache_server *ms, const int sec, const int msec) {
3053   ms->tv.tv_sec = sec;
3054   ms->tv.tv_usec = msec;
3055 
3056 #ifdef USE_SO_SNDTIMEO
3057   /* If any of the setsockopt(2) calls fail, close the socket, set the
3058    * file descriptor to -1, and continue trying to connect to the rest
3059    * of the servers that match this hostname.  More than likely there
3060    * is only one IP per host name, but, in the event there isn't,
3061    * continue to the next entry. */
3062   if (setsockopt(ms->fd, SOL_SOCKET, SO_SNDTIMEO, &ms->tv, (socklen_t)sizeof(struct timeval)) != 0) {
3063     MCM_ERR_MSG(MCM_ERR_SYS_SETSOCKOPT, "setsockopt(SO_SNDTIMEO) failed");
3064     return 0;
3065   }
3066 #endif
3067 
3068 #ifdef USE_SO_RCVTIMEO
3069   if (setsockopt(ms->fd, SOL_SOCKET, SO_RCVTIMEO, &ms->tv, (socklen_t)sizeof(struct timeval)) != 0) {
3070     MCM_ERR_MSG(MCM_ERR_SYS_SETSOCKOPT, "setsockopt(SO_RCVTIMEO) failed");
3071     return 0;
3072   }
3073 #endif
3074 
3075   return 1;
3076 }
3077 
3078 
3079 void
mcm_server_stats_free(const struct memcache_ctxt * ctxt,struct memcache_server_stats * s)3080 mcm_server_stats_free(const struct memcache_ctxt *ctxt, struct memcache_server_stats *s) {
3081   if (s->version != NULL)
3082     ctxt->mcFree(s->version);
3083   ctxt->mcFree(s);
3084 }
3085 
3086 
3087 static struct memcache_server_stats *
mcm_server_stats_new(const struct memcache_ctxt * ctxt)3088 mcm_server_stats_new(const struct memcache_ctxt *ctxt) {
3089   struct memcache_server_stats *s;
3090   s = (struct memcache_server_stats *)ctxt->mcMalloc(sizeof(struct memcache_server_stats));
3091   if (s != NULL) {
3092     bzero(s, sizeof(struct memcache_server_stats));
3093   }
3094 
3095   return s;
3096 }
3097 
3098 
3099 static int
mcm_server_writable(struct memcache_ctxt * ctxt,struct memcache_server * ms,struct timeval * tv)3100 mcm_server_writable(struct memcache_ctxt *ctxt, struct memcache_server *ms, struct timeval *tv) {
3101 #ifndef HAVE_SELECT
3102   return 1;
3103 #else
3104   struct timeval local_tv;
3105   socklen_t so_err_length;
3106   int ret, so_err;
3107 
3108   retry_check_writable:
3109 
3110   FD_ZERO(&ms->fds);
3111   FD_SET(ms->fd, &ms->fds);
3112 
3113 #ifdef DEBUG_MC_PROTO_ASSERT
3114   if (FD_ISSET(ms->fd, &ms->fds) == 0) {
3115     MCM_ERRX(MCM_ERR_ASSERT);
3116     return -1;
3117   }
3118 #endif
3119 
3120   memcpy(&local_tv, tv, sizeof(struct timeval));
3121 
3122 #ifdef DEBUG_MC_PROTO
3123   do {
3124     char *tm;
3125     size_t tml;
3126     tml = asprintf(&tm, "Begin select(2)'ing to see if fd %d is write(2)able.  Timeout %llu.%llu", ms->fd, (u_int64_t)local_tv.tv_sec, (u_int64_t)local_tv.tv_usec);
3127     if (tml > 0 && tm != NULL) {
3128       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
3129       free(tm);
3130     }
3131   } while (0);
3132 #endif
3133 
3134   /* Before we writev(2) anything, check to make sure the socket is
3135    * ready to accept data to be written out.  No sense in wastefully
3136    * calling writev(2) constantly in a loop. */
3137   ret = select(ms->fd + 1, NULL, &ms->fds, NULL, &local_tv);
3138 #ifdef DEBUG_MC_PROTO
3139   do {
3140     char *tm;
3141     size_t tml;
3142     tml = asprintf(&tm, "write(2)able fds: %d/%d", ret, FD_SETSIZE);
3143     if (tml > 0 && tm != NULL) {
3144       MCM_WARNX_MSG(MCM_ERR_TRACE, tm);
3145       free(tm);
3146     }
3147   } while (0);
3148 #endif
3149   if (ret > 0) {
3150     /* Check where writable flag is set */
3151     if (!FD_ISSET(ms->fd, &ms->fds)) {
3152       MCM_ERR(MCM_ERR_SYS_SELECT);
3153       return 0;
3154     }
3155 
3156     /* Check for the socket errors */
3157     so_err_length = sizeof(so_err);
3158     if (getsockopt(ms->fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &so_err_length) == -1) {
3159       MCM_ERR(MCM_ERR_SYS_SELECT); /* Socket error */
3160       return 0;
3161     } else {
3162       return ret;
3163     }
3164   } else if (ret == -1) {
3165     switch (errno) {
3166     case EINTR: /* retry this checking again */
3167       goto retry_check_writable;
3168     default:
3169       MCM_ERR(MCM_ERR_SYS_SELECT);
3170       return 0;
3171     }
3172   } else if (ret == 0) {
3173     MCM_ERR_MSG(MCM_ERR_TIMEOUT, "write select(2) call timed out");
3174     return 0;
3175   }
3176 
3177 #ifdef DEBUG_MC_PROTO
3178   MCM_WARNX_MSG(MCM_ERR_TRACE, "End select(2)'ing to see if fd is write(2)able");
3179 #endif
3180 
3181   return ret;
3182 #endif
3183 }
3184 
3185 
3186 int
mcm_set(struct memcache_ctxt * ctxt,struct memcache * mc,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)3187 mcm_set(struct memcache_ctxt *ctxt, struct memcache *mc,
3188 	char *key, const size_t key_len,
3189 	const void *val, const size_t bytes,
3190 	const time_t expire, const u_int16_t flags) {
3191   return mcm_storage_cmd(ctxt, mc, str_set_cmd, str_set_len, key, key_len, val, bytes, expire, flags);
3192 }
3193 
3194 
3195 struct memcache_server_stats *
mcm_stats(struct memcache_ctxt * ctxt,struct memcache * mc)3196 mcm_stats(struct memcache_ctxt *ctxt, struct memcache *mc) {
3197   struct memcache_server *ms;
3198   struct memcache_server_stats *s, *ts;
3199 
3200   s = mcm_server_stats_new(ctxt);
3201   for (ms = mc->server_list.tqh_first; ms != NULL; ms = ms->entries.tqe_next) {
3202     ts = mcm_server_stats(ctxt, mc, ms);
3203     if (ts == NULL)
3204       continue;
3205 
3206     /* Merge the values from ts into s.  Any per-server specific data
3207      * is pulled from the last server. */
3208     s->pid = ts->pid;
3209     s->uptime = ts->uptime;
3210     s->time = ts->time;
3211     if (s->version == NULL && ts->version != NULL)
3212       s->version = mcm_strdup(ctxt, ts->version);
3213 
3214     s->rusage_user.tv_sec += ts->rusage_user.tv_sec;
3215     s->rusage_user.tv_usec += ts->rusage_user.tv_usec;
3216     if (s->rusage_user.tv_usec > 1000000) {
3217       s->rusage_user.tv_sec += s->rusage_user.tv_usec / 1000000;
3218       s->rusage_user.tv_usec -= 1000000 * (s->rusage_user.tv_usec / 1000000);
3219     }
3220 
3221     s->rusage_system.tv_sec += ts->rusage_system.tv_sec;
3222     s->rusage_system.tv_usec += ts->rusage_system.tv_usec;
3223     if (s->rusage_system.tv_usec > 1000000) {
3224       s->rusage_system.tv_sec += s->rusage_system.tv_usec / 1000000;
3225       s->rusage_system.tv_usec -= 1000000 * (s->rusage_system.tv_usec / 1000000);
3226     }
3227 
3228     s->curr_items += ts->curr_items;
3229     s->total_items += ts->total_items;
3230     s->bytes = s->bytes + ts->bytes;
3231     s->curr_connections += ts->curr_connections;
3232     s->total_connections += ts->total_connections;
3233     s->connection_structures += ts->connection_structures;
3234     s->cmd_get += ts->cmd_get;
3235 #ifdef SEAN_HACKS
3236     s->cmd_refresh += ts->cmd_refresh;
3237 #endif
3238     s->cmd_set += ts->cmd_set;
3239     s->get_hits += ts->get_hits;
3240     s->get_misses += ts->get_misses;
3241 #ifdef SEAN_HACKS
3242     s->refresh_hits += ts->refresh_hits;
3243     s->refresh_misses += ts->refresh_misses;
3244 #endif
3245     s->bytes_read += ts->bytes_read;
3246     s->bytes_written += ts->bytes_written;
3247     s->limit_maxbytes += ts->limit_maxbytes;
3248 
3249     mcm_server_stats_free(ctxt, ts);
3250   }
3251 
3252   return s;
3253 }
3254 
3255 
3256 static int
mcm_storage_cmd(struct memcache_ctxt * ctxt,struct memcache * mc,const char * cmd,const size_t cmd_len,char * key,const size_t key_len,const void * val,const size_t bytes,const time_t expire,const u_int16_t flags)3257 mcm_storage_cmd(struct memcache_ctxt *ctxt, struct memcache *mc,
3258 		const char *cmd, const size_t cmd_len,
3259 		char *key, const size_t key_len,
3260 		const void *val, const size_t bytes,
3261 		const time_t expire, const u_int16_t flags) {
3262   char numbuf[11]; /* 10 == (2 ** 32).to_s.length + '\0'.length */
3263   struct memcache_server *ms;
3264   u_int32_t hash;
3265   size_t i;
3266   char *cp;
3267 
3268   MCM_VALIDATE_KEY(key, key_len);
3269 
3270   /* Reset ctxt->errnum upon entry into memcache(3). */
3271   ctxt->errnum = 0;
3272 
3273   hash = ctxt->mcHashKey(ctxt, mc, key, key_len);
3274 
3275   ms = mcm_server_connect_next_avail(ctxt, mc, hash);
3276   if (ms == NULL)
3277     return -1;
3278 
3279   mcm_buf_append(ctxt, ms->wbuf, cmd, cmd_len);
3280   mcm_buf_append(ctxt, ms->wbuf, key, key_len);
3281   mcm_buf_append_char(ctxt, ms->wbuf, ' ');
3282 
3283   /* Convert the value to a string */
3284   i = (size_t)snprintf(numbuf, sizeof(numbuf), "%u", (u_int32_t)flags);
3285   if (i < 1) {
3286     MCM_ERR(MCM_ERR_LIB_SNPRINTF);
3287     MCM_CLEAN_BUFS(ctxt, ms);
3288     return (int)MCM_RET_CODE(-3);
3289   }
3290 
3291   mcm_buf_append(ctxt, ms->wbuf, numbuf, i);
3292   mcm_buf_append_char(ctxt, ms->wbuf, ' ');
3293 
3294   /* Convert the value to a string */
3295   i = (size_t)snprintf(numbuf, sizeof(numbuf), "%lu", (long int unsigned)expire);
3296   if (i < 1) {
3297     MCM_ERR(MCM_ERR_LIB_SNPRINTF);
3298     MCM_CLEAN_BUFS(ctxt, ms);
3299     return (int)MCM_RET_CODE(-5);
3300   }
3301 
3302   mcm_buf_append(ctxt, ms->wbuf, numbuf, i);
3303   mcm_buf_append_char(ctxt, ms->wbuf, ' ');
3304 
3305   /* Convert the value to a string */
3306   i = (size_t)snprintf(numbuf, sizeof(numbuf), "%lu", (long int unsigned)bytes);
3307   if (i < 1) {
3308     MCM_ERR(MCM_ERR_LIB_SNPRINTF);
3309     MCM_CLEAN_BUFS(ctxt, ms);
3310     return (int)MCM_RET_CODE(-7);
3311   }
3312 
3313   mcm_buf_append(ctxt, ms->wbuf, numbuf, i);
3314   mcm_buf_append(ctxt, ms->wbuf, str_endl, str_endl_len);
3315 
3316   /* Add the data */
3317   mcm_buf_append(ctxt, ms->wbuf, val, bytes);
3318 
3319   /* Add another carriage return */
3320   mcm_buf_append(ctxt, ms->wbuf, str_endl, str_endl_len);
3321 
3322   if (mcm_server_send_cmd(ctxt, mc, ms) < 0) {
3323     MCM_CLEAN_BUFS(ctxt, ms);
3324     return (int)MCM_RET_CODE(-8);
3325   }
3326 
3327   cp = mcm_get_line(ctxt, mc, ms);
3328   if (cp != NULL && memcmp(cp, "STORED", MCM_CSTRLEN("STORED")) == 0) {
3329     /* Groovy Tuesday */
3330     MCM_CLEAN_BUFS(ctxt, ms);
3331     return 0;
3332   } else if (cp != NULL && memcmp(cp, "NOT_STORED", MCM_CSTRLEN("NOT_STORED")) == 0) {
3333     /* Fuck beans.  That was them, wasn't it? */
3334     MCM_ERR_MSG(MCM_ERR_MC_STORE, cmd);
3335     MCM_CLEAN_BUFS(ctxt, ms);
3336     return (int)MCM_RET_CODE(1);
3337   } else if (cp != NULL && memcmp(cp, "SERVER_ERROR ", MCM_CSTRLEN("SERVER_ERROR ")) == 0) {
3338     /* Drat!  Not enough memory on the server for this key. */
3339     MCM_ERR_MSG(MCM_ERR_MC_STORE, cp + MCM_CSTRLEN("SERVER_ERROR "));
3340     MCM_CLEAN_BUFS(ctxt, ms);
3341     return (int)MCM_RET_CODE(4);
3342   }
3343 
3344   if (mc->num_servers == 0) {
3345     MCM_ERRX(MCM_ERR_MC_SERV_LIST);
3346     MCM_CLEAN_BUFS(ctxt, ms);
3347     return (int)MCM_RET_CODE(3);
3348   } else {
3349     MCM_CLEAN_BUFS(ctxt, ms);
3350     return (int)MCM_RET_CODE(2);
3351   }
3352 }
3353 
3354 
3355 char *
mcm_strdup(const struct memcache_ctxt * ctxt,const char * str)3356 mcm_strdup(const struct memcache_ctxt *ctxt, const char *str) {
3357   return mcm_strndup(ctxt, str, strlen(str));
3358 }
3359 
3360 
3361 char *
mcm_strnchr(const struct memcache_ctxt * ctxt,mc_const char * str,int c,const size_t len)3362 mcm_strnchr(const struct memcache_ctxt *ctxt, mc_const char *str, int c, const size_t len) {
3363   char *cp;
3364   size_t i;
3365 
3366   for (cp = str, i = 0; i < len && *cp != '\0'; i++, cp++) {
3367     if (c == (int)*cp)
3368       return cp;
3369   }
3370 
3371   return '\0';
3372 }
3373 
3374 
3375 char *
mcm_strndup(const struct memcache_ctxt * ctxt,const char * str,const size_t len)3376 mcm_strndup(const struct memcache_ctxt *ctxt, const char *str, const size_t len) {
3377   char *cp;
3378 
3379   cp = ctxt->mcMallocAtomic(len + MCM_CSTRLEN("\0"));
3380   if (cp != NULL) {
3381     memcpy(cp, str, len);
3382     cp[len] = '\0';
3383   }
3384 
3385   return cp;
3386 }
3387 
3388 
3389 /*
3390  * Find the first occurrence of find in s, where the search is limited to the
3391  * first slen characters of s.
3392  */
3393 char *
mcm_strnstr(const struct memcache_ctxt * ctxt,mc_const char * s,const char * find,size_t slen)3394 mcm_strnstr(const struct memcache_ctxt *ctxt, mc_const char *s, const char *find, size_t slen) {
3395   char c, sc;
3396   size_t len;
3397 
3398   if ((c = *find++) != '\0') {
3399     len = strlen(find);
3400     do {
3401       do {
3402 	if (slen-- < 1 || (sc = *s++) == '\0')
3403 	  return (NULL);
3404       } while (sc != c);
3405       if (len > slen)
3406 	return (NULL);
3407     } while (strncmp(s, find, len) != 0);
3408     s--;
3409   }
3410   return ((char *)s);
3411 }
3412 
3413 
3414 void
mcm_timeout(const struct memcache_ctxt * ctxt,struct memcache * mc,const int sec,const int msec)3415 mcm_timeout(const struct memcache_ctxt *ctxt, struct memcache *mc, const int sec, const int msec) {
3416   mc->tv.tv_sec = sec;
3417   mc->tv.tv_usec = msec;
3418 }
3419 
3420 
3421 inline static int32_t
mcm_validate_key(const struct memcache_ctxt * ctxt,char * key,size_t len)3422 mcm_validate_key(const struct memcache_ctxt *ctxt, char *key, size_t len) {
3423   return (ctxt->mcKeyValid != NULL ? ctxt->mcKeyValid(ctxt, key, len) : 0);
3424 }
3425 
3426 
3427 static int32_t
mcm_validate_key_func(MCM_KEY_VALID_FUNC_ARGS)3428 mcm_validate_key_func(MCM_KEY_VALID_FUNC_ARGS) {
3429   const struct memcache_ctxt *ctxt;
3430   char *cp, *key;
3431   size_t len;
3432   size_t i;
3433 
3434   MCM_KEY_VALID_INIT(ctxt, key, len);
3435 
3436   for (i = 0, cp = key; i < len; i++, cp++) {
3437     if (isspace(*cp)) {
3438       MCM_ERRX_MSG_LVL(MCM_ERR_PROTO, "isspace(3) returned true for character in key", MCM_ERR_LVL_ERR);
3439       return (int32_t)MCM_RET_CODE((int32_t)(i + 1));
3440     }
3441   }
3442 
3443   return 0;
3444 }
3445 
3446 
3447 u_int32_t
mcm_vernum(const struct memcache_ctxt * ctxt)3448 mcm_vernum(const struct memcache_ctxt *ctxt) {
3449   return MEMCACHE_VERNUM;
3450 }
3451 
3452 
3453 const char *
mcm_version(const struct memcache_ctxt * ctxt)3454 mcm_version(const struct memcache_ctxt *ctxt) {
3455   return MEMCACHE_VER;
3456 }
3457 
3458 
3459 /* BEGIN memcache memory API */
3460 int
mcErrGet(mcErrFunc * errFunc)3461 mcErrGet(mcErrFunc *errFunc) {
3462   if (errFunc != NULL)
3463     *errFunc = mcGlobalCtxt.mcErr;
3464 
3465   return 0;
3466 }
3467 
3468 
3469 int
mcErrSetup(mcErrFunc errFunc)3470 mcErrSetup(mcErrFunc errFunc) {
3471   return mcErrSetupCtxt(&mcGlobalCtxt, errFunc);
3472 }
3473 
3474 
3475 int
mcErrSetupCtxt(struct memcache_ctxt * ctxt,mcErrFunc errFunc)3476 mcErrSetupCtxt(struct memcache_ctxt *ctxt, mcErrFunc errFunc) {
3477   if (ctxt == NULL || errFunc == NULL)
3478     return 1;
3479 
3480   ctxt->mcErr = errFunc;
3481 
3482   return 0;
3483 }
3484 
3485 
3486 int
mcMemGet(mcFreeFunc * freeFunc,mcMallocFunc * mallocFunc,mcMallocFunc * mallocAtomicFunc,mcReallocFunc * reallocFunc)3487 mcMemGet(mcFreeFunc *freeFunc, mcMallocFunc *mallocFunc, mcMallocFunc *mallocAtomicFunc,
3488 	 mcReallocFunc *reallocFunc) {
3489   if (freeFunc != NULL)
3490     *freeFunc = mcGlobalCtxt.mcFree;
3491 
3492   if (mallocFunc != NULL)
3493     *mallocFunc = mcGlobalCtxt.mcMalloc;
3494 
3495   if (mallocAtomicFunc != NULL)
3496     *mallocAtomicFunc = mcGlobalCtxt.mcMallocAtomic;
3497 
3498   if (reallocFunc != NULL)
3499     *reallocFunc = mcGlobalCtxt.mcRealloc;
3500 
3501   return 0;
3502 }
3503 
3504 
3505 struct memcache_ctxt *
mcMemNewCtxt(mcFreeFunc freeFunc,mcMallocFunc mallocFunc,mcMallocFunc mallocAtomicFunc,mcReallocFunc reallocFunc)3506 mcMemNewCtxt(mcFreeFunc freeFunc, mcMallocFunc mallocFunc, mcMallocFunc mallocAtomicFunc,
3507 	     mcReallocFunc reallocFunc) {
3508   struct memcache_ctxt *ctxt;
3509 
3510   if (freeFunc == NULL || mallocFunc == NULL || reallocFunc == NULL)
3511     return NULL;
3512 
3513   ctxt = mallocFunc(sizeof(struct memcache_ctxt));
3514   if (ctxt != NULL) {
3515     bzero(ctxt, sizeof(struct memcache_ctxt));
3516 
3517     ctxt->ectxt = mallocFunc(sizeof(struct memcache_err_ctxt));
3518     if (ctxt->ectxt == NULL) {
3519       freeFunc(ctxt);
3520       return NULL;
3521     }
3522     bzero(ctxt->ectxt, sizeof(struct memcache_err_ctxt));
3523 
3524     if (mcMemSetupCtxt(ctxt, freeFunc, mallocFunc, mallocAtomicFunc, reallocFunc) != 0) {
3525       bzero(ctxt, sizeof(struct memcache_ctxt));
3526       freeFunc(ctxt->ectxt);
3527       freeFunc(ctxt);
3528       return NULL;
3529     }
3530 
3531     /* Install our default error handler */
3532     ctxt->mcErr = mcm_err_func;
3533     ctxt->mcKeyValid = mcm_validate_key_func;
3534     ctxt->mcHashKey = mcm_hash_key_func;
3535     ctxt->mcServerFind = mcm_server_find_func;
3536 
3537     /* By default, ignore INFO and NOTICE level messages */
3538     ctxt->MCM_ERR_MASK = MCM_ERR_LVL_INFO | MCM_ERR_LVL_NOTICE;
3539   }
3540   return ctxt;
3541 }
3542 
3543 
3544 void
mcMemFreeCtxt(struct memcache_ctxt * ctxt)3545 mcMemFreeCtxt(struct memcache_ctxt *ctxt) {
3546   mcFreeFunc freeFunc;
3547 
3548   if (ctxt == NULL || ctxt->mcFree == NULL)
3549     return;
3550 
3551   freeFunc = ctxt->mcFree;
3552   freeFunc(ctxt->ectxt);
3553   freeFunc(ctxt);
3554 }
3555 
3556 
3557 int
mcMemSetup(mcFreeFunc freeFunc,mcMallocFunc mallocFunc,mcMallocFunc mallocAtomicFunc,mcReallocFunc reallocFunc)3558 mcMemSetup(mcFreeFunc freeFunc, mcMallocFunc mallocFunc,
3559 	   mcMallocFunc mallocAtomicFunc, mcReallocFunc reallocFunc) {
3560   return mcMemSetupCtxt(&mcGlobalCtxt, freeFunc, mallocFunc, mallocAtomicFunc, reallocFunc);
3561 }
3562 
3563 
3564 int
mcMemSetupCtxt(struct memcache_ctxt * ctxt,mcFreeFunc freeFunc,mcMallocFunc mallocFunc,mcMallocFunc mallocAtomicFunc,mcReallocFunc reallocFunc)3565 mcMemSetupCtxt(struct memcache_ctxt *ctxt, mcFreeFunc freeFunc, mcMallocFunc mallocFunc,
3566 	       mcMallocFunc mallocAtomicFunc, mcReallocFunc reallocFunc) {
3567   if (ctxt == NULL || freeFunc == NULL || mallocFunc == NULL || reallocFunc == NULL)
3568     return(1);
3569 
3570   ctxt->mcFree = freeFunc;
3571   ctxt->mcMalloc = mallocFunc;
3572   ctxt->mcMallocAtomic = (mallocAtomicFunc != NULL ? mallocAtomicFunc : mallocFunc);
3573   ctxt->mcRealloc = reallocFunc;
3574 
3575   return 0;
3576 }
3577 /* END memcache memory API */
3578