Back to index

citadel  8.12
Functions | Variables
context.c File Reference
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <syslog.h>
#include <sys/syslog.h>
#include <time.h>
#include <limits.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/un.h>
#include <string.h>
#include <pwd.h>
#include <errno.h>
#include <stdarg.h>
#include <grp.h>
#include <libcitadel.h>
#include "citadel.h"
#include "server.h"
#include "sysdep_decls.h"
#include "citserver.h"
#include "support.h"
#include "config.h"
#include "database.h"
#include "housekeeping.h"
#include "modules/crypto/serv_crypto.h"
#include "ecrash.h"
#include "snprintf.h"
#include "ctdl_module.h"
#include "threads.h"
#include "user_ops.h"
#include "control.h"

Go to the source code of this file.

Functions

int CtdlTrySingleUser (void)
void CtdlEndSingleUser (void)
int CtdlWantSingleUser (void)
int CtdlIsSingleUser (void)
int CtdlTerminateOtherSession (int session_num)
void BumpNewMailCounter (long which_user)
void CtdlBumpNewMailCounter (long which_user)
int CtdlIsUserLoggedIn (char *user_name)
int CtdlIsUserLoggedInByNum (long usernum)
CitContextMyContext (void)
void terminate_idle_sessions (void)
void terminate_all_sessions (void)
void RemoveContext (CitContext *con)
CitContextCreateNewContext (void)
CitContextCloneContext (CitContext *CloneMe)
CitContextCtdlGetContextArray (int *count)
void CtdlFillSystemContext (CitContext *context, char *name)
void context_cleanup (void)
void dead_session_purge (int force)
void InitializeMasterCC (void)
void set_async_waiting (struct CitContext *ccptr)
void DebugSessionEnable (const int n)
 CTDL_MODULE_INIT (session)

Variables

int DebugSession = 0
pthread_key_t MyConKey
CitContext masterCC
CitContextContextList = NULL
time_t last_purge = 0
int num_sessions = 0
static int want_single_user = 0

Function Documentation

void BumpNewMailCounter ( long  which_user)

Definition at line 185 of file context.c.

{
       CtdlBumpNewMailCounter(which_user);
}

Here is the call graph for this function:

TODO: what about the room/user?

Definition at line 445 of file context.c.

                                              {
       CitContext *me;
       static int next_pid = 0;

       me = (CitContext *) malloc(sizeof(CitContext));
       if (me == NULL) {
              CONM_syslog(LOG_ALERT, "citserver: can't allocate memory!!\n");
              return NULL;
       }
       memcpy(me, CloneMe, sizeof(CitContext));

       memset(&me->RecvBuf, 0, sizeof(IOBuffer));
       memset(&me->SendBuf, 0, sizeof(IOBuffer));
       memset(&me->SBuf, 0, sizeof(IOBuffer));
       me->MigrateBuf = NULL;
       me->sMigrateBuf = NULL;
       me->redirect_buffer = NULL;
#ifdef HAVE_OPENSSL
       me->ssl = NULL;
#endif

       me->download_fp = NULL;
       me->upload_fp = NULL;
       me->ma = NULL;
       me->openid_data = NULL;
       me->ldap_dn = NULL;
       me->session_specific_data = NULL;

       me->download_fp = NULL;
       me->upload_fp = NULL;
       me->client_socket = 0;

       me->MigrateBuf = NewStrBuf();
       me->RecvBuf.Buf = NewStrBuf();
       
       begin_critical_section(S_SESSION_TABLE);
       {
              me->cs_pid = ++next_pid;
              me->prev = NULL;
              me->next = ContextList;
              me->lastcmd = time(NULL);   /* set lastcmd to now to prevent idle timer infanticide */
              ContextList = me;
              if (me->next != NULL) {
                     me->next->prev = me;
              }
              ++num_sessions;
       }
       end_critical_section(S_SESSION_TABLE);
       return (me);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void context_cleanup ( void  )

Definition at line 566 of file context.c.

{
       CitContext *ptr = NULL;
       CitContext *rem = NULL;

       /*
        * Clean up the contexts.
        * There are no threads so no critical_section stuff is needed.
        */
       ptr = ContextList;
       
       /* We need to update the ContextList because some modules may want to itterate it
        * Question is should we NULL it before iterating here or should we just keep updating it
        * as we remove items?
        *
        * Answer is to NULL it first to prevent modules from doing any actions on the list at all
        */
       ContextList=NULL;
       while (ptr != NULL){
              /* Remove the session from the active list */
              rem = ptr->next;
              --num_sessions;

              CON_syslog(LOG_DEBUG, "context_cleanup(): purging session %d\n", ptr->cs_pid);
              RemoveContext(ptr);
              free (ptr);
              ptr = rem;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 395 of file context.c.

                                   {
       CitContext *me;
       static int next_pid = 0;

       me = (CitContext *) malloc(sizeof(CitContext));
       if (me == NULL) {
              CONM_syslog(LOG_ALERT, "citserver: can't allocate memory!!\n");
              return NULL;
       }
       memset(me, 0, sizeof(CitContext));

       /* Give the context a name. Hopefully makes it easier to track */
       strcpy (me->user.fullname, "SYS_notauth");
       
       /* The new context will be created already in the CON_EXECUTING state
        * in order to prevent another thread from grabbing it while it's
        * being set up.
        */
       me->state = CON_EXECUTING;
       /*
        * Generate a unique session number and insert this context into
        * the list.
        */
       me->MigrateBuf = NewStrBuf();

       me->RecvBuf.Buf = NewStrBuf();

       me->lastcmd = time(NULL);   /* set lastcmd to now to prevent idle timer infanticide TODO: if we have a valid IO, use that to set the timer. */


       begin_critical_section(S_SESSION_TABLE);
       me->cs_pid = ++next_pid;
       me->prev = NULL;
       me->next = ContextList;
       ContextList = me;
       if (me->next != NULL) {
              me->next->prev = me;
       }
       ++num_sessions;
       end_critical_section(S_SESSION_TABLE);
       return (me);
}

Here is the call graph for this function:

Here is the caller graph for this function:

CTDL_MODULE_INIT ( session  )

Definition at line 694 of file context.c.

{
       if (!threading) {
              CtdlRegisterDebugFlagHook(HKEY("session"), DebugSessionEnable, &DebugSession);
       }
       return "session";
}

Here is the call graph for this function:

void CtdlBumpNewMailCounter ( long  which_user)

Definition at line 190 of file context.c.

{
       CitContext *ptr;

       begin_critical_section(S_SESSION_TABLE);

       for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
              if (ptr->user.usernum == which_user) {
                     ptr->newmail += 1;
              }
       }

       end_critical_section(S_SESSION_TABLE);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void CtdlEndSingleUser ( void  )

Definition at line 119 of file context.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void CtdlFillSystemContext ( CitContext context,
char *  name 
)

Definition at line 530 of file context.c.

{
       char sysname[SIZ];
       long len;

       memset(context, 0, sizeof(CitContext));
       context->internal_pgm = 1;
       context->cs_pid = 0;
       strcpy (sysname, "SYS_");
       strcat (sysname, name);
       len = cutuserkey(sysname);
       memcpy(context->curr_user, sysname, len + 1);
       context->client_socket = (-1);
       context->state = CON_SYS;
       context->ServiceName = name;

       /* internal_create_user has the side effect of loading the user regardless of wether they
        * already existed or needed to be created
        */
       internal_create_user (sysname, len, &(context->user), -1) ;
       
       /* Check to see if the system user needs upgrading */
       if (context->user.usernum == 0)
       {      /* old system user with number 0, upgrade it */
              context->user.usernum = get_new_user_number();
              CON_syslog(LOG_INFO, "Upgrading system user \"%s\" from user number 0 to user number %ld\n", context->user.fullname, context->user.usernum);
              /* add user to the database */
              CtdlPutUser(&(context->user));
              cdb_store(CDB_USERSBYNUMBER, &(context->user.usernum), sizeof(long), context->user.fullname, strlen(context->user.fullname)+1);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

CitContext* CtdlGetContextArray ( int *  count) [read]

Definition at line 503 of file context.c.

{
       int nContexts, i;
       CitContext *nptr, *cptr;
       
       nContexts = num_sessions;
       nptr = malloc(sizeof(CitContext) * nContexts);
       if (!nptr) {
              *count = 0;
              return NULL;
       }
       begin_critical_section(S_SESSION_TABLE);
       for (cptr = ContextList, i=0; cptr != NULL && i < nContexts; cptr = cptr->next, i++) {
              memcpy(&nptr[i], cptr, sizeof (CitContext));
       }
       end_critical_section (S_SESSION_TABLE);
       
       *count = i;
       return nptr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int CtdlIsSingleUser ( void  )

Definition at line 132 of file context.c.

{
       if (want_single_user)
       {
              /* check for only one context here */
              if (num_sessions == 1)
                     return TRUE;
       }
       return FALSE;
}
int CtdlIsUserLoggedIn ( char *  user_name)

Definition at line 212 of file context.c.

{
       CitContext *cptr;
       int ret = 0;

       begin_critical_section (S_SESSION_TABLE);
       for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
              if (!strcasecmp(cptr->user.fullname, user_name)) {
                     ret = 1;
                     break;
              }
       }
       end_critical_section(S_SESSION_TABLE);
       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int CtdlIsUserLoggedInByNum ( long  usernum)

Definition at line 237 of file context.c.

{
       CitContext *cptr;
       int ret = 0;

       begin_critical_section(S_SESSION_TABLE);
       for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
              if (cptr->user.usernum == usernum) {
                     ret = 1;
              }
       }
       end_critical_section(S_SESSION_TABLE);
       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int CtdlTerminateOtherSession ( int  session_num)

Definition at line 153 of file context.c.

{
       int ret = 0;
       CitContext *ccptr;

       if (session_num == CC->cs_pid) {
              return TERM_NOTALLOWED;
       }

       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)) {
                            ret |= TERM_ALLOWED;
                            ccptr->kill_me = KILLME_ADMIN_TERMINATE;
                     }
              }
       }
       end_critical_section(S_SESSION_TABLE);
       return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int CtdlTrySingleUser ( void  )

Definition at line 103 of file context.c.

{
       int can_do = 0;
       
       begin_critical_section(S_SINGLE_USER);
       if (want_single_user)
              can_do = 0;
       else
       {
              can_do = 1;
              want_single_user = 1;
       }
       end_critical_section(S_SINGLE_USER);
       return can_do;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int CtdlWantSingleUser ( void  )

Definition at line 127 of file context.c.

{
       return want_single_user;
}

Here is the caller graph for this function:

void dead_session_purge ( int  force)

Definition at line 605 of file context.c.

                                   {
       CitContext *ptr, *ptr2;            /* general-purpose utility pointer */
       CitContext *rem = NULL;            /* list of sessions to be destroyed */
       
       if (force == 0) {
              if ( (time(NULL) - last_purge) < 5 ) {
                     return;       /* Too soon, go away */
              }
       }
       time(&last_purge);

       if (try_critical_section(S_SESSION_TABLE))
              return;
              
       ptr = ContextList;
       while (ptr) {
              ptr2 = ptr;
              ptr = ptr->next;
              
              if ( (ptr2->state == CON_IDLE) && (ptr2->kill_me) ) {
                     /* Remove the session from the active list */
                     if (ptr2->prev) {
                            ptr2->prev->next = ptr2->next;
                     }
                     else {
                            ContextList = ptr2->next;
                     }
                     if (ptr2->next) {
                            ptr2->next->prev = ptr2->prev;
                     }

                     --num_sessions;
                     /* And put it on our to-be-destroyed list */
                     ptr2->next = rem;
                     rem = ptr2;
              }
       }
       end_critical_section(S_SESSION_TABLE);

       /* Now that we no longer have the session list locked, we can take
        * our time and destroy any sessions on the to-be-killed list, which
        * is allocated privately on this thread's stack.
        */
       while (rem != NULL) {
              CON_syslog(LOG_DEBUG, "dead_session_purge(): purging session %d, reason=%d\n", rem->cs_pid, rem->kill_me);
              RemoveContext(rem);
              ptr = rem;
              rem = rem->next;
              free(ptr);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void DebugSessionEnable ( const int  n)

Definition at line 690 of file context.c.

{
       DebugSession = n;
}

Here is the caller graph for this function:

void InitializeMasterCC ( void  )

Definition at line 665 of file context.c.

                              {
       memset(&masterCC, 0, sizeof(struct CitContext));
       masterCC.internal_pgm = 1;
       masterCC.cs_pid = 0;
}

Here is the caller graph for this function:

CitContext* MyContext ( void  )

Definition at line 261 of file context.c.

                            {
       register CitContext *c;
       return ((c = (CitContext *) pthread_getspecific(MyConKey), c == NULL) ? &masterCC : c);
}

Here is the caller graph for this function:

void RemoveContext ( CitContext con)

cit_backtrace();

Definition at line 336 of file context.c.

{
       const char *c;
       if (con == NULL) {
              CONM_syslog(LOG_ERR, "WARNING: RemoveContext() called with NULL!");
              return;
       }
       c = con->ServiceName;
       if (c == NULL) {
              c = "WTF?";
       }
       CON_syslog(LOG_DEBUG, "RemoveContext(%s) session %d", c, con->cs_pid);

       /* Run any cleanup routines registered by loadable modules.
        * Note: We have to "become_session()" because the cleanup functions
        *       might make references to "CC" assuming it's the right one.
        */
       become_session(con);
       CtdlUserLogout();
       PerformSessionHooks(EVT_STOP);
       client_close();                           /* If the client is still connected, blow 'em away. */
       become_session(NULL);

       CON_syslog(LOG_NOTICE, "[%3d]SRV[%s] Session ended.", con->cs_pid, c);

       /* 
        * If the client is still connected, blow 'em away. 
        * if the socket is 0 or -1, its already gone or was never there.
        */
       if (con->client_socket > 0)
       {
              CON_syslog(LOG_NOTICE, "Closing socket %d", con->client_socket);
              close(con->client_socket);
       }

       /* If using AUTHMODE_LDAP, free the DN */
       if (con->ldap_dn) {
              free(con->ldap_dn);
              con->ldap_dn = NULL;
       }
       FreeStrBuf(&con->StatusMessage);
       FreeStrBuf(&con->MigrateBuf);
       FreeStrBuf(&con->RecvBuf.Buf);
       if (con->cached_msglist) {
              free(con->cached_msglist);
       }

       CONM_syslog(LOG_DEBUG, "Done with RemoveContext()");
}

Here is the call graph for this function:

Here is the caller graph for this function:

void set_async_waiting ( struct CitContext ccptr)

Definition at line 678 of file context.c.

{
       CON_syslog(LOG_DEBUG, "Setting async_waiting flag for session %d\n", ccptr->cs_pid);
       if (ccptr->is_async) {
              ccptr->async_waiting++;
              if (ccptr->state == CON_IDLE) {
                     ccptr->state = CON_READY;
              }
       }
}

Here is the caller graph for this function:

void terminate_all_sessions ( void  )

Definition at line 310 of file context.c.

{
       CitContext *ccptr;
       int killed = 0;

       begin_critical_section(S_SESSION_TABLE);
       for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
              if (ccptr->client_socket != -1)
              {
                     CON_syslog(LOG_INFO, "terminate_all_sessions() is murdering %s", ccptr->curr_user);
                     close(ccptr->client_socket);
                     ccptr->client_socket = -1;
                     killed++;
              }
       }
       end_critical_section(S_SESSION_TABLE);
       if (killed > 0) {
              CON_syslog(LOG_INFO, "Flushed %d stuck sessions\n", killed);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void terminate_idle_sessions ( void  )

Definition at line 275 of file context.c.

{
       CitContext *ccptr;
       time_t now;
       int killed = 0;
       int longrunners = 0;

       now = time(NULL);
       begin_critical_section(S_SESSION_TABLE);
       for (ccptr = ContextList; ccptr != NULL; ccptr = ccptr->next) {
              if (
                     (ccptr != CC)
                     && (config.c_sleeping > 0)
                     && (now - (ccptr->lastcmd) > config.c_sleeping)
              ) {
                     if (!ccptr->dont_term) {
                            ccptr->kill_me = KILLME_IDLE;
                            ++killed;
                     }
                     else {
                            ++longrunners;
                     }
              }
       }
       end_critical_section(S_SESSION_TABLE);
       if (killed > 0)
              CON_syslog(LOG_INFO, "Scheduled %d idle sessions for termination\n", killed);
       if (longrunners > 0)
              CON_syslog(LOG_INFO, "Didn't terminate %d protected idle sessions", longrunners);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 93 of file context.c.

int DebugSession = 0

Definition at line 87 of file context.c.

time_t last_purge = 0

Definition at line 95 of file context.c.

Definition at line 92 of file context.c.

pthread_key_t MyConKey

Definition at line 89 of file context.c.

int num_sessions = 0

Definition at line 96 of file context.c.

int want_single_user = 0 [static]

Definition at line 99 of file context.c.