2 * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
3 * Copyright (C) 2005 QSDN,Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 #ifdef USE_MEMCACHE_COOKIE
19 #include "chxj_cookie.h"
20 #include "chxj_url_encode.h"
21 #include "chxj_apply_convrule.h"
22 #include "chxj_str_util.h"
24 #include "ap_release.h"
29 #include "apr_base64.h"
34 /* for apr-memcache */
35 #include "apr_memcache.h"
37 #define MEMCACHE_MIN_CONNECTION (0)
38 #define MEMCACHE_SMAX_CONNECTION (1)
39 #define MEMCACHE_MAX_CONNECTION (1)
40 #define MEMCACHE_TTL_CONNECTION (600)
42 #define MEMCACHE_LOCK_KEY "chxj::lock"
43 #define MEMCACHE_WAIT_MICRO_SECOND (5000)
44 #define MEMCACHE_LOCK_RETRY_COUNT (100)
47 #define MEMCACHE_MAX_SERVER (10)
48 #define MEMCACHE_FLAGS (0)
50 #define DEFAULT_MEMCACHE_TIMEOUT (1000)
51 #define DEFAULT_DELETE_TIMEOUT (0)
53 #define DEFAULT_COOKIE_DB_NAME "chxj_cookie"
54 #define DEFAULT_COOKIE_EXPIRE_DB_NAME "chxj_cookie_expire"
56 /* The underlying apr_memcache system is thread safe. */
57 static apr_memcache_t* mc = NULL;
60 _memcache_cleanup(void *UNUSED(notused))
67 chxj_memcache_init(request_rec *r, mod_chxj_config *m)
69 apr_memcache_server_t* st;
70 DBG(r, "start chxj_memcache_init()");
72 if (!chxj_memcache_and_memcache_server_create(r, m, &st, &mc)) {
73 ERR(r, "%s:%d end chxj_memcache_init() failed: chxj_memcache_and_memcache_server_create()", APLOG_MARK);
76 apr_pool_cleanup_register(r->pool, (void *)NULL, _memcache_cleanup, _memcache_cleanup);
78 DBG(r, "end chxj_memcache_init()");
83 chxj_memcache_and_memcache_server_create(request_rec *r, mod_chxj_config *m, apr_memcache_server_t **memcache_server, apr_memcache_t **memcache)
85 DBG(r, "start chxj_memcache_server_create()");
86 if (apr_memcache_server_create(r->pool,
89 MEMCACHE_MIN_CONNECTION,
90 MEMCACHE_SMAX_CONNECTION,
91 MEMCACHE_MAX_CONNECTION,
92 MEMCACHE_TTL_CONNECTION,
93 memcache_server) != APR_SUCCESS) {
94 ERR(r, "%s:%d end chxj_memcache_server_create() failed apr_memcache_server_create() host:[%s] port:[%d]", APLOG_MARK, m->memcache.host, m->memcache.port);
97 DBG(r, "done create_server");
98 if (apr_memcache_create(r->pool, MEMCACHE_MAX_SERVER, MEMCACHE_FLAGS, memcache) != APR_SUCCESS) {
99 ERR(r, "%s:%d end chxj_memcache_server_create() failed apr_memcache_create()", APLOG_MARK);
102 DBG(r, "done create memcache");
103 if (apr_memcache_add_server(*memcache, *memcache_server) != APR_SUCCESS) {
104 ERR(r, "%s:%d end chxj_memcache_server_create() failed apr_memcache_add_server()", APLOG_MARK);
107 DBG(r, "end chxj_memcache_server_create()");
114 chxj_memcache_set_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
117 apr_uint32_t timeout = (apr_uint32_t) ((m->cookie_timeout) ? m->cookie_timeout : DEFAULT_COOKIE_TIMEOUT);
118 DBG(r, "start chxj_memcache_set_cookie()");
121 if ((ret = apr_memcache_set(mc, cookie_id, (char *)store_string, strlen(store_string), timeout, 0)) != APR_SUCCESS) {
122 if (ret == APR_EAGAIN) {
125 ERR(r, "%s:%d chxj_memcache_set_cookie() failed: apr_memcache_set() ret:[%d]", APLOG_MARK, ret);
131 DBG(r, "end chxj_memcache_set_cookie()");
137 chxj_memcache_reset_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id)
140 DBG(r, "start chxj_memcache_reset_cookie()");
143 if (! (store_string = chxj_memcache_get_cookie(r, m, cookie_id))) {
144 ERR(r, "%s:%d chxj_memcache_reset_cookie() failed: chxj_memcache_get_cookie() cookie_id:[%s]", APLOG_MARK, cookie_id);
148 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
149 ERR(r, "%s:%d chxj_memcache_reset_cookie() failed: apr_memcache_set() cookie_id:[%s]", APLOG_MARK, cookie_id);
153 DBG(r, "end chxj_memcache_reset_cookie()");
159 chxj_memcache_get_cookie(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
165 DBG(r, "start chxj_memcache_get_cookie()");
168 if ((ret = apr_memcache_getp(mc, r->pool, cookie_id, &load_string, &len, 0)) != APR_SUCCESS) {
170 if (ret == APR_EAGAIN) {
173 ERR(r, "%s:%d chxj_memcache_get_cookie() failed: apr_memcache_get() cookie_id:[%s] ret:[%d:%s]", APLOG_MARK,
174 cookie_id, ret, apr_strerror(ret,errstr,255));
180 ret_value = apr_palloc(r->pool, len+1);
181 memset(ret_value, 0, len+1);
182 memcpy(ret_value, load_string, len);
184 DBG(r, "end chxj_memcache_get_cookie()");
190 chxj_memcache_delete_cookie(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
193 DBG(r, "start chxj_memcache_delete_cookie()");
196 if ((ret = apr_memcache_delete(mc, cookie_id, 0)) != APR_SUCCESS) {
197 if (ret == APR_EAGAIN) {
200 ERR(r, "%s:%d chxj_memcache_delete_cookie(): failed: apr_memcache_delete() cookie_id:[%s] ret:[%d]", APLOG_MARK, cookie_id, ret);
206 DBG(r, "end chxj_memcache_delete_cookie()");
213 chxj_save_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
215 DBG(r, "start chxj_save_cookie_memcache() cookie_id:[%s]", cookie_id);
216 if (! chxj_memcache_init(r, m)) {
217 ERR(r, "%s:%d end chxj_save_cookie_memcache(): Cannot create memcache server: cookie_id:[%s] store_string:[%s]", APLOG_MARK, cookie_id, store_string);
221 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
222 ERR(r, "%s:%d end chxj_save_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s] store_string:[%s]",
223 APLOG_MARK, m->memcache.host, m->memcache.port, cookie_id, store_string);
226 DBG(r, "stored DATA:[%s]", chxj_memcache_get_cookie(r, m, cookie_id));
227 DBG(r, "end chxj_save_cookie_memcache() cookie_id:[%s]", cookie_id);
233 chxj_update_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
235 DBG(r, "start chxj_update_cookie_memcache() cookie_id:[%s]", cookie_id);
236 if (! chxj_memcache_init(r, m)) {
237 ERR(r, "%s:%d end chxj_update_cookie_memcache(): Cannot create memcache server: cookie_id:[%s] store_string:[%s]",APLOG_MARK,cookie_id, store_string);
241 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
243 "%s:%d end chxj_update_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s] store_string:[%s]",
244 APLOG_MARK, m->memcache.host, m->memcache.port, cookie_id, store_string);
247 DBG(r, "end chxj_update_cookie_memcache() cookie_id:[%s]", cookie_id);
253 chxj_load_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
256 DBG(r, "start chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
258 if (! chxj_memcache_init(r, m)) {
259 ERR(r, "%s:%d end chxj_load_cookie_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK, cookie_id);
263 if (! (load_string = chxj_memcache_get_cookie(r, m, cookie_id))) {
264 ERR(r, "%s:%d end chxj_load_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
265 m->memcache.host, m->memcache.port, cookie_id);
268 DBG(r, "end chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
274 chxj_delete_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
276 DBG(r, "start chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
277 if (! chxj_memcache_init(r, m)) {
278 ERR(r, "%s:%d end chxj_delete_cookie_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK, cookie_id);
282 if (! chxj_memcache_delete_cookie(r, m, cookie_id)) {
283 ERR(r, "%s:%d end chxj_delete_cookie_memcache(): Cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
284 m->memcache.host, m->memcache.port, cookie_id);
287 DBG(r, "end chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
293 chxj_save_cookie_expire_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
295 DBG(r, "start chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
296 if (! chxj_memcache_init(r, m)) {
297 ERR(r, "%s:%d end chxj_save_cookie_expire_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK,cookie_id);
301 if (! chxj_memcache_reset_cookie(r, m, cookie_id)) {
302 ERR(r, "%s:%d end chxj_save_cookie_expire_memcache(): Cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
303 m->memcache.host, m->memcache.port, cookie_id);
306 DBG(r, "end chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
312 chxj_delete_cookie_expire_memcache(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
314 DBG(r, "start chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
316 DBG(r, "end chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
322 chxj_cookie_expire_gc_memcache(request_rec *r, mod_chxj_config *UNUSED(m))
324 DBG(r, "start chxj_cookie_expire_gc_memcache()");
326 DBG(r, "end chxj_cookie_expire_gc_memcache()");
332 chxj_cookie_lock_memcache(request_rec *r, mod_chxj_config *m)
336 apr_uint32_t timeout = (apr_uint32_t) ((m->cookie_timeout) ? m->cookie_timeout : DEFAULT_COOKIE_TIMEOUT);
337 apr_interval_time_t wait_time = MEMCACHE_WAIT_MICRO_SECOND;
338 DBG(r, "start chxj_cookie_lock_memcache()");
340 if (! chxj_memcache_init(r, m)) {
341 ERR(r, "%s:%d end chxj_cookie_lock_memcache(): Cannot create memcache server", APLOG_MARK);
345 apr_snprintf(baton, sizeof(baton)-1, "dummy");
347 apr_status_t rv = apr_memcache_add(mc, MEMCACHE_LOCK_KEY, baton, strlen(baton), timeout, 0);
348 if (APR_SUCCESS == rv) {
353 if (rv == APR_EAGAIN) {
357 if (retry_count >= MEMCACHE_LOCK_RETRY_COUNT) {
358 ERR(r, "%s:%d end chxj_cookie_lock_memcache(): retry over.",APLOG_MARK);
361 apr_sleep(wait_time);
364 DBG(r, "end chxj_cookie_lock_memcache()");
370 chxj_cookie_unlock_memcache(request_rec *r, mod_chxj_config *UNUSED(m))
373 DBG(r, "start chxj_cookie_unlock_memcache()");
375 ERR(r, "%s:%d end chxj_cookie_unlock_memcache(): runtime exception: programing failure.", APLOG_MARK);
380 if ((ret = apr_memcache_delete(mc, MEMCACHE_LOCK_KEY, 0)) != APR_SUCCESS) {
382 if (ret == APR_EAGAIN) {
385 ERR(r, "%s:%d end chxj_cookie_unlock_memcache(): failed: apr_memcache_delete() (lock data) ret:[%d:%s]", APLOG_MARK,ret, apr_strerror(ret, errstr, 255));
390 DBG(r, "end chxj_cookie_unlock_memcache()");