2 * Copyright (C) 2005-2009 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"
35 #include <libmemcached/memcached.h>
37 #define MEMCACHE_MIN_CONNECTION (0)
38 #define MEMCACHE_SMAX_CONNECTION (1)
39 #define MEMCACHE_MAX_CONNECTION (1)
40 #define MEMCACHE_CONNECTION_TIMEOUT (60)
41 #define MEMCACHE_POLL_TIMEOUT (60)
42 #define MEMCACHE_RETRY_TIMEOUT (60)
44 #define MEMCACHE_LOCK_KEY "chxj::lock"
45 #define MEMCACHE_WAIT_MICRO_SECOND (5000)
46 #define MEMCACHE_LOCK_RETRY_COUNT (100)
49 #define MEMCACHE_MAX_SERVER (10)
50 #define MEMCACHE_FLAGS (0)
52 #define DEFAULT_MEMCACHE_TIMEOUT (1000)
53 #define DEFAULT_DELETE_TIMEOUT (0)
55 #define DEFAULT_COOKIE_DB_NAME "chxj_cookie"
56 #define DEFAULT_COOKIE_EXPIRE_DB_NAME "chxj_cookie_expire"
58 /* The underlying memcache system is thread safe. */
59 static memcached_st *memc = NULL;
60 static memcached_server_st *servers = NULL;
63 _memcache_cleanup(void *UNUSED(unused))
66 memcached_server_list_free(servers);
77 chxj_memcache_init(request_rec *r, mod_chxj_config *m)
79 DBG(r, "start chxj_memcache_init()");
81 if (!chxj_memcache_and_memcache_server_create(r, m)) {
82 ERR(r, "%s:%d end chxj_memcache_init() failed: chxj_memcache_and_memcache_server_create()", APLOG_MARK);
85 apr_pool_cleanup_register(r->pool, NULL, _memcache_cleanup, _memcache_cleanup);
87 DBG(r, "end chxj_memcache_init()");
92 chxj_memcache_and_memcache_server_create(request_rec *r, mod_chxj_config *m)
95 DBG(r, "start chxj_memcache_server_create()");
97 memc = memcached_create(NULL);
99 ERR(r, "%s:%d end chxj_memcache_server_create(): failed allocation of memcached_st.", APLOG_MARK);
102 servers = memcached_server_list_append(NULL, m->memcache.host, m->memcache.port, &rc);
103 if (servers == NULL || rc != MEMCACHED_SUCCESS) {
104 ERR(r, "%s:%d end chxj_memcache_server_create(): host:[%s] port:[%d]: %s", APLOG_MARK, m->memcache.host, m->memcache.port, memcached_strerror(memc, rc));
107 rc = memcached_server_push(memc, servers);
108 if (rc != MEMCACHED_SUCCESS) {
109 ERR(r, "%s:%d end chxj_memcache_server_create(): host:[%s] port:[%d]: %s\n", APLOG_MARK, m->memcache.host, m->memcache.port, memcached_strerror(memc, rc));
113 rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_POLL_TIMEOUT, (uint64_t)MEMCACHE_POLL_TIMEOUT);
114 if (rc != MEMCACHED_SUCCESS) {
115 ERR(r, "%s:%d end chxj_memcache_server_create(): memcached_behavior_set(MEMCACHED_BEHAVIOR_POLL_TIMEOUT): %s", APLOG_MARK, memcached_strerror(memc, rc));
118 rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, (uint64_t)MEMCACHE_CONNECTION_TIMEOUT);
119 if (rc != MEMCACHED_SUCCESS) {
120 ERR(r, "%s:%d end chxj_memcache_server_create(): memcached_behavior_set(MEMCACHED_BEHAVIOR_CONNECTION_TIMEOUT): %s", APLOG_MARK, memcached_strerror(memc, rc));
123 rc = memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_RETRY_TIMEOUT, (uint64_t)MEMCACHE_RETRY_TIMEOUT);
124 if (rc != MEMCACHED_SUCCESS) {
125 ERR(r, "%s:%d end chxj_memcache_server_create(): memcached_behavior_set(MEMCACHED_BEHAVIOR_RETRY_TIMEOUT): %s", APLOG_MARK, memcached_strerror(memc, rc));
129 DBG(r, "end chxj_memcache_server_create()");
135 chxj_memcache_set_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
138 time_t timeout = (time_t) ((m->cookie_timeout) ? m->cookie_timeout : DEFAULT_COOKIE_TIMEOUT);
139 DBG(r, "start chxj_memcache_set_cookie()");
141 rc= memcached_set(memc, (char *)cookie_id, strlen(cookie_id),
142 (char *)store_string, strlen(store_string),
143 (time_t)timeout, (uint32_t)0);
144 if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_BUFFERED) {
145 ERR(r, "%s:%d end chxj_memcache_set_cookie(): failed memcache_set(): %s", APLOG_MARK, memcached_strerror(memc, rc));
149 DBG(r, "end chxj_memcache_set_cookie()");
155 chxj_memcache_reset_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id)
158 DBG(r, "start chxj_memcache_reset_cookie()");
160 if (! (store_string = chxj_memcache_get_cookie(r, m, cookie_id))) {
161 ERR(r, "%s:%d end chxj_memcache_reset_cookie() failed: chxj_memcache_get_cookie() cookie_id:[%s]", APLOG_MARK, cookie_id);
165 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
166 ERR(r, "%s:%d end chxj_memcache_reset_cookie() failed: chxj_memcache_set_cookie() cookie_id:[%s]", APLOG_MARK, cookie_id);
170 DBG(r, "end chxj_memcache_reset_cookie()");
176 chxj_memcache_get_cookie(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
184 DBG(r, "start chxj_memcache_get_cookie()");
186 load_string = memcached_get(memc, (char *)cookie_id, strlen(cookie_id), &value_length, &flags, &rc);
187 if (rc != MEMCACHED_SUCCESS) {
188 ERR(r, "%s:%d end chxj_memcache_get_cookie(): failed memcached_get(): %s", APLOG_MARK, memcached_strerror(memc, rc));
191 ret = apr_pstrdup(r->pool, load_string);
194 DBG(r, "end chxj_memcache_get_cookie()");
200 chxj_memcache_delete_cookie(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
204 DBG(r, "start chxj_memcache_delete_cookie()");
206 rc = memcached_delete(memc, (char *)cookie_id, strlen(cookie_id), (time_t)0);
207 if (rc != MEMCACHED_SUCCESS && rc == MEMCACHED_BUFFERED) {
208 ERR(r,"%s:%d end chxj_memcache_delete_cookie(): failed memcached_delete(): %s", APLOG_MARK, memcached_strerror(memc, rc));
212 DBG(r, "end chxj_memcache_delete_cookie()");
219 chxj_save_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
221 DBG(r, "start chxj_save_cookie_memcache() cookie_id:[%s]", cookie_id);
223 if (! chxj_memcache_init(r, m)) {
224 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);
228 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
229 ERR(r, "%s:%d end chxj_save_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s] store_string:[%s]",
230 APLOG_MARK, m->memcache.host, m->memcache.port, cookie_id, store_string);
234 DBG(r, "stored DATA:[%s]", chxj_memcache_get_cookie(r, m, cookie_id));
235 DBG(r, "end chxj_save_cookie_memcache() cookie_id:[%s]", cookie_id);
241 chxj_update_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
243 DBG(r, "start chxj_update_cookie_memcache() cookie_id:[%s]", cookie_id);
244 if (! chxj_memcache_init(r, m)) {
245 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);
249 if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
251 "%s:%d end chxj_update_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s] store_string:[%s]",
252 APLOG_MARK, m->memcache.host, m->memcache.port, cookie_id, store_string);
255 DBG(r, "end chxj_update_cookie_memcache() cookie_id:[%s]", cookie_id);
261 chxj_load_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
264 DBG(r, "start chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
266 if (! chxj_memcache_init(r, m)) {
267 ERR(r, "%s:%d end chxj_load_cookie_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK, cookie_id);
271 if (! (load_string = chxj_memcache_get_cookie(r, m, cookie_id))) {
272 ERR(r, "%s:%d end chxj_load_cookie_memcache(): cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
273 m->memcache.host, m->memcache.port, cookie_id);
276 DBG(r, "end chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
282 chxj_delete_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
284 DBG(r, "start chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
285 if (! chxj_memcache_init(r, m)) {
286 ERR(r, "%s:%d end chxj_delete_cookie_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK, cookie_id);
290 if (! chxj_memcache_delete_cookie(r, m, cookie_id)) {
291 ERR(r, "%s:%d end chxj_delete_cookie_memcache(): Cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
292 m->memcache.host, m->memcache.port, cookie_id);
295 DBG(r, "end chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
301 chxj_save_cookie_expire_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
303 DBG(r, "start chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
304 if (! chxj_memcache_init(r, m)) {
305 ERR(r, "%s:%d end chxj_save_cookie_expire_memcache(): Cannot create memcache server: cookie_id:[%s]",APLOG_MARK,cookie_id);
309 if (! chxj_memcache_reset_cookie(r, m, cookie_id)) {
310 ERR(r, "%s:%d end chxj_save_cookie_expire_memcache(): Cannot store to memcache host:[%s] port:[%d] cookie_id:[%s]", APLOG_MARK,
311 m->memcache.host, m->memcache.port, cookie_id);
314 DBG(r, "end chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
320 chxj_delete_cookie_expire_memcache(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
322 DBG(r, "start chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
324 DBG(r, "end chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
330 chxj_cookie_expire_gc_memcache(request_rec *r, mod_chxj_config *UNUSED(m))
332 DBG(r, "start chxj_cookie_expire_gc_memcache()");
334 DBG(r, "end chxj_cookie_expire_gc_memcache()");
340 chxj_cookie_lock_memcache(request_rec *r, mod_chxj_config *m)
344 apr_uint32_t timeout = (apr_uint32_t) ((m->cookie_timeout) ? m->cookie_timeout : DEFAULT_COOKIE_TIMEOUT);
345 apr_interval_time_t wait_time = MEMCACHE_WAIT_MICRO_SECOND;
347 DBG(r, "start chxj_cookie_lock_memcache()");
349 if (! chxj_memcache_init(r, m)) {
350 ERR(r, "%s:%d end chxj_cookie_lock_memcache(): Cannot create memcache server", APLOG_MARK);
354 apr_snprintf(baton, sizeof(baton)-1, "dummy");
357 rc = memcached_add(memc, MEMCACHE_LOCK_KEY, sizeof(MEMCACHE_LOCK_KEY)-1, baton, strlen(baton), (time_t)timeout, (uint32_t)0);
358 if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_STORED && rc != MEMCACHED_NOTSTORED) {
359 ERR(r, "%s:%d end chxj_cookie_lock_memcache(): failed memcached_add(): %s\n", APLOG_MARK, memcached_strerror(memc, rc));
362 if (rc == MEMCACHED_SUCCESS || rc == MEMCACHED_STORED) {
368 if (retry_count >= MEMCACHE_LOCK_RETRY_COUNT) {
369 ERR(r, "%s:%d end chxj_cookie_lock_memcache(): retry over.",APLOG_MARK);
372 apr_sleep(wait_time);
375 DBG(r, "end chxj_cookie_lock_memcache()");
381 chxj_cookie_unlock_memcache(request_rec *r, mod_chxj_config *m)
383 DBG(r, "start chxj_cookie_unlock_memcache()");
385 ERR(r, "%s:%d end chxj_cookie_unlock_memcache(): runtime exception: programing failure.", APLOG_MARK);
389 if (! chxj_memcache_delete_cookie(r, m, MEMCACHE_LOCK_KEY)) {
390 ERR(r, "%s:%d end chxj_cookie_unlock_memcache(): failed: chxj_memcache_delete_cookie() (lock data)", APLOG_MARK);
393 DBG(r, "end chxj_cookie_unlock_memcache()");