OSDN Git Service

* temp commit
[modchxj/mod_chxj.git] / src / chxj_memcache.c
1 /*
2  * Copyright (C) 2005-2008 Atsushi Konno All rights reserved.
3  * Copyright (C) 2005 QSDN,Inc. All rights reserved.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 #ifdef USE_MEMCACHE_COOKIE
18 #include "mod_chxj.h"
19 #include "chxj_cookie.h"
20 #include "chxj_url_encode.h"
21 #include "chxj_apply_convrule.h"
22 #include "chxj_str_util.h"
23
24 #include "ap_release.h"
25
26 #include "apu.h"
27 #include "apr_uuid.h"
28 #include "apr_md5.h"
29 #include "apr_base64.h"
30 #include "apr_uri.h"
31
32 #include <unistd.h>
33
34 /* for apr-memcache */
35 #include "apr_memcache.h"
36
37 #define MEMCACHE_MIN_CONNECTION (0)
38 #define MEMCACHE_SMAX_CONNECTION (1)
39 #define MEMCACHE_MAX_CONNECTION (1)
40 #define MEMCACHE_TTL_CONNECTION (600)
41
42 #define MEMCACHE_LOCK_KEY "chxj::lock"
43 #define MEMCACHE_WAIT_MICRO_SECOND (5000)
44 #define MEMCACHE_LOCK_RETRY_COUNT (100)
45
46
47 #define MEMCACHE_MAX_SERVER (10)
48 #define MEMCACHE_FLAGS (0)
49
50 #define DEFAULT_MEMCACHE_TIMEOUT (1000)
51 #define DEFAULT_DELETE_TIMEOUT (0)
52
53 #define DEFAULT_COOKIE_DB_NAME "chxj_cookie"
54 #define DEFAULT_COOKIE_EXPIRE_DB_NAME "chxj_cookie_expire"
55
56 /* The underlying apr_memcache system is thread safe. */
57 static apr_memcache_t* mc = NULL;
58
59 static apr_status_t
60 _memcache_cleanup(void *UNUSED(notused))
61 {
62   mc = NULL;
63   return APR_SUCCESS;
64 }
65
66 int
67 chxj_memcache_init(request_rec *r, mod_chxj_config *m)
68 {
69   apr_memcache_server_t* st;
70   DBG(r, "start chxj_memcache_init()");
71   if (! mc) {
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);
74       return CHXJ_FALSE;
75     }
76     apr_pool_cleanup_register(r->pool, (void *)NULL, _memcache_cleanup, _memcache_cleanup);
77   }
78   DBG(r, "end chxj_memcache_init()");
79   return CHXJ_TRUE;
80 }
81
82 int
83 chxj_memcache_and_memcache_server_create(request_rec *r, mod_chxj_config *m, apr_memcache_server_t **memcache_server, apr_memcache_t **memcache)
84 {
85   DBG(r, "start chxj_memcache_server_create()");
86   if (apr_memcache_server_create(r->pool, 
87                                  m->memcache.host,
88                                  m->memcache.port,
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);
95     return CHXJ_FALSE;
96   }
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);
100     return CHXJ_FALSE;
101   }
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);
105     return CHXJ_FALSE;
106   }
107   DBG(r, "end chxj_memcache_server_create()");
108
109   return CHXJ_TRUE;
110 }
111
112
113 int
114 chxj_memcache_set_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
115 {
116   apr_status_t ret;
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()");
119
120   do {
121     if ((ret = apr_memcache_set(mc, cookie_id, (char *)store_string, strlen(store_string), timeout, 0)) != APR_SUCCESS) {
122       if (ret == APR_EAGAIN) {
123         continue;
124       }
125       ERR(r, "%s:%d chxj_memcache_set_cookie() failed: apr_memcache_set() ret:[%d]", APLOG_MARK, ret);
126       return CHXJ_FALSE;
127     }
128   }
129   while(0);
130
131   DBG(r, "end chxj_memcache_set_cookie()");
132   return CHXJ_TRUE;
133 }
134
135
136 int
137 chxj_memcache_reset_cookie(request_rec *r, mod_chxj_config *m, const char *cookie_id)
138 {
139   char *store_string;
140   DBG(r, "start chxj_memcache_reset_cookie()");
141
142
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);
145     return CHXJ_FALSE;
146   }
147
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);
150     return CHXJ_FALSE;
151   }
152
153   DBG(r, "end chxj_memcache_reset_cookie()");
154   return CHXJ_TRUE;
155 }
156
157
158 char *
159 chxj_memcache_get_cookie(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
160 {
161   char *load_string;
162   char *ret_value;
163   apr_size_t len;
164   apr_status_t ret;
165   DBG(r, "start chxj_memcache_get_cookie()");
166
167   do {
168     if ((ret = apr_memcache_getp(mc, r->pool, cookie_id, &load_string, &len, 0)) != APR_SUCCESS) {
169       char errstr[255];
170       if (ret == APR_EAGAIN) {
171         continue;
172       }
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));
175       return NULL;
176     }
177   }
178   while(0);
179   
180   ret_value = apr_palloc(r->pool, len+1);
181   memset(ret_value, 0, len+1);
182   memcpy(ret_value, load_string, len);
183
184   DBG(r, "end chxj_memcache_get_cookie()");
185   return ret_value;
186 }
187
188
189 int
190 chxj_memcache_delete_cookie(request_rec *r, mod_chxj_config *UNUSED(m),  const char *cookie_id)
191 {
192   apr_status_t ret;
193   DBG(r, "start chxj_memcache_delete_cookie()");
194
195   do {
196     if ((ret = apr_memcache_delete(mc, cookie_id, 0)) != APR_SUCCESS) {
197       if (ret == APR_EAGAIN) {
198         continue;
199       }
200       ERR(r, "%s:%d chxj_memcache_delete_cookie(): failed: apr_memcache_delete() cookie_id:[%s] ret:[%d]", APLOG_MARK, cookie_id, ret);
201       return CHXJ_FALSE;
202     }
203   }
204   while(0);
205
206   DBG(r, "end chxj_memcache_delete_cookie()");
207   return CHXJ_TRUE;
208 }
209
210
211
212 int
213 chxj_save_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
214 {
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);
218     return CHXJ_FALSE;
219   }
220
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);
224     return CHXJ_FALSE;
225   }
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);
228   return CHXJ_TRUE;
229 }
230
231
232 int
233 chxj_update_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id, const char *store_string)
234 {
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);
238     return CHXJ_FALSE;
239   }
240
241   if (! chxj_memcache_set_cookie(r, m, cookie_id, store_string)) {
242     ERR(r, 
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);
245     return CHXJ_FALSE;
246   }
247   DBG(r, "end chxj_update_cookie_memcache() cookie_id:[%s]", cookie_id);
248   return CHXJ_TRUE;
249 }
250
251
252 char *
253 chxj_load_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
254 {
255   char *load_string;
256   DBG(r, "start chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
257
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);
260     return NULL;
261   }
262
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);
266     return NULL;
267   }
268   DBG(r, "end   chxj_load_cookie_memcache() cookie_id:[%s]", cookie_id);
269   return load_string;
270 }
271
272
273 int
274 chxj_delete_cookie_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
275 {
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);
279     return CHXJ_FALSE;
280   }
281
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);
285     return CHXJ_FALSE;
286   }
287   DBG(r, "end   chxj_delete_cookie_memcache() cookie_id:[%s]", cookie_id);
288   return CHXJ_TRUE;
289 }
290
291
292 int
293 chxj_save_cookie_expire_memcache(request_rec *r, mod_chxj_config *m, const char *cookie_id)
294 {
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);
298     return CHXJ_FALSE;
299   }
300
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);
304     return CHXJ_FALSE;
305   }
306   DBG(r, "end   chxj_save_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
307   return CHXJ_TRUE;
308 }
309
310
311 int
312 chxj_delete_cookie_expire_memcache(request_rec *r, mod_chxj_config *UNUSED(m), const char *cookie_id)
313 {
314   DBG(r, "start chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
315   /* PASS */
316   DBG(r, "end   chxj_delete_cookie_expire_memcache() cookie_id:[%s]", cookie_id);
317   return CHXJ_TRUE;
318 }
319
320
321 int
322 chxj_cookie_expire_gc_memcache(request_rec *r, mod_chxj_config *UNUSED(m))
323 {
324   DBG(r, "start chxj_cookie_expire_gc_memcache()");
325   /* PASS */
326   DBG(r, "end   chxj_cookie_expire_gc_memcache()");
327   return CHXJ_TRUE;
328 }
329
330
331 int
332 chxj_cookie_lock_memcache(request_rec *r, mod_chxj_config *m)
333 {
334   char baton[256];
335   int retry_count = 0;
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()");
339
340   if (! chxj_memcache_init(r, m)) {
341     ERR(r, "%s:%d end chxj_cookie_lock_memcache(): Cannot create memcache server", APLOG_MARK);
342     return CHXJ_FALSE;
343   }
344
345   apr_snprintf(baton, sizeof(baton)-1, "dummy");
346   while(1) {
347     apr_status_t rv = apr_memcache_add(mc, MEMCACHE_LOCK_KEY, baton, strlen(baton), timeout, 0);
348     if (APR_SUCCESS == rv) {
349       /* got lock */
350       DBG(r, "got lock");
351       break;
352     }
353     if (rv == APR_EAGAIN) {
354       continue;
355     }
356     retry_count++;
357     if (retry_count >= MEMCACHE_LOCK_RETRY_COUNT) {
358       ERR(r, "%s:%d end chxj_cookie_lock_memcache(): retry over.",APLOG_MARK);
359       return CHXJ_FALSE;
360     }
361     apr_sleep(wait_time);
362   }
363
364   DBG(r, "end chxj_cookie_lock_memcache()");
365   return CHXJ_TRUE;
366 }
367
368
369 int
370 chxj_cookie_unlock_memcache(request_rec *r, mod_chxj_config *UNUSED(m))
371 {
372   apr_status_t ret;
373   DBG(r, "start chxj_cookie_unlock_memcache()");
374   if (! mc) {
375     ERR(r, "%s:%d end chxj_cookie_unlock_memcache(): runtime exception: programing failure.", APLOG_MARK);
376     return CHXJ_FALSE;
377   }
378
379   while(1) {
380     if ((ret = apr_memcache_delete(mc, MEMCACHE_LOCK_KEY, 0)) != APR_SUCCESS) {
381       char errstr[255];
382       if (ret == APR_EAGAIN) {
383         continue;
384       }
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));
386       return CHXJ_FALSE;
387     }
388     break;
389   }
390   DBG(r, "end chxj_cookie_unlock_memcache()");
391   return CHXJ_TRUE;
392 }
393
394 #endif
395 /*
396  * vim:ts=2 et
397  */