1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "apr_memcache.h"
18 #include "apr_poll.h"
19 #include "apr_version.h"
20 #include <stdlib.h>
21 
22 #define BUFFER_SIZE 512
23 struct apr_memcache_conn_t
24 {
25     char *buffer;
26     apr_size_t blen;
27     apr_pool_t *p;
28     apr_pool_t *tp;
29     apr_socket_t *sock;
30     apr_bucket_brigade *bb;
31     apr_bucket_brigade *tb;
32     apr_memcache_server_t *ms;
33 };
34 
35 /* Strings for Client Commands */
36 
37 #define MC_EOL "\r\n"
38 #define MC_EOL_LEN (sizeof(MC_EOL)-1)
39 
40 #define MC_WS " "
41 #define MC_WS_LEN (sizeof(MC_WS)-1)
42 
43 #define MC_GET "get "
44 #define MC_GET_LEN (sizeof(MC_GET)-1)
45 
46 #define MC_SET "set "
47 #define MC_SET_LEN (sizeof(MC_SET)-1)
48 
49 #define MC_ADD "add "
50 #define MC_ADD_LEN (sizeof(MC_ADD)-1)
51 
52 #define MC_REPLACE "replace "
53 #define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1)
54 
55 #define MC_DELETE "delete "
56 #define MC_DELETE_LEN (sizeof(MC_DELETE)-1)
57 
58 #define MC_INCR "incr "
59 #define MC_INCR_LEN (sizeof(MC_INCR)-1)
60 
61 #define MC_DECR "decr "
62 #define MC_DECR_LEN (sizeof(MC_DECR)-1)
63 
64 #define MC_VERSION "version"
65 #define MC_VERSION_LEN (sizeof(MC_VERSION)-1)
66 
67 #define MC_STATS "stats"
68 #define MC_STATS_LEN (sizeof(MC_STATS)-1)
69 
70 #define MC_QUIT "quit"
71 #define MC_QUIT_LEN (sizeof(MC_QUIT)-1)
72 
73 /* Strings for Server Replies */
74 
75 #define MS_STORED "STORED"
76 #define MS_STORED_LEN (sizeof(MS_STORED)-1)
77 
78 #define MS_NOT_STORED "NOT_STORED"
79 #define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1)
80 
81 #define MS_DELETED "DELETED"
82 #define MS_DELETED_LEN (sizeof(MS_DELETED)-1)
83 
84 #define MS_NOT_FOUND "NOT_FOUND"
85 #define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1)
86 
87 #define MS_VALUE "VALUE"
88 #define MS_VALUE_LEN (sizeof(MS_VALUE)-1)
89 
90 #define MS_ERROR "ERROR"
91 #define MS_ERROR_LEN (sizeof(MS_ERROR)-1)
92 
93 #define MS_VERSION "VERSION"
94 #define MS_VERSION_LEN (sizeof(MS_VERSION)-1)
95 
96 #define MS_STAT "STAT"
97 #define MS_STAT_LEN (sizeof(MS_STAT)-1)
98 
99 #define MS_END "END"
100 #define MS_END_LEN (sizeof(MS_END)-1)
101 
102 /** Server and Query Structure for a multiple get */
103 struct cache_server_query_t {
104     apr_memcache_server_t* ms;
105     apr_memcache_conn_t* conn;
106     struct iovec* query_vec;
107     apr_int32_t query_vec_count;
108 };
109 
110 #define MULT_GET_TIMEOUT 50000
111 
make_server_dead(apr_memcache_t * mc,apr_memcache_server_t * ms)112 static apr_status_t make_server_dead(apr_memcache_t *mc, apr_memcache_server_t *ms)
113 {
114 #if APR_HAS_THREADS
115     apr_thread_mutex_lock(ms->lock);
116 #endif
117     ms->status = APR_MC_SERVER_DEAD;
118     ms->btime = apr_time_now();
119 #if APR_HAS_THREADS
120     apr_thread_mutex_unlock(ms->lock);
121 #endif
122     return APR_SUCCESS;
123 }
124 
make_server_live(apr_memcache_t * mc,apr_memcache_server_t * ms)125 static apr_status_t make_server_live(apr_memcache_t *mc, apr_memcache_server_t *ms)
126 {
127     ms->status = APR_MC_SERVER_LIVE;
128     return APR_SUCCESS;
129 }
130 
131 
apr_memcache_add_server(apr_memcache_t * mc,apr_memcache_server_t * ms)132 APU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
133 {
134     apr_status_t rv = APR_SUCCESS;
135 
136     if(mc->ntotal >= mc->nalloc) {
137         return APR_ENOMEM;
138     }
139 
140     mc->live_servers[mc->ntotal] = ms;
141     mc->ntotal++;
142     make_server_live(mc, ms);
143     return rv;
144 }
145 
146 static apr_status_t mc_version_ping(apr_memcache_server_t *ms);
147 
148 APU_DECLARE(apr_memcache_server_t *)
apr_memcache_find_server_hash(apr_memcache_t * mc,const apr_uint32_t hash)149 apr_memcache_find_server_hash(apr_memcache_t *mc, const apr_uint32_t hash)
150 {
151     if (mc->server_func) {
152         return mc->server_func(mc->server_baton, mc, hash);
153     }
154     else {
155         return apr_memcache_find_server_hash_default(NULL, mc, hash);
156     }
157 }
158 
159 APU_DECLARE(apr_memcache_server_t *)
apr_memcache_find_server_hash_default(void * baton,apr_memcache_t * mc,const apr_uint32_t hash)160 apr_memcache_find_server_hash_default(void *baton, apr_memcache_t *mc,
161                                       const apr_uint32_t hash)
162 {
163     apr_memcache_server_t *ms = NULL;
164     apr_uint32_t h = hash ? hash : 1;
165     apr_uint32_t i = 0;
166     apr_time_t curtime = 0;
167 
168     if(mc->ntotal == 0) {
169         return NULL;
170     }
171 
172     do {
173         ms = mc->live_servers[h % mc->ntotal];
174         if(ms->status == APR_MC_SERVER_LIVE) {
175             break;
176         }
177         else {
178             if (curtime == 0) {
179                 curtime = apr_time_now();
180             }
181 #if APR_HAS_THREADS
182             apr_thread_mutex_lock(ms->lock);
183 #endif
184             /* Try the dead server, every 5 seconds */
185             if (curtime - ms->btime >  apr_time_from_sec(5)) {
186                 ms->btime = curtime;
187                 if (mc_version_ping(ms) == APR_SUCCESS) {
188                     make_server_live(mc, ms);
189 #if APR_HAS_THREADS
190                     apr_thread_mutex_unlock(ms->lock);
191 #endif
192                     break;
193                 }
194             }
195 #if APR_HAS_THREADS
196             apr_thread_mutex_unlock(ms->lock);
197 #endif
198         }
199         h++;
200         i++;
201     } while(i < mc->ntotal);
202 
203     if (i == mc->ntotal) {
204         ms = NULL;
205     }
206 
207     return ms;
208 }
209 
apr_memcache_find_server(apr_memcache_t * mc,const char * host,apr_port_t port)210 APU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, const char *host, apr_port_t port)
211 {
212     int i;
213 
214     for (i = 0; i < mc->ntotal; i++) {
215         if (strcmp(mc->live_servers[i]->host, host) == 0
216             && mc->live_servers[i]->port == port) {
217 
218             return mc->live_servers[i];
219         }
220     }
221 
222     return NULL;
223 }
224 
ms_find_conn(apr_memcache_server_t * ms,apr_memcache_conn_t ** conn)225 static apr_status_t ms_find_conn(apr_memcache_server_t *ms, apr_memcache_conn_t **conn)
226 {
227     apr_status_t rv;
228     apr_bucket_alloc_t *balloc;
229     apr_bucket *e;
230 
231 #if APR_HAS_THREADS
232     rv = apr_reslist_acquire(ms->conns, (void **)conn);
233 #else
234     *conn = ms->conn;
235     rv = APR_SUCCESS;
236 #endif
237 
238     if (rv != APR_SUCCESS) {
239         return rv;
240     }
241 
242     balloc = apr_bucket_alloc_create((*conn)->tp);
243     (*conn)->bb = apr_brigade_create((*conn)->tp, balloc);
244     (*conn)->tb = apr_brigade_create((*conn)->tp, balloc);
245 
246     e = apr_bucket_socket_create((*conn)->sock, balloc);
247     APR_BRIGADE_INSERT_TAIL((*conn)->bb, e);
248 
249     return rv;
250 }
251 
ms_bad_conn(apr_memcache_server_t * ms,apr_memcache_conn_t * conn)252 static apr_status_t ms_bad_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn)
253 {
254 #if APR_HAS_THREADS
255     return apr_reslist_invalidate(ms->conns, conn);
256 #else
257     return APR_SUCCESS;
258 #endif
259 }
260 
ms_release_conn(apr_memcache_server_t * ms,apr_memcache_conn_t * conn)261 static apr_status_t ms_release_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn)
262 {
263     apr_pool_clear(conn->tp);
264 #if APR_HAS_THREADS
265     return apr_reslist_release(ms->conns, conn);
266 #else
267     return APR_SUCCESS;
268 #endif
269 }
270 
apr_memcache_enable_server(apr_memcache_t * mc,apr_memcache_server_t * ms)271 APU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
272 {
273     apr_status_t rv = APR_SUCCESS;
274 
275     if (ms->status == APR_MC_SERVER_LIVE) {
276         return rv;
277     }
278 
279     rv = make_server_live(mc, ms);
280     return rv;
281 }
282 
apr_memcache_disable_server(apr_memcache_t * mc,apr_memcache_server_t * ms)283 APU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
284 {
285     return make_server_dead(mc, ms);
286 }
287 
conn_connect(apr_memcache_conn_t * conn)288 static apr_status_t conn_connect(apr_memcache_conn_t *conn)
289 {
290     apr_status_t rv = APR_SUCCESS;
291     apr_sockaddr_t *sa;
292 #if APR_HAVE_SOCKADDR_UN
293     apr_int32_t family = conn->ms->host[0] != '/' ? APR_INET : APR_UNIX;
294 #else
295     apr_int32_t family = APR_INET;
296 #endif
297 
298     rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p);
299     if (rv != APR_SUCCESS) {
300         return rv;
301     }
302 
303     rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC);
304     if (rv != APR_SUCCESS) {
305         return rv;
306     }
307 
308     rv = apr_socket_connect(conn->sock, sa);
309     if (rv != APR_SUCCESS) {
310         return rv;
311     }
312 
313     rv = apr_socket_timeout_set(conn->sock, -1);
314     if (rv != APR_SUCCESS) {
315         return rv;
316     }
317 
318     return rv;
319 }
320 
321 
322 static apr_status_t
mc_conn_construct(void ** conn_,void * params,apr_pool_t * pool)323 mc_conn_construct(void **conn_, void *params, apr_pool_t *pool)
324 {
325     apr_status_t rv = APR_SUCCESS;
326     apr_memcache_conn_t *conn;
327     apr_pool_t *np;
328     apr_pool_t *tp;
329     apr_memcache_server_t *ms = params;
330 #if APR_HAVE_SOCKADDR_UN
331     apr_int32_t family = ms->host[0] != '/' ? APR_INET : APR_UNIX;
332 #else
333     apr_int32_t family = APR_INET;
334 #endif
335 
336     rv = apr_pool_create(&np, pool);
337     if (rv != APR_SUCCESS) {
338         return rv;
339     }
340 
341     rv = apr_pool_create(&tp, np);
342     if (rv != APR_SUCCESS) {
343         apr_pool_destroy(np);
344         return rv;
345     }
346 
347     conn = apr_palloc(np, sizeof( apr_memcache_conn_t ));
348 
349     conn->p = np;
350     conn->tp = tp;
351 
352     rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np);
353 
354     if (rv != APR_SUCCESS) {
355         apr_pool_destroy(np);
356         return rv;
357     }
358 
359     conn->buffer = apr_palloc(conn->p, BUFFER_SIZE);
360     conn->blen = 0;
361     conn->ms = ms;
362 
363     rv = conn_connect(conn);
364     if (rv != APR_SUCCESS) {
365         apr_pool_destroy(np);
366     }
367     else {
368         *conn_ = conn;
369     }
370 
371     return rv;
372 }
373 
374 #if APR_HAS_THREADS
375 static apr_status_t
mc_conn_destruct(void * conn_,void * params,apr_pool_t * pool)376 mc_conn_destruct(void *conn_, void *params, apr_pool_t *pool)
377 {
378     apr_memcache_conn_t *conn = (apr_memcache_conn_t*)conn_;
379     struct iovec vec[2];
380     apr_size_t written;
381 
382     /* send a quit message to the memcached server to be nice about it. */
383     vec[0].iov_base = MC_QUIT;
384     vec[0].iov_len = MC_QUIT_LEN;
385 
386     vec[1].iov_base = MC_EOL;
387     vec[1].iov_len = MC_EOL_LEN;
388 
389     /* Return values not checked, since we just want to make it go away. */
390     apr_socket_sendv(conn->sock, vec, 2, &written);
391     apr_socket_close(conn->sock);
392 
393     apr_pool_destroy(conn->p);
394 
395     return APR_SUCCESS;
396 }
397 #endif
398 
apr_memcache_server_create(apr_pool_t * p,const char * host,apr_port_t port,apr_uint32_t min,apr_uint32_t smax,apr_uint32_t max,apr_uint32_t ttl,apr_memcache_server_t ** ms)399 APU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p,
400                                                      const char *host, apr_port_t port,
401                                                      apr_uint32_t min, apr_uint32_t smax,
402                                                      apr_uint32_t max, apr_uint32_t ttl,
403                                                      apr_memcache_server_t **ms)
404 {
405     apr_status_t rv = APR_SUCCESS;
406     apr_memcache_server_t *server;
407     apr_pool_t *np;
408 
409     rv = apr_pool_create(&np, p);
410 
411     server = apr_palloc(np, sizeof(apr_memcache_server_t));
412 
413     server->p = np;
414     server->host = apr_pstrdup(np, host);
415     server->port = port;
416     server->status = APR_MC_SERVER_DEAD;
417 #if APR_HAS_THREADS
418     rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np);
419     if (rv != APR_SUCCESS) {
420         return rv;
421     }
422 
423     rv = apr_reslist_create(&server->conns,
424                                min,                     /* hard minimum */
425                                smax,                    /* soft maximum */
426                                max,                     /* hard maximum */
427                                ttl,                     /* Time to live */
428                                mc_conn_construct,       /* Make a New Connection */
429                                mc_conn_destruct,        /* Kill Old Connection */
430                                server, np);
431     if (rv != APR_SUCCESS) {
432         return rv;
433     }
434 
435     apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST);
436 #else
437     rv = mc_conn_construct((void**)&(server->conn), server, np);
438     if (rv != APR_SUCCESS) {
439         return rv;
440     }
441 #endif
442 
443     *ms = server;
444 
445     return rv;
446 }
447 
apr_memcache_create(apr_pool_t * p,apr_uint16_t max_servers,apr_uint32_t flags,apr_memcache_t ** memcache)448 APU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p,
449                                               apr_uint16_t max_servers, apr_uint32_t flags,
450                                               apr_memcache_t **memcache)
451 {
452     apr_status_t rv = APR_SUCCESS;
453     apr_memcache_t *mc;
454 
455     mc = apr_palloc(p, sizeof(apr_memcache_t));
456     mc->p = p;
457     mc->nalloc = max_servers;
458     mc->ntotal = 0;
459     mc->live_servers = apr_palloc(p, mc->nalloc * sizeof(struct apr_memcache_server_t *));
460     mc->hash_func = NULL;
461     mc->hash_baton = NULL;
462     mc->server_func = NULL;
463     mc->server_baton = NULL;
464     *memcache = mc;
465     return rv;
466 }
467 
468 
469 /* The crc32 functions and data was originally written by Spencer
470  * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
471  * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
472  * src/usr.bin/cksum/crc32.c.
473  */
474 
475 static const apr_uint32_t crc32tab[256] = {
476   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
477   0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
478   0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
479   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
480   0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
481   0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
482   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
483   0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
484   0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
485   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
486   0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
487   0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
488   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
489   0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
490   0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
491   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
492   0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
493   0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
494   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
495   0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
496   0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
497   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
498   0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
499   0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
500   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
501   0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
502   0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
503   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
504   0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
505   0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
506   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
507   0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
508   0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
509   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
510   0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
511   0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
512   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
513   0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
514   0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
515   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
516   0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
517   0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
518   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
519   0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
520   0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
521   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
522   0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
523   0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
524   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
525   0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
526   0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
527   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
528   0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
529   0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
530   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
531   0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
532   0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
533   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
534   0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
535   0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
536   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
537   0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
538   0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
539   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
540 };
541 
apr_memcache_hash_crc32(void * baton,const char * data,const apr_size_t data_len)542 APU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton,
543                                                   const char *data,
544                                                   const apr_size_t data_len)
545 {
546     apr_uint32_t i;
547     apr_uint32_t crc;
548     crc = ~0;
549 
550     for (i = 0; i < data_len; i++)
551         crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff];
552 
553     return ~crc;
554 }
555 
apr_memcache_hash_default(void * baton,const char * data,const apr_size_t data_len)556 APU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton,
557                                                     const char *data,
558                                                     const apr_size_t data_len)
559 {
560     /* The default Perl Client doesn't actually use just crc32 -- it shifts it again
561      * like this....
562      */
563     return ((apr_memcache_hash_crc32(baton, data, data_len) >> 16) & 0x7fff);
564 }
565 
apr_memcache_hash(apr_memcache_t * mc,const char * data,const apr_size_t data_len)566 APU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc,
567                                             const char *data,
568                                             const apr_size_t data_len)
569 {
570     if (mc->hash_func) {
571         return mc->hash_func(mc->hash_baton, data, data_len);
572     }
573     else {
574         return apr_memcache_hash_default(NULL, data, data_len);
575     }
576 }
577 
get_server_line(apr_memcache_conn_t * conn)578 static apr_status_t get_server_line(apr_memcache_conn_t *conn)
579 {
580     apr_size_t bsize = BUFFER_SIZE;
581     apr_status_t rv = APR_SUCCESS;
582 
583     rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, BUFFER_SIZE);
584 
585     if (rv != APR_SUCCESS) {
586         return rv;
587     }
588 
589     rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize);
590 
591     if (rv != APR_SUCCESS) {
592         return rv;
593     }
594 
595     conn->blen = bsize;
596     conn->buffer[bsize] = '\0';
597 
598     return apr_brigade_cleanup(conn->tb);
599 }
600 
storage_cmd_write(apr_memcache_t * mc,char * cmd,const apr_size_t cmd_size,const char * key,char * data,const apr_size_t data_size,apr_uint32_t timeout,apr_uint16_t flags)601 static apr_status_t storage_cmd_write(apr_memcache_t *mc,
602                                       char *cmd,
603                                       const apr_size_t cmd_size,
604                                       const char *key,
605                                       char *data,
606                                       const apr_size_t data_size,
607                                       apr_uint32_t timeout,
608                                       apr_uint16_t flags)
609 {
610     apr_uint32_t hash;
611     apr_memcache_server_t *ms;
612     apr_memcache_conn_t *conn;
613     apr_status_t rv;
614     apr_size_t written;
615     struct iovec vec[5];
616     apr_size_t klen;
617 
618     apr_size_t key_size = strlen(key);
619 
620     hash = apr_memcache_hash(mc, key, key_size);
621 
622     ms = apr_memcache_find_server_hash(mc, hash);
623 
624     if (ms == NULL)
625         return APR_NOTFOUND;
626 
627     rv = ms_find_conn(ms, &conn);
628 
629     if (rv != APR_SUCCESS) {
630         apr_memcache_disable_server(mc, ms);
631         return rv;
632     }
633 
634     /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */
635 
636     vec[0].iov_base = cmd;
637     vec[0].iov_len  = cmd_size;
638 
639     vec[1].iov_base = (void*)key;
640     vec[1].iov_len  = key_size;
641 
642     klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u %u %" APR_SIZE_T_FMT " " MC_EOL,
643                         flags, timeout, data_size);
644 
645     vec[2].iov_base = conn->buffer;
646     vec[2].iov_len  = klen;
647 
648     vec[3].iov_base = data;
649     vec[3].iov_len  = data_size;
650 
651     vec[4].iov_base = MC_EOL;
652     vec[4].iov_len  = MC_EOL_LEN;
653 
654     rv = apr_socket_sendv(conn->sock, vec, 5, &written);
655 
656     if (rv != APR_SUCCESS) {
657         ms_bad_conn(ms, conn);
658         apr_memcache_disable_server(mc, ms);
659         return rv;
660     }
661 
662     rv = get_server_line(conn);
663 
664     if (rv != APR_SUCCESS) {
665         ms_bad_conn(ms, conn);
666         apr_memcache_disable_server(mc, ms);
667         return rv;
668     }
669 
670     if (strcmp(conn->buffer, MS_STORED MC_EOL) == 0) {
671         rv = APR_SUCCESS;
672     }
673     else if (strcmp(conn->buffer, MS_NOT_STORED MC_EOL) == 0) {
674         rv = APR_EEXIST;
675     }
676     else {
677         rv = APR_EGENERAL;
678     }
679 
680     ms_release_conn(ms, conn);
681 
682     return rv;
683 }
684 
685 APU_DECLARE(apr_status_t)
apr_memcache_set(apr_memcache_t * mc,const char * key,char * data,const apr_size_t data_size,apr_uint32_t timeout,apr_uint16_t flags)686 apr_memcache_set(apr_memcache_t *mc,
687                  const char *key,
688                  char *data,
689                  const apr_size_t data_size,
690                  apr_uint32_t timeout,
691                  apr_uint16_t flags)
692 {
693     return storage_cmd_write(mc,
694                            MC_SET, MC_SET_LEN,
695                            key,
696                            data, data_size,
697                            timeout, flags);
698 }
699 
700 APU_DECLARE(apr_status_t)
apr_memcache_add(apr_memcache_t * mc,const char * key,char * data,const apr_size_t data_size,apr_uint32_t timeout,apr_uint16_t flags)701 apr_memcache_add(apr_memcache_t *mc,
702                  const char *key,
703                  char *data,
704                  const apr_size_t data_size,
705                  apr_uint32_t timeout,
706                  apr_uint16_t flags)
707 {
708     return storage_cmd_write(mc,
709                            MC_ADD, MC_ADD_LEN,
710                            key,
711                            data, data_size,
712                            timeout, flags);
713 }
714 
715 APU_DECLARE(apr_status_t)
apr_memcache_replace(apr_memcache_t * mc,const char * key,char * data,const apr_size_t data_size,apr_uint32_t timeout,apr_uint16_t flags)716 apr_memcache_replace(apr_memcache_t *mc,
717                  const char *key,
718                  char *data,
719                  const apr_size_t data_size,
720                  apr_uint32_t timeout,
721                  apr_uint16_t flags)
722 {
723     return storage_cmd_write(mc,
724                            MC_REPLACE, MC_REPLACE_LEN,
725                            key,
726                            data, data_size,
727                            timeout, flags);
728 
729 }
730 
731 APU_DECLARE(apr_status_t)
apr_memcache_getp(apr_memcache_t * mc,apr_pool_t * p,const char * key,char ** baton,apr_size_t * new_length,apr_uint16_t * flags_)732 apr_memcache_getp(apr_memcache_t *mc,
733                   apr_pool_t *p,
734                   const char *key,
735                   char **baton,
736                   apr_size_t *new_length,
737                   apr_uint16_t *flags_)
738 {
739     apr_status_t rv;
740     apr_memcache_server_t *ms;
741     apr_memcache_conn_t *conn;
742     apr_uint32_t hash;
743     apr_size_t written;
744     apr_size_t klen = strlen(key);
745     struct iovec vec[3];
746 
747     hash = apr_memcache_hash(mc, key, klen);
748     ms = apr_memcache_find_server_hash(mc, hash);
749     if (ms == NULL)
750         return APR_NOTFOUND;
751 
752     rv = ms_find_conn(ms, &conn);
753 
754     if (rv != APR_SUCCESS) {
755         apr_memcache_disable_server(mc, ms);
756         return rv;
757     }
758 
759     /* get <key>[ <key>[...]]\r\n */
760     vec[0].iov_base = MC_GET;
761     vec[0].iov_len  = MC_GET_LEN;
762 
763     vec[1].iov_base = (void*)key;
764     vec[1].iov_len  = klen;
765 
766     vec[2].iov_base = MC_EOL;
767     vec[2].iov_len  = MC_EOL_LEN;
768 
769     rv = apr_socket_sendv(conn->sock, vec, 3, &written);
770 
771     if (rv != APR_SUCCESS) {
772         ms_bad_conn(ms, conn);
773         apr_memcache_disable_server(mc, ms);
774         return rv;
775     }
776 
777     rv = get_server_line(conn);
778     if (rv != APR_SUCCESS) {
779         ms_bad_conn(ms, conn);
780         apr_memcache_disable_server(mc, ms);
781         return rv;
782     }
783 
784     if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) {
785         char *flags;
786         char *length;
787         char *last;
788         apr_size_t len = 0;
789 
790         flags = apr_strtok(conn->buffer, " ", &last);
791         flags = apr_strtok(NULL, " ", &last);
792         flags = apr_strtok(NULL, " ", &last);
793 
794         if (flags_) {
795             *flags_ = atoi(flags);
796         }
797 
798         length = apr_strtok(NULL, " ", &last);
799         if (length) {
800             len = strtol(length, (char **)NULL, 10);
801         }
802 
803         if (len == 0 )  {
804             *new_length = 0;
805             *baton = NULL;
806         }
807         else {
808             apr_bucket_brigade *bbb;
809             apr_bucket *e;
810 
811             /* eat the trailing \r\n */
812             rv = apr_brigade_partition(conn->bb, len+2, &e);
813 
814             if (rv != APR_SUCCESS) {
815                 ms_bad_conn(ms, conn);
816                 apr_memcache_disable_server(mc, ms);
817                 return rv;
818             }
819 
820             bbb = apr_brigade_split(conn->bb, e);
821 
822             rv = apr_brigade_pflatten(conn->bb, baton, &len, p);
823 
824             if (rv != APR_SUCCESS) {
825                 ms_bad_conn(ms, conn);
826                 apr_memcache_disable_server(mc, ms);
827                 return rv;
828             }
829 
830             rv = apr_brigade_destroy(conn->bb);
831             if (rv != APR_SUCCESS) {
832                 ms_bad_conn(ms, conn);
833                 apr_memcache_disable_server(mc, ms);
834                 return rv;
835             }
836 
837             conn->bb = bbb;
838 
839             *new_length = len - 2;
840             (*baton)[*new_length] = '\0';
841         }
842 
843         rv = get_server_line(conn);
844         if (rv != APR_SUCCESS) {
845             ms_bad_conn(ms, conn);
846             apr_memcache_disable_server(mc, ms);
847             return rv;
848         }
849 
850         if (strncmp(MS_END, conn->buffer, MS_END_LEN) != 0) {
851             rv = APR_EGENERAL;
852         }
853     }
854     else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
855         rv = APR_NOTFOUND;
856     }
857     else {
858         rv = APR_EGENERAL;
859     }
860 
861     ms_release_conn(ms, conn);
862 
863     return rv;
864 }
865 
866 APU_DECLARE(apr_status_t)
apr_memcache_delete(apr_memcache_t * mc,const char * key,apr_uint32_t timeout)867 apr_memcache_delete(apr_memcache_t *mc,
868                     const char *key,
869                     apr_uint32_t timeout)
870 {
871     apr_status_t rv;
872     apr_memcache_server_t *ms;
873     apr_memcache_conn_t *conn;
874     apr_uint32_t hash;
875     apr_size_t written;
876     struct iovec vec[3];
877     apr_size_t klen = strlen(key);
878 
879     hash = apr_memcache_hash(mc, key, klen);
880     ms = apr_memcache_find_server_hash(mc, hash);
881     if (ms == NULL)
882         return APR_NOTFOUND;
883 
884     rv = ms_find_conn(ms, &conn);
885 
886     if (rv != APR_SUCCESS) {
887         apr_memcache_disable_server(mc, ms);
888         return rv;
889     }
890 
891     /* delete <key> <time>\r\n */
892     vec[0].iov_base = MC_DELETE;
893     vec[0].iov_len  = MC_DELETE_LEN;
894 
895     vec[1].iov_base = (void*)key;
896     vec[1].iov_len  = klen;
897 
898     klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, timeout);
899 
900     vec[2].iov_base = conn->buffer;
901     vec[2].iov_len  = klen;
902 
903     rv = apr_socket_sendv(conn->sock, vec, 3, &written);
904 
905     if (rv != APR_SUCCESS) {
906         ms_bad_conn(ms, conn);
907         apr_memcache_disable_server(mc, ms);
908         return rv;
909     }
910 
911     rv = get_server_line(conn);
912     if (rv != APR_SUCCESS) {
913         ms_bad_conn(ms, conn);
914         apr_memcache_disable_server(mc, ms);
915         return rv;
916     }
917 
918     if (strncmp(MS_DELETED, conn->buffer, MS_DELETED_LEN) == 0) {
919         rv = APR_SUCCESS;
920     }
921     else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) {
922         rv = APR_NOTFOUND;
923     }
924     else {
925         rv = APR_EGENERAL;
926     }
927 
928     ms_release_conn(ms, conn);
929 
930     return rv;
931 }
932 
num_cmd_write(apr_memcache_t * mc,char * cmd,const apr_uint32_t cmd_size,const char * key,const apr_int32_t inc,apr_uint32_t * new_value)933 static apr_status_t num_cmd_write(apr_memcache_t *mc,
934                                       char *cmd,
935                                       const apr_uint32_t cmd_size,
936                                       const char *key,
937                                       const apr_int32_t inc,
938                                       apr_uint32_t *new_value)
939 {
940     apr_status_t rv;
941     apr_memcache_server_t *ms;
942     apr_memcache_conn_t *conn;
943     apr_uint32_t hash;
944     apr_size_t written;
945     struct iovec vec[3];
946     apr_size_t klen = strlen(key);
947 
948     hash = apr_memcache_hash(mc, key, klen);
949     ms = apr_memcache_find_server_hash(mc, hash);
950     if (ms == NULL)
951         return APR_NOTFOUND;
952 
953     rv = ms_find_conn(ms, &conn);
954 
955     if (rv != APR_SUCCESS) {
956         apr_memcache_disable_server(mc, ms);
957         return rv;
958     }
959 
960     /* <cmd> <key> <value>\r\n */
961     vec[0].iov_base = cmd;
962     vec[0].iov_len  = cmd_size;
963 
964     vec[1].iov_base = (void*)key;
965     vec[1].iov_len  = klen;
966 
967     klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, inc);
968 
969     vec[2].iov_base = conn->buffer;
970     vec[2].iov_len  = klen;
971 
972     rv = apr_socket_sendv(conn->sock, vec, 3, &written);
973 
974     if (rv != APR_SUCCESS) {
975         ms_bad_conn(ms, conn);
976         apr_memcache_disable_server(mc, ms);
977         return rv;
978     }
979 
980     rv = get_server_line(conn);
981     if (rv != APR_SUCCESS) {
982         ms_bad_conn(ms, conn);
983         apr_memcache_disable_server(mc, ms);
984         return rv;
985     }
986 
987     if (strncmp(MS_ERROR, conn->buffer, MS_ERROR_LEN) == 0) {
988         rv = APR_EGENERAL;
989     }
990     else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) {
991         rv = APR_NOTFOUND;
992     }
993     else {
994         if (new_value) {
995             *new_value = atoi(conn->buffer);
996         }
997         rv = APR_SUCCESS;
998     }
999 
1000     ms_release_conn(ms, conn);
1001 
1002     return rv;
1003 }
1004 
1005 APU_DECLARE(apr_status_t)
apr_memcache_incr(apr_memcache_t * mc,const char * key,apr_int32_t inc,apr_uint32_t * new_value)1006 apr_memcache_incr(apr_memcache_t *mc,
1007                     const char *key,
1008                     apr_int32_t inc,
1009                     apr_uint32_t *new_value)
1010 {
1011     return num_cmd_write(mc,
1012                          MC_INCR,
1013                          MC_INCR_LEN,
1014                          key,
1015                          inc,
1016                          new_value);
1017 }
1018 
1019 
1020 APU_DECLARE(apr_status_t)
apr_memcache_decr(apr_memcache_t * mc,const char * key,apr_int32_t inc,apr_uint32_t * new_value)1021 apr_memcache_decr(apr_memcache_t *mc,
1022                     const char *key,
1023                     apr_int32_t inc,
1024                     apr_uint32_t *new_value)
1025 {
1026     return num_cmd_write(mc,
1027                          MC_DECR,
1028                          MC_DECR_LEN,
1029                          key,
1030                          inc,
1031                          new_value);
1032 }
1033 
1034 
1035 
1036 APU_DECLARE(apr_status_t)
apr_memcache_version(apr_memcache_server_t * ms,apr_pool_t * p,char ** baton)1037 apr_memcache_version(apr_memcache_server_t *ms,
1038                   apr_pool_t *p,
1039                   char **baton)
1040 {
1041     apr_status_t rv;
1042     apr_memcache_conn_t *conn;
1043     apr_size_t written;
1044     struct iovec vec[2];
1045 
1046     rv = ms_find_conn(ms, &conn);
1047 
1048     if (rv != APR_SUCCESS) {
1049         return rv;
1050     }
1051 
1052     /* version\r\n */
1053     vec[0].iov_base = MC_VERSION;
1054     vec[0].iov_len  = MC_VERSION_LEN;
1055 
1056     vec[1].iov_base = MC_EOL;
1057     vec[1].iov_len  = MC_EOL_LEN;
1058 
1059     rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1060 
1061     if (rv != APR_SUCCESS) {
1062         ms_bad_conn(ms, conn);
1063         return rv;
1064     }
1065 
1066     rv = get_server_line(conn);
1067     if (rv != APR_SUCCESS) {
1068         ms_bad_conn(ms, conn);
1069         return rv;
1070     }
1071 
1072     if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) {
1073         *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1,
1074                                 conn->blen - MS_VERSION_LEN - 2);
1075         rv = APR_SUCCESS;
1076     }
1077     else {
1078         rv = APR_EGENERAL;
1079     }
1080 
1081     ms_release_conn(ms, conn);
1082 
1083     return rv;
1084 }
1085 
mc_version_ping(apr_memcache_server_t * ms)1086 apr_status_t mc_version_ping(apr_memcache_server_t *ms)
1087 {
1088     apr_status_t rv;
1089     apr_size_t written;
1090     struct iovec vec[2];
1091     apr_memcache_conn_t *conn;
1092 
1093     rv = ms_find_conn(ms, &conn);
1094 
1095     if (rv != APR_SUCCESS) {
1096         return rv;
1097     }
1098 
1099     /* version\r\n */
1100     vec[0].iov_base = MC_VERSION;
1101     vec[0].iov_len  = MC_VERSION_LEN;
1102 
1103     vec[1].iov_base = MC_EOL;
1104     vec[1].iov_len  = MC_EOL_LEN;
1105 
1106     rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1107 
1108     if (rv != APR_SUCCESS) {
1109         ms_bad_conn(ms, conn);
1110         return rv;
1111     }
1112 
1113     rv = get_server_line(conn);
1114     ms_release_conn(ms, conn);
1115     return rv;
1116 }
1117 
1118 
1119 APU_DECLARE(void)
apr_memcache_add_multget_key(apr_pool_t * data_pool,const char * key,apr_hash_t ** values)1120 apr_memcache_add_multget_key(apr_pool_t *data_pool,
1121                              const char* key,
1122                              apr_hash_t **values)
1123 {
1124     apr_memcache_value_t* value;
1125     apr_size_t klen = strlen(key);
1126 
1127     /* create the value hash if need be */
1128     if (!*values) {
1129         *values = apr_hash_make(data_pool);
1130     }
1131 
1132     /* init key and add it to the value hash */
1133     value = apr_pcalloc(data_pool, sizeof(apr_memcache_value_t));
1134 
1135     value->status = APR_NOTFOUND;
1136     value->key = apr_pstrdup(data_pool, key);
1137 
1138     apr_hash_set(*values, value->key, klen, value);
1139 }
1140 
mget_conn_result(int serverup,int connup,apr_status_t rv,apr_memcache_t * mc,apr_memcache_server_t * ms,apr_memcache_conn_t * conn,struct cache_server_query_t * server_query,apr_hash_t * values,apr_hash_t * server_queries)1141 static void mget_conn_result(int serverup,
1142                              int connup,
1143                              apr_status_t rv,
1144                              apr_memcache_t *mc,
1145                              apr_memcache_server_t *ms,
1146                              apr_memcache_conn_t *conn,
1147                              struct cache_server_query_t *server_query,
1148                              apr_hash_t *values,
1149                              apr_hash_t *server_queries)
1150 {
1151     apr_int32_t j;
1152     apr_memcache_value_t* value;
1153 
1154     apr_hash_set(server_queries, &ms, sizeof(ms), NULL);
1155 
1156     if (connup) {
1157         ms_release_conn(ms, conn);
1158     } else {
1159         ms_bad_conn(ms, conn);
1160 
1161         if (!serverup) {
1162             apr_memcache_disable_server(mc, ms);
1163         }
1164     }
1165 
1166     for (j = 1; j < server_query->query_vec_count ; j+=2) {
1167         if (server_query->query_vec[j].iov_base) {
1168             value = apr_hash_get(values, server_query->query_vec[j].iov_base,
1169                                  strlen(server_query->query_vec[j].iov_base));
1170 
1171             if (value->status == APR_NOTFOUND) {
1172                 value->status = rv;
1173             }
1174         }
1175     }
1176 }
1177 
1178 APU_DECLARE(apr_status_t)
apr_memcache_multgetp(apr_memcache_t * mc,apr_pool_t * temp_pool,apr_pool_t * data_pool,apr_hash_t * values)1179 apr_memcache_multgetp(apr_memcache_t *mc,
1180                       apr_pool_t *temp_pool,
1181                       apr_pool_t *data_pool,
1182                       apr_hash_t *values)
1183 {
1184     apr_status_t rv;
1185     apr_memcache_server_t* ms;
1186     apr_memcache_conn_t* conn;
1187     apr_uint32_t hash;
1188     apr_size_t written;
1189     apr_size_t klen;
1190 
1191     apr_memcache_value_t* value;
1192     apr_hash_index_t* value_hash_index;
1193 
1194     /* this is a little over aggresive, but beats multiple loops
1195      * to figure out how long each vector needs to be per-server.
1196      */
1197     apr_int32_t veclen = 2 + 2 * apr_hash_count(values) - 1; /* get <key>[<space><key>...]\r\n */
1198     apr_int32_t i, j;
1199     apr_int32_t queries_sent;
1200     apr_int32_t queries_recvd;
1201 
1202     apr_hash_t * server_queries = apr_hash_make(temp_pool);
1203     struct cache_server_query_t* server_query;
1204     apr_hash_index_t * query_hash_index;
1205 
1206     apr_pollset_t* pollset;
1207     const apr_pollfd_t* activefds;
1208     apr_pollfd_t* pollfds;
1209 
1210 
1211     /* build all the queries */
1212     value_hash_index = apr_hash_first(temp_pool, values);
1213     while (value_hash_index) {
1214         void *v;
1215         apr_hash_this(value_hash_index, NULL, NULL, &v);
1216         value = v;
1217         value_hash_index = apr_hash_next(value_hash_index);
1218         klen = strlen(value->key);
1219 
1220         hash = apr_memcache_hash(mc, value->key, klen);
1221         ms = apr_memcache_find_server_hash(mc, hash);
1222         if (ms == NULL) {
1223             continue;
1224         }
1225 
1226         server_query = apr_hash_get(server_queries, &ms, sizeof(ms));
1227 
1228         if (!server_query) {
1229             rv = ms_find_conn(ms, &conn);
1230 
1231             if (rv != APR_SUCCESS) {
1232                 apr_memcache_disable_server(mc, ms);
1233                 value->status = rv;
1234                 continue;
1235             }
1236 
1237             server_query = apr_pcalloc(temp_pool,sizeof(struct cache_server_query_t));
1238 
1239             apr_hash_set(server_queries, &ms, sizeof(ms), server_query);
1240 
1241             server_query->ms = ms;
1242             server_query->conn = conn;
1243             server_query->query_vec = apr_pcalloc(temp_pool, sizeof(struct iovec)*veclen);
1244 
1245             /* set up the first key */
1246             server_query->query_vec[0].iov_base = MC_GET;
1247             server_query->query_vec[0].iov_len  = MC_GET_LEN;
1248 
1249             server_query->query_vec[1].iov_base = (void*)(value->key);
1250             server_query->query_vec[1].iov_len  = klen;
1251 
1252             server_query->query_vec[2].iov_base = MC_EOL;
1253             server_query->query_vec[2].iov_len  = MC_EOL_LEN;
1254 
1255             server_query->query_vec_count = 3;
1256         }
1257         else {
1258             j = server_query->query_vec_count - 1;
1259 
1260             server_query->query_vec[j].iov_base = MC_WS;
1261             server_query->query_vec[j].iov_len  = MC_WS_LEN;
1262             j++;
1263 
1264             server_query->query_vec[j].iov_base = (void*)(value->key);
1265             server_query->query_vec[j].iov_len  = klen;
1266             j++;
1267 
1268             server_query->query_vec[j].iov_base = MC_EOL;
1269             server_query->query_vec[j].iov_len  = MC_EOL_LEN;
1270             j++;
1271 
1272            server_query->query_vec_count = j;
1273         }
1274     }
1275 
1276     /* create polling structures */
1277     pollfds = apr_pcalloc(temp_pool, apr_hash_count(server_queries) * sizeof(apr_pollfd_t));
1278 
1279     rv = apr_pollset_create(&pollset, apr_hash_count(server_queries), temp_pool, 0);
1280 
1281     if (rv != APR_SUCCESS) {
1282         query_hash_index = apr_hash_first(temp_pool, server_queries);
1283 
1284         while (query_hash_index) {
1285             void *v;
1286             apr_hash_this(query_hash_index, NULL, NULL, &v);
1287             server_query = v;
1288             query_hash_index = apr_hash_next(query_hash_index);
1289 
1290             mget_conn_result(TRUE, TRUE, rv, mc, server_query->ms, server_query->conn,
1291                              server_query, values, server_queries);
1292         }
1293 
1294         return rv;
1295     }
1296 
1297     /* send all the queries */
1298     queries_sent = 0;
1299     query_hash_index = apr_hash_first(temp_pool, server_queries);
1300 
1301     while (query_hash_index) {
1302         void *v;
1303         apr_hash_this(query_hash_index, NULL, NULL, &v);
1304         server_query = v;
1305         query_hash_index = apr_hash_next(query_hash_index);
1306 
1307         conn = server_query->conn;
1308         ms = server_query->ms;
1309 
1310         for (i = 0, rv = APR_SUCCESS; i < veclen && rv == APR_SUCCESS; i += APR_MAX_IOVEC_SIZE) {
1311             rv = apr_socket_sendv(conn->sock, &(server_query->query_vec[i]),
1312                                   veclen-i>APR_MAX_IOVEC_SIZE ? APR_MAX_IOVEC_SIZE : veclen-i , &written);
1313         }
1314 
1315         if (rv != APR_SUCCESS) {
1316             mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1317                              server_query, values, server_queries);
1318             continue;
1319         }
1320 
1321         pollfds[queries_sent].desc_type = APR_POLL_SOCKET;
1322         pollfds[queries_sent].reqevents = APR_POLLIN;
1323         pollfds[queries_sent].p = temp_pool;
1324         pollfds[queries_sent].desc.s = conn->sock;
1325         pollfds[queries_sent].client_data = (void *)server_query;
1326         apr_pollset_add (pollset, &pollfds[queries_sent]);
1327 
1328         queries_sent++;
1329     }
1330 
1331     while (queries_sent) {
1332         rv = apr_pollset_poll(pollset, MULT_GET_TIMEOUT, &queries_recvd, &activefds);
1333 
1334         if (rv != APR_SUCCESS) {
1335             /* timeout */
1336             queries_sent = 0;
1337             continue;
1338         }
1339         for (i = 0; i < queries_recvd; i++) {
1340             server_query = activefds[i].client_data;
1341             conn = server_query->conn;
1342             ms = server_query->ms;
1343 
1344            rv = get_server_line(conn);
1345 
1346            if (rv != APR_SUCCESS) {
1347                apr_pollset_remove (pollset, &activefds[i]);
1348                mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1349                                 server_query, values, server_queries);
1350                queries_sent--;
1351                continue;
1352            }
1353 
1354            if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) {
1355                char *key;
1356                char *flags;
1357                char *length;
1358                char *last;
1359                char *data;
1360                apr_size_t len = 0;
1361 
1362                key = apr_strtok(conn->buffer, " ", &last); /* just the VALUE, ignore */
1363                key = apr_strtok(NULL, " ", &last);
1364                flags = apr_strtok(NULL, " ", &last);
1365 
1366 
1367                length = apr_strtok(NULL, " ", &last);
1368                if (length) {
1369                    len = strtol(length, (char **) NULL, 10);
1370                }
1371 
1372                value = apr_hash_get(values, key, strlen(key));
1373 
1374 
1375                if (value) {
1376                    if (len != 0)  {
1377                        apr_bucket_brigade *bbb;
1378                        apr_bucket *e;
1379 
1380                        /* eat the trailing \r\n */
1381                        rv = apr_brigade_partition(conn->bb, len+2, &e);
1382 
1383                        if (rv != APR_SUCCESS) {
1384                            apr_pollset_remove (pollset, &activefds[i]);
1385                            mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1386                                             server_query, values, server_queries);
1387                            queries_sent--;
1388                            continue;
1389                        }
1390 
1391                        bbb = apr_brigade_split(conn->bb, e);
1392 
1393                        rv = apr_brigade_pflatten(conn->bb, &data, &len, data_pool);
1394 
1395                        if (rv != APR_SUCCESS) {
1396                            apr_pollset_remove (pollset, &activefds[i]);
1397                            mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1398                                             server_query, values, server_queries);
1399                            queries_sent--;
1400                            continue;
1401                        }
1402 
1403                        rv = apr_brigade_destroy(conn->bb);
1404                        if (rv != APR_SUCCESS) {
1405                            apr_pollset_remove (pollset, &activefds[i]);
1406                            mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1407                                             server_query, values, server_queries);
1408                            queries_sent--;
1409                            continue;
1410                        }
1411 
1412                        conn->bb = bbb;
1413 
1414                        value->len = len - 2;
1415                        data[value->len] = '\0';
1416                        value->data = data;
1417                    }
1418 
1419                    value->status = rv;
1420                    value->flags = atoi(flags);
1421 
1422                    /* stay on the server */
1423                    i--;
1424 
1425                }
1426                else {
1427                    /* TODO: Server Sent back a key I didn't ask for or my
1428                     *       hash is corrupt */
1429                }
1430            }
1431            else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
1432                /* this connection is done */
1433                apr_pollset_remove (pollset, &activefds[i]);
1434                ms_release_conn(ms, conn);
1435                apr_hash_set(server_queries, &ms, sizeof(ms), NULL);
1436 
1437                queries_sent--;
1438            }
1439            else {
1440                /* unknown reply? */
1441                rv = APR_EGENERAL;
1442            }
1443 
1444         } /* /for */
1445     } /* /while */
1446 
1447     query_hash_index = apr_hash_first(temp_pool, server_queries);
1448     while (query_hash_index) {
1449         void *v;
1450         apr_hash_this(query_hash_index, NULL, NULL, &v);
1451         server_query = v;
1452         query_hash_index = apr_hash_next(query_hash_index);
1453 
1454         conn = server_query->conn;
1455         ms = server_query->ms;
1456 
1457         mget_conn_result(TRUE, (rv == APR_SUCCESS), rv, mc, ms, conn,
1458                          server_query, values, server_queries);
1459         continue;
1460     }
1461 
1462     apr_pollset_destroy(pollset);
1463     apr_pool_clear(temp_pool);
1464     return APR_SUCCESS;
1465 
1466 }
1467 
1468 
1469 
1470 /**
1471  * Define all of the strings for stats
1472  */
1473 
1474 #define STAT_pid MS_STAT " pid "
1475 #define STAT_pid_LEN (sizeof(STAT_pid)-1)
1476 
1477 #define STAT_uptime MS_STAT " uptime "
1478 #define STAT_uptime_LEN (sizeof(STAT_uptime)-1)
1479 
1480 #define STAT_time MS_STAT " time "
1481 #define STAT_time_LEN (sizeof(STAT_time)-1)
1482 
1483 #define STAT_version MS_STAT " version "
1484 #define STAT_version_LEN (sizeof(STAT_version)-1)
1485 
1486 #define STAT_pointer_size MS_STAT " pointer_size "
1487 #define STAT_pointer_size_LEN (sizeof(STAT_pointer_size)-1)
1488 
1489 #define STAT_rusage_user MS_STAT " rusage_user "
1490 #define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1)
1491 
1492 #define STAT_rusage_system MS_STAT " rusage_system "
1493 #define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1)
1494 
1495 #define STAT_curr_items MS_STAT " curr_items "
1496 #define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1)
1497 
1498 #define STAT_total_items MS_STAT " total_items "
1499 #define STAT_total_items_LEN (sizeof(STAT_total_items)-1)
1500 
1501 #define STAT_bytes MS_STAT " bytes "
1502 #define STAT_bytes_LEN (sizeof(STAT_bytes)-1)
1503 
1504 #define STAT_curr_connections MS_STAT " curr_connections "
1505 #define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1)
1506 
1507 #define STAT_total_connections MS_STAT " total_connections "
1508 #define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1)
1509 
1510 #define STAT_connection_structures MS_STAT " connection_structures "
1511 #define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1)
1512 
1513 #define STAT_cmd_get MS_STAT " cmd_get "
1514 #define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1)
1515 
1516 #define STAT_cmd_set MS_STAT " cmd_set "
1517 #define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1)
1518 
1519 #define STAT_get_hits MS_STAT " get_hits "
1520 #define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1)
1521 
1522 #define STAT_get_misses MS_STAT " get_misses "
1523 #define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1)
1524 
1525 #define STAT_evictions MS_STAT " evictions "
1526 #define STAT_evictions_LEN (sizeof(STAT_evictions)-1)
1527 
1528 #define STAT_bytes_read MS_STAT " bytes_read "
1529 #define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1)
1530 
1531 #define STAT_bytes_written MS_STAT " bytes_written "
1532 #define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1)
1533 
1534 #define STAT_limit_maxbytes MS_STAT " limit_maxbytes "
1535 #define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1)
1536 
1537 #define STAT_threads MS_STAT " threads "
1538 #define STAT_threads_LEN (sizeof(STAT_threads)-1)
1539 
stat_read_string(apr_pool_t * p,char * buf,apr_size_t len)1540 static const char *stat_read_string(apr_pool_t *p, char *buf, apr_size_t len)
1541 {
1542     /* remove trailing \r\n and null char */
1543     return apr_pstrmemdup(p, buf, len-2);
1544 }
1545 
stat_read_uint32(apr_pool_t * p,char * buf,apr_size_t len)1546 static apr_uint32_t stat_read_uint32(apr_pool_t *p, char *buf, apr_size_t  len)
1547 {
1548     buf[len-2] = '\0';
1549     return atoi(buf);
1550 }
1551 
stat_read_uint64(apr_pool_t * p,char * buf,apr_size_t len)1552 static apr_uint64_t stat_read_uint64(apr_pool_t *p, char *buf, apr_size_t  len)
1553 {
1554     buf[len-2] = '\0';
1555     return apr_atoi64(buf);
1556 }
1557 
stat_read_time(apr_pool_t * p,char * buf,apr_size_t len)1558 static apr_time_t stat_read_time(apr_pool_t *p, char *buf, apr_size_t  len)
1559 {
1560     buf[len-2] = '\0';
1561     return apr_time_from_sec(atoi(buf));
1562 }
1563 
stat_read_rtime(apr_pool_t * p,char * buf,apr_size_t len)1564 static apr_time_t stat_read_rtime(apr_pool_t *p, char *buf, apr_size_t  len)
1565 {
1566     char *tok;
1567     char *secs;
1568     char *usecs;
1569     const char *sep = ":.";
1570 
1571     buf[len-2] = '\0';
1572 
1573     secs = apr_strtok(buf, sep, &tok);
1574     usecs = apr_strtok(NULL, sep, &tok);
1575     if (secs && usecs) {
1576         return apr_time_make(atoi(secs), atoi(usecs));
1577     }
1578     else {
1579         return apr_time_make(0, 0);
1580     }
1581 }
1582 
1583 /**
1584  * I got tired of Typing. Meh.
1585  *
1586  * TODO: Convert it to static tables to make it cooler.
1587  */
1588 
1589 #define mc_stat_cmp(name) \
1590     strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0
1591 
1592 #define mc_stat_str(name) \
1593     stat_read_string(p, conn->buffer + name, \
1594                      conn->blen - name)
1595 
1596 #define mc_stat_uint32(name) \
1597     stat_read_uint32(p, conn->buffer + name, \
1598                      conn->blen - name)
1599 
1600 #define mc_stat_uint64(name) \
1601     stat_read_uint64(p, conn->buffer + name, \
1602                      conn->blen - name)
1603 
1604 #define mc_stat_time(name) \
1605     stat_read_time(p, conn->buffer + name, \
1606                      conn->blen - name)
1607 
1608 #define mc_stat_rtime(name) \
1609     stat_read_rtime(p, conn->buffer + name, \
1610                      conn->blen - name)
1611 
1612 
1613 #define mc_do_stat(name, type) \
1614     if (mc_stat_cmp(name)) { \
1615         stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \
1616     }
1617 
update_stats(apr_pool_t * p,apr_memcache_conn_t * conn,apr_memcache_stats_t * stats)1618 static void update_stats(apr_pool_t *p, apr_memcache_conn_t *conn,
1619                          apr_memcache_stats_t *stats)
1620 {
1621 
1622     mc_do_stat(version, str)
1623     else mc_do_stat(pid, uint32)
1624     else mc_do_stat(uptime, uint32)
1625     else mc_do_stat(pointer_size, uint32)
1626     else mc_do_stat(time, time)
1627     else mc_do_stat(rusage_user, rtime)
1628     else mc_do_stat(rusage_system, rtime)
1629     else mc_do_stat(curr_items, uint32)
1630     else mc_do_stat(total_items, uint32)
1631     else mc_do_stat(bytes, uint64)
1632     else mc_do_stat(curr_connections, uint32)
1633     else mc_do_stat(total_connections, uint32)
1634     else mc_do_stat(connection_structures, uint32)
1635     else mc_do_stat(cmd_get, uint32)
1636     else mc_do_stat(cmd_set, uint32)
1637     else mc_do_stat(get_hits, uint32)
1638     else mc_do_stat(get_misses, uint32)
1639     else mc_do_stat(evictions, uint64)
1640     else mc_do_stat(bytes_read, uint64)
1641     else mc_do_stat(bytes_written, uint64)
1642     else mc_do_stat(limit_maxbytes, uint32)
1643     else mc_do_stat(threads, uint32)
1644 }
1645 
1646 APU_DECLARE(apr_status_t)
apr_memcache_stats(apr_memcache_server_t * ms,apr_pool_t * p,apr_memcache_stats_t ** stats)1647 apr_memcache_stats(apr_memcache_server_t *ms,
1648                   apr_pool_t *p,
1649                   apr_memcache_stats_t **stats)
1650 {
1651     apr_memcache_stats_t *ret;
1652     apr_status_t rv;
1653     apr_memcache_conn_t *conn;
1654     apr_size_t written;
1655     struct iovec vec[2];
1656 
1657     rv = ms_find_conn(ms, &conn);
1658 
1659     if (rv != APR_SUCCESS) {
1660         return rv;
1661     }
1662 
1663     /* version\r\n */
1664     vec[0].iov_base = MC_STATS;
1665     vec[0].iov_len  = MC_STATS_LEN;
1666 
1667     vec[1].iov_base = MC_EOL;
1668     vec[1].iov_len  = MC_EOL_LEN;
1669 
1670     rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1671 
1672     if (rv != APR_SUCCESS) {
1673         ms_bad_conn(ms, conn);
1674         return rv;
1675     }
1676 
1677     ret = apr_pcalloc(p, sizeof(apr_memcache_stats_t));
1678 
1679     do {
1680         rv = get_server_line(conn);
1681         if (rv != APR_SUCCESS) {
1682             ms_bad_conn(ms, conn);
1683             return rv;
1684         }
1685 
1686         if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
1687             rv = APR_SUCCESS;
1688             break;
1689         }
1690         else if (strncmp(MS_STAT, conn->buffer, MS_STAT_LEN) == 0) {
1691             update_stats(p, conn, ret);
1692             continue;
1693         }
1694         else {
1695             rv = APR_EGENERAL;
1696             break;
1697         }
1698 
1699     } while(1);
1700 
1701     ms_release_conn(ms, conn);
1702 
1703     if (stats) {
1704         *stats = ret;
1705     }
1706 
1707     return rv;
1708 }
1709 
1710