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