Main Page | Class List | File List | Class Members | File Members

mycgisession.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2005 Christian Theil Have (christiantheilhave@gmail.com)
00003  *
00004  * This file is part of mycgisession.
00005  * 
00006  * mycgisession is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  * 
00011  * mycgisession is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  * 
00016  * You should have received a copy of the GNU General Public License
00017  * along with mycgisession; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #ifndef mycgisession_c
00023 #define mycgisession_c
00024 
00025 #include "mycgisession.h"
00026 
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 
00031 #define SESSION_TIMEOUT 600
00032 #define SESSION_TABLE   "cgi_session"
00033 
00034 #define ERROR 1;
00035 
00036 #define ENC_TYPE_NONE 0
00037 #define ENC_TYPE_BASE64 1
00038 
00039 #define MAX_TABLE_NAME 64
00040 
00041 static MYSQL *cgisession_mysql_conn = NULL;
00042 static char cgisession_table_name[MAX_TABLE_NAME];
00043 static int have_connection = 0;
00044 
00045 struct CGISESSION_struct {
00046     char *key;
00047     char *data;
00048     unsigned int size;
00049     unsigned int timeout;
00050     unsigned int timestamp;
00051     int encoding;
00052     int stored;
00053 };
00054 
00055 static struct CGISESSION_struct cs;
00056 
00057 /* static function, implemented below */
00058 static void cgisession_init();
00059 static int cgisession_database_init();
00060 static int cgisession_delete_expired();
00061 static int cgisession_update();
00062 static int cgisession_load_all();
00063 static char *cgisession_genkey();
00064 static char *cgisession_encode_data();
00065 static int cgisession_decode_data(char *encoded, long enc_size);
00066 
00067 /**************************************************************************\
00068  * Public interface functions                                             *
00069 \**************************************************************************/
00070 
00076 int
00077 cgisession_init_mysql_connection(char *host, char *username,
00078                                  char *password, char *database,
00079                                  unsigned int port)
00080 {
00081     cgisession_mysql_conn = mysql_init(NULL);
00082 
00083     if (NULL == mysql_real_connect(cgisession_mysql_conn,
00084                                    host, username, password, database,
00085                                    port, NULL, 0)) {
00086 #ifdef DEBUG1
00087         printf("mysql_real_connect failed: "
00088                "host: %s, user: %s, database: %s, password: %s\n",
00089                host, username, database, password);
00090 #endif
00091         return -ERROR;
00092     }
00093 
00094     cgisession_init();
00095 
00096     return cgisession_database_init();
00097 }
00098 
00103 int cgisession_have_mysql_connection(MYSQL * m)
00104 {
00105     if (!m)
00106         return -ERROR;
00107 
00108     cgisession_mysql_conn = m;
00109 
00110     have_connection = 1;
00111 
00112     cgisession_init();
00113 
00114     return cgisession_database_init();
00115 }
00116 
00127 int cgisession_load(char *key)
00128 {
00129     if (key) {
00130         if (0 != cgisession_update(key))
00131             return -ERROR;
00132         if (0 != cgisession_load_all())
00133             return -ERROR;
00134     } else {
00135         return -ERROR;
00136     }
00137 
00138     cs.stored = 1;
00139     return 0;
00140 }
00141 
00145 int cgisession_save()
00146 {
00147     char *query;
00148     char *encoded_data;
00149     int ret = 0;
00150 
00151     encoded_data = cgisession_encode_data();
00152 
00153     query = (char *) malloc(sizeof(encoded_data) + 1024);
00154 
00155     if (cs.stored) {
00156       if (encoded_data) {
00157         sprintf(query, "update %s set mtime=now(), "
00158                 "timeout='%d', data='%s', datasize='%d' where session_key='%s'",
00159                 cgisession_table_name, cs.timeout, encoded_data, cs.size, cs.key);
00160       } else {
00161         sprintf(query, "update %s set mtime=now(), "
00162                 "timeout='%d' where session_key='%s'",
00163                 cgisession_table_name, cs.timeout, cs.key);
00164       }
00165     } else {
00166       
00167       if (encoded_data) {
00168         sprintf(query,
00169                 "insert into %s (session_key, mtime, timeout, data, datasize) "
00170                 "values ('%s', now(), %d, '%s', '%d')", cgisession_table_name,
00171                 cs.key, cs.timeout, encoded_data, cs.size);
00172       } else {
00173         sprintf(query,
00174                 "insert into %s (session_key, mtime, timeout, data, datasize) "
00175                 "values ('%s', now(), %d, null, 0)", cgisession_table_name,
00176                 cs.key, cs.timeout);
00177       }
00178     }
00179 
00180     if ((ret = mysql_query(cgisession_mysql_conn, query))) {
00181 #ifdef DEBUG1
00182         printf("\nquery %s failed with return code %d\n", query, ret);
00183         return -ERROR;
00184 #endif
00185     }
00186 
00187     free(query);
00188     if (NULL!=encoded_data)
00189       free(encoded_data);
00190     return ret;
00191 }
00192 
00198 int cgisession_new()
00199 {
00200     cs.key = cgisession_genkey();
00201     if (!cs.key)
00202         return -ERROR;
00203     return 0;
00204 }
00205 
00206 void cgisession_free()
00207 {
00208   if (!have_connection)
00209     mysql_close(cgisession_mysql_conn);
00210 }
00211 
00212 
00216 int cgisession_set_data(void *data, unsigned int size)
00217 {
00218   if (cs.data)
00219    free(cs.data);
00220 
00221   cs.data = malloc(size);
00222   memcpy(cs.data, data, size);
00223   cs.size = size;
00224   return 0;
00225 }
00226 
00230 void *cgisession_get_data()
00231 {
00232     return cs.data;
00233 }
00234 
00238 char *cgisession_get_key()
00239 {
00240     return cs.key;
00241 }
00242 
00246 void cgisession_dump() {
00247   printf("\n**** cgisession dump ****\n");
00248   printf("key: %s\n", cs.key?cs.key:"null");
00249   printf("data: %s\n", cs.data?cs.data:"null");
00250   printf("size: %d\n", cs.size);
00251   printf("timeout: %d\n", cs.timeout);
00252   printf("encoding: %d\n", cs.encoding);
00253   printf("stored: %d\n", cs.stored);
00254   printf("**** dump ends ****\n");
00255 }
00256 
00257 /******************************************/
00259 /******************************************/
00260 
00264 int cgisession_option_encoding(int enc)
00265 {
00266     switch (enc) {
00267     case ENC_TYPE_NONE:
00268     case ENC_TYPE_BASE64:
00269         cs.encoding = enc;
00270         return 0;
00271     default:
00272         return -ERROR;
00273     }
00274 }
00275 
00279 int cgisession_option_timeout(unsigned int secs)
00280 {
00281     cs.encoding = secs;
00282     return 0;
00283 }
00284 
00288 int cgisession_option_table(char *table_name)
00289 {
00290     if (strlen(table_name) > MAX_TABLE_NAME)
00291         return -ERROR;
00292     strcpy(cgisession_table_name, table_name);
00293     return 0;
00294 }
00295 
00296 /**************************************************************************\
00297  * Private functions                                                      *
00298 \**************************************************************************/
00299 
00300 /*
00301  * initialize a the struct to the default values
00302  */
00303 static void cgisession_init()
00304 {
00305     cs.key = NULL;
00306     cs.data = NULL;
00307     cs.size = 0;
00308     cs.timeout = 0;
00309     cs.timestamp = 0;
00310     cs.encoding = ENC_TYPE_NONE;
00311     cs.stored = 0;              /* not yet stored */
00312     strcpy(cgisession_table_name, "cgi_sessions");
00313 }
00314 
00318 static int cgisession_database_init()
00319 {
00320     char query[1024];
00321     int ret = 0;
00322 
00323     sprintf(query, "create table if not exists %s "
00324             "(session_key varchar(20) primary key, "
00325             "mtime timestamp, timeout int, data blob, datasize int)",
00326             cgisession_table_name);
00327     if ((ret = mysql_query(cgisession_mysql_conn, query))) {
00328 #ifdef DEBUG1
00329         printf("query: %s failed with error code %d", query, ret);
00330 #endif
00331         return ret;
00332     }
00333 
00334     if ((ret = cgisession_delete_expired()))
00335         return ret;
00336 
00337     return ret;
00338 }
00339 
00343 static int cgisession_delete_expired()
00344 {
00345     char query[1024];
00346     int ret;
00347 
00348     sprintf(query, "delete from %s where mtime<'now()-%d'",
00349             cgisession_table_name, cs.timeout);
00350 
00351     ret = mysql_query(cgisession_mysql_conn, query);
00352 #ifdef DEBUG1
00353     if (ret)
00354         printf("query: %s failed with error code %d", query, ret);
00355 #endif
00356     return ret;
00357 }
00358 
00362 int cgisession_update(char *key)
00363 {
00364     char *new_session_key;
00365     char query[1024];
00366     MYSQL_RES *res;
00367     int ret;
00368 
00369     sprintf(query, "select * from %s where session_key='%s'",
00370             cgisession_table_name, key);
00371 
00372     if (0 != (ret = mysql_query(cgisession_mysql_conn, query))) {
00373 #ifdef DEBUG1
00374         printf("\nquery: %s failed with error code %d\n", query, ret);
00375 #endif
00376         return -ERROR;
00377     }
00378 
00379     if (NULL==(res = mysql_store_result(cgisession_mysql_conn))) {
00380 #ifdef DEBUG1
00381       printf("\nmysql_store_result failed\n");
00382       return -ERROR;
00383 #endif
00384     }
00385 
00386     if (1 != (ret = mysql_num_rows(res))) {
00387 #ifdef DEBUG1
00388       printf("\ninvalid number of rows: %d\n", ret);
00389 #endif
00390         return -ERROR;
00391     }
00392 
00393     /* At this point were are sure we have a valid session:
00394        We don't have to check if the session has
00395        expired since expired session have allready
00396        been deleted  */
00397 
00398     new_session_key = cgisession_genkey();
00399 
00400     sprintf(query, "update %s set session_key='%s' "
00401             "where session_key='%s'", cgisession_table_name,
00402             new_session_key, key);
00403 
00404     if (0!=(ret = mysql_query(cgisession_mysql_conn, query))) {
00405 #ifdef DEBUG1
00406         printf("query: %s failed with error code %d", query, ret);
00407 #endif
00408         return -ERROR;
00409     }
00410 
00411     if (cs.key != NULL)
00412       free(cs.key);
00413     cs.key = new_session_key;
00414 
00415     return 0;
00416 }
00417 
00418 static int cgisession_load_all()
00419 {
00420     char query[1024];
00421     char buf[1024];
00422     MYSQL_RES *res;
00423     MYSQL_ROW row;
00424     unsigned long *lengths;
00425     int ret;
00426 
00427     sprintf(query, "select * from %s where session_key='%s'",
00428             cgisession_table_name, cs.key);
00429 
00430     if (0!=(ret = mysql_query(cgisession_mysql_conn, query))) {
00431 #ifdef DEBUG1
00432         printf("query: %s failed with error code %d", query, ret);
00433 #endif
00434         return -ERROR;
00435     }
00436 
00437     if (NULL == (res = mysql_store_result(cgisession_mysql_conn)))
00438         return -ERROR;
00439 
00440     if (NULL == (row = mysql_fetch_row(res)))
00441         return -ERROR;
00442 
00443     lengths = mysql_fetch_lengths(res);
00444 
00445     /* copy timestamp */
00446     memcpy(buf, row[1], lengths[1]);
00447     buf[lengths[1]] = '\0';
00448     cs.timestamp = atoi(buf);
00449 
00450     /* copy timeout */
00451     memcpy(buf, row[2], lengths[2]);
00452     buf[lengths[2]] = '\0';
00453     cs.timeout = atoi(buf);
00454 
00455     if (0 != cgisession_decode_data(row[3], lengths[3]))
00456         return -ERROR;
00457 
00458     mysql_free_result(res);
00459 
00460     return 0;
00461 }
00462 
00467 static char *cgisession_genkey()
00468 {
00469     MYSQL_ROW row;
00470     MYSQL_RES *res;
00471     char *new_session = NULL;
00472     char *query = "select password(rand())";
00473     unsigned long *lengths;
00474     int ret;
00475 
00476     /* generate session id */
00477     
00478     if (0!=(ret = mysql_query(cgisession_mysql_conn, query))) {
00479 #ifdef DEBUG1
00480       printf("\nquery: %s failed with code %d\n", query, ret);
00481 #endif
00482         return NULL;
00483     }
00484 
00485     if (NULL==(res = mysql_store_result(cgisession_mysql_conn)))
00486         return NULL;
00487 
00488     if (NULL==(row = mysql_fetch_row(res)))
00489         return NULL;
00490 
00491     lengths = mysql_fetch_lengths(res);
00492 
00493     /* we only expect row with one field */
00494     new_session = (char *) malloc(lengths[0] + 1);
00495     if (new_session == NULL)
00496         return NULL;
00497 
00498     memcpy(new_session, row[0], lengths[0]);
00499 
00500     new_session[lengths[0]] = '\0';
00501 
00502     mysql_free_result(res);
00503 
00504     return new_session;
00505 }
00506 
00507 
00508 static char *cgisession_encode_data()
00509 {
00510    char *encoded = NULL;
00511    switch (cs.encoding) {
00512         case ENC_TYPE_NONE:
00513         if (NULL==cs.data)
00514                 return NULL;
00515         encoded = malloc(cs.size);
00516         memcpy(encoded, cs.data, cs.size);
00517         break;
00518    default:
00519 #ifdef DEBUG1
00520         printf("cgisession_encode_data: unknown encoding type!");
00521 #endif
00522         return NULL;
00523    }
00524 
00525    return encoded;
00526 }
00527 
00528 /*
00529  * operates directly on cs
00530  */
00531 static int cgisession_decode_data(char *encoded, long enc_size)
00532 {
00533 
00534 
00535     if (NULL != cs.data)
00536         free(cs.data);
00537 
00538     switch (cs.encoding) {
00539     case ENC_TYPE_NONE:
00540         cs.data = malloc(enc_size);
00541         memcpy(cs.data, encoded, enc_size);
00542         cs.data[enc_size]='\0';
00543         cs.size = enc_size;
00544         return 0;
00545     case ENC_TYPE_BASE64:
00546         exit(1000);
00547         return -ERROR;
00548     }
00549 
00550     return -ERROR;
00551 }
00552 
00553 #endif                          /* mycgisession_c */

Generated on Tue Feb 15 13:35:47 2005 for MyCGISession by  doxygen 1.3.9.1