From 76d164b80c99cfc9ec73643cce21fa3255de5982 Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 16 Sep 2013 15:04:06 +0100 Subject: [PATCH] make sessions start on any request and clean them when they have timed out. --- include/application/application.h | 31 +++-- include/http/worker.h | 3 + include/session.h | 9 +- src/Makefile.am | 2 +- src/application/adapter/http/update.c | 160 +++++++++++++++----------- src/application/application.c | 25 +++- src/application/login.c | 33 +++++- src/application/session_get.c | 5 +- src/application/session_start.c | 12 +- src/application/session_stop.c | 6 +- src/application/session_update.c | 20 ++-- src/http/Makefile.am | 3 +- src/http/response/session.c | 7 +- src/http/worker.c | 7 ++ src/http/worker/add_computed_header.c | 47 ++++++++ src/http/worker/process.c | 2 + src/session/session.c | 20 ++-- src/taskrambler.c | 15 ++- src/uuid.c | 18 +++ 19 files changed, 294 insertions(+), 131 deletions(-) create mode 100644 src/http/worker/add_computed_header.c create mode 100644 src/uuid.c diff --git a/include/application/application.h b/include/application/application.h index 01c51dc..e9113c4 100644 --- a/include/application/application.h +++ b/include/application/application.h @@ -27,8 +27,11 @@ #include "class.h" #include "session.h" -#include "hash.h" +#include "queue.h" #include "auth/credential.h" +#include "storage.h" +#include "session.h" + struct randval { time_t timestamp; @@ -36,18 +39,24 @@ struct randval { }; CLASS(Application) { - Hash active_sessions; - void * auth; - struct randval * val; + // should be a list and not a queue but currently queue is + // the closest I have. + Queue active_sessions; + + void ** auth; + size_t nauth; + struct randval * val; + + Storage users; }; -// this should return a user account....now it only return success or failure. -int applicationLogin(Application, Credential); -unsigned long applicationSessionStart(Application, const char *, size_t); -void applicationSessionStop(Application, unsigned long); -void applicationSessionUpdate( - Application, unsigned long, const char *, size_t); -Session applicationSessionGet(Application, unsigned long); +int applicationLogin(Application, Credential, Session); + +Session applicationSessionStart(Application); +Session applicationSessionGet(Application, const char *); +void applicationSessionStop(Application, const char *); +void applicationSessionUpdate( + Application, const char *, const char *, size_t); #endif // __HTTP_HEADER_H__ diff --git a/include/http/worker.h b/include/http/worker.h index af935e6..00414a2 100644 --- a/include/http/worker.h +++ b/include/http/worker.h @@ -36,6 +36,7 @@ #include "http/request.h" #include "http/response.h" +#include "queue.h" #include "commons.h" @@ -50,6 +51,8 @@ CLASS(HttpWorker) { HttpRequest current_request; HttpMessage current_response; + Queue additional_headers; + HttpParser parser; HttpWriter writer; }; diff --git a/include/session.h b/include/session.h index 8ca5d56..a411c5c 100644 --- a/include/session.h +++ b/include/session.h @@ -25,17 +25,20 @@ #include #include +#include #include "class.h" -#define SESSION_LIVETIME 30 +// livetime of a session in seconds +#define SESSION_LIVETIME 300 // 5 minutes CLASS(Session) { - unsigned long id; + char id[37]; + unsigned long hash; time_t livetime; - char * username; + User user; }; #endif // __SESSION_H__ diff --git a/src/Makefile.am b/src/Makefile.am index 771d173..d1cced4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,7 +34,7 @@ bin_PROGRAMS = taskrambler taskrambler_SOURCES = taskrambler.c $(IFACE) $(UTILS) taskrambler_CFLAGS = $(CFLAGS) -Wall -DPWD=\"$(PWD)\" -I ../include/# $(COVERAGE_CFLAGS) -taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap -lgdbm +taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap -lgdbm -luuid #taskrambler_LDFLAGS = $(COVERAGE_LDFLAGS) SUBDIRS = asset auth cbuf class hash queue http \ diff --git a/src/application/adapter/http/update.c b/src/application/adapter/http/update.c index 145a5c1..6d0a6d8 100644 --- a/src/application/adapter/http/update.c +++ b/src/application/adapter/http/update.c @@ -39,26 +39,92 @@ #include "utils/memory.h" -#define NO_SESSION_SID 0 +#define NO_SESSION_SID NULL +#define SESS_HEADER "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}" static inline -unsigned long +char * getSessionId(Hash cookies) { HashValue sidstr = hashGet(cookies, CSTRA("sid")); if (NULL != sidstr) { - return strtoul((char*)(sidstr->value), NULL, 10); + return (char*)sidstr->value; } return NO_SESSION_SID; } +static +Session +getSession(Queue sess_queue, const char * sid) +{ + Session sess = NULL; + time_t now = time(NULL); + + /** + * session start or update + * + * @TODO + * I need to walk through the whole hash at this point to find + * expired sessions and remove them....this is not good and + * probably I need another(faster) way to identify expired + * sessions.... + * + * @TODO + * Build a way to cleanup the hash by a filter...currently + * there is nothing I could use for this. + * Well this is practically impossible in reasonable time + * because every time I remove one element the tree has to + * be rebalanced.... + * + * I have to store all nodes in a different structure that + * gives me the possibility to find fast expired objects. + * These can then be removed from both structures.... + * + * Anyway this is the pure horror...because I have to compute + * the condition for every stored session....and I really have to + * do this...else the tree would grow and grow all the time... + * + * I think the best I can do at this point is, at least for the moment, + * to store the sessions in a list and not in a stack. + * Each request will than have to walk through that list, + * remove expired sessions and pick out its own.... + * this is O(n), but currently I gave no better idea at all. + */ + while (NULL != sess_queue->next) { + Session session = (Session)sess_queue->next->msg; + + if (now >= session->livetime) { + Queue to_delete = sess_queue->next; + sess_queue->next = sess_queue->next->next; + delete(session); + delete(to_delete); + continue; + } + + if (NULL != sid && 0 == memcmp(session->id, sid, 36)) { + session->livetime = time(NULL) + SESSION_LIVETIME; + sess = session; + } + + sess_queue = sess_queue->next; + } + + if (NULL == sess) { + sess = new(Session); + queuePut(sess_queue, sess); + } + + return sess; +} + + static void -loginAdapter(Application application, HttpWorker worker, unsigned long sid) +loginAdapter(Application application, HttpWorker worker, Session session) { HashValue username; HashValue password; @@ -82,34 +148,7 @@ loginAdapter(Application application, HttpWorker worker, unsigned long sid) (char *)(username->value), username->nvalue, (char *)(password->value), password->nvalue); - if (applicationLogin(application, credential)) { - char buffer[200]; - size_t nbuf; - - if (NO_SESSION_SID == sid - || NULL == applicationSessionGet(application, sid)) { - sid = applicationSessionStart( - application, - (char *)(username->value), - username->nvalue); - } else { - applicationSessionUpdate( - application, - sid, - username->value, - username->nvalue); - } - - nbuf = sprintf(buffer, "sid=%lu;Path=/", sid); - - worker->current_response = - (HttpMessage)httpResponseSession( - applicationSessionGet(application, sid)); - - hashAdd( - worker->current_response->header, - new(HttpHeader, CSTRA("Set-Cookie"), buffer, nbuf)); - } else { + if (! applicationLogin(application, credential, session)) { worker->current_response = new(HttpResponse, "HTTP/1.1", 403, "Forbidden"); } @@ -117,53 +156,42 @@ loginAdapter(Application application, HttpWorker worker, unsigned long sid) delete(credential); } - void applicationAdapterHttpUpdate(void * _this, void * subject) { ApplicationAdapterHttp this = _this; - HttpWorker worker = (HttpWorker)subject; - unsigned long sid = getSessionId(worker->current_request->cookies); - Session session = applicationSessionGet(this->application, sid); - - if (NULL != session) { - if (time(NULL) < session->livetime) { - session->livetime = time(NULL) + SESSION_LIVETIME; - } else { - applicationSessionStop(this->application, sid); - } - - } + HttpWorker worker = (HttpWorker)subject; + char * sid; + Session session; + char buf[200]; + size_t nbuf; + + sid = getSessionId(worker->current_request->cookies); + session = getSession(this->application->active_sessions, sid); + + nbuf = sprintf(buf, SESS_HEADER, + session->id, + SESSION_LIVETIME, + session->livetime - time(NULL)); + queuePut( + worker->additional_headers, + new(HttpHeader, CSTRA("X-TaskramblerSession"), buf, nbuf)); + + nbuf = sprintf(buf, "sid=%s;Path=/", session->id); + queuePut( + worker->additional_headers, + new(HttpHeader, CSTRA("Set-Cookie"), buf, nbuf)); if (0 == strcmp("POST", worker->current_request->method)) { if (0 == strcmp("/login/", worker->current_request->path)) { - loginAdapter(this->application, worker, sid); + loginAdapter(this->application, worker, session); return; } } if (0 == strcmp("GET", worker->current_request->method)) { - if (0 == strcmp("/sessinfo/", worker->current_request->path)) { - worker->current_response = - (HttpMessage)httpResponseSession( - applicationSessionGet(this->application, sid)); - return; - } - - if (0 == strcmp("/sess/", worker->current_request->path)) { - if (NO_SESSION_SID == sid - || NULL == applicationSessionGet(this->application, sid)) { - sid = applicationSessionStart(this->application, NULL, 0); - } - - worker->current_response = - (HttpMessage)httpResponseSession( - applicationSessionGet(this->application, sid)); - return; - } - if (0 == strcmp("/randval/", worker->current_request->path)) { - if (NO_SESSION_SID != sid) { + if (NO_SESSION_SID != session->id) { worker->current_response = (HttpMessage)httpResponseRandval( this->application->val->timestamp, diff --git a/src/application/application.c b/src/application/application.c index 16da56f..31c146f 100644 --- a/src/application/application.c +++ b/src/application/application.c @@ -25,8 +25,9 @@ #include #include "class.h" -#include "hash.h" +#include "queue.h" #include "application/application.h" +#include "storage.h" #include "utils/memory.h" @@ -35,11 +36,20 @@ int applicationCtor(void * _this, va_list * params) { Application this = _this; + size_t i; - this->val = va_arg(*params, struct randval *); - this->auth = va_arg(*params, void *); + this->val = va_arg(*params, struct randval *); - this->active_sessions = new(Hash); + // initialize authenticators to use. + this->nauth = va_arg(*params, size_t); + this->auth = memMalloc(this->nauth * sizeof(void*)); + for (i=0; inauth; i++) { + this->auth[i] = va_arg(*params, void *); + } + + this->active_sessions = new(Queue); + + this->users = new(Storage, "./run/users.db"); return 0; } @@ -49,8 +59,15 @@ void applicationDtor(void * _this) { Application this = _this; + size_t i; delete(this->active_sessions); + + for (i=0; inauth; i++) { + delete(this->auth[i]); + } + + MEM_FREE(this->auth); } diff --git a/src/application/login.c b/src/application/login.c index e10f5f5..02e2246 100644 --- a/src/application/login.c +++ b/src/application/login.c @@ -34,9 +34,38 @@ int -applicationLogin(Application this, Credential credential) +applicationLogin( + Application this, + Credential credential, + Session session) { - return authenticate(this->auth, credential); + size_t i; + + for (i=0; inauth; i++) { + if (authenticate(this->auth, credential)) { + session->user = new(User, NULL); + + switch (credential->type) { + case CRED_PASSWORD: + session->user->email = CRED_PWD(credential).user; + session->user->nemail = &CRED_PWD(credential).nuser; + + if (NULL == userLoad(session->user, this->users)) { + session->user->email = NULL; + session->user->nemail = NULL; + } + + break; + + default: + break; + } + + return 1; + } + } + + return 0; } // vim: set ts=4 sw=4: diff --git a/src/application/session_get.c b/src/application/session_get.c index 46eaa10..db626fb 100644 --- a/src/application/session_get.c +++ b/src/application/session_get.c @@ -33,9 +33,10 @@ Session -applicationSessionGet(Application this, unsigned long sid) +applicationSessionGet(Application this, const char * sid) { - return hashGetByVal(this->active_sessions, sid); +// return hashGet(this->active_sessions, sid, 36); + return NULL; } // vim: set ts=4 sw=4: diff --git a/src/application/session_start.c b/src/application/session_start.c index 594e7e0..ec28ff1 100644 --- a/src/application/session_start.c +++ b/src/application/session_start.c @@ -26,20 +26,20 @@ #include "class.h" #include "session.h" -#include "hash.h" +#include "queue.h" #include "application/application.h" #include "utils/memory.h" -unsigned long -applicationSessionStart(Application this, const char * name, size_t nname) +Session +applicationSessionStart(Application this) { - Session session = new(Session, name, nname); + Session session = new(Session); - hashAdd(this->active_sessions, session); + queuePut(this->active_sessions, session); - return session->id; + return session; } // vim: set ts=4 sw=4: diff --git a/src/application/session_stop.c b/src/application/session_stop.c index 1d876a0..73459d5 100644 --- a/src/application/session_stop.c +++ b/src/application/session_stop.c @@ -33,10 +33,10 @@ void -applicationSessionStop(Application this, unsigned long sid) +applicationSessionStop(Application this, const char * sid) { - Session session = hashDeleteByVal(this->active_sessions, sid); - delete(session); + //Session session = hashDelete(this->active_sessions, sid, 36); + //delete(session); } // vim: set ts=4 sw=4: diff --git a/src/application/session_update.c b/src/application/session_update.c index eaa144f..7e8a8bf 100644 --- a/src/application/session_update.c +++ b/src/application/session_update.c @@ -36,19 +36,19 @@ void applicationSessionUpdate( Application this, - unsigned long sid, + const char * sid, const char * name, size_t nname) { - Session session = hashGetByVal(this->active_sessions, sid); - - if (NULL != session) { - MEM_FREE(session->username); - - session->username = memMalloc(nname + 1); - session->username[nname] = 0; - memcpy(session->username, name, nname); - } +// Session session = hashGet(this->active_sessions, sid, 36); +// +// if (NULL != session) { +// MEM_FREE(session->username); +// +// session->username = memMalloc(nname + 1); +// session->username[nname] = 0; +// memcpy(session->username, name, nname); +// } } // vim: set ts=4 sw=4: diff --git a/src/http/Makefile.am b/src/http/Makefile.am index b3745b6..0b3a9f7 100644 --- a/src/http/Makefile.am +++ b/src/http/Makefile.am @@ -31,7 +31,8 @@ WORKER = worker.c \ worker/process.c \ worker/answer.c \ worker/get_asset.c \ - worker/add_common_header.c + worker/add_common_header.c \ + worker/add_computed_header.c HEADER = header.c \ header/to_string.c diff --git a/src/http/response/session.c b/src/http/response/session.c index 5aae94a..34ec44b 100644 --- a/src/http/response/session.c +++ b/src/http/response/session.c @@ -36,7 +36,7 @@ #include "utils/memory.h" #include "hash.h" -#define RESP_DATA "{\"id\":\"%lu\",\"timeout\":%d,\"timeleft\":%ld,\"username\":\"%s\"}" +#define RESP_DATA "{\"id\":\"%s\",\"timeout\":%d,\"timeleft\":%ld}" HttpResponse httpResponseSession(Session session) @@ -53,10 +53,9 @@ httpResponseSession(Session session) new(HttpHeader, CSTRA("Content-Type"), CSTRA("application/json"))); nbuf = sprintf(buffer, RESP_DATA, - (NULL != session)? session->id : 0, + (NULL != session)? session->id : "", (NULL != session)? SESSION_LIVETIME : 0, - (NULL != session)? session->livetime - time(NULL) : 0, - (NULL != session)? session->username : ""); + (NULL != session)? session->livetime - time(NULL) : 0); message->nbody = nbuf; message->body = memMalloc(nbuf); diff --git a/src/http/worker.c b/src/http/worker.c index 6ccb07f..8d59303 100644 --- a/src/http/worker.c +++ b/src/http/worker.c @@ -33,6 +33,7 @@ #include "class.h" #include "stream.h" #include "hash.h" +#include "queue.h" #include "http/worker.h" #include "http/parser.h" #include "http/writer.h" @@ -57,6 +58,8 @@ httpWorkerCtor(void * _this, va_list * params) sprintf(cbuf_id, "%s_%s", "parser", id); this->pbuf = new(Cbuf, cbuf_id, PARSER_MAX_BUF); + this->additional_headers = new(Queue); + this->parser = new(HttpParser, this->pbuf); this->writer = new(HttpWriter); @@ -71,6 +74,8 @@ httpWorkerDtor(void * _this) MEM_FREE(this->id); + delete(this->additional_headers); + delete(this->parser); delete(this->writer); @@ -90,6 +95,8 @@ httpWorkerClone(void * _this, void * _base) this->asset_pool = base->asset_pool; this->application_adapter = base->application_adapter; + this->additional_headers = new(Queue); + this->parser = new(HttpParser, base->pbuf); /* * I am pretty sure that it is not neccessary to have a diff --git a/src/http/worker/add_computed_header.c b/src/http/worker/add_computed_header.c new file mode 100644 index 0000000..52d37e3 --- /dev/null +++ b/src/http/worker/add_computed_header.c @@ -0,0 +1,47 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "class.h" + +#include "http/message.h" +#include "http/header.h" +#include "http/worker.h" + +#include "queue.h" + +#include "utils/memory.h" + + +void +httpWorkerAddComputedHeader(HttpWorker this) +{ + HttpHeader header = (HttpHeader)queueGet(this->additional_headers); + + while(NULL != header) { + hashAdd(this->current_response->header, header); + header = (HttpHeader)queueGet(this->additional_headers); + } +} + +// vim: set ts=4 sw=4: diff --git a/src/http/worker/process.c b/src/http/worker/process.c index 26ccf07..2e5f90f 100644 --- a/src/http/worker/process.c +++ b/src/http/worker/process.c @@ -50,6 +50,7 @@ HttpMessage httpWorkerGetAsset(HttpWorker, const char *); void httpWorkerAddCommonHeader(HttpWorker); +void httpWorkerAddComputedHeader(HttpWorker); ssize_t @@ -117,6 +118,7 @@ httpWorkerProcess(HttpWorker this, Stream st) } httpWorkerAddCommonHeader(this); + httpWorkerAddComputedHeader(this); delete(this->current_request); queuePut(this->writer->queue, this->current_response); this->current_response = NULL; diff --git a/src/session/session.c b/src/session/session.c index fe2975c..ff46cc2 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "session.h" #include "hash.h" @@ -40,15 +41,13 @@ int sessionCtor(void * _this, va_list * params) { Session this = _this; - char * uname = va_arg(* params, char *); - size_t nuname = va_arg(* params, size_t); + uuid_t uuid; this->livetime = time(NULL) + SESSION_LIVETIME; - this->id = sdbm((unsigned char *)uname, nuname) ^ this->livetime; + uuid_generate(uuid); + uuid_unparse(uuid, this->id); - this->username = memMalloc(nuname + 1); - this->username[nuname] = 0; - memcpy(this->username, uname, nuname); + this->hash = sdbm((unsigned char *)this->id, 36); return 0; } @@ -57,18 +56,15 @@ static void sessionDtor(void * _this) { - Session this = _this; - - MEM_FREE(this->username); } static unsigned long -sessionGetId(void * _this) +sessionGetHash(void * _this) { Session this = _this; - return this->id; + return this->hash; } static @@ -78,7 +74,7 @@ sessionHandleDouble(void * _this, void * _doub) } INIT_IFACE(Class, sessionCtor, sessionDtor, NULL); -INIT_IFACE(Hashable, sessionGetId, sessionHandleDouble); +INIT_IFACE(Hashable, sessionGetHash, sessionHandleDouble); CREATE_CLASS(Session, NULL, IFACE(Class), IFACE(Hashable)); // vim: set ts=4 sw=4: diff --git a/src/taskrambler.c b/src/taskrambler.c index 6020e92..c0eada7 100644 --- a/src/taskrambler.c +++ b/src/taskrambler.c @@ -55,6 +55,9 @@ //#define DEFAULT_SECS 1 #define DEFAULT_USECS 0 +#define LDAP_BASE "ou=user,dc=yabrog,dc=weird-web-workers,dc=org" + + void nullhandler() {} void daemonize(void); @@ -137,7 +140,7 @@ main() default: { - AuthLdap auth; + AuthLdap ldap; Application application; ApplicationAdapterHttp adapterHttp; HttpWorker worker; @@ -150,11 +153,12 @@ main() close(shm); logger = new(LoggerSyslog, LOGGER_DEBUG); - auth = new(AuthLdap, - "ldap://hosted/", - CSTRA("ou=user,dc=yabrog,dc=weird-web-workers,dc=org")); + worker = new(HttpWorker, "testserver"); - application = new(Application, value, auth); + ldap = new( + AuthLdap, "ldap://hosted/", CSTRA(LDAP_BASE)); + application = new(Application, value, 1, ldap); + adapterHttp = new(ApplicationAdapterHttp, application); subjectAttach(worker, adapterHttp); @@ -206,7 +210,6 @@ main() delete(worker); delete(adapterHttp); delete(application); - delete(auth); delete(logger); clearMimeTypes(); diff --git a/src/uuid.c b/src/uuid.c new file mode 100644 index 0000000..8ab3022 --- /dev/null +++ b/src/uuid.c @@ -0,0 +1,18 @@ +#include +#include + +int +main(int argc, char * argv[]) +{ + uuid_t uuid; + char uuid_str[37]; + + uuid_generate(uuid); + uuid_unparse(uuid, uuid_str); + + printf("%s\n", uuid_str); + + return 0; +} + +// vim: set ts=4 sw=4: