From 194ee6709f01560434de4450b70d1f667731966d Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Mon, 23 Jul 2012 16:26:35 +0200 Subject: [PATCH] cmd_TERM: also kill AsyncIO contexts - the next_pid var has to be global, so we have a uniq source of session numbers. - during cloning sessions, cached_msglist and CIT_ICAL mustn't be copied. - FreeAsyncIOContents(): NULL pointer to context after flagging it for deletion. - InitIOStruct() / InitcURLIOStruct(): IO and CC are now doublepointered, know each others. - KillAsyncIOContext () detect in which event-queue the context is running - Join that queue, and call the terminator hook of the other session. - self-terminate afterwards. --- citadel/context.c | 40 +++++++++++++++----- citadel/context.h | 9 +++-- citadel/event_client.c | 86 +++++++++++++++++++++++++++++++++++++++++- citadel/event_client.h | 5 ++- 4 files changed, 124 insertions(+), 16 deletions(-) diff --git a/citadel/context.c b/citadel/context.c index 953d1d6ae..255458d50 100644 --- a/citadel/context.c +++ b/citadel/context.c @@ -88,6 +88,7 @@ CitContext *ContextList = NULL; time_t last_purge = 0; /* Last dead session purge */ int num_sessions = 0; /* Current number of sessions */ +int next_pid = 0; /* Flag for single user mode */ static int want_single_user = 0; @@ -146,26 +147,46 @@ int CtdlIsSingleUser(void) */ int CtdlTerminateOtherSession (int session_num) { + struct CitContext *CCC = CC; int ret = 0; CitContext *ccptr; + int aide; - if (session_num == CC->cs_pid) { - return TERM_NOTALLOWED; - } + if (session_num == CCC->cs_pid) return TERM_NOTALLOWED; + + aide = ( (CCC->user.axlevel >= AxAideU) || (CCC->internal_pgm) ) ; CONM_syslog(LOG_DEBUG, "Locating session to kill\n"); begin_critical_section(S_SESSION_TABLE); for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) { if (session_num == ccptr->cs_pid) { ret |= TERM_FOUND; - if ((ccptr->user.usernum == CC->user.usernum) - || (CC->user.axlevel >= AxAideU)) { + if ((ccptr->user.usernum == CCC->user.usernum) || aide) { ret |= TERM_ALLOWED; - ccptr->kill_me = KILLME_ADMIN_TERMINATE; } + break; } } - end_critical_section(S_SESSION_TABLE); + + if (((ret & TERM_FOUND) != 0) && ((ret & TERM_ALLOWED) == 0)) + { + if (ccptr->IO != NULL) { + AsyncIO *IO = ccptr->IO; + end_critical_section(S_SESSION_TABLE); + KillAsyncIOContext(IO); + } + else + { + if (ccptr->user.usernum == CCC->user.usernum) + ccptr->kill_me = KILLME_ADMIN_TERMINATE; + else + ccptr->kill_me = KILLME_IDLE; + end_critical_section(S_SESSION_TABLE); + } + } + else + end_critical_section(S_SESSION_TABLE); + return ret; } @@ -388,7 +409,6 @@ void RemoveContext (CitContext *con) */ CitContext *CreateNewContext(void) { CitContext *me; - static int next_pid = 0; me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { @@ -438,7 +458,6 @@ CitContext *CreateNewContext(void) { */ CitContext *CloneContext(CitContext *CloneMe) { CitContext *me; - static int next_pid = 0; me = (CitContext *) malloc(sizeof(CitContext)); if (me == NULL) { @@ -464,7 +483,10 @@ CitContext *CloneContext(CitContext *CloneMe) { me->openid_data = NULL; me->ldap_dn = NULL; me->session_specific_data = NULL; + + me->CIT_ICAL = NULL; + me->cached_msglist = NULL; me->download_fp = NULL; me->upload_fp = NULL; me->client_socket = 0; diff --git a/citadel/context.h b/citadel/context.h index 903195c37..9243d5148 100644 --- a/citadel/context.h +++ b/citadel/context.h @@ -28,6 +28,8 @@ typedef enum __CCState { CON_SYS /* This is a system context and mustn't be purged */ } CCState; +typedef struct AsyncIO AsyncIO; /* forward declaration for event_client.h */ +typedef struct CitContext CitContext; /* * Here's the big one... the Citadel context structure. @@ -37,8 +39,8 @@ typedef enum __CCState { * */ struct CitContext { - struct CitContext *prev; /* Link to previous session in list */ - struct CitContext *next; /* Link to next session in the list */ + CitContext *prev; /* Link to previous session in list */ + CitContext *next; /* Link to next session in the list */ int cs_pid; /* session ID */ int dont_term; /* for special activities like artv so we don't get killed */ @@ -140,9 +142,10 @@ struct CitContext { long *cached_msglist; /* results of the previous CtdlForEachMessage() */ int cached_num_msgs; + + AsyncIO *IO; /* if this session has AsyncIO going on... */ }; -typedef struct CitContext CitContext; #define CC MyContext() diff --git a/citadel/event_client.c b/citadel/event_client.c index 35581e516..eb8a682fc 100644 --- a/citadel/event_client.c +++ b/citadel/event_client.c @@ -298,6 +298,7 @@ void FreeAsyncIOContents(AsyncIO *IO) if (Ctx) { Ctx->state = CON_IDLE; Ctx->kill_me = 1; + IO->CitContext = NULL; } } @@ -1031,7 +1032,8 @@ void InitIOStruct(AsyncIO *IO, IO->Data = Data; IO->CitContext = CloneContext(CC); - ((CitContext *)IO->CitContext)->session_specific_data = (char*) Data; + IO->CitContext->session_specific_data = (char*) Data; + IO->CitContext->IO = IO; IO->NextState = NextState; @@ -1068,7 +1070,8 @@ int InitcURLIOStruct(AsyncIO *IO, IO->Data = Data; IO->CitContext = CloneContext(CC); - ((CitContext *)IO->CitContext)->session_specific_data = (char*) Data; + IO->CitContext->session_specific_data = (char*) Data; + IO->CitContext->IO = IO; IO->SendDone = SendDone; IO->Terminate = Terminate; @@ -1082,6 +1085,85 @@ int InitcURLIOStruct(AsyncIO *IO, } + +typedef struct KillOtherSessionContext { + AsyncIO IO; + AsyncIO *OtherOne; +}KillOtherSessionContext; + +eNextState KillTerminate(AsyncIO *IO) +{ + KillOtherSessionContext *Ctx = (KillOtherSessionContext*)IO->Data; + EV_syslog(LOG_DEBUG, "%s Exit\n", __FUNCTION__); + FreeAsyncIOContents(IO); + memset(Ctx, 0, sizeof(KillOtherSessionContext)); + free(Ctx); + return eAbort; + +} + +eNextState KillShutdown(AsyncIO *IO) +{ + return eTerminateConnection; +} + +eNextState KillOtherContextNow(AsyncIO *IO) +{ + KillOtherSessionContext *Ctx = IO->Data; + + if (Ctx->OtherOne->ShutdownAbort != NULL) + Ctx->OtherOne->ShutdownAbort(Ctx->OtherOne); + return eTerminateConnection; +} + +void KillAsyncIOContext(AsyncIO *IO) +{ + KillOtherSessionContext *Ctx; + + Ctx = (KillOtherSessionContext*) malloc(sizeof(KillOtherSessionContext)); + memset(Ctx, 0, sizeof(KillOtherSessionContext)); + + InitIOStruct(&Ctx->IO, + Ctx, + eReadMessage, + NULL, + NULL, + NULL, + NULL, + KillTerminate, + NULL, + NULL, + NULL, + KillShutdown); + + Ctx->OtherOne = IO; + + switch(IO->NextState) { + case eSendDNSQuery: + case eReadDNSReply: + + case eConnect: + case eSendReply: + case eSendMore: + case eSendFile: + + case eReadMessage: + case eReadMore: + case eReadPayload: + case eReadFile: + QueueEventContext(&Ctx->IO, KillOtherContextNow); + break; + case eDBQuery: + QueueDBOperation(&Ctx->IO, KillOtherContextNow); + break; + case eTerminateConnection: + case eAbort: + /*hm, its already dying, dunno which Queue its in... */ + free(Ctx); + } + +} + extern int DebugEventLoopBacktrace; void EV_backtrace(AsyncIO *IO) { diff --git a/citadel/event_client.h b/citadel/event_client.h index 9c1303991..2d26c2877 100644 --- a/citadel/event_client.h +++ b/citadel/event_client.h @@ -24,6 +24,7 @@ #include typedef struct AsyncIO AsyncIO; +typedef struct CitContext CitContext; typedef enum _eNextState { eSendDNSQuery, @@ -164,7 +165,7 @@ struct AsyncIO { /* Context specific data; Hint: put AsyncIO in there */ void *Data; /* application specific data */ - void *CitContext; /* Citadel Session context... */ + CitContext *CitContext; /* Citadel Session context... */ }; typedef struct _IOAddHandler { @@ -296,7 +297,7 @@ int InitcURLIOStruct(AsyncIO *IO, IO_CallBack Terminate, IO_CallBack DBTerminate, IO_CallBack ShutdownAbort); - +void KillAsyncIOContext(AsyncIO *IO); void StopCurlWatchers(AsyncIO *IO); -- 2.30.2