ses_mem.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  * $Id: ses_mem.c,v 1.28 2007/12/07 16:37:56 tat Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #include <stdlib.h>
00015 #include <time.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 #include <u/libu.h>
00019 #include <klone/session.h>
00020 #include <klone/request.h>
00021 #include <klone/context.h>
00022 #include <klone/response.h>
00023 #include <klone/vars.h>
00024 #include <klone/utils.h>
00025 #include <klone/atom.h>
00026 #include <klone/ses_prv.h>
00027 #include <klone/ppc.h>
00028 #include <klone/ppc_cmd.h>
00029 
00030 enum { SESSION_FILENAME_MAX_LENGTH = 256 };
00031 
00032 struct enc_ses_mem_s
00033 {
00034     time_t mtime;                                   /* modification time    */
00035     char filename[SESSION_FILENAME_MAX_LENGTH];     /* session filename     */
00036     size_t size;                                    /* data size            */
00037     char data[1];                                   /* data block           */
00038 };
00039 
00040 typedef struct enc_ses_mem_s enc_ses_mem_t;
00041 
00042 static int so_atom_delete_oldest(session_opt_t *so)
00043 {
00044     atom_t *atom, *oldest;
00045     size_t count, i;
00046 
00047     dbg_err_if (so == NULL);
00048 
00049     count = atoms_count(so->atoms);
00050     nop_err_if(count == 0);
00051 
00052     dbg_err_if(atoms_getn(so->atoms, 0, &oldest));
00053     for(i = 1; i < count; ++i)
00054     {
00055         dbg_err_if(atoms_getn(so->atoms, i, &atom));
00056 
00057         /* save if older */
00058         if(atom->arg <= oldest->arg)
00059             oldest = atom;
00060     }
00061 
00062     dbg_err_if(atoms_remove(so->atoms, oldest));
00063 
00064     return 0;
00065 err:
00066     return ~0;
00067 }
00068 
00069 static int session_delete_oldest(session_opt_t *so)
00070 {
00071     ppc_t *ppc;
00072 
00073     dbg_err_if (so == NULL);
00074 
00075     if(ctx->pipc)
00076     {   /* children context, delete parent atom */
00077         ppc = server_get_ppc(ctx->server);
00078         dbg_err_if(ppc == NULL);
00079 
00080         dbg_err_if(ppc_write(ppc, ctx->pipc, PPC_CMD_MSES_DELOLD, "", 1) < 0);
00081 
00082         /* delete it from the local copy of atom list */
00083         dbg_err_if(so_atom_delete_oldest(so));
00084     } else {
00085         /* parent context */
00086         dbg_err_if(so_atom_delete_oldest(so));
00087     }
00088 
00089     return 0;
00090 err:
00091     return ~0;
00092 }
00093 
00094 static int so_atom_remove(session_opt_t *so, const char *id)
00095 {
00096     atom_t *atom = NULL;
00097 
00098     dbg_err_if (so == NULL);
00099     dbg_err_if (id == NULL);
00100 
00101     /* find the atom bound to this session */
00102     if(atoms_get(so->atoms, id, &atom))
00103         return 0;
00104 
00105     /* remove it from the list */
00106     dbg_err_if(atoms_remove(so->atoms, atom));
00107 
00108     atom_free(atom);
00109 
00110     return 0;
00111 err:
00112     return ~0;
00113 }
00114 
00115 
00116 static int so_atom_add(session_opt_t *so, const char *id, char *buf, 
00117     size_t size, void *arg)
00118 {
00119     atom_t *atom = NULL, *old = NULL;
00120     size_t new_size, old_found = 0;
00121 
00122     dbg_err_if (so == NULL);
00123     dbg_err_if (id == NULL);
00124     dbg_err_if (buf == NULL);
00125 
00126     /* get the old atom associated to this id */
00127     if(!atoms_get(so->atoms, id, &old))
00128         old_found = 1;
00129 
00130     /* delete the oldest session if there are already max_count sessions */
00131     if(so->max_count && atoms_count(so->atoms) - old_found >= so->max_count)
00132         dbg_err_if(session_delete_oldest(so));
00133 
00134     /* delete the oldest session(s) if we are using already mem_limit bytes */
00135     if(so->mem_limit)
00136     {
00137         warn_err_ifm(size > so->mem_limit, 
00138             "session size is bigger the memory.limit, save aborted...");
00139         for(;;)
00140         {
00141             /* new_size = size of all atoms + size of the atom we're going to
00142                add - the size of the atom (if found) we're going to remove */
00143             new_size = atoms_size(so->atoms) + size - (old ? old->size : 0);
00144             if(atoms_count(so->atoms) && new_size > so->mem_limit)
00145                 dbg_err_if(session_delete_oldest(so));
00146             else
00147                 break;
00148         }
00149     }
00150 
00151     /* create a new atom */
00152     dbg_err_if(atom_create(id, buf, size, arg, &atom));
00153 
00154     /* add it to the list */
00155     dbg_err_if(atoms_add(so->atoms, atom));
00156 
00157     /* remove the old atom associated to this id */
00158     if(old)
00159     {
00160         dbg_err_if(atoms_remove(so->atoms, old));
00161         atom_free(old);
00162     }
00163 
00164     return 0;
00165 err:
00166     if(atom)
00167         atom_free(atom);
00168     return ~0;
00169 }
00170 
00171 
00172 /* [parent] remove a sessioin*/
00173 static int session_cmd_remove(ppc_t *ppc, int fd, unsigned char cmd, 
00174     char *data, size_t size, void *vso)
00175 {
00176     session_opt_t *so = vso;
00177 
00178     u_unused_args(ppc, fd, cmd, size);
00179 
00180     dbg_err_if (data == NULL);
00181     dbg_err_if (vso == NULL);
00182 
00183     dbg_err_if(so_atom_remove(so, data /* filename */));
00184 
00185     return 0;
00186 err:
00187     return ~0;
00188 }
00189 
00190 /* [parent] delete oldest session */
00191 static int session_cmd_delold(ppc_t *ppc, int fd, unsigned char cmd, 
00192     char *data, size_t size, void *vso)
00193 {
00194     session_opt_t *so = vso;
00195 
00196     u_unused_args(ppc, fd, cmd, data, size);
00197 
00198     dbg_err_if (vso == NULL);
00199 
00200     dbg_err_if (so_atom_delete_oldest(so));
00201 
00202     return 0;
00203 err:
00204     return ~0;
00205 }
00206 
00207 /* [parent] save a session */
00208 static int session_cmd_save(ppc_t *ppc, int fd, unsigned char cmd, char *data, 
00209     size_t size, void *vso)
00210 {
00211     session_opt_t *so = vso;
00212     enc_ses_mem_t *esm = (enc_ses_mem_t*)data;
00213 
00214     u_unused_args(ppc, fd, cmd, size);
00215 
00216     dbg_err_if (vso == NULL);
00217     dbg_err_if (data == NULL);
00218 
00219     dbg_err_if(so_atom_add(so, esm->filename, esm->data, esm->size, 
00220         (void*)esm->mtime));
00221 
00222     return 0;
00223 err:
00224     return ~0;
00225 }
00226 
00227 /* [parent] get session data */
00228 static int session_cmd_get(ppc_t *ppc, int fd, unsigned char cmd, char *data, 
00229     size_t size, void *vso)
00230 {
00231     enum { BUFSZ = 4096 };
00232     session_opt_t *so = vso;
00233     enc_ses_mem_t *esm = NULL;
00234     atom_t *atom = NULL;
00235     char buf[BUFSZ];
00236     size_t esm_size;
00237 
00238     u_unused_args(cmd, size);
00239 
00240     dbg_err_if (ppc == NULL);
00241     dbg_err_if (vso == NULL);
00242     dbg_err_if (data == NULL);
00243     dbg_err_if (strlen(data) > SESSION_FILENAME_MAX_LENGTH);
00244 
00245     /* find the atom whose name is stored into 'data' buffer */
00246     nop_err_if(atoms_get(so->atoms, data, &atom));
00247 
00248     /* if the buffer on the stack is big enough use it, otherwise alloc a 
00249        bigger one on the heap */
00250     if((esm_size = sizeof(enc_ses_mem_t) + atom->size) > BUFSZ)
00251     {
00252         esm = u_malloc(1 + esm_size);
00253         dbg_err_if(esm == NULL);
00254     } else
00255         esm = (enc_ses_mem_t*)buf;
00256         
00257     /* fill the enc_ses_mem_t struct */
00258     esm->mtime = (time_t)atom->arg;
00259     u_strlcpy(esm->filename, data, sizeof esm->filename);
00260     esm->size = atom->size;
00261     memcpy(esm->data, atom->data, atom->size);
00262 
00263     dbg_err_if(ppc_write(ppc, fd, PPC_CMD_RESPONSE_OK, (char*)esm,
00264         esm_size) <= 0);
00265 
00266     if(esm && esm != (void*)buf)
00267         U_FREE(esm);
00268 
00269     return 0;
00270 err:
00271     if(ppc)
00272         ppc_write(ppc, fd, PPC_CMD_RESPONSE_ERROR, (char *)"", 1);
00273     if(esm && esm != (void *)buf)
00274         U_FREE(esm);
00275     return ~0;
00276 }
00277 
00278 /* add an atom to the list of global atoms */
00279 static int session_mem_add(session_opt_t *so, const char *filename, char *buf, 
00280     size_t size, time_t mtime)
00281 {
00282     atom_t *atom = NULL;
00283     enc_ses_mem_t *esm = NULL;
00284     ppc_t *ppc;
00285     size_t esize;
00286 
00287     dbg_err_if (so == NULL);
00288     dbg_err_if (filename == NULL);
00289     dbg_err_if (buf == NULL);
00290 
00291     if(ctx->pipc)
00292     {   /* children context */
00293         ppc = server_get_ppc(ctx->server);
00294         dbg_err_if(ppc == NULL);
00295 
00296         /* build the encoded parameters structure */
00297         esize = size + sizeof(enc_ses_mem_t);
00298         esm = (enc_ses_mem_t*)u_malloc(esize);
00299         dbg_err_if(esm == NULL);
00300 
00301         /* fill esm fields */
00302         esm->mtime = time(0);
00303         esm->size = size;
00304         dbg_err_if(strlen(filename) > SESSION_FILENAME_MAX_LENGTH); 
00305         u_strlcpy(esm->filename, filename, sizeof esm->filename);
00306         memcpy(esm->data, buf, size);
00307 
00308         /* send the command request */
00309         dbg_err_if(ppc_write(ppc, ctx->pipc, PPC_CMD_MSES_SAVE, 
00310             (char*)esm, esize) < 0);
00311 
00312         U_FREE(esm);
00313 
00314         /* add it to the local copy of atom list */
00315         dbg_err_if(so_atom_add(so, filename, buf, size, (void*)mtime));
00316 
00317     } else {
00318         /* parent context */
00319         dbg_err_if(so_atom_add(so, filename, buf, size, (void*)mtime));
00320     }
00321 
00322     return 0;
00323 err:
00324     U_FREE(esm);
00325     if(atom)
00326         atom_free(atom);
00327     return ~0;
00328 }
00329 
00330 
00331 static int session_mem_save(session_t *ss)
00332 {
00333     char *buf = NULL;
00334     size_t sz;
00335 
00336     dbg_err_if (ss == NULL);
00337     
00338     /* save the session data to freshly alloc'd buf of size sz */
00339     dbg_err_if(session_prv_save_to_buf(ss, &buf, &sz));
00340 
00341     /* add the session to the in-memory session list */
00342     dbg_err_if(session_mem_add(ss->so, ss->filename, buf, sz, time(0)));
00343 
00344     U_FREE(buf);
00345 
00346     return 0;
00347 err:
00348     U_FREE(buf);
00349     return ~0;
00350 }
00351 
00352 static int session_mem_load(session_t *ss)
00353 {
00354     enum { BUFSZ = 4096 };
00355     atom_t *atom;
00356     char buf[BUFSZ];
00357     size_t size;
00358     enc_ses_mem_t *esm;
00359     ppc_t *ppc;
00360     unsigned char cmd;
00361 
00362     dbg_err_if (ss == NULL);
00363     nop_err_if (ss->filename == NULL || strlen(ss->filename) == 0);
00364 
00365     /* in fork and iterative model we can get the session from the current
00366        address space, in prefork we must ask the parent for a fresh copy of 
00367        the session */
00368     if(ctx->backend && ctx->backend->model == SERVER_MODEL_PREFORK)
00369     {   /* get the session data through ppc */
00370         ppc = server_get_ppc(ctx->server);
00371         dbg_err_if(ppc == NULL);
00372 
00373         /* send a get request */
00374         dbg_err_if(ppc_write(ppc, ctx->pipc, PPC_CMD_MSES_GET, ss->filename, 
00375             strlen(ss->filename) + 1) < 0);
00376 
00377         /* get the response from the parent */
00378         dbg_err_if((size = ppc_read(ppc, ctx->pipc, &cmd, buf, BUFSZ)) <= 0);
00379 
00380         nop_err_if(cmd != PPC_CMD_RESPONSE_OK);
00381 
00382         /* load session from esm */
00383         esm = (enc_ses_mem_t*)buf;
00384         ss->mtime = esm->mtime;
00385         dbg_err_if(session_prv_load_from_buf(ss, esm->data, esm->size));
00386 
00387     } else {
00388         /* find the file into the atom list */
00389         if(atoms_get(ss->so->atoms, ss->filename, &atom))
00390             return ~0; /* not found */
00391 
00392         /* copy stored mtime */
00393         ss->mtime = (time_t)atom->arg;
00394 
00395         /* load session from atom->data */
00396         dbg_err_if(session_prv_load_from_buf(ss, atom->data, atom->size));
00397     }
00398 
00399     return 0;
00400 err:
00401     return ~0;
00402 }
00403 
00404 static int session_mem_remove(session_t *ss)
00405 {
00406     ppc_t *ppc;
00407 
00408     dbg_err_if (ss == NULL);
00409     
00410     if(ctx->pipc)
00411     {   /* children context */
00412         ppc = server_get_ppc(ctx->server);
00413         dbg_err_if(ppc == NULL);
00414 
00415         dbg_err_if(ppc_write(ppc, ctx->pipc, PPC_CMD_MSES_REMOVE, ss->filename, 
00416             strlen(ss->filename) + 1) < 0);
00417 
00418         /* remove the session-atom from the (local copy) atom list */
00419         dbg_err_if(so_atom_remove(ss->so, ss->filename));
00420     } else {
00421         /* parent context */
00422         dbg_err_if(so_atom_remove(ss->so, ss->filename));
00423     }
00424 
00425     return 0;
00426 err:
00427     return ~0;
00428 }
00429 
00430 static int session_mem_term(session_t *ss)
00431 {
00432     /* nothing to do */
00433     u_unused_args(ss);
00434     return 0;
00435 }
00436 
00437 int session_mem_create(session_opt_t *so, request_t *rq, response_t *rs, 
00438         session_t **pss)
00439 {
00440     session_t *ss = NULL;
00441 
00442     dbg_err_if (so == NULL);
00443     dbg_err_if (rq == NULL);
00444     dbg_err_if (rs == NULL);
00445     dbg_err_if (pss == NULL);
00446 
00447     ss = u_zalloc(sizeof(session_t));
00448     dbg_err_if(ss == NULL);
00449 
00450     ss->load = session_mem_load;
00451     ss->save = session_mem_save;
00452     ss->remove = session_mem_remove;
00453     ss->term = session_mem_term;
00454     ss->mtime = time(0);
00455     ss->so = so;
00456 
00457     dbg_err_if(session_prv_init(ss, rq, rs));
00458 
00459     *pss = ss;
00460 
00461     return 0;
00462 err:
00463     if(ss)
00464         session_free(ss);
00465     return ~0;
00466 }
00467 
00468 /* this function will be called once by the server during startup */
00469 int session_mem_module_init(u_config_t *config, session_opt_t *so)
00470 {
00471     ppc_t *ppc;
00472     u_config_t *c;
00473     const char *v;
00474 
00475     /* config may be NULL */
00476     dbg_err_if (so == NULL);
00477 
00478     /* defaults */
00479     so->max_count = 0;  /* no limits */
00480     so->mem_limit = 0;  /* no limits */
00481 
00482     if(config && u_config_get_subkey(config, "memory", &c) == 0)
00483     {
00484         if((v = u_config_get_subkey_value(c, "max_count")) != NULL)
00485             so->max_count = atoi(v);
00486 
00487         if((v = u_config_get_subkey_value(c, "limit")) != NULL)
00488             so->mem_limit = atoi(v);
00489     }
00490 
00491     /* setup ppc parent <-> child channel */
00492     ppc = server_get_ppc(ctx->server);
00493     dbg_err_if(ppc == NULL);
00494 
00495     /* create an atom list to store in-memory session data */
00496     dbg_err_if(atoms_create(&so->atoms));
00497 
00498     /* register PPC commands callbacks */
00499     dbg_err_if(ppc_register(ppc, PPC_CMD_MSES_SAVE, session_cmd_save, so));
00500     dbg_err_if(ppc_register(ppc, PPC_CMD_MSES_GET, session_cmd_get, so));
00501     dbg_err_if(ppc_register(ppc, PPC_CMD_MSES_DELOLD, session_cmd_delold, so));
00502     dbg_err_if(ppc_register(ppc, PPC_CMD_MSES_REMOVE, session_cmd_remove, so));
00503 
00504     return 0;
00505 err:
00506     return ~0;
00507 }
00508 

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved