1251876Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251876Speter * contributor license agreements.  See the NOTICE file distributed with
3251876Speter * this work for additional information regarding copyright ownership.
4251876Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251876Speter * (the "License"); you may not use this file except in compliance with
6251876Speter * the License.  You may obtain a copy of the License at
7251876Speter *
8251876Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251876Speter *
10251876Speter * Unless required by applicable law or agreed to in writing, software
11251876Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251876Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251876Speter * See the License for the specific language governing permissions and
14251876Speter * limitations under the License.
15251876Speter */
16251876Speter
17251876Speter#include "apr_memcache.h"
18251876Speter#include "apr_poll.h"
19251876Speter#include "apr_version.h"
20251876Speter#include <stdlib.h>
21251876Speter
22251876Speter#define BUFFER_SIZE 512
23251876Speterstruct apr_memcache_conn_t
24251876Speter{
25251876Speter    char *buffer;
26251876Speter    apr_size_t blen;
27251876Speter    apr_pool_t *p;
28251876Speter    apr_pool_t *tp;
29251876Speter    apr_socket_t *sock;
30251876Speter    apr_bucket_brigade *bb;
31251876Speter    apr_bucket_brigade *tb;
32251876Speter    apr_memcache_server_t *ms;
33251876Speter};
34251876Speter
35251876Speter/* Strings for Client Commands */
36251876Speter
37251876Speter#define MC_EOL "\r\n"
38251876Speter#define MC_EOL_LEN (sizeof(MC_EOL)-1)
39251876Speter
40251876Speter#define MC_WS " "
41251876Speter#define MC_WS_LEN (sizeof(MC_WS)-1)
42251876Speter
43251876Speter#define MC_GET "get "
44251876Speter#define MC_GET_LEN (sizeof(MC_GET)-1)
45251876Speter
46251876Speter#define MC_SET "set "
47251876Speter#define MC_SET_LEN (sizeof(MC_SET)-1)
48251876Speter
49251876Speter#define MC_ADD "add "
50251876Speter#define MC_ADD_LEN (sizeof(MC_ADD)-1)
51251876Speter
52251876Speter#define MC_REPLACE "replace "
53251876Speter#define MC_REPLACE_LEN (sizeof(MC_REPLACE)-1)
54251876Speter
55251876Speter#define MC_DELETE "delete "
56251876Speter#define MC_DELETE_LEN (sizeof(MC_DELETE)-1)
57251876Speter
58251876Speter#define MC_INCR "incr "
59251876Speter#define MC_INCR_LEN (sizeof(MC_INCR)-1)
60251876Speter
61251876Speter#define MC_DECR "decr "
62251876Speter#define MC_DECR_LEN (sizeof(MC_DECR)-1)
63251876Speter
64251876Speter#define MC_VERSION "version"
65251876Speter#define MC_VERSION_LEN (sizeof(MC_VERSION)-1)
66251876Speter
67251876Speter#define MC_STATS "stats"
68251876Speter#define MC_STATS_LEN (sizeof(MC_STATS)-1)
69251876Speter
70251876Speter#define MC_QUIT "quit"
71251876Speter#define MC_QUIT_LEN (sizeof(MC_QUIT)-1)
72251876Speter
73251876Speter/* Strings for Server Replies */
74251876Speter
75251876Speter#define MS_STORED "STORED"
76251876Speter#define MS_STORED_LEN (sizeof(MS_STORED)-1)
77251876Speter
78251876Speter#define MS_NOT_STORED "NOT_STORED"
79251876Speter#define MS_NOT_STORED_LEN (sizeof(MS_NOT_STORED)-1)
80251876Speter
81251876Speter#define MS_DELETED "DELETED"
82251876Speter#define MS_DELETED_LEN (sizeof(MS_DELETED)-1)
83251876Speter
84251876Speter#define MS_NOT_FOUND "NOT_FOUND"
85251876Speter#define MS_NOT_FOUND_LEN (sizeof(MS_NOT_FOUND)-1)
86251876Speter
87251876Speter#define MS_VALUE "VALUE"
88251876Speter#define MS_VALUE_LEN (sizeof(MS_VALUE)-1)
89251876Speter
90251876Speter#define MS_ERROR "ERROR"
91251876Speter#define MS_ERROR_LEN (sizeof(MS_ERROR)-1)
92251876Speter
93251876Speter#define MS_VERSION "VERSION"
94251876Speter#define MS_VERSION_LEN (sizeof(MS_VERSION)-1)
95251876Speter
96251876Speter#define MS_STAT "STAT"
97251876Speter#define MS_STAT_LEN (sizeof(MS_STAT)-1)
98251876Speter
99251876Speter#define MS_END "END"
100251876Speter#define MS_END_LEN (sizeof(MS_END)-1)
101251876Speter
102251876Speter/** Server and Query Structure for a multiple get */
103251876Speterstruct cache_server_query_t {
104251876Speter    apr_memcache_server_t* ms;
105251876Speter    apr_memcache_conn_t* conn;
106251876Speter    struct iovec* query_vec;
107251876Speter    apr_int32_t query_vec_count;
108251876Speter};
109251876Speter
110251876Speter#define MULT_GET_TIMEOUT 50000
111251876Speter
112251876Speterstatic apr_status_t make_server_dead(apr_memcache_t *mc, apr_memcache_server_t *ms)
113251876Speter{
114251876Speter#if APR_HAS_THREADS
115251876Speter    apr_thread_mutex_lock(ms->lock);
116251876Speter#endif
117251876Speter    ms->status = APR_MC_SERVER_DEAD;
118251876Speter    ms->btime = apr_time_now();
119251876Speter#if APR_HAS_THREADS
120251876Speter    apr_thread_mutex_unlock(ms->lock);
121251876Speter#endif
122251876Speter    return APR_SUCCESS;
123251876Speter}
124251876Speter
125251876Speterstatic apr_status_t make_server_live(apr_memcache_t *mc, apr_memcache_server_t *ms)
126251876Speter{
127251876Speter    ms->status = APR_MC_SERVER_LIVE;
128251876Speter    return APR_SUCCESS;
129251876Speter}
130251876Speter
131251876Speter
132251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_add_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
133251876Speter{
134251876Speter    apr_status_t rv = APR_SUCCESS;
135251876Speter
136251876Speter    if(mc->ntotal >= mc->nalloc) {
137251876Speter        return APR_ENOMEM;
138251876Speter    }
139251876Speter
140251876Speter    mc->live_servers[mc->ntotal] = ms;
141251876Speter    mc->ntotal++;
142251876Speter    make_server_live(mc, ms);
143251876Speter    return rv;
144251876Speter}
145251876Speter
146251876Speterstatic apr_status_t mc_version_ping(apr_memcache_server_t *ms);
147251876Speter
148251876SpeterAPU_DECLARE(apr_memcache_server_t *)
149251876Speterapr_memcache_find_server_hash(apr_memcache_t *mc, const apr_uint32_t hash)
150251876Speter{
151251876Speter    if (mc->server_func) {
152251876Speter        return mc->server_func(mc->server_baton, mc, hash);
153251876Speter    }
154251876Speter    else {
155251876Speter        return apr_memcache_find_server_hash_default(NULL, mc, hash);
156251876Speter    }
157251876Speter}
158251876Speter
159251876SpeterAPU_DECLARE(apr_memcache_server_t *)
160251876Speterapr_memcache_find_server_hash_default(void *baton, apr_memcache_t *mc,
161251876Speter                                      const apr_uint32_t hash)
162251876Speter{
163251876Speter    apr_memcache_server_t *ms = NULL;
164251876Speter    apr_uint32_t h = hash ? hash : 1;
165251876Speter    apr_uint32_t i = 0;
166251876Speter    apr_time_t curtime = 0;
167251876Speter
168251876Speter    if(mc->ntotal == 0) {
169251876Speter        return NULL;
170251876Speter    }
171251876Speter
172251876Speter    do {
173251876Speter        ms = mc->live_servers[h % mc->ntotal];
174251876Speter        if(ms->status == APR_MC_SERVER_LIVE) {
175251876Speter            break;
176251876Speter        }
177251876Speter        else {
178251876Speter            if (curtime == 0) {
179251876Speter                curtime = apr_time_now();
180251876Speter            }
181251876Speter#if APR_HAS_THREADS
182251876Speter            apr_thread_mutex_lock(ms->lock);
183251876Speter#endif
184262253Speter            /* Try the dead server, every 5 seconds */
185251876Speter            if (curtime - ms->btime >  apr_time_from_sec(5)) {
186253734Speter                ms->btime = curtime;
187251876Speter                if (mc_version_ping(ms) == APR_SUCCESS) {
188251876Speter                    make_server_live(mc, ms);
189251876Speter#if APR_HAS_THREADS
190251876Speter                    apr_thread_mutex_unlock(ms->lock);
191251876Speter#endif
192251876Speter                    break;
193251876Speter                }
194251876Speter            }
195251876Speter#if APR_HAS_THREADS
196251876Speter            apr_thread_mutex_unlock(ms->lock);
197251876Speter#endif
198251876Speter        }
199251876Speter        h++;
200251876Speter        i++;
201251876Speter    } while(i < mc->ntotal);
202251876Speter
203251876Speter    if (i == mc->ntotal) {
204251876Speter        ms = NULL;
205251876Speter    }
206251876Speter
207251876Speter    return ms;
208251876Speter}
209251876Speter
210251876SpeterAPU_DECLARE(apr_memcache_server_t *) apr_memcache_find_server(apr_memcache_t *mc, const char *host, apr_port_t port)
211251876Speter{
212251876Speter    int i;
213251876Speter
214251876Speter    for (i = 0; i < mc->ntotal; i++) {
215251876Speter        if (strcmp(mc->live_servers[i]->host, host) == 0
216251876Speter            && mc->live_servers[i]->port == port) {
217251876Speter
218251876Speter            return mc->live_servers[i];
219251876Speter        }
220251876Speter    }
221251876Speter
222251876Speter    return NULL;
223251876Speter}
224251876Speter
225251876Speterstatic apr_status_t ms_find_conn(apr_memcache_server_t *ms, apr_memcache_conn_t **conn)
226251876Speter{
227251876Speter    apr_status_t rv;
228251876Speter    apr_bucket_alloc_t *balloc;
229251876Speter    apr_bucket *e;
230251876Speter
231251876Speter#if APR_HAS_THREADS
232251876Speter    rv = apr_reslist_acquire(ms->conns, (void **)conn);
233251876Speter#else
234251876Speter    *conn = ms->conn;
235251876Speter    rv = APR_SUCCESS;
236251876Speter#endif
237251876Speter
238251876Speter    if (rv != APR_SUCCESS) {
239251876Speter        return rv;
240251876Speter    }
241251876Speter
242251876Speter    balloc = apr_bucket_alloc_create((*conn)->tp);
243251876Speter    (*conn)->bb = apr_brigade_create((*conn)->tp, balloc);
244251876Speter    (*conn)->tb = apr_brigade_create((*conn)->tp, balloc);
245251876Speter
246251876Speter    e = apr_bucket_socket_create((*conn)->sock, balloc);
247251876Speter    APR_BRIGADE_INSERT_TAIL((*conn)->bb, e);
248251876Speter
249251876Speter    return rv;
250251876Speter}
251251876Speter
252251876Speterstatic apr_status_t ms_bad_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn)
253251876Speter{
254251876Speter#if APR_HAS_THREADS
255251876Speter    return apr_reslist_invalidate(ms->conns, conn);
256251876Speter#else
257251876Speter    return APR_SUCCESS;
258251876Speter#endif
259251876Speter}
260251876Speter
261251876Speterstatic apr_status_t ms_release_conn(apr_memcache_server_t *ms, apr_memcache_conn_t *conn)
262251876Speter{
263251876Speter    apr_pool_clear(conn->tp);
264251876Speter#if APR_HAS_THREADS
265251876Speter    return apr_reslist_release(ms->conns, conn);
266251876Speter#else
267251876Speter    return APR_SUCCESS;
268251876Speter#endif
269251876Speter}
270251876Speter
271251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_enable_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
272251876Speter{
273251876Speter    apr_status_t rv = APR_SUCCESS;
274251876Speter
275251876Speter    if (ms->status == APR_MC_SERVER_LIVE) {
276251876Speter        return rv;
277251876Speter    }
278251876Speter
279251876Speter    rv = make_server_live(mc, ms);
280251876Speter    return rv;
281251876Speter}
282251876Speter
283251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_disable_server(apr_memcache_t *mc, apr_memcache_server_t *ms)
284251876Speter{
285251876Speter    return make_server_dead(mc, ms);
286251876Speter}
287251876Speter
288251876Speterstatic apr_status_t conn_connect(apr_memcache_conn_t *conn)
289251876Speter{
290251876Speter    apr_status_t rv = APR_SUCCESS;
291251876Speter    apr_sockaddr_t *sa;
292262253Speter#if APR_HAVE_SOCKADDR_UN
293262253Speter    apr_int32_t family = conn->ms->host[0] != '/' ? APR_INET : APR_UNIX;
294262253Speter#else
295262253Speter    apr_int32_t family = APR_INET;
296262253Speter#endif
297251876Speter
298262253Speter    rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p);
299251876Speter    if (rv != APR_SUCCESS) {
300251876Speter        return rv;
301251876Speter    }
302251876Speter
303251876Speter    rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC);
304251876Speter    if (rv != APR_SUCCESS) {
305251876Speter        return rv;
306251876Speter    }
307251876Speter
308251876Speter    rv = apr_socket_connect(conn->sock, sa);
309251876Speter    if (rv != APR_SUCCESS) {
310251876Speter        return rv;
311251876Speter    }
312251876Speter
313251876Speter    rv = apr_socket_timeout_set(conn->sock, -1);
314251876Speter    if (rv != APR_SUCCESS) {
315251876Speter        return rv;
316251876Speter    }
317251876Speter
318251876Speter    return rv;
319251876Speter}
320251876Speter
321251876Speter
322251876Speterstatic apr_status_t
323251876Spetermc_conn_construct(void **conn_, void *params, apr_pool_t *pool)
324251876Speter{
325251876Speter    apr_status_t rv = APR_SUCCESS;
326251876Speter    apr_memcache_conn_t *conn;
327251876Speter    apr_pool_t *np;
328251876Speter    apr_pool_t *tp;
329251876Speter    apr_memcache_server_t *ms = params;
330262253Speter#if APR_HAVE_SOCKADDR_UN
331262253Speter    apr_int32_t family = ms->host[0] != '/' ? APR_INET : APR_UNIX;
332262253Speter#else
333262253Speter    apr_int32_t family = APR_INET;
334262253Speter#endif
335251876Speter
336251876Speter    rv = apr_pool_create(&np, pool);
337251876Speter    if (rv != APR_SUCCESS) {
338251876Speter        return rv;
339251876Speter    }
340251876Speter
341251876Speter    rv = apr_pool_create(&tp, np);
342251876Speter    if (rv != APR_SUCCESS) {
343251876Speter        apr_pool_destroy(np);
344251876Speter        return rv;
345251876Speter    }
346251876Speter
347251876Speter    conn = apr_palloc(np, sizeof( apr_memcache_conn_t ));
348251876Speter
349251876Speter    conn->p = np;
350251876Speter    conn->tp = tp;
351251876Speter
352262253Speter    rv = apr_socket_create(&conn->sock, family, SOCK_STREAM, 0, np);
353251876Speter
354251876Speter    if (rv != APR_SUCCESS) {
355251876Speter        apr_pool_destroy(np);
356251876Speter        return rv;
357251876Speter    }
358251876Speter
359251876Speter    conn->buffer = apr_palloc(conn->p, BUFFER_SIZE);
360251876Speter    conn->blen = 0;
361251876Speter    conn->ms = ms;
362251876Speter
363251876Speter    rv = conn_connect(conn);
364251876Speter    if (rv != APR_SUCCESS) {
365251876Speter        apr_pool_destroy(np);
366251876Speter    }
367251876Speter    else {
368251876Speter        *conn_ = conn;
369251876Speter    }
370251876Speter
371251876Speter    return rv;
372251876Speter}
373251876Speter
374251876Speter#if APR_HAS_THREADS
375251876Speterstatic apr_status_t
376251876Spetermc_conn_destruct(void *conn_, void *params, apr_pool_t *pool)
377251876Speter{
378251876Speter    apr_memcache_conn_t *conn = (apr_memcache_conn_t*)conn_;
379251876Speter    struct iovec vec[2];
380251876Speter    apr_size_t written;
381251876Speter
382251876Speter    /* send a quit message to the memcached server to be nice about it. */
383251876Speter    vec[0].iov_base = MC_QUIT;
384251876Speter    vec[0].iov_len = MC_QUIT_LEN;
385251876Speter
386251876Speter    vec[1].iov_base = MC_EOL;
387251876Speter    vec[1].iov_len = MC_EOL_LEN;
388251876Speter
389251876Speter    /* Return values not checked, since we just want to make it go away. */
390251876Speter    apr_socket_sendv(conn->sock, vec, 2, &written);
391251876Speter    apr_socket_close(conn->sock);
392251876Speter
393251876Speter    apr_pool_destroy(conn->p);
394251876Speter
395251876Speter    return APR_SUCCESS;
396251876Speter}
397251876Speter#endif
398251876Speter
399251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_server_create(apr_pool_t *p,
400251876Speter                                                     const char *host, apr_port_t port,
401251876Speter                                                     apr_uint32_t min, apr_uint32_t smax,
402251876Speter                                                     apr_uint32_t max, apr_uint32_t ttl,
403251876Speter                                                     apr_memcache_server_t **ms)
404251876Speter{
405251876Speter    apr_status_t rv = APR_SUCCESS;
406251876Speter    apr_memcache_server_t *server;
407251876Speter    apr_pool_t *np;
408251876Speter
409251876Speter    rv = apr_pool_create(&np, p);
410251876Speter
411251876Speter    server = apr_palloc(np, sizeof(apr_memcache_server_t));
412251876Speter
413251876Speter    server->p = np;
414251876Speter    server->host = apr_pstrdup(np, host);
415251876Speter    server->port = port;
416251876Speter    server->status = APR_MC_SERVER_DEAD;
417251876Speter#if APR_HAS_THREADS
418251876Speter    rv = apr_thread_mutex_create(&server->lock, APR_THREAD_MUTEX_DEFAULT, np);
419251876Speter    if (rv != APR_SUCCESS) {
420251876Speter        return rv;
421251876Speter    }
422251876Speter
423251876Speter    rv = apr_reslist_create(&server->conns,
424251876Speter                               min,                     /* hard minimum */
425251876Speter                               smax,                    /* soft maximum */
426251876Speter                               max,                     /* hard maximum */
427251876Speter                               ttl,                     /* Time to live */
428251876Speter                               mc_conn_construct,       /* Make a New Connection */
429251876Speter                               mc_conn_destruct,        /* Kill Old Connection */
430251876Speter                               server, np);
431251876Speter    if (rv != APR_SUCCESS) {
432251876Speter        return rv;
433251876Speter    }
434251876Speter
435251876Speter    apr_reslist_cleanup_order_set(server->conns, APR_RESLIST_CLEANUP_FIRST);
436251876Speter#else
437251876Speter    rv = mc_conn_construct((void**)&(server->conn), server, np);
438251876Speter    if (rv != APR_SUCCESS) {
439251876Speter        return rv;
440251876Speter    }
441251876Speter#endif
442251876Speter
443251876Speter    *ms = server;
444251876Speter
445251876Speter    return rv;
446251876Speter}
447251876Speter
448251876SpeterAPU_DECLARE(apr_status_t) apr_memcache_create(apr_pool_t *p,
449251876Speter                                              apr_uint16_t max_servers, apr_uint32_t flags,
450251876Speter                                              apr_memcache_t **memcache)
451251876Speter{
452251876Speter    apr_status_t rv = APR_SUCCESS;
453251876Speter    apr_memcache_t *mc;
454251876Speter
455251876Speter    mc = apr_palloc(p, sizeof(apr_memcache_t));
456251876Speter    mc->p = p;
457251876Speter    mc->nalloc = max_servers;
458251876Speter    mc->ntotal = 0;
459251876Speter    mc->live_servers = apr_palloc(p, mc->nalloc * sizeof(struct apr_memcache_server_t *));
460251876Speter    mc->hash_func = NULL;
461251876Speter    mc->hash_baton = NULL;
462251876Speter    mc->server_func = NULL;
463251876Speter    mc->server_baton = NULL;
464251876Speter    *memcache = mc;
465251876Speter    return rv;
466251876Speter}
467251876Speter
468251876Speter
469251876Speter/* The crc32 functions and data was originally written by Spencer
470251876Speter * Garrett <srg@quick.com> and was gleaned from the PostgreSQL source
471251876Speter * tree via the files contrib/ltree/crc32.[ch] and from FreeBSD at
472251876Speter * src/usr.bin/cksum/crc32.c.
473251876Speter */
474251876Speter
475251876Speterstatic const apr_uint32_t crc32tab[256] = {
476251876Speter  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
477251876Speter  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
478251876Speter  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
479251876Speter  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
480251876Speter  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
481251876Speter  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
482251876Speter  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
483251876Speter  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
484251876Speter  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
485251876Speter  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
486251876Speter  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
487251876Speter  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
488251876Speter  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
489251876Speter  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
490251876Speter  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
491251876Speter  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
492251876Speter  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
493251876Speter  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
494251876Speter  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
495251876Speter  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
496251876Speter  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
497251876Speter  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
498251876Speter  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
499251876Speter  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
500251876Speter  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
501251876Speter  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
502251876Speter  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
503251876Speter  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
504251876Speter  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
505251876Speter  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
506251876Speter  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
507251876Speter  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
508251876Speter  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
509251876Speter  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
510251876Speter  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
511251876Speter  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
512251876Speter  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
513251876Speter  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
514251876Speter  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
515251876Speter  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
516251876Speter  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
517251876Speter  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
518251876Speter  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
519251876Speter  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
520251876Speter  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
521251876Speter  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
522251876Speter  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
523251876Speter  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
524251876Speter  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
525251876Speter  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
526251876Speter  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
527251876Speter  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
528251876Speter  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
529251876Speter  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
530251876Speter  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
531251876Speter  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
532251876Speter  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
533251876Speter  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
534251876Speter  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
535251876Speter  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
536251876Speter  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
537251876Speter  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
538251876Speter  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
539251876Speter  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
540251876Speter};
541251876Speter
542251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash_crc32(void *baton,
543251876Speter                                                  const char *data,
544251876Speter                                                  const apr_size_t data_len)
545251876Speter{
546251876Speter    apr_uint32_t i;
547251876Speter    apr_uint32_t crc;
548251876Speter    crc = ~0;
549251876Speter
550251876Speter    for (i = 0; i < data_len; i++)
551251876Speter        crc = (crc >> 8) ^ crc32tab[(crc ^ (data[i])) & 0xff];
552251876Speter
553251876Speter    return ~crc;
554251876Speter}
555251876Speter
556251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash_default(void *baton,
557251876Speter                                                    const char *data,
558251876Speter                                                    const apr_size_t data_len)
559251876Speter{
560251876Speter    /* The default Perl Client doesn't actually use just crc32 -- it shifts it again
561251876Speter     * like this....
562251876Speter     */
563251876Speter    return ((apr_memcache_hash_crc32(baton, data, data_len) >> 16) & 0x7fff);
564251876Speter}
565251876Speter
566251876SpeterAPU_DECLARE(apr_uint32_t) apr_memcache_hash(apr_memcache_t *mc,
567251876Speter                                            const char *data,
568251876Speter                                            const apr_size_t data_len)
569251876Speter{
570251876Speter    if (mc->hash_func) {
571251876Speter        return mc->hash_func(mc->hash_baton, data, data_len);
572251876Speter    }
573251876Speter    else {
574251876Speter        return apr_memcache_hash_default(NULL, data, data_len);
575251876Speter    }
576251876Speter}
577251876Speter
578251876Speterstatic apr_status_t get_server_line(apr_memcache_conn_t *conn)
579251876Speter{
580251876Speter    apr_size_t bsize = BUFFER_SIZE;
581251876Speter    apr_status_t rv = APR_SUCCESS;
582251876Speter
583251876Speter    rv = apr_brigade_split_line(conn->tb, conn->bb, APR_BLOCK_READ, BUFFER_SIZE);
584251876Speter
585251876Speter    if (rv != APR_SUCCESS) {
586251876Speter        return rv;
587251876Speter    }
588251876Speter
589251876Speter    rv = apr_brigade_flatten(conn->tb, conn->buffer, &bsize);
590251876Speter
591251876Speter    if (rv != APR_SUCCESS) {
592251876Speter        return rv;
593251876Speter    }
594251876Speter
595251876Speter    conn->blen = bsize;
596251876Speter    conn->buffer[bsize] = '\0';
597251876Speter
598251876Speter    return apr_brigade_cleanup(conn->tb);
599251876Speter}
600251876Speter
601251876Speterstatic apr_status_t storage_cmd_write(apr_memcache_t *mc,
602251876Speter                                      char *cmd,
603251876Speter                                      const apr_size_t cmd_size,
604251876Speter                                      const char *key,
605251876Speter                                      char *data,
606251876Speter                                      const apr_size_t data_size,
607251876Speter                                      apr_uint32_t timeout,
608251876Speter                                      apr_uint16_t flags)
609251876Speter{
610251876Speter    apr_uint32_t hash;
611251876Speter    apr_memcache_server_t *ms;
612251876Speter    apr_memcache_conn_t *conn;
613251876Speter    apr_status_t rv;
614251876Speter    apr_size_t written;
615251876Speter    struct iovec vec[5];
616251876Speter    apr_size_t klen;
617251876Speter
618251876Speter    apr_size_t key_size = strlen(key);
619251876Speter
620251876Speter    hash = apr_memcache_hash(mc, key, key_size);
621251876Speter
622251876Speter    ms = apr_memcache_find_server_hash(mc, hash);
623251876Speter
624251876Speter    if (ms == NULL)
625251876Speter        return APR_NOTFOUND;
626251876Speter
627251876Speter    rv = ms_find_conn(ms, &conn);
628251876Speter
629251876Speter    if (rv != APR_SUCCESS) {
630251876Speter        apr_memcache_disable_server(mc, ms);
631251876Speter        return rv;
632251876Speter    }
633251876Speter
634251876Speter    /* <command name> <key> <flags> <exptime> <bytes>\r\n<data>\r\n */
635251876Speter
636251876Speter    vec[0].iov_base = cmd;
637251876Speter    vec[0].iov_len  = cmd_size;
638251876Speter
639251876Speter    vec[1].iov_base = (void*)key;
640251876Speter    vec[1].iov_len  = key_size;
641251876Speter
642251876Speter    klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u %u %" APR_SIZE_T_FMT " " MC_EOL,
643251876Speter                        flags, timeout, data_size);
644251876Speter
645251876Speter    vec[2].iov_base = conn->buffer;
646251876Speter    vec[2].iov_len  = klen;
647251876Speter
648251876Speter    vec[3].iov_base = data;
649251876Speter    vec[3].iov_len  = data_size;
650251876Speter
651251876Speter    vec[4].iov_base = MC_EOL;
652251876Speter    vec[4].iov_len  = MC_EOL_LEN;
653251876Speter
654251876Speter    rv = apr_socket_sendv(conn->sock, vec, 5, &written);
655251876Speter
656251876Speter    if (rv != APR_SUCCESS) {
657251876Speter        ms_bad_conn(ms, conn);
658251876Speter        apr_memcache_disable_server(mc, ms);
659251876Speter        return rv;
660251876Speter    }
661251876Speter
662251876Speter    rv = get_server_line(conn);
663251876Speter
664251876Speter    if (rv != APR_SUCCESS) {
665251876Speter        ms_bad_conn(ms, conn);
666251876Speter        apr_memcache_disable_server(mc, ms);
667251876Speter        return rv;
668251876Speter    }
669251876Speter
670251876Speter    if (strcmp(conn->buffer, MS_STORED MC_EOL) == 0) {
671251876Speter        rv = APR_SUCCESS;
672251876Speter    }
673251876Speter    else if (strcmp(conn->buffer, MS_NOT_STORED MC_EOL) == 0) {
674251876Speter        rv = APR_EEXIST;
675251876Speter    }
676251876Speter    else {
677251876Speter        rv = APR_EGENERAL;
678251876Speter    }
679251876Speter
680251876Speter    ms_release_conn(ms, conn);
681251876Speter
682251876Speter    return rv;
683251876Speter}
684251876Speter
685251876SpeterAPU_DECLARE(apr_status_t)
686251876Speterapr_memcache_set(apr_memcache_t *mc,
687251876Speter                 const char *key,
688251876Speter                 char *data,
689251876Speter                 const apr_size_t data_size,
690251876Speter                 apr_uint32_t timeout,
691251876Speter                 apr_uint16_t flags)
692251876Speter{
693251876Speter    return storage_cmd_write(mc,
694251876Speter                           MC_SET, MC_SET_LEN,
695251876Speter                           key,
696251876Speter                           data, data_size,
697251876Speter                           timeout, flags);
698251876Speter}
699251876Speter
700251876SpeterAPU_DECLARE(apr_status_t)
701251876Speterapr_memcache_add(apr_memcache_t *mc,
702251876Speter                 const char *key,
703251876Speter                 char *data,
704251876Speter                 const apr_size_t data_size,
705251876Speter                 apr_uint32_t timeout,
706251876Speter                 apr_uint16_t flags)
707251876Speter{
708251876Speter    return storage_cmd_write(mc,
709251876Speter                           MC_ADD, MC_ADD_LEN,
710251876Speter                           key,
711251876Speter                           data, data_size,
712251876Speter                           timeout, flags);
713251876Speter}
714251876Speter
715251876SpeterAPU_DECLARE(apr_status_t)
716251876Speterapr_memcache_replace(apr_memcache_t *mc,
717251876Speter                 const char *key,
718251876Speter                 char *data,
719251876Speter                 const apr_size_t data_size,
720251876Speter                 apr_uint32_t timeout,
721251876Speter                 apr_uint16_t flags)
722251876Speter{
723251876Speter    return storage_cmd_write(mc,
724251876Speter                           MC_REPLACE, MC_REPLACE_LEN,
725251876Speter                           key,
726251876Speter                           data, data_size,
727251876Speter                           timeout, flags);
728251876Speter
729251876Speter}
730251876Speter
731251876SpeterAPU_DECLARE(apr_status_t)
732251876Speterapr_memcache_getp(apr_memcache_t *mc,
733251876Speter                  apr_pool_t *p,
734251876Speter                  const char *key,
735251876Speter                  char **baton,
736251876Speter                  apr_size_t *new_length,
737251876Speter                  apr_uint16_t *flags_)
738251876Speter{
739251876Speter    apr_status_t rv;
740251876Speter    apr_memcache_server_t *ms;
741251876Speter    apr_memcache_conn_t *conn;
742251876Speter    apr_uint32_t hash;
743251876Speter    apr_size_t written;
744251876Speter    apr_size_t klen = strlen(key);
745251876Speter    struct iovec vec[3];
746251876Speter
747251876Speter    hash = apr_memcache_hash(mc, key, klen);
748251876Speter    ms = apr_memcache_find_server_hash(mc, hash);
749251876Speter    if (ms == NULL)
750251876Speter        return APR_NOTFOUND;
751251876Speter
752251876Speter    rv = ms_find_conn(ms, &conn);
753251876Speter
754251876Speter    if (rv != APR_SUCCESS) {
755251876Speter        apr_memcache_disable_server(mc, ms);
756251876Speter        return rv;
757251876Speter    }
758251876Speter
759251876Speter    /* get <key>[ <key>[...]]\r\n */
760251876Speter    vec[0].iov_base = MC_GET;
761251876Speter    vec[0].iov_len  = MC_GET_LEN;
762251876Speter
763251876Speter    vec[1].iov_base = (void*)key;
764251876Speter    vec[1].iov_len  = klen;
765251876Speter
766251876Speter    vec[2].iov_base = MC_EOL;
767251876Speter    vec[2].iov_len  = MC_EOL_LEN;
768251876Speter
769251876Speter    rv = apr_socket_sendv(conn->sock, vec, 3, &written);
770251876Speter
771251876Speter    if (rv != APR_SUCCESS) {
772251876Speter        ms_bad_conn(ms, conn);
773251876Speter        apr_memcache_disable_server(mc, ms);
774251876Speter        return rv;
775251876Speter    }
776251876Speter
777251876Speter    rv = get_server_line(conn);
778251876Speter    if (rv != APR_SUCCESS) {
779251876Speter        ms_bad_conn(ms, conn);
780251876Speter        apr_memcache_disable_server(mc, ms);
781251876Speter        return rv;
782251876Speter    }
783251876Speter
784251876Speter    if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) {
785251876Speter        char *flags;
786251876Speter        char *length;
787251876Speter        char *last;
788251876Speter        apr_size_t len = 0;
789251876Speter
790251876Speter        flags = apr_strtok(conn->buffer, " ", &last);
791251876Speter        flags = apr_strtok(NULL, " ", &last);
792251876Speter        flags = apr_strtok(NULL, " ", &last);
793251876Speter
794251876Speter        if (flags_) {
795251876Speter            *flags_ = atoi(flags);
796251876Speter        }
797251876Speter
798251876Speter        length = apr_strtok(NULL, " ", &last);
799251876Speter        if (length) {
800253734Speter            len = strtol(length, (char **)NULL, 10);
801251876Speter        }
802251876Speter
803253734Speter        if (len == 0 )  {
804251876Speter            *new_length = 0;
805251876Speter            *baton = NULL;
806251876Speter        }
807251876Speter        else {
808251876Speter            apr_bucket_brigade *bbb;
809251876Speter            apr_bucket *e;
810251876Speter
811251876Speter            /* eat the trailing \r\n */
812251876Speter            rv = apr_brigade_partition(conn->bb, len+2, &e);
813251876Speter
814251876Speter            if (rv != APR_SUCCESS) {
815251876Speter                ms_bad_conn(ms, conn);
816251876Speter                apr_memcache_disable_server(mc, ms);
817251876Speter                return rv;
818251876Speter            }
819251876Speter
820251876Speter            bbb = apr_brigade_split(conn->bb, e);
821251876Speter
822251876Speter            rv = apr_brigade_pflatten(conn->bb, baton, &len, p);
823251876Speter
824251876Speter            if (rv != APR_SUCCESS) {
825251876Speter                ms_bad_conn(ms, conn);
826251876Speter                apr_memcache_disable_server(mc, ms);
827251876Speter                return rv;
828251876Speter            }
829251876Speter
830251876Speter            rv = apr_brigade_destroy(conn->bb);
831251876Speter            if (rv != APR_SUCCESS) {
832251876Speter                ms_bad_conn(ms, conn);
833251876Speter                apr_memcache_disable_server(mc, ms);
834251876Speter                return rv;
835251876Speter            }
836251876Speter
837251876Speter            conn->bb = bbb;
838251876Speter
839251876Speter            *new_length = len - 2;
840251876Speter            (*baton)[*new_length] = '\0';
841251876Speter        }
842251876Speter
843251876Speter        rv = get_server_line(conn);
844251876Speter        if (rv != APR_SUCCESS) {
845251876Speter            ms_bad_conn(ms, conn);
846251876Speter            apr_memcache_disable_server(mc, ms);
847251876Speter            return rv;
848251876Speter        }
849251876Speter
850251876Speter        if (strncmp(MS_END, conn->buffer, MS_END_LEN) != 0) {
851251876Speter            rv = APR_EGENERAL;
852251876Speter        }
853251876Speter    }
854251876Speter    else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
855251876Speter        rv = APR_NOTFOUND;
856251876Speter    }
857251876Speter    else {
858251876Speter        rv = APR_EGENERAL;
859251876Speter    }
860251876Speter
861251876Speter    ms_release_conn(ms, conn);
862251876Speter
863251876Speter    return rv;
864251876Speter}
865251876Speter
866251876SpeterAPU_DECLARE(apr_status_t)
867251876Speterapr_memcache_delete(apr_memcache_t *mc,
868251876Speter                    const char *key,
869251876Speter                    apr_uint32_t timeout)
870251876Speter{
871251876Speter    apr_status_t rv;
872251876Speter    apr_memcache_server_t *ms;
873251876Speter    apr_memcache_conn_t *conn;
874251876Speter    apr_uint32_t hash;
875251876Speter    apr_size_t written;
876251876Speter    struct iovec vec[3];
877251876Speter    apr_size_t klen = strlen(key);
878251876Speter
879251876Speter    hash = apr_memcache_hash(mc, key, klen);
880251876Speter    ms = apr_memcache_find_server_hash(mc, hash);
881251876Speter    if (ms == NULL)
882251876Speter        return APR_NOTFOUND;
883251876Speter
884251876Speter    rv = ms_find_conn(ms, &conn);
885251876Speter
886251876Speter    if (rv != APR_SUCCESS) {
887251876Speter        apr_memcache_disable_server(mc, ms);
888251876Speter        return rv;
889251876Speter    }
890251876Speter
891251876Speter    /* delete <key> <time>\r\n */
892251876Speter    vec[0].iov_base = MC_DELETE;
893251876Speter    vec[0].iov_len  = MC_DELETE_LEN;
894251876Speter
895251876Speter    vec[1].iov_base = (void*)key;
896251876Speter    vec[1].iov_len  = klen;
897251876Speter
898251876Speter    klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, timeout);
899251876Speter
900251876Speter    vec[2].iov_base = conn->buffer;
901251876Speter    vec[2].iov_len  = klen;
902251876Speter
903251876Speter    rv = apr_socket_sendv(conn->sock, vec, 3, &written);
904251876Speter
905251876Speter    if (rv != APR_SUCCESS) {
906251876Speter        ms_bad_conn(ms, conn);
907251876Speter        apr_memcache_disable_server(mc, ms);
908251876Speter        return rv;
909251876Speter    }
910251876Speter
911251876Speter    rv = get_server_line(conn);
912251876Speter    if (rv != APR_SUCCESS) {
913251876Speter        ms_bad_conn(ms, conn);
914251876Speter        apr_memcache_disable_server(mc, ms);
915251876Speter        return rv;
916251876Speter    }
917251876Speter
918251876Speter    if (strncmp(MS_DELETED, conn->buffer, MS_DELETED_LEN) == 0) {
919251876Speter        rv = APR_SUCCESS;
920251876Speter    }
921251876Speter    else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) {
922251876Speter        rv = APR_NOTFOUND;
923251876Speter    }
924251876Speter    else {
925251876Speter        rv = APR_EGENERAL;
926251876Speter    }
927251876Speter
928251876Speter    ms_release_conn(ms, conn);
929251876Speter
930251876Speter    return rv;
931251876Speter}
932251876Speter
933251876Speterstatic apr_status_t num_cmd_write(apr_memcache_t *mc,
934251876Speter                                      char *cmd,
935251876Speter                                      const apr_uint32_t cmd_size,
936251876Speter                                      const char *key,
937251876Speter                                      const apr_int32_t inc,
938251876Speter                                      apr_uint32_t *new_value)
939251876Speter{
940251876Speter    apr_status_t rv;
941251876Speter    apr_memcache_server_t *ms;
942251876Speter    apr_memcache_conn_t *conn;
943251876Speter    apr_uint32_t hash;
944251876Speter    apr_size_t written;
945251876Speter    struct iovec vec[3];
946251876Speter    apr_size_t klen = strlen(key);
947251876Speter
948251876Speter    hash = apr_memcache_hash(mc, key, klen);
949251876Speter    ms = apr_memcache_find_server_hash(mc, hash);
950251876Speter    if (ms == NULL)
951251876Speter        return APR_NOTFOUND;
952251876Speter
953251876Speter    rv = ms_find_conn(ms, &conn);
954251876Speter
955251876Speter    if (rv != APR_SUCCESS) {
956251876Speter        apr_memcache_disable_server(mc, ms);
957251876Speter        return rv;
958251876Speter    }
959251876Speter
960251876Speter    /* <cmd> <key> <value>\r\n */
961251876Speter    vec[0].iov_base = cmd;
962251876Speter    vec[0].iov_len  = cmd_size;
963251876Speter
964251876Speter    vec[1].iov_base = (void*)key;
965251876Speter    vec[1].iov_len  = klen;
966251876Speter
967251876Speter    klen = apr_snprintf(conn->buffer, BUFFER_SIZE, " %u" MC_EOL, inc);
968251876Speter
969251876Speter    vec[2].iov_base = conn->buffer;
970251876Speter    vec[2].iov_len  = klen;
971251876Speter
972251876Speter    rv = apr_socket_sendv(conn->sock, vec, 3, &written);
973251876Speter
974251876Speter    if (rv != APR_SUCCESS) {
975251876Speter        ms_bad_conn(ms, conn);
976251876Speter        apr_memcache_disable_server(mc, ms);
977251876Speter        return rv;
978251876Speter    }
979251876Speter
980251876Speter    rv = get_server_line(conn);
981251876Speter    if (rv != APR_SUCCESS) {
982251876Speter        ms_bad_conn(ms, conn);
983251876Speter        apr_memcache_disable_server(mc, ms);
984251876Speter        return rv;
985251876Speter    }
986251876Speter
987251876Speter    if (strncmp(MS_ERROR, conn->buffer, MS_ERROR_LEN) == 0) {
988251876Speter        rv = APR_EGENERAL;
989251876Speter    }
990251876Speter    else if (strncmp(MS_NOT_FOUND, conn->buffer, MS_NOT_FOUND_LEN) == 0) {
991251876Speter        rv = APR_NOTFOUND;
992251876Speter    }
993251876Speter    else {
994251876Speter        if (new_value) {
995251876Speter            *new_value = atoi(conn->buffer);
996251876Speter        }
997251876Speter        rv = APR_SUCCESS;
998251876Speter    }
999251876Speter
1000251876Speter    ms_release_conn(ms, conn);
1001251876Speter
1002251876Speter    return rv;
1003251876Speter}
1004251876Speter
1005251876SpeterAPU_DECLARE(apr_status_t)
1006251876Speterapr_memcache_incr(apr_memcache_t *mc,
1007251876Speter                    const char *key,
1008251876Speter                    apr_int32_t inc,
1009251876Speter                    apr_uint32_t *new_value)
1010251876Speter{
1011251876Speter    return num_cmd_write(mc,
1012251876Speter                         MC_INCR,
1013251876Speter                         MC_INCR_LEN,
1014251876Speter                         key,
1015251876Speter                         inc,
1016251876Speter                         new_value);
1017251876Speter}
1018251876Speter
1019251876Speter
1020251876SpeterAPU_DECLARE(apr_status_t)
1021251876Speterapr_memcache_decr(apr_memcache_t *mc,
1022251876Speter                    const char *key,
1023251876Speter                    apr_int32_t inc,
1024251876Speter                    apr_uint32_t *new_value)
1025251876Speter{
1026251876Speter    return num_cmd_write(mc,
1027251876Speter                         MC_DECR,
1028251876Speter                         MC_DECR_LEN,
1029251876Speter                         key,
1030251876Speter                         inc,
1031251876Speter                         new_value);
1032251876Speter}
1033251876Speter
1034251876Speter
1035251876Speter
1036251876SpeterAPU_DECLARE(apr_status_t)
1037251876Speterapr_memcache_version(apr_memcache_server_t *ms,
1038251876Speter                  apr_pool_t *p,
1039251876Speter                  char **baton)
1040251876Speter{
1041251876Speter    apr_status_t rv;
1042251876Speter    apr_memcache_conn_t *conn;
1043251876Speter    apr_size_t written;
1044251876Speter    struct iovec vec[2];
1045251876Speter
1046251876Speter    rv = ms_find_conn(ms, &conn);
1047251876Speter
1048251876Speter    if (rv != APR_SUCCESS) {
1049251876Speter        return rv;
1050251876Speter    }
1051251876Speter
1052251876Speter    /* version\r\n */
1053251876Speter    vec[0].iov_base = MC_VERSION;
1054251876Speter    vec[0].iov_len  = MC_VERSION_LEN;
1055251876Speter
1056251876Speter    vec[1].iov_base = MC_EOL;
1057251876Speter    vec[1].iov_len  = MC_EOL_LEN;
1058251876Speter
1059251876Speter    rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1060251876Speter
1061251876Speter    if (rv != APR_SUCCESS) {
1062251876Speter        ms_bad_conn(ms, conn);
1063251876Speter        return rv;
1064251876Speter    }
1065251876Speter
1066251876Speter    rv = get_server_line(conn);
1067251876Speter    if (rv != APR_SUCCESS) {
1068251876Speter        ms_bad_conn(ms, conn);
1069251876Speter        return rv;
1070251876Speter    }
1071251876Speter
1072251876Speter    if (strncmp(MS_VERSION, conn->buffer, MS_VERSION_LEN) == 0) {
1073251876Speter        *baton = apr_pstrmemdup(p, conn->buffer+MS_VERSION_LEN+1,
1074251876Speter                                conn->blen - MS_VERSION_LEN - 2);
1075251876Speter        rv = APR_SUCCESS;
1076251876Speter    }
1077251876Speter    else {
1078251876Speter        rv = APR_EGENERAL;
1079251876Speter    }
1080251876Speter
1081251876Speter    ms_release_conn(ms, conn);
1082251876Speter
1083251876Speter    return rv;
1084251876Speter}
1085251876Speter
1086251876Speterapr_status_t mc_version_ping(apr_memcache_server_t *ms)
1087251876Speter{
1088251876Speter    apr_status_t rv;
1089251876Speter    apr_size_t written;
1090251876Speter    struct iovec vec[2];
1091251876Speter    apr_memcache_conn_t *conn;
1092251876Speter
1093251876Speter    rv = ms_find_conn(ms, &conn);
1094251876Speter
1095251876Speter    if (rv != APR_SUCCESS) {
1096251876Speter        return rv;
1097251876Speter    }
1098251876Speter
1099251876Speter    /* version\r\n */
1100251876Speter    vec[0].iov_base = MC_VERSION;
1101251876Speter    vec[0].iov_len  = MC_VERSION_LEN;
1102251876Speter
1103251876Speter    vec[1].iov_base = MC_EOL;
1104251876Speter    vec[1].iov_len  = MC_EOL_LEN;
1105251876Speter
1106251876Speter    rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1107251876Speter
1108251876Speter    if (rv != APR_SUCCESS) {
1109251876Speter        ms_bad_conn(ms, conn);
1110251876Speter        return rv;
1111251876Speter    }
1112251876Speter
1113251876Speter    rv = get_server_line(conn);
1114251876Speter    ms_release_conn(ms, conn);
1115251876Speter    return rv;
1116251876Speter}
1117251876Speter
1118251876Speter
1119251876SpeterAPU_DECLARE(void)
1120251876Speterapr_memcache_add_multget_key(apr_pool_t *data_pool,
1121251876Speter                             const char* key,
1122251876Speter                             apr_hash_t **values)
1123251876Speter{
1124251876Speter    apr_memcache_value_t* value;
1125251876Speter    apr_size_t klen = strlen(key);
1126251876Speter
1127251876Speter    /* create the value hash if need be */
1128251876Speter    if (!*values) {
1129251876Speter        *values = apr_hash_make(data_pool);
1130251876Speter    }
1131251876Speter
1132251876Speter    /* init key and add it to the value hash */
1133251876Speter    value = apr_pcalloc(data_pool, sizeof(apr_memcache_value_t));
1134251876Speter
1135251876Speter    value->status = APR_NOTFOUND;
1136251876Speter    value->key = apr_pstrdup(data_pool, key);
1137251876Speter
1138251876Speter    apr_hash_set(*values, value->key, klen, value);
1139251876Speter}
1140251876Speter
1141251876Speterstatic void mget_conn_result(int serverup,
1142251876Speter                             int connup,
1143251876Speter                             apr_status_t rv,
1144251876Speter                             apr_memcache_t *mc,
1145251876Speter                             apr_memcache_server_t *ms,
1146251876Speter                             apr_memcache_conn_t *conn,
1147251876Speter                             struct cache_server_query_t *server_query,
1148251876Speter                             apr_hash_t *values,
1149251876Speter                             apr_hash_t *server_queries)
1150251876Speter{
1151251876Speter    apr_int32_t j;
1152251876Speter    apr_memcache_value_t* value;
1153251876Speter
1154251876Speter    apr_hash_set(server_queries, &ms, sizeof(ms), NULL);
1155251876Speter
1156251876Speter    if (connup) {
1157251876Speter        ms_release_conn(ms, conn);
1158251876Speter    } else {
1159251876Speter        ms_bad_conn(ms, conn);
1160251876Speter
1161251876Speter        if (!serverup) {
1162251876Speter            apr_memcache_disable_server(mc, ms);
1163251876Speter        }
1164251876Speter    }
1165251876Speter
1166251876Speter    for (j = 1; j < server_query->query_vec_count ; j+=2) {
1167251876Speter        if (server_query->query_vec[j].iov_base) {
1168251876Speter            value = apr_hash_get(values, server_query->query_vec[j].iov_base,
1169251876Speter                                 strlen(server_query->query_vec[j].iov_base));
1170251876Speter
1171251876Speter            if (value->status == APR_NOTFOUND) {
1172251876Speter                value->status = rv;
1173251876Speter            }
1174251876Speter        }
1175251876Speter    }
1176251876Speter}
1177251876Speter
1178251876SpeterAPU_DECLARE(apr_status_t)
1179251876Speterapr_memcache_multgetp(apr_memcache_t *mc,
1180251876Speter                      apr_pool_t *temp_pool,
1181251876Speter                      apr_pool_t *data_pool,
1182251876Speter                      apr_hash_t *values)
1183251876Speter{
1184251876Speter    apr_status_t rv;
1185251876Speter    apr_memcache_server_t* ms;
1186251876Speter    apr_memcache_conn_t* conn;
1187251876Speter    apr_uint32_t hash;
1188251876Speter    apr_size_t written;
1189251876Speter    apr_size_t klen;
1190251876Speter
1191251876Speter    apr_memcache_value_t* value;
1192251876Speter    apr_hash_index_t* value_hash_index;
1193251876Speter
1194251876Speter    /* this is a little over aggresive, but beats multiple loops
1195251876Speter     * to figure out how long each vector needs to be per-server.
1196251876Speter     */
1197251876Speter    apr_int32_t veclen = 2 + 2 * apr_hash_count(values) - 1; /* get <key>[<space><key>...]\r\n */
1198251876Speter    apr_int32_t i, j;
1199251876Speter    apr_int32_t queries_sent;
1200251876Speter    apr_int32_t queries_recvd;
1201251876Speter
1202251876Speter    apr_hash_t * server_queries = apr_hash_make(temp_pool);
1203251876Speter    struct cache_server_query_t* server_query;
1204251876Speter    apr_hash_index_t * query_hash_index;
1205251876Speter
1206251876Speter    apr_pollset_t* pollset;
1207251876Speter    const apr_pollfd_t* activefds;
1208251876Speter    apr_pollfd_t* pollfds;
1209251876Speter
1210251876Speter
1211251876Speter    /* build all the queries */
1212251876Speter    value_hash_index = apr_hash_first(temp_pool, values);
1213251876Speter    while (value_hash_index) {
1214251876Speter        void *v;
1215251876Speter        apr_hash_this(value_hash_index, NULL, NULL, &v);
1216251876Speter        value = v;
1217251876Speter        value_hash_index = apr_hash_next(value_hash_index);
1218251876Speter        klen = strlen(value->key);
1219251876Speter
1220251876Speter        hash = apr_memcache_hash(mc, value->key, klen);
1221251876Speter        ms = apr_memcache_find_server_hash(mc, hash);
1222251876Speter        if (ms == NULL) {
1223251876Speter            continue;
1224251876Speter        }
1225251876Speter
1226251876Speter        server_query = apr_hash_get(server_queries, &ms, sizeof(ms));
1227251876Speter
1228251876Speter        if (!server_query) {
1229251876Speter            rv = ms_find_conn(ms, &conn);
1230251876Speter
1231251876Speter            if (rv != APR_SUCCESS) {
1232251876Speter                apr_memcache_disable_server(mc, ms);
1233251876Speter                value->status = rv;
1234251876Speter                continue;
1235251876Speter            }
1236251876Speter
1237251876Speter            server_query = apr_pcalloc(temp_pool,sizeof(struct cache_server_query_t));
1238251876Speter
1239251876Speter            apr_hash_set(server_queries, &ms, sizeof(ms), server_query);
1240251876Speter
1241251876Speter            server_query->ms = ms;
1242251876Speter            server_query->conn = conn;
1243251876Speter            server_query->query_vec = apr_pcalloc(temp_pool, sizeof(struct iovec)*veclen);
1244251876Speter
1245251876Speter            /* set up the first key */
1246251876Speter            server_query->query_vec[0].iov_base = MC_GET;
1247251876Speter            server_query->query_vec[0].iov_len  = MC_GET_LEN;
1248251876Speter
1249251876Speter            server_query->query_vec[1].iov_base = (void*)(value->key);
1250251876Speter            server_query->query_vec[1].iov_len  = klen;
1251251876Speter
1252251876Speter            server_query->query_vec[2].iov_base = MC_EOL;
1253251876Speter            server_query->query_vec[2].iov_len  = MC_EOL_LEN;
1254251876Speter
1255251876Speter            server_query->query_vec_count = 3;
1256251876Speter        }
1257251876Speter        else {
1258251876Speter            j = server_query->query_vec_count - 1;
1259251876Speter
1260251876Speter            server_query->query_vec[j].iov_base = MC_WS;
1261251876Speter            server_query->query_vec[j].iov_len  = MC_WS_LEN;
1262251876Speter            j++;
1263251876Speter
1264251876Speter            server_query->query_vec[j].iov_base = (void*)(value->key);
1265251876Speter            server_query->query_vec[j].iov_len  = klen;
1266251876Speter            j++;
1267251876Speter
1268251876Speter            server_query->query_vec[j].iov_base = MC_EOL;
1269251876Speter            server_query->query_vec[j].iov_len  = MC_EOL_LEN;
1270251876Speter            j++;
1271251876Speter
1272251876Speter           server_query->query_vec_count = j;
1273251876Speter        }
1274251876Speter    }
1275251876Speter
1276251876Speter    /* create polling structures */
1277251876Speter    pollfds = apr_pcalloc(temp_pool, apr_hash_count(server_queries) * sizeof(apr_pollfd_t));
1278251876Speter
1279251876Speter    rv = apr_pollset_create(&pollset, apr_hash_count(server_queries), temp_pool, 0);
1280251876Speter
1281251876Speter    if (rv != APR_SUCCESS) {
1282251876Speter        query_hash_index = apr_hash_first(temp_pool, server_queries);
1283251876Speter
1284251876Speter        while (query_hash_index) {
1285251876Speter            void *v;
1286251876Speter            apr_hash_this(query_hash_index, NULL, NULL, &v);
1287251876Speter            server_query = v;
1288251876Speter            query_hash_index = apr_hash_next(query_hash_index);
1289251876Speter
1290251876Speter            mget_conn_result(TRUE, TRUE, rv, mc, server_query->ms, server_query->conn,
1291251876Speter                             server_query, values, server_queries);
1292251876Speter        }
1293251876Speter
1294251876Speter        return rv;
1295251876Speter    }
1296251876Speter
1297251876Speter    /* send all the queries */
1298251876Speter    queries_sent = 0;
1299251876Speter    query_hash_index = apr_hash_first(temp_pool, server_queries);
1300251876Speter
1301251876Speter    while (query_hash_index) {
1302251876Speter        void *v;
1303251876Speter        apr_hash_this(query_hash_index, NULL, NULL, &v);
1304251876Speter        server_query = v;
1305251876Speter        query_hash_index = apr_hash_next(query_hash_index);
1306251876Speter
1307251876Speter        conn = server_query->conn;
1308251876Speter        ms = server_query->ms;
1309251876Speter
1310251876Speter        for (i = 0, rv = APR_SUCCESS; i < veclen && rv == APR_SUCCESS; i += APR_MAX_IOVEC_SIZE) {
1311251876Speter            rv = apr_socket_sendv(conn->sock, &(server_query->query_vec[i]),
1312251876Speter                                  veclen-i>APR_MAX_IOVEC_SIZE ? APR_MAX_IOVEC_SIZE : veclen-i , &written);
1313251876Speter        }
1314251876Speter
1315251876Speter        if (rv != APR_SUCCESS) {
1316251876Speter            mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1317251876Speter                             server_query, values, server_queries);
1318251876Speter            continue;
1319251876Speter        }
1320251876Speter
1321251876Speter        pollfds[queries_sent].desc_type = APR_POLL_SOCKET;
1322251876Speter        pollfds[queries_sent].reqevents = APR_POLLIN;
1323251876Speter        pollfds[queries_sent].p = temp_pool;
1324251876Speter        pollfds[queries_sent].desc.s = conn->sock;
1325251876Speter        pollfds[queries_sent].client_data = (void *)server_query;
1326251876Speter        apr_pollset_add (pollset, &pollfds[queries_sent]);
1327251876Speter
1328251876Speter        queries_sent++;
1329251876Speter    }
1330251876Speter
1331251876Speter    while (queries_sent) {
1332251876Speter        rv = apr_pollset_poll(pollset, MULT_GET_TIMEOUT, &queries_recvd, &activefds);
1333251876Speter
1334251876Speter        if (rv != APR_SUCCESS) {
1335251876Speter            /* timeout */
1336251876Speter            queries_sent = 0;
1337251876Speter            continue;
1338251876Speter        }
1339251876Speter        for (i = 0; i < queries_recvd; i++) {
1340251876Speter            server_query = activefds[i].client_data;
1341251876Speter            conn = server_query->conn;
1342251876Speter            ms = server_query->ms;
1343251876Speter
1344251876Speter           rv = get_server_line(conn);
1345251876Speter
1346251876Speter           if (rv != APR_SUCCESS) {
1347251876Speter               apr_pollset_remove (pollset, &activefds[i]);
1348251876Speter               mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1349251876Speter                                server_query, values, server_queries);
1350251876Speter               queries_sent--;
1351251876Speter               continue;
1352251876Speter           }
1353251876Speter
1354251876Speter           if (strncmp(MS_VALUE, conn->buffer, MS_VALUE_LEN) == 0) {
1355251876Speter               char *key;
1356251876Speter               char *flags;
1357251876Speter               char *length;
1358251876Speter               char *last;
1359251876Speter               char *data;
1360251876Speter               apr_size_t len = 0;
1361251876Speter
1362251876Speter               key = apr_strtok(conn->buffer, " ", &last); /* just the VALUE, ignore */
1363251876Speter               key = apr_strtok(NULL, " ", &last);
1364251876Speter               flags = apr_strtok(NULL, " ", &last);
1365251876Speter
1366251876Speter
1367251876Speter               length = apr_strtok(NULL, " ", &last);
1368251876Speter               if (length) {
1369253734Speter                   len = strtol(length, (char **) NULL, 10);
1370251876Speter               }
1371251876Speter
1372251876Speter               value = apr_hash_get(values, key, strlen(key));
1373251876Speter
1374251876Speter
1375251876Speter               if (value) {
1376253734Speter                   if (len != 0)  {
1377251876Speter                       apr_bucket_brigade *bbb;
1378251876Speter                       apr_bucket *e;
1379251876Speter
1380251876Speter                       /* eat the trailing \r\n */
1381251876Speter                       rv = apr_brigade_partition(conn->bb, len+2, &e);
1382251876Speter
1383251876Speter                       if (rv != APR_SUCCESS) {
1384251876Speter                           apr_pollset_remove (pollset, &activefds[i]);
1385251876Speter                           mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1386251876Speter                                            server_query, values, server_queries);
1387251876Speter                           queries_sent--;
1388251876Speter                           continue;
1389251876Speter                       }
1390251876Speter
1391251876Speter                       bbb = apr_brigade_split(conn->bb, e);
1392251876Speter
1393251876Speter                       rv = apr_brigade_pflatten(conn->bb, &data, &len, data_pool);
1394251876Speter
1395251876Speter                       if (rv != APR_SUCCESS) {
1396251876Speter                           apr_pollset_remove (pollset, &activefds[i]);
1397251876Speter                           mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1398251876Speter                                            server_query, values, server_queries);
1399251876Speter                           queries_sent--;
1400251876Speter                           continue;
1401251876Speter                       }
1402251876Speter
1403251876Speter                       rv = apr_brigade_destroy(conn->bb);
1404251876Speter                       if (rv != APR_SUCCESS) {
1405251876Speter                           apr_pollset_remove (pollset, &activefds[i]);
1406251876Speter                           mget_conn_result(FALSE, FALSE, rv, mc, ms, conn,
1407251876Speter                                            server_query, values, server_queries);
1408251876Speter                           queries_sent--;
1409251876Speter                           continue;
1410251876Speter                       }
1411251876Speter
1412251876Speter                       conn->bb = bbb;
1413251876Speter
1414251876Speter                       value->len = len - 2;
1415251876Speter                       data[value->len] = '\0';
1416251876Speter                       value->data = data;
1417251876Speter                   }
1418251876Speter
1419251876Speter                   value->status = rv;
1420251876Speter                   value->flags = atoi(flags);
1421251876Speter
1422251876Speter                   /* stay on the server */
1423251876Speter                   i--;
1424251876Speter
1425251876Speter               }
1426251876Speter               else {
1427251876Speter                   /* TODO: Server Sent back a key I didn't ask for or my
1428251876Speter                    *       hash is corrupt */
1429251876Speter               }
1430251876Speter           }
1431251876Speter           else if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
1432251876Speter               /* this connection is done */
1433251876Speter               apr_pollset_remove (pollset, &activefds[i]);
1434251876Speter               ms_release_conn(ms, conn);
1435251876Speter               apr_hash_set(server_queries, &ms, sizeof(ms), NULL);
1436251876Speter
1437251876Speter               queries_sent--;
1438251876Speter           }
1439251876Speter           else {
1440251876Speter               /* unknown reply? */
1441251876Speter               rv = APR_EGENERAL;
1442251876Speter           }
1443251876Speter
1444251876Speter        } /* /for */
1445251876Speter    } /* /while */
1446251876Speter
1447251876Speter    query_hash_index = apr_hash_first(temp_pool, server_queries);
1448251876Speter    while (query_hash_index) {
1449251876Speter        void *v;
1450251876Speter        apr_hash_this(query_hash_index, NULL, NULL, &v);
1451251876Speter        server_query = v;
1452251876Speter        query_hash_index = apr_hash_next(query_hash_index);
1453251876Speter
1454251876Speter        conn = server_query->conn;
1455251876Speter        ms = server_query->ms;
1456251876Speter
1457251876Speter        mget_conn_result(TRUE, (rv == APR_SUCCESS), rv, mc, ms, conn,
1458251876Speter                         server_query, values, server_queries);
1459251876Speter        continue;
1460251876Speter    }
1461251876Speter
1462251876Speter    apr_pollset_destroy(pollset);
1463251876Speter    apr_pool_clear(temp_pool);
1464251876Speter    return APR_SUCCESS;
1465251876Speter
1466251876Speter}
1467251876Speter
1468251876Speter
1469251876Speter
1470251876Speter/**
1471251876Speter * Define all of the strings for stats
1472251876Speter */
1473251876Speter
1474251876Speter#define STAT_pid MS_STAT " pid "
1475251876Speter#define STAT_pid_LEN (sizeof(STAT_pid)-1)
1476251876Speter
1477251876Speter#define STAT_uptime MS_STAT " uptime "
1478251876Speter#define STAT_uptime_LEN (sizeof(STAT_uptime)-1)
1479251876Speter
1480251876Speter#define STAT_time MS_STAT " time "
1481251876Speter#define STAT_time_LEN (sizeof(STAT_time)-1)
1482251876Speter
1483251876Speter#define STAT_version MS_STAT " version "
1484251876Speter#define STAT_version_LEN (sizeof(STAT_version)-1)
1485251876Speter
1486251876Speter#define STAT_pointer_size MS_STAT " pointer_size "
1487251876Speter#define STAT_pointer_size_LEN (sizeof(STAT_pointer_size)-1)
1488251876Speter
1489251876Speter#define STAT_rusage_user MS_STAT " rusage_user "
1490251876Speter#define STAT_rusage_user_LEN (sizeof(STAT_rusage_user)-1)
1491251876Speter
1492251876Speter#define STAT_rusage_system MS_STAT " rusage_system "
1493251876Speter#define STAT_rusage_system_LEN (sizeof(STAT_rusage_system)-1)
1494251876Speter
1495251876Speter#define STAT_curr_items MS_STAT " curr_items "
1496251876Speter#define STAT_curr_items_LEN (sizeof(STAT_curr_items)-1)
1497251876Speter
1498251876Speter#define STAT_total_items MS_STAT " total_items "
1499251876Speter#define STAT_total_items_LEN (sizeof(STAT_total_items)-1)
1500251876Speter
1501251876Speter#define STAT_bytes MS_STAT " bytes "
1502251876Speter#define STAT_bytes_LEN (sizeof(STAT_bytes)-1)
1503251876Speter
1504251876Speter#define STAT_curr_connections MS_STAT " curr_connections "
1505251876Speter#define STAT_curr_connections_LEN (sizeof(STAT_curr_connections)-1)
1506251876Speter
1507251876Speter#define STAT_total_connections MS_STAT " total_connections "
1508251876Speter#define STAT_total_connections_LEN (sizeof(STAT_total_connections)-1)
1509251876Speter
1510251876Speter#define STAT_connection_structures MS_STAT " connection_structures "
1511251876Speter#define STAT_connection_structures_LEN (sizeof(STAT_connection_structures)-1)
1512251876Speter
1513251876Speter#define STAT_cmd_get MS_STAT " cmd_get "
1514251876Speter#define STAT_cmd_get_LEN (sizeof(STAT_cmd_get)-1)
1515251876Speter
1516251876Speter#define STAT_cmd_set MS_STAT " cmd_set "
1517251876Speter#define STAT_cmd_set_LEN (sizeof(STAT_cmd_set)-1)
1518251876Speter
1519251876Speter#define STAT_get_hits MS_STAT " get_hits "
1520251876Speter#define STAT_get_hits_LEN (sizeof(STAT_get_hits)-1)
1521251876Speter
1522251876Speter#define STAT_get_misses MS_STAT " get_misses "
1523251876Speter#define STAT_get_misses_LEN (sizeof(STAT_get_misses)-1)
1524251876Speter
1525251876Speter#define STAT_evictions MS_STAT " evictions "
1526251876Speter#define STAT_evictions_LEN (sizeof(STAT_evictions)-1)
1527251876Speter
1528251876Speter#define STAT_bytes_read MS_STAT " bytes_read "
1529251876Speter#define STAT_bytes_read_LEN (sizeof(STAT_bytes_read)-1)
1530251876Speter
1531251876Speter#define STAT_bytes_written MS_STAT " bytes_written "
1532251876Speter#define STAT_bytes_written_LEN (sizeof(STAT_bytes_written)-1)
1533251876Speter
1534251876Speter#define STAT_limit_maxbytes MS_STAT " limit_maxbytes "
1535251876Speter#define STAT_limit_maxbytes_LEN (sizeof(STAT_limit_maxbytes)-1)
1536251876Speter
1537251876Speter#define STAT_threads MS_STAT " threads "
1538251876Speter#define STAT_threads_LEN (sizeof(STAT_threads)-1)
1539251876Speter
1540251876Speterstatic const char *stat_read_string(apr_pool_t *p, char *buf, apr_size_t len)
1541251876Speter{
1542251876Speter    /* remove trailing \r\n and null char */
1543251876Speter    return apr_pstrmemdup(p, buf, len-2);
1544251876Speter}
1545251876Speter
1546251876Speterstatic apr_uint32_t stat_read_uint32(apr_pool_t *p, char *buf, apr_size_t  len)
1547251876Speter{
1548251876Speter    buf[len-2] = '\0';
1549251876Speter    return atoi(buf);
1550251876Speter}
1551251876Speter
1552251876Speterstatic apr_uint64_t stat_read_uint64(apr_pool_t *p, char *buf, apr_size_t  len)
1553251876Speter{
1554251876Speter    buf[len-2] = '\0';
1555251876Speter    return apr_atoi64(buf);
1556251876Speter}
1557251876Speter
1558251876Speterstatic apr_time_t stat_read_time(apr_pool_t *p, char *buf, apr_size_t  len)
1559251876Speter{
1560251876Speter    buf[len-2] = '\0';
1561251876Speter    return apr_time_from_sec(atoi(buf));
1562251876Speter}
1563251876Speter
1564251876Speterstatic apr_time_t stat_read_rtime(apr_pool_t *p, char *buf, apr_size_t  len)
1565251876Speter{
1566251876Speter    char *tok;
1567251876Speter    char *secs;
1568251876Speter    char *usecs;
1569251876Speter    const char *sep = ":.";
1570251876Speter
1571251876Speter    buf[len-2] = '\0';
1572251876Speter
1573251876Speter    secs = apr_strtok(buf, sep, &tok);
1574251876Speter    usecs = apr_strtok(NULL, sep, &tok);
1575251876Speter    if (secs && usecs) {
1576251876Speter        return apr_time_make(atoi(secs), atoi(usecs));
1577251876Speter    }
1578251876Speter    else {
1579251876Speter        return apr_time_make(0, 0);
1580251876Speter    }
1581251876Speter}
1582251876Speter
1583251876Speter/**
1584251876Speter * I got tired of Typing. Meh.
1585251876Speter *
1586251876Speter * TODO: Convert it to static tables to make it cooler.
1587251876Speter */
1588251876Speter
1589251876Speter#define mc_stat_cmp(name) \
1590251876Speter    strncmp(STAT_ ## name, conn->buffer, STAT_ ## name ## _LEN) == 0
1591251876Speter
1592251876Speter#define mc_stat_str(name) \
1593251876Speter    stat_read_string(p, conn->buffer + name, \
1594251876Speter                     conn->blen - name)
1595251876Speter
1596251876Speter#define mc_stat_uint32(name) \
1597251876Speter    stat_read_uint32(p, conn->buffer + name, \
1598251876Speter                     conn->blen - name)
1599251876Speter
1600251876Speter#define mc_stat_uint64(name) \
1601251876Speter    stat_read_uint64(p, conn->buffer + name, \
1602251876Speter                     conn->blen - name)
1603251876Speter
1604251876Speter#define mc_stat_time(name) \
1605251876Speter    stat_read_time(p, conn->buffer + name, \
1606251876Speter                     conn->blen - name)
1607251876Speter
1608251876Speter#define mc_stat_rtime(name) \
1609251876Speter    stat_read_rtime(p, conn->buffer + name, \
1610251876Speter                     conn->blen - name)
1611251876Speter
1612251876Speter
1613251876Speter#define mc_do_stat(name, type) \
1614251876Speter    if (mc_stat_cmp(name)) { \
1615251876Speter        stats-> name = mc_stat_ ## type ((STAT_ ## name ## _LEN)); \
1616251876Speter    }
1617251876Speter
1618251876Speterstatic void update_stats(apr_pool_t *p, apr_memcache_conn_t *conn,
1619251876Speter                         apr_memcache_stats_t *stats)
1620251876Speter{
1621251876Speter
1622251876Speter    mc_do_stat(version, str)
1623251876Speter    else mc_do_stat(pid, uint32)
1624251876Speter    else mc_do_stat(uptime, uint32)
1625251876Speter    else mc_do_stat(pointer_size, uint32)
1626251876Speter    else mc_do_stat(time, time)
1627251876Speter    else mc_do_stat(rusage_user, rtime)
1628251876Speter    else mc_do_stat(rusage_system, rtime)
1629251876Speter    else mc_do_stat(curr_items, uint32)
1630251876Speter    else mc_do_stat(total_items, uint32)
1631251876Speter    else mc_do_stat(bytes, uint64)
1632251876Speter    else mc_do_stat(curr_connections, uint32)
1633251876Speter    else mc_do_stat(total_connections, uint32)
1634251876Speter    else mc_do_stat(connection_structures, uint32)
1635251876Speter    else mc_do_stat(cmd_get, uint32)
1636251876Speter    else mc_do_stat(cmd_set, uint32)
1637251876Speter    else mc_do_stat(get_hits, uint32)
1638251876Speter    else mc_do_stat(get_misses, uint32)
1639251876Speter    else mc_do_stat(evictions, uint64)
1640251876Speter    else mc_do_stat(bytes_read, uint64)
1641251876Speter    else mc_do_stat(bytes_written, uint64)
1642251876Speter    else mc_do_stat(limit_maxbytes, uint32)
1643251876Speter    else mc_do_stat(threads, uint32)
1644251876Speter}
1645251876Speter
1646251876SpeterAPU_DECLARE(apr_status_t)
1647251876Speterapr_memcache_stats(apr_memcache_server_t *ms,
1648251876Speter                  apr_pool_t *p,
1649251876Speter                  apr_memcache_stats_t **stats)
1650251876Speter{
1651251876Speter    apr_memcache_stats_t *ret;
1652251876Speter    apr_status_t rv;
1653251876Speter    apr_memcache_conn_t *conn;
1654251876Speter    apr_size_t written;
1655251876Speter    struct iovec vec[2];
1656251876Speter
1657251876Speter    rv = ms_find_conn(ms, &conn);
1658251876Speter
1659251876Speter    if (rv != APR_SUCCESS) {
1660251876Speter        return rv;
1661251876Speter    }
1662251876Speter
1663251876Speter    /* version\r\n */
1664251876Speter    vec[0].iov_base = MC_STATS;
1665251876Speter    vec[0].iov_len  = MC_STATS_LEN;
1666251876Speter
1667251876Speter    vec[1].iov_base = MC_EOL;
1668251876Speter    vec[1].iov_len  = MC_EOL_LEN;
1669251876Speter
1670251876Speter    rv = apr_socket_sendv(conn->sock, vec, 2, &written);
1671251876Speter
1672251876Speter    if (rv != APR_SUCCESS) {
1673251876Speter        ms_bad_conn(ms, conn);
1674251876Speter        return rv;
1675251876Speter    }
1676251876Speter
1677251876Speter    ret = apr_pcalloc(p, sizeof(apr_memcache_stats_t));
1678251876Speter
1679251876Speter    do {
1680251876Speter        rv = get_server_line(conn);
1681251876Speter        if (rv != APR_SUCCESS) {
1682251876Speter            ms_bad_conn(ms, conn);
1683251876Speter            return rv;
1684251876Speter        }
1685251876Speter
1686251876Speter        if (strncmp(MS_END, conn->buffer, MS_END_LEN) == 0) {
1687251876Speter            rv = APR_SUCCESS;
1688251876Speter            break;
1689251876Speter        }
1690251876Speter        else if (strncmp(MS_STAT, conn->buffer, MS_STAT_LEN) == 0) {
1691251876Speter            update_stats(p, conn, ret);
1692251876Speter            continue;
1693251876Speter        }
1694251876Speter        else {
1695251876Speter            rv = APR_EGENERAL;
1696251876Speter            break;
1697251876Speter        }
1698251876Speter
1699251876Speter    } while(1);
1700251876Speter
1701251876Speter    ms_release_conn(ms, conn);
1702251876Speter
1703251876Speter    if (stats) {
1704251876Speter        *stats = ret;
1705251876Speter    }
1706251876Speter
1707251876Speter    return rv;
1708251876Speter}
1709251876Speter
1710