The qDecoder Project

[svn] / releases / qDecoder-8.0.0 / src / qSession.c

Parent Directory Parent Directory Revision Log Revision Log


Revision 494 - Download Blame
Mon Jan 4 22:18:09 2010 UTC (8 months ago) by wolkykim
File size: 17527 byte(s)
Renaming RB-8.0 to qDecoder-8.0
    1 /************************************************************************
    2 qDecoder - Web Application Interface for C/C++    http://www.qDecoder.org
    3 
    4 Copyright (C) 2001 The qDecoder Project.
    5 Copyright (C) 1999,2000 Hongik Internet, Inc.
    6 Copyright (C) 1998 Nobreak Technologies, Inc.
    7 Copyright (C) 1996,1997 Seung-young Kim.
    8 
    9 This library is free software; you can redistribute it and/or
   10 modify it under the terms of the GNU Lesser General Public
   11 License as published by the Free Software Foundation; either
   12 version 2.1 of the License, or (at your option) any later version.
   13 
   14 This library is distributed in the hope that it will be useful,
   15 but WITHOUT ANY WARRANTY; without even the implied warranty of
   16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   17 Lesser General Public License for more details.
   18 
   19 You should have received a copy of the GNU Lesser General Public
   20 License along with this library; if not, write to the Free Software
   21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22 
   23 Copyright Disclaimer:
   24   Hongik Internet, Inc., hereby disclaims all copyright interest.
   25   President, Christopher Roh, 6 April 2000
   26 
   27   Nobreak Technologies, Inc., hereby disclaims all copyright interest.
   28   President, Yoon Cho, 6 April 2000
   29 
   30   Seung-young Kim, hereby disclaims all copyright interest.
   31   Author, Seung-young Kim, 6 April 2000
   32 ************************************************************************/
   33 
   34 #include "qDecoder.h"
   35 #include "qInternal.h"
   36 
   37 
   38 /**********************************************
   39 ** Define Paragraph
   40 **********************************************/
   41 
   42 #ifdef _WIN32
   43 #define	SESSION_DEFAULT_REPOSITORY	"C:\\Windows\\Temp"
   44 #else
   45 #define	SESSION_DEFAULT_REPOSITORY	"/tmp"
   46 #endif
   47 
   48 #define SESSION_ID			"QSESSIONID"
   49 #define SESSION_PREFIX			"qsession-"
   50 #define SESSION_STORAGE_EXTENSION	".properties"
   51 #define SESSION_TIMEOUT_EXTENSION	".timeout"
   52 #define SESSION_TIMETOCLEAR_FILENAME	"qsession-timetoclear"
   53 
   54 #define INTER_PREFIX			"_Q_"
   55 #define INTER_SESSIONID			INTER_PREFIX "SESSIONID"
   56 #define INTER_CREATED_GMT		INTER_PREFIX "CREATED-GMT"
   57 #define INTER_CREATED_SEC		INTER_PREFIX "CREATED"
   58 #define INTER_INTERVAL_SEC		INTER_PREFIX "INTERVAL"
   59 #define INTER_CONNECTIONS		INTER_PREFIX "CONNECTIONS"
   60 
   61 #define SESSION_DEFAULT_TIMEOUT_INTERVAL	(30 * 60)
   62 
   63 
   64 /**********************************************
   65 ** Internal Functions Definition
   66 **********************************************/
   67 
   68 static int _clearRepository(void);
   69 static int _isValidSession(char *filename);
   70 static time_t _updateTimeout(char *filename, time_t timeout_interval);
   71 
   72 
   73 /**********************************************
   74 ** Static Values Definition used only internal
   75 **********************************************/
   76 
   77 static int _session_started = 0;
   78 static int _session_new = 0;
   79 static int _session_modified = 0;
   80 static Q_Entry *_session_first_entry = NULL;
   81 
   82 static char _session_repository_path[1024];
   83 static char _session_storage_path[1024];
   84 static char _session_timeout_path[1024];
   85 static time_t _session_timeout_interval = (time_t)SESSION_DEFAULT_TIMEOUT_INTERVAL; /* seconds */
   86 
   87 
   88 /**********************************************
   89 ** Usage : qSession(Repository Path);
   90 ** Return: New session 1 else 0.
   91 ** Do    : Start Session.
   92 **
   93 ** ex) qSession(NULL);   // use default storage
   94 **     qSession("/tmp"); // use /tmp for session storage
   95 **********************************************/
   96 /* Initialize session data */
   97 int qSession(char *repository) {
   98   int new_session;
   99   char *sessionkey;
  100 
  101   /* check if session already started */
  102   if(_session_started) return _session_new;
  103   _session_first_entry = NULL;
  104   _session_started = 1;
  105   _session_modified = 0;
  106 
  107   /* check content flag */
  108   if(qGetContentFlag() == 1) qError("qSession(): must be called before qContentType() and any stream out.");
  109 
  110   /* check session status & get session id */
  111   sessionkey = qValue(SESSION_ID);
  112   if(sessionkey == NULL) {  /* new session */
  113     sessionkey = qUniqueID();
  114     new_session = 1;
  115   }
  116   else {
  117     new_session = 0;
  118   }
  119 
  120   /* make storage path for session */
  121   if (repository != NULL) strcpy(_session_repository_path, repository);
  122   else strcpy(_session_repository_path, SESSION_DEFAULT_REPOSITORY);
  123   sprintf(_session_storage_path, "%s/%s%s%s", _session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
  124   sprintf(_session_timeout_path, "%s/%s%s%s", _session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
  125 
  126   /* validate exist session */
  127   if(new_session == 0) {
  128     if(_isValidSession(_session_timeout_path) <= 0) { /* expired or not found */
  129       unlink(_session_storage_path);
  130       unlink(_session_timeout_path);
  131 
  132       /* remake storage path */
  133       sessionkey = qUniqueID();
  134       sprintf(_session_storage_path, "%s/%s%s%s", _session_repository_path, SESSION_PREFIX, sessionkey, SESSION_STORAGE_EXTENSION);
  135       sprintf(_session_timeout_path, "%s/%s%s%s", _session_repository_path, SESSION_PREFIX, sessionkey, SESSION_TIMEOUT_EXTENSION);
  136 
  137       /* set flag */
  138       new_session = 1;
  139     }
  140   }
  141 
  142   /* if new session, set session id */
  143   if(new_session == 1) {
  144     char created_gmt[32], created_sec[32];
  145     time_t nowtime;
  146 
  147     qCookieSet(SESSION_ID, sessionkey, 0, "/", NULL, NULL);
  148     qValueAdd(SESSION_ID, sessionkey); /* force to add session_in to query list */
  149 
  150     /* save session informations */
  151     nowtime = qGetGMTime(created_gmt, (time_t)0);
  152     sprintf(created_sec, "%ld", (long)nowtime);
  153 
  154     _session_first_entry = _EntryAdd(_session_first_entry, INTER_SESSIONID, sessionkey, 1);
  155     _EntryAdd(_session_first_entry, INTER_CREATED_GMT, created_gmt, 1);
  156     _EntryAdd(_session_first_entry, INTER_CREATED_SEC, created_sec, 1);
  157     _EntryAdd(_session_first_entry, INTER_CONNECTIONS, "1", 1);
  158 
  159     /* set timeout interval */
  160     qSessionSetTimeout(_session_timeout_interval);
  161   }
  162   /* else read session properties */
  163   else {
  164     int conns;
  165     char connstr[16];
  166 
  167     /* read exist session informations */
  168     _session_first_entry = _EntryLoad(_session_storage_path);
  169 
  170     /* update session informations */
  171     conns = qSessionValueInteger(INTER_CONNECTIONS);
  172     sprintf(connstr, "%d", ++conns);
  173     _EntryAdd(_session_first_entry, INTER_CONNECTIONS, connstr, 1);
  174 
  175     /* set timeout interval */
  176     qSessionSetTimeout((time_t)atol(qSessionValue(INTER_INTERVAL_SEC)));
  177   }
  178 
  179   /* set globals */
  180   _session_new = new_session;
  181   return _session_new;
  182 }
  183 
  184 /**********************************************
  185 ** Usage : qSessionAdd(name, value);
  186 ** Return: Stored String pointer of value.
  187 ** Do    : Add session value.
  188 **
  189 ** ex) qSessionAdd("name", "qDecoder");
  190 **     qSessionAdd("cginame", "%s", qCGIname());
  191 **********************************************/
  192 char *qSessionAdd(char *name, char *format, ...) {
  193   Q_Entry *new_entry;
  194   char value[1024];
  195   int status;
  196   va_list arglist;
  197 
  198   if(_session_started == 0) qError("qSessionAdd(): qSession() must be called before.");
  199   if(!strcmp(name, "")) qError("qSessionAdd(): can not add empty name.");
  200   if(!strncmp(name, INTER_PREFIX, strlen(INTER_PREFIX))) qError("qSessionAdd(): Name can not start with %s. It's reserved for internal uses.", INTER_PREFIX);
  201 
  202   va_start(arglist, format);
  203   status = vsprintf(value, format, arglist);
  204   if(strlen(value) + 1 > sizeof(value) || status == EOF) qError("qSessionAdd(): Message is too long or invalid.");
  205   va_end(arglist);
  206 
  207   new_entry = _EntryAdd(_session_first_entry, name, value, 1);
  208   if(!_session_first_entry) _session_first_entry = new_entry;
  209 
  210   /* set modified flag */
  211   _session_modified = 1;
  212 
  213   return qSessionValue(name);
  214 }
  215 
  216 /**********************************************
  217 ** Usage : qSessionAddInteger(name, integer);
  218 ** Return: Stored integer value.
  219 ** Do    : Add session value of integer type.
  220 **
  221 ** ex) qSessionAddInteger("count", 32);
  222 **********************************************/
  223 int qSessionAddInteger(char *name, int valueint) {
  224   char value[32];
  225 
  226   sprintf(value, "%d", valueint);
  227   qSessionAdd(name, value);
  228 
  229   return qSessionValueInteger(name);
  230 }
  231 
  232 /**********************************************
  233 ** Usage : qSessionUpdateInteger(name, plus integer);
  234 ** Return: Updated integer value.
  235 ** Do    : Update session value of integer type.
  236 **
  237 ** ex) qSessionUpdateInteger("count", -4);
  238 **********************************************/
  239 int qSessionUpdateInteger(char *name, int plusint) {
  240   qSessionAddInteger(name, qSessionValueInteger(name) + plusint);
  241 
  242   return qSessionValueInteger(name);
  243 }
  244 
  245 /**********************************************
  246 ** Usage : qSessionRemove(name);
  247 ** Do    : Remove session variable.
  248 **
  249 ** ex) qSessionRemove("name");
  250 **     qSessionRemove("%d.name", i);
  251 **********************************************/
  252 void qSessionRemove(char *format, ...) {
  253   char name[1024];
  254   int status;
  255   va_list arglist;
  256 
  257   va_start(arglist, format);
  258   status = vsprintf(name, format, arglist);
  259   if(strlen(name) + 1 > sizeof(name) || status == EOF) qError("qSessionRemove(): Message is too long or invalid.");
  260   va_end(arglist);
  261 
  262   if(!strcmp(name, "")) qError("qAddRemove(): can not remove empty name.");
  263   if(_session_started == 0) qError("qSessionRemove(): qSession() must be called before.");
  264   if(!strncmp(name, INTER_PREFIX, strlen(INTER_PREFIX))) qError("qSessionRemove(): can not remove reserved words.");
  265 
  266   _session_first_entry = _EntryRemove(_session_first_entry, name);
  267 
  268   /* set modified flag */
  269   _session_modified = 1;
  270 }
  271 
  272 /**********************************************
  273 ** Usage : qSessionValue(name);
  274 ** Return: Success pointer of value string, Fail NULL.
  275 ** Do    : Return session value.
  276 **
  277 ** ex) char *value;
  278 **     value = qSessionValue("name");
  279 **     value = qSessionValue("%d.name", i);
  280 **********************************************/
  281 char *qSessionValue(char *format, ...) {
  282   char name[1024], *value;
  283   int status;
  284   va_list arglist;
  285 
  286   if(_session_started == 0) qError("qSessionValue(): qSession() must be called before.");
  287 
  288   va_start(arglist, format);
  289   status = vsprintf(name, format, arglist);
  290   if(strlen(name) + 1 > sizeof(name) || status == EOF) qError("qSessionValue(): Message is too long or invalid.");
  291   va_end(arglist);
  292 
  293   value = _EntryValue(_session_first_entry, name);
  294 
  295   return value;
  296 }
  297 
  298 /**********************************************
  299 ** Usage : qSessionValueInteger(name);
  300 ** Return: Success integer of value, Fail 0.
  301 ** Do    : Return session value.
  302 **
  303 ** ex) int value;
  304 **     value = qSessionValueInteger("count");
  305 **********************************************/
  306 int qSessionValueInteger(char *format, ...) {
  307   char name[1024];
  308   int value;
  309   int status;
  310   va_list arglist;
  311 
  312   if(_session_started == 0) qError("qSessionValue(): qSession() must be called before.");
  313 
  314   va_start(arglist, format);
  315   status = vsprintf(name, format, arglist);
  316   if(strlen(name) + 1 > sizeof(name) || status == EOF) qError("qSessionValue(): Message is too long or invalid.");
  317   va_end(arglist);
  318 
  319   value = _EntryiValue(_session_first_entry, name);
  320 
  321   return value;
  322 }
  323 
  324 /**********************************************
  325 ** Usage : qSessionPrint();
  326 ** Do    : Print all session variables for debugging
  327 **********************************************/
  328 int qSessionPrint(void) {
  329   if(_session_started == 0) qError("qSessionPrint(): qSession() must be called before.");
  330   return _EntryPrint(_session_first_entry);
  331 }
  332 
  333 /**********************************************
  334 ** Usage : qSessionSave();
  335 ** Do    : Save session data immediately.
  336 **********************************************/
  337 void qSessionSave(void) {
  338   if(_session_started == 0 || _session_first_entry == NULL) return;
  339   if(_session_new == 1 && _session_modified == 0) return;
  340 
  341   if(_EntrySave(_session_first_entry, _session_storage_path) == 0) {
  342     qError("qSessionSave(): Can not access session repository(%s).", _session_storage_path);
  343   }
  344   if(_updateTimeout(_session_timeout_path, _session_timeout_interval) == 0) {
  345     qError("qSessionSave(): Can not access session repository(%s).", _session_timeout_path);
  346   }
  347 
  348   /* clear modified flag */
  349   _session_modified = 0;
  350 }
  351 
  352 /**********************************************
  353 ** Usage : qSessionFree();
  354 ** Do    : Save session data and deallocate memories.
  355 **********************************************/
  356 /* Free & Save */
  357 void qSessionFree(void) {
  358   if(_session_started == 0) return;
  359 
  360   qSessionSave();
  361   _clearRepository();
  362 
  363   if(_session_first_entry) _EntryFree(_session_first_entry);
  364   _session_first_entry = NULL;
  365   _session_started = 0;
  366   _session_new = 0;
  367   _session_modified = 0;
  368   _session_timeout_interval = (time_t)SESSION_DEFAULT_TIMEOUT_INTERVAL;
  369   strcpy(_session_repository_path, "");
  370   strcpy(_session_storage_path, "");
  371   strcpy(_session_timeout_path, "");
  372 }
  373 
  374 /**********************************************
  375 ** Usage : qSessionDestroy();
  376 ** Do    : Destroy current session and stored all session data
  377 **         will be removed.
  378 **********************************************/
  379 void qSessionDestroy(void) {
  380   if(_session_started == 0) qError("qSessionDestroy(): qSession() must be called before.");
  381 
  382   unlink(_session_storage_path);
  383   unlink(_session_timeout_path);
  384   if(_session_first_entry) _EntryFree(_session_first_entry);
  385   _session_first_entry = NULL;
  386 
  387   qSessionFree();
  388 
  389   if(qGetContentFlag() == 0) {
  390     qCookieRemove(SESSION_ID, "/", NULL, NULL);
  391   }
  392 }
  393 
  394 /**********************************************
  395 ** Usage : qSessionSetTimeout(interval seconds);
  396 ** Return: New expiration period.
  397 ** Do    : Change session expiration period.
  398 **
  399 ** ex) qSessionSetTimeout((time_t)3600);
  400 **********************************************/
  401 time_t qSessionSetTimeout(time_t seconds) {
  402   char interval_sec[32];
  403 
  404   if(_session_started == 0) qError("qSessionSetTimeout(): qSession() must be called before.");
  405   if(seconds <= (time_t)0) qError("qSessionSetTimeout(): can not set negative interval. Use qSessionDestory() instead.");
  406 
  407   _session_timeout_interval = seconds;
  408 
  409   /* save session informations */
  410   sprintf(interval_sec, "%ld", (long)_session_timeout_interval);
  411   _EntryAdd(_session_first_entry, INTER_INTERVAL_SEC, interval_sec, 1);
  412 
  413   return _session_timeout_interval;
  414 }
  415 
  416 /**********************************************
  417 ** Usage : qSessionGetID();
  418 ** Return: String pointer of session id.
  419 ** Do    : Return current session id.
  420 **
  421 ** ex) char *sessionid;
  422 **     sessionid = qSessionGetID();
  423 **********************************************/
  424 char *qSessionGetID(void) {
  425   if(_session_started == 0) qError("qSessionGetID(): qSession() must be called before.");
  426   return qSessionValue(INTER_SESSIONID);
  427 }
  428 
  429 /**********************************************
  430 ** Usage : qSessionGetCreated();
  431 ** Return: Value of time in seconds since 0 hours,
  432 **         0 minutes, 0 seconds, January 1, 1970.
  433 ** Do    : Return session created time in seconds.
  434 **
  435 ** ex) time_t created;
  436 **     struct tm *gmtime;
  437 **     created = qSessionGetCreated();
  438 **     gmtime = gmtime(&created);
  439 **********************************************/
  440 time_t qSessionGetCreated(void) {
  441   time_t created;
  442   char *tmp;
  443 
  444   if(_session_started == 0) qError("qSessionGetCreated(): qSession() must be called before.");
  445   tmp = qSessionValue(INTER_CREATED_SEC);
  446   created = (time_t)atol(tmp);
  447 
  448   return created;
  449 }
  450 
  451 /**********************************************
  452 ** Internal Functions
  453 **********************************************/
  454 
  455 static int _clearRepository(void) {
  456 #ifdef _WIN32
  457   return 0;
  458 #else
  459   DIR *dp;
  460   struct dirent *dirp;
  461   char timeoutpath[1024];
  462   int clearcnt;
  463 
  464   if(_session_started == 0) qError("_clearRepository(): qSession() must be called before.");
  465   sprintf(timeoutpath, "%s/%s", _session_repository_path, SESSION_TIMETOCLEAR_FILENAME);
  466 
  467   if(_isValidSession(timeoutpath) > 0) return 0; /* Valid */
  468 
  469   /* expired or not found, main routine start here */
  470   /* to prevent race condition, update time stamp first */
  471   if(_updateTimeout(timeoutpath, _session_timeout_interval) == 0) {
  472     qError("_clearRepository(): Can not access session repository(%s).", timeoutpath);
  473   }
  474 
  475   /* clear old session data */
  476   if((dp = opendir(_session_repository_path)) == NULL) qError("_clearRepository(): Can not access session repository(%s).", _session_repository_path);
  477 
  478   for (clearcnt = 0; (dirp = readdir(dp)) != NULL; ) {
  479     if(strstr(dirp->d_name, SESSION_PREFIX) && strstr(dirp->d_name, SESSION_TIMEOUT_EXTENSION)) {
  480       sprintf(timeoutpath, "%s/%s", _session_repository_path, dirp->d_name);
  481       if(_isValidSession(timeoutpath) <= 0) { /* expired */
  482         /* remove timeout */
  483         unlink(timeoutpath);
  484 
  485         /* remove properties */
  486         timeoutpath[strlen(timeoutpath) - strlen(SESSION_TIMEOUT_EXTENSION)] = '\0';
  487         strcat(timeoutpath, SESSION_STORAGE_EXTENSION);
  488         unlink(timeoutpath);
  489 
  490         clearcnt++;
  491       }
  492     }
  493   }
  494   closedir(dp);
  495 
  496   return clearcnt;
  497 #endif
  498 }
  499 
  500 /* session not found 0, session expired -1, session valid 1 */
  501 static int _isValidSession(char *filename) {
  502   FILE *fp;
  503   time_t timeout, timenow;
  504   double timediff;
  505 
  506   if((fp = qfopen(filename, "r")) == NULL) return 0;
  507   fscanf(fp, "%ld", &timeout);
  508   qfclose(fp);
  509 
  510   timenow = time(NULL);
  511   timediff = difftime(timeout, timenow); /* return timeout - timenow */
  512 
  513   if(timediff >= (double)0) return 1; /* valid */
  514   return -1; /* expired */
  515 }
  516 
  517 /* success > 0, write fail 0 */
  518 static time_t _updateTimeout(char *filename, time_t timeout_interval) {
  519   FILE *fp;
  520   time_t timeout;
  521 
  522   timeout = time(NULL);
  523   timeout += timeout_interval;
  524 
  525   if((fp = qfopen(filename, "w")) == NULL) return 0;
  526   fprintf(fp, "%ld\n", (long)timeout);
  527   qfclose(fp);
  528 
  529   return timeout;
  530 }
  531 

Home | About | Examples | Changes | Download | SVN Repository | Install | Reference