* All NON-system-dependent stuff is done in this function.
* System-dependent session/thread cleanup is in cleanup() in sysdep.c
*/
-void cleanup_stuff(void *arg)
+void cleanup(int exit_code)
{
- lprintf(9, "cleanup_stuff() called\n");
+ lprintf(9, "cleanup(%d) called\n", exit_code);
lprintf(7, "Calling logout(%d)\n", CC->cs_pid);
logout(CC);
/* Deallocate any user-data attached to this session */
deallocate_user_data(CC);
- /* Tell the housekeeping thread to remove the session and context.
- * This can't be done inline because the context data gets destroyed
- * halfway through, and the context being destroyed can't be the one
- * doing the work.
- */
- lprintf(7, "Calling RemoveContext(%d)\n", CC->cs_pid);
- RemoveContext(CC);
+ /* And flag the context as in need of being killed */
+ CC->state = CON_DYING;
}
/*
- * main context loop
+ *
*/
-void *context_loop(struct CitContext *con)
+void begin_session(struct CitContext *con)
{
- char cmdbuf[256];
int num_sessions, len;
struct sockaddr_in sin;
- /*
- * Wedge our way into the context table.
- */
- InitMyContext(con);
-
/*
* Initialize some variables specific to our context.
*/
- CC->logged_in = 0;
- CC->internal_pgm = 0;
- CC->download_fp = NULL;
- CC->upload_fp = NULL;
- CC->cs_pid = con->client_socket; /* not necessarily portable */
- CC->FirstExpressMessage = NULL;
- time(&CC->lastcmd);
- time(&CC->lastidle);
- strcpy(CC->lastcmdname, " ");
- strcpy(CC->cs_clientname, "(unknown)");
- strcpy(CC->curr_user,"(not logged in)");
- strcpy(CC->net_node,"");
- snprintf(CC->temp, sizeof CC->temp, tmpnam(NULL));
- safestrncpy(CC->cs_host, config.c_fqdn, sizeof CC->cs_host);
- CC->cs_host[sizeof CC->cs_host - 1] = 0;
+ con->logged_in = 0;
+ con->internal_pgm = 0;
+ con->download_fp = NULL;
+ con->upload_fp = NULL;
+ con->cs_pid = con->client_socket; /* not necessarily portable */
+ con->FirstExpressMessage = NULL;
+ time(&con->lastcmd);
+ time(&con->lastidle);
+ strcpy(con->lastcmdname, " ");
+ strcpy(con->cs_clientname, "(unknown)");
+ strcpy(con->curr_user,"(not logged in)");
+ strcpy(con->net_node,"");
+ snprintf(con->temp, sizeof con->temp, tmpnam(NULL));
+ safestrncpy(con->cs_host, config.c_fqdn, sizeof con->cs_host);
+ con->cs_host[sizeof con->cs_host - 1] = 0;
len = sizeof sin;
- if (!getpeername(CC->client_socket, (struct sockaddr *) &sin, &len))
- locate_host(CC->cs_host, &sin.sin_addr);
- CC->cs_flags = 0;
- CC->upload_type = UPL_FILE;
- CC->dl_is_net = 0;
- CC->FirstSessData = NULL;
+ if (!getpeername(con->client_socket, (struct sockaddr *) &sin, &len))
+ locate_host(con->cs_host, &sin.sin_addr);
+ con->cs_flags = 0;
+ con->upload_type = UPL_FILE;
+ con->dl_is_net = 0;
+ con->FirstSessData = NULL;
num_sessions = session_count();
- CC->nologin = 0;
+ con->nologin = 0;
if ((config.c_maxsessions > 0)&&(num_sessions > config.c_maxsessions))
- CC->nologin = 1;
+ con->nologin = 1;
- if (CC->nologin==1) {
- cprintf("%d %s: Too many users are already online (maximum is %d)\n",
- ERROR+MAX_SESSIONS_EXCEEDED,
- config.c_nodename,config.c_maxsessions);
+ if (con->nologin==1) {
+ cprintf("%d %s: Too many users are already online "
+ "(maximum is %d)\n",
+ ERROR+MAX_SESSIONS_EXCEEDED,
+ config.c_nodename, config.c_maxsessions);
}
else {
- cprintf("%d %s Citadel/UX server ready.\n",OK,config.c_nodename);
+ cprintf("%d %s Citadel/UX server ready.\n",
+ OK, config.c_nodename);
}
- lprintf(3, "citserver[%3d]: started.\n", CC->cs_pid);
+ lprintf(3, "citserver[%3d]: started.\n", con->cs_pid);
/* Run any session startup routines registered by loadable modules */
PerformSessionHooks(EVT_START);
rec_log(CL_CONNECT, "");
+}
+
+
+
- do {
- time(&CC->lastcmd);
- memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
- if (client_gets(cmdbuf) < 1) cleanup(EXIT_NULL);
- lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
-
- /*
- * Let other clients see the last command we executed, and
- * update the idle time, but not NOOP, PEXP, or GEXP.
- */
- if ( (strncasecmp(cmdbuf, "NOOP", 4))
- && (strncasecmp(cmdbuf, "PEXP", 4))
- && (strncasecmp(cmdbuf, "GEXP", 4)) ) {
- strcpy(CC->lastcmdname, " ");
- safestrncpy(CC->lastcmdname, cmdbuf,
- sizeof(CC->lastcmdname) );
- time(&CC->lastidle);
- }
-
- if ((strncasecmp(cmdbuf, "ENT0", 4)) && (strncasecmp(cmdbuf, "MESG", 4)) && (strncasecmp(cmdbuf, "MSGS", 4)))
- {
- CC->cs_flags &= ~CS_POSTING;
- }
-
/*
* This loop recognizes all server commands.
*/
+void do_command_loop(void) {
+ char cmdbuf[256];
- if (!strncasecmp(cmdbuf,"NOOP",4)) {
- cprintf("%d%cok\n",OK,check_express());
- }
+ lprintf(9, "Hi, I'm do_command_loop() and I have client socket %d\n",
+ CC->client_socket);
- else if (!strncasecmp(cmdbuf,"QUIT",4)) {
- cprintf("%d Goodbye.\n",OK);
- }
+ time(&CC->lastcmd);
+ memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
+ if (client_gets(cmdbuf) < 1) {
+ lprintf(3, "Socket is broken, I think.\n");
+ cleanup(EXIT_NULL);
+ }
+ lprintf(5, "citserver[%3d]: %s\n", CC->cs_pid, cmdbuf);
- else if (!strncasecmp(cmdbuf,"LOUT",4)) {
- if (CC->logged_in) logout(CC);
- cprintf("%d logged out.\n",OK);
- }
+ /*
+ * Let other clients see the last command we executed, and
+ * update the idle time, but not NOOP, PEXP, or GEXP.
+ */
+ if ( (strncasecmp(cmdbuf, "NOOP", 4))
+ && (strncasecmp(cmdbuf, "PEXP", 4))
+ && (strncasecmp(cmdbuf, "GEXP", 4)) ) {
+ strcpy(CC->lastcmdname, " ");
+ safestrncpy(CC->lastcmdname, cmdbuf,
+ sizeof(CC->lastcmdname) );
+ time(&CC->lastidle);
+ }
+
+ if ((strncasecmp(cmdbuf, "ENT0", 4))
+ && (strncasecmp(cmdbuf, "MESG", 4))
+ && (strncasecmp(cmdbuf, "MSGS", 4)))
+ {
+ CC->cs_flags &= ~CS_POSTING;
+ }
+
+ if (!strncasecmp(cmdbuf,"NOOP",4)) {
+ cprintf("%d%cok\n",OK,check_express());
+ }
- else if (!strncasecmp(cmdbuf,"USER",4)) {
- cmd_user(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"QUIT",4)) {
+ cprintf("%d Goodbye.\n",OK);
+ }
- else if (!strncasecmp(cmdbuf,"PASS",4)) {
- cmd_pass(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LOUT",4)) {
+ if (CC->logged_in) logout(CC);
+ cprintf("%d logged out.\n",OK);
+ }
- else if (!strncasecmp(cmdbuf,"NEWU",4)) {
- cmd_newu(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"USER",4)) {
+ cmd_user(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"SETP",4)) {
- cmd_setp(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"PASS",4)) {
+ cmd_pass(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LRMS",4)) {
- cmd_lrms(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"NEWU",4)) {
+ cmd_newu(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LKRA",4)) {
- cmd_lkra(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"SETP",4)) {
+ cmd_setp(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LKRN",4)) {
- cmd_lkrn(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LRMS",4)) {
+ cmd_lrms(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LKRO",4)) {
- cmd_lkro(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LKRA",4)) {
+ cmd_lkra(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LZRM",4)) {
- cmd_lzrm(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LKRN",4)) {
+ cmd_lkrn(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"GETU",4)) {
- cmd_getu();
- }
+ else if (!strncasecmp(cmdbuf,"LKRO",4)) {
+ cmd_lkro(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"SETU",4)) {
- cmd_setu(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LZRM",4)) {
+ cmd_lzrm(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"GOTO",4)) {
- cmd_goto(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"GETU",4)) {
+ cmd_getu();
+ }
- else if (!strncasecmp(cmdbuf,"MSGS",4)) {
- cmd_msgs(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"SETU",4)) {
+ cmd_setu(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"WHOK",4)) {
- cmd_whok();
- }
+ else if (!strncasecmp(cmdbuf,"GOTO",4)) {
+ cmd_goto(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"RDIR",4)) {
- cmd_rdir();
- }
+ else if (!strncasecmp(cmdbuf,"MSGS",4)) {
+ cmd_msgs(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"MSG0",4)) {
- cmd_msg0(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"WHOK",4)) {
+ cmd_whok();
+ }
- else if (!strncasecmp(cmdbuf,"MSG2",4)) {
- cmd_msg2(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"RDIR",4)) {
+ cmd_rdir();
+ }
- else if (!strncasecmp(cmdbuf,"MSG3",4)) {
- cmd_msg3(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"MSG0",4)) {
+ cmd_msg0(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"MSG4",4)) {
- cmd_msg4(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"MSG2",4)) {
+ cmd_msg2(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"OPNA",4)) {
- cmd_opna(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"MSG3",4)) {
+ cmd_msg3(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"INFO",4)) {
- cmd_info();
- }
+ else if (!strncasecmp(cmdbuf,"MSG4",4)) {
+ cmd_msg4(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"SLRP",4)) {
- cmd_slrp(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"OPNA",4)) {
+ cmd_opna(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"INVT",4)) {
- cmd_invt_kick(&cmdbuf[5],1);
- }
+ else if (!strncasecmp(cmdbuf,"INFO",4)) {
+ cmd_info();
+ }
- else if (!strncasecmp(cmdbuf,"KICK",4)) {
- cmd_invt_kick(&cmdbuf[5],0);
- }
+ else if (!strncasecmp(cmdbuf,"SLRP",4)) {
+ cmd_slrp(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"GETR",4)) {
- cmd_getr();
- }
+ else if (!strncasecmp(cmdbuf,"INVT",4)) {
+ cmd_invt_kick(&cmdbuf[5],1);
+ }
- else if (!strncasecmp(cmdbuf,"SETR",4)) {
- cmd_setr(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"KICK",4)) {
+ cmd_invt_kick(&cmdbuf[5],0);
+ }
- else if (!strncasecmp(cmdbuf,"GETA",4)) {
- cmd_geta();
- }
+ else if (!strncasecmp(cmdbuf,"GETR",4)) {
+ cmd_getr();
+ }
- else if (!strncasecmp(cmdbuf,"SETA",4)) {
- cmd_seta(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"SETR",4)) {
+ cmd_setr(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"ENT0",4)) {
- cmd_ent0(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"GETA",4)) {
+ cmd_geta();
+ }
- else if (!strncasecmp(cmdbuf,"ENT3",4)) {
- cmd_ent3(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"SETA",4)) {
+ cmd_seta(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"RINF",4)) {
- cmd_rinf();
- }
+ else if (!strncasecmp(cmdbuf,"ENT0",4)) {
+ cmd_ent0(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"DELE",4)) {
- cmd_dele(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"ENT3",4)) {
+ cmd_ent3(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"KILL",4)) {
- cmd_kill(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"RINF",4)) {
+ cmd_rinf();
+ }
- else if (!strncasecmp(cmdbuf,"CRE8",4)) {
- cmd_cre8(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"DELE",4)) {
+ cmd_dele(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"MOVE",4)) {
- cmd_move(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"KILL",4)) {
+ cmd_kill(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"FORG",4)) {
- cmd_forg();
- }
+ else if (!strncasecmp(cmdbuf,"CRE8",4)) {
+ cmd_cre8(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"MESG",4)) {
- cmd_mesg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"MOVE",4)) {
+ cmd_move(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"EMSG",4)) {
- cmd_emsg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"FORG",4)) {
+ cmd_forg();
+ }
- else if (!strncasecmp(cmdbuf,"GNUR",4)) {
- cmd_gnur();
- }
+ else if (!strncasecmp(cmdbuf,"MESG",4)) {
+ cmd_mesg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"VALI",4)) {
- cmd_vali(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"EMSG",4)) {
+ cmd_emsg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"EINF",4)) {
- cmd_einf(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"GNUR",4)) {
+ cmd_gnur();
+ }
- else if (!strncasecmp(cmdbuf,"LIST",4)) {
- cmd_list();
- }
+ else if (!strncasecmp(cmdbuf,"VALI",4)) {
+ cmd_vali(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"CHEK",4)) {
- cmd_chek();
- }
+ else if (!strncasecmp(cmdbuf,"EINF",4)) {
+ cmd_einf(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"DELF",4)) {
- cmd_delf(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LIST",4)) {
+ cmd_list();
+ }
- else if (!strncasecmp(cmdbuf,"MOVF",4)) {
- cmd_movf(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"CHEK",4)) {
+ cmd_chek();
+ }
- else if (!strncasecmp(cmdbuf,"NETF",4)) {
- cmd_netf(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"DELF",4)) {
+ cmd_delf(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"RWHO",4)) {
- cmd_rwho();
- }
+ else if (!strncasecmp(cmdbuf,"MOVF",4)) {
+ cmd_movf(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"OPEN",4)) {
- cmd_open(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"NETF",4)) {
+ cmd_netf(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"CLOS",4)) {
- cmd_clos();
- }
+ else if (!strncasecmp(cmdbuf,"RWHO",4)) {
+ cmd_rwho();
+ }
- else if (!strncasecmp(cmdbuf,"UOPN",4)) {
- cmd_uopn(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"OPEN",4)) {
+ cmd_open(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"UCLS",4)) {
- cmd_ucls(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"CLOS",4)) {
+ cmd_clos();
+ }
- else if (!strncasecmp(cmdbuf,"READ",4)) {
- cmd_read(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"UOPN",4)) {
+ cmd_uopn(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"WRIT",4)) {
- cmd_writ(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"UCLS",4)) {
+ cmd_ucls(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"QUSR",4)) {
- cmd_qusr(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"READ",4)) {
+ cmd_read(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"ECHO",4)) {
- cmd_echo(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"WRIT",4)) {
+ cmd_writ(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"OIMG",4)) {
- cmd_oimg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"QUSR",4)) {
+ cmd_qusr(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"MORE",4)) {
- cmd_more();
- }
+ else if (!strncasecmp(cmdbuf,"ECHO",4)) {
+ cmd_echo(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"NETP",4)) {
- cmd_netp(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"OIMG",4)) {
+ cmd_oimg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"NDOP",4)) {
- cmd_ndop(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"MORE",4)) {
+ cmd_more();
+ }
- else if (!strncasecmp(cmdbuf,"NUOP",4)) {
- cmd_nuop(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"NETP",4)) {
+ cmd_netp(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LFLR",4)) {
- cmd_lflr();
- }
+ else if (!strncasecmp(cmdbuf,"NDOP",4)) {
+ cmd_ndop(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"CFLR",4)) {
- cmd_cflr(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"NUOP",4)) {
+ cmd_nuop(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"KFLR",4)) {
- cmd_kflr(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LFLR",4)) {
+ cmd_lflr();
+ }
- else if (!strncasecmp(cmdbuf,"EFLR",4)) {
- cmd_eflr(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"CFLR",4)) {
+ cmd_cflr(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"IDEN",4)) {
- cmd_iden(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"KFLR",4)) {
+ cmd_kflr(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"IPGM",4)) {
- cmd_ipgm(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"EFLR",4)) {
+ cmd_eflr(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"EBIO",4)) {
- cmd_ebio();
- }
+ else if (!strncasecmp(cmdbuf,"IDEN",4)) {
+ cmd_iden(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"RBIO",4)) {
- cmd_rbio(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"IPGM",4)) {
+ cmd_ipgm(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"LBIO",4)) {
- cmd_lbio();
- }
+ else if (!strncasecmp(cmdbuf,"EBIO",4)) {
+ cmd_ebio();
+ }
- else if (!strncasecmp(cmdbuf,"STEL",4)) {
- cmd_stel(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"RBIO",4)) {
+ cmd_rbio(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"TERM",4)) {
- cmd_term(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"LBIO",4)) {
+ cmd_lbio();
+ }
- else if (!strncasecmp(cmdbuf,"DOWN",4)) {
- cmd_down();
- }
+ else if (!strncasecmp(cmdbuf,"STEL",4)) {
+ cmd_stel(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf,"SCDN",4)) {
- cmd_scdn(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"TERM",4)) {
+ cmd_term(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "NSET", 4)) {
- cmd_nset(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"DOWN",4)) {
+ cmd_down();
+ }
- else if (!strncasecmp(cmdbuf, "UIMG", 4)) {
- cmd_uimg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf,"SCDN",4)) {
+ cmd_scdn(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "UCHG", 4)) {
- cmd_uchg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "NSET", 4)) {
+ cmd_nset(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "TIME", 4)) {
- cmd_time();
- }
+ else if (!strncasecmp(cmdbuf, "UIMG", 4)) {
+ cmd_uimg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "HCHG", 4)) {
- cmd_hchg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "UCHG", 4)) {
+ cmd_uchg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "RCHG", 4)) {
- cmd_rchg(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "TIME", 4)) {
+ cmd_time();
+ }
- else if (!strncasecmp(cmdbuf, "AGUP", 4)) {
- cmd_agup(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "HCHG", 4)) {
+ cmd_hchg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "ASUP", 4)) {
- cmd_asup(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "RCHG", 4)) {
+ cmd_rchg(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "GPEX", 4)) {
- cmd_gpex(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "AGUP", 4)) {
+ cmd_agup(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "SPEX", 4)) {
- cmd_spex(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "ASUP", 4)) {
+ cmd_asup(&cmdbuf[5]);
+ }
- else if (!strncasecmp(cmdbuf, "CONF", 4)) {
- cmd_conf(&cmdbuf[5]);
- }
+ else if (!strncasecmp(cmdbuf, "GPEX", 4)) {
+ cmd_gpex(&cmdbuf[5]);
+ }
-#ifdef DEBUG_MEMORY_LEAKS
- else if (!strncasecmp(cmdbuf, "LEAK", 4)) {
- dump_tracked();
- }
-#endif
+ else if (!strncasecmp(cmdbuf, "SPEX", 4)) {
+ cmd_spex(&cmdbuf[5]);
+ }
- else if (!DLoader_Exec_Cmd(cmdbuf))
- {
- cprintf("%d Unrecognized or unsupported command.\n",
- ERROR);
- }
+ else if (!strncasecmp(cmdbuf, "CONF", 4)) {
+ cmd_conf(&cmdbuf[5]);
+ }
- /* Run any after-each-command outines registered by modules */
- PerformSessionHooks(EVT_CMD);
+#ifdef DEBUG_MEMORY_LEAKS
+ else if (!strncasecmp(cmdbuf, "LEAK", 4)) {
+ dump_tracked();
+ }
+#endif
- } while(strncasecmp(cmdbuf, "QUIT", 4));
+ else if (!DLoader_Exec_Cmd(cmdbuf))
+ {
+ cprintf("%d Unrecognized or unsupported command.\n",
+ ERROR);
+ }
- cleanup(EXIT_NORMAL);
- return(NULL);
- }
+ /* Run any after-each-command outines registered by modules */
+ PerformSessionHooks(EVT_CMD);
+}
int verbosity = 9; /* Logging level */
struct CitContext masterCC;
-
+int rescan[2]; /* The Rescan Pipe */
/*
* lprintf() ... Write logging information
*/
void begin_critical_section(int which_one)
{
-#ifdef HAVE_PTHREAD_CANCEL
- int oldval;
-#else
- sigset_t set;
-#endif
-
- /* lprintf(8, "begin_critical_section(%d)\n", which_one); */
-
- if (!pthread_equal(pthread_self(), main_thread_id)) {
- /* Keep a count of how many critical sections this thread has
- * open, so that end_critical_section() doesn't enable
- * cancellation prematurely. */
- if (CC != NULL) CC->n_crit++;
-#ifdef HAVE_PTHREAD_CANCEL
- /* Don't get interrupted during the critical section */
- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldval);
-#else
- /* We're faking cancellation with signals. Block SIGUSR1 while
- * we're in the critical section. */
- sigemptyset(&set);
- sigaddset(&set, SIGUSR1);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-#endif
- }
-
- /* Obtain a semaphore */
pthread_mutex_lock(&Critters[which_one]);
-
- }
+}
/*
* Release a semaphore lock to end a critical section.
*/
void end_critical_section(int which_one)
{
-#ifdef HAVE_PTHREAD_CANCEL
- int oldval;
-#else
- sigset_t set;
-#endif
-
- /* lprintf(8, " end_critical_section(%d)\n", which_one); */
-
- /* Let go of the semaphore */
pthread_mutex_unlock(&Critters[which_one]);
-
- if (!pthread_equal(pthread_self(), main_thread_id))
- if (CC != NULL)
- if (!--CC->n_crit) {
-#ifdef HAVE_PTHREAD_CANCEL
- /* If a cancel was sent during the critical section, do it now.
- * Then re-enable thread cancellation.
- */
- pthread_testcancel();
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldval);
- pthread_testcancel();
-#else
- /* We're faking it. Unblock SIGUSR1; signals sent during the
- * critical section should now be able to kill us. */
- sigemptyset(&set);
- sigaddset(&set, SIGUSR1);
- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-#endif
- }
-
- }
+}
}
-/*
- * Return a pointer to a thread's own CitContext structure (old)
- * NOTE: this version of MyContext() is commented out because it is no longer
- * in use. It was written before I discovered TSD keys. This
- * version pounds through the context list until it finds the one matching
- * the currently running thread. It remains here, commented out, in case it
- * is needed for future ports to threading libraries which have the equivalent
- * of pthread_self() but not pthread_key_create() and its ilk.
- *
- * struct CitContext *MyContext() {
- * struct CitContext *ptr;
- * THREAD me;
- *
- * me = pthread_self();
- * for (ptr=ContextList; ptr!=NULL; ptr=ptr->next) {
- * if (ptr->mythread == me) return(ptr);
- * }
- * return(NULL);
- * }
- */
/*
* Return a pointer to a thread's own CitContext structure (new)
me = (struct CitContext *) mallok(sizeof(struct CitContext));
if (me == NULL) {
lprintf(1, "citserver: can't allocate memory!!\n");
- pthread_exit(NULL);
+ return NULL;
}
memset(me, 0, sizeof(struct CitContext));
+ /* 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;
+
begin_critical_section(S_SESSION_TABLE);
me->next = ContextList;
ContextList = me;
return(me);
}
-/*
- * Add a thread's thread ID to the context
- */
-void InitMyContext(struct CitContext *con)
-{
-#ifdef HAVE_PTHREAD_CANCEL
- int oldval;
-#endif
-
- con->mythread = pthread_self();
-#ifdef HAVE_PTHREAD_CANCEL
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldval);
- pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldval);
-#endif
- if (pthread_setspecific(MyConKey, (void *)con) != 0) {
- lprintf(1, "ERROR! pthread_setspecific() failed: %s\n",
- strerror(errno));
- }
- }
-
/*
* Remove a context from the context list.
*/
while(len<bytes) {
FD_ZERO(&rfds);
FD_SET(CC->client_socket, &rfds);
- tv.tv_sec = timeout;
+ tv.tv_sec = 1;
tv.tv_usec = 0;
retval = select( (CC->client_socket)+1,
&rfds, NULL, NULL, &tv);
+
if (FD_ISSET(CC->client_socket, &rfds) == 0) {
return(0);
}
close(msock);
}
-/*
- * Cleanup routine to be called when one thread is shutting down.
- */
-void cleanup(int exit_code)
-{
- /* Terminate the thread.
- * Its cleanup handler will call cleanup_stuff()
- */
- lprintf(7, "Calling pthread_exit()\n");
- pthread_exit(NULL);
- }
/*
* Terminate another session.
*/
void kill_session(int session_to_kill) {
struct CitContext *ptr;
- THREAD killme = 0;
begin_critical_section(S_SESSION_TABLE);
for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
if (ptr->cs_pid == session_to_kill) {
- killme = ptr->mythread;
+ ptr->state = CON_DYING;
}
}
end_critical_section(S_SESSION_TABLE);
-
- if (killme != 0) {
-#ifdef HAVE_PTHREAD_CANCEL
- pthread_cancel(killme);
-#else
- pthread_kill(killme, SIGUSR1);
-#ifdef __FreeBSD__
- /* there's a very stupid bug in the user threads package on
- FreeBSD 3.1 which prevents a signal from being properly
- dispatched to a thread that's in a blocking syscall. the
- first signal interrupts the syscall, the second one actually
- gets delivered. */
- pthread_kill(killme, SIGUSR1);
-#endif
-#endif
- }
}
-/*
- * The system-dependent wrapper around the main context loop.
- */
-void *sd_context_loop(struct CitContext *con) {
- pthread_cleanup_push(*cleanup_stuff, NULL);
- context_loop(con);
- pthread_cleanup_pop(0);
- return NULL;
- }
/*
*/
int main(int argc, char **argv)
{
- struct sockaddr_in fsin; /* Data for master socket */
- int alen; /* Data for master socket */
- int ssock; /* Descriptor for master socket */
- THREAD SessThread; /* Thread descriptor */
THREAD HousekeepingThread; /* Thread descriptor */
pthread_attr_t attr; /* Thread attributes */
- struct CitContext *con; /* Temporary context pointer */
char tracefile[128]; /* Name of file to log traces to */
int a, i; /* General-purpose variables */
- fd_set readfds;
- struct timeval tv;
struct passwd *pw;
int drop_root_perms = 1;
char *moddir;
strerror(errno));
}
- /*
- * Endless loop. Listen on the master socket. When a connection
- * comes in, create a socket, a context, and a thread.
- */
+
+ /*
+ * The rescan pipe exists so that worker threads can be woken up and
+ * told to re-scan the context list for fd's to listen on. This is
+ * necessary, for example, when a context is about to go idle and needs
+ * to get back on that list.
+ */
+ if (pipe(rescan)) {
+ lprintf(1, "Can't create rescan pipe!\n");
+ exit(errno);
+ }
+
+ /*
+ * Now create a bunch of worker threads.
+ */
+ for (i=0; i<(NUM_WORKER_THREADS-1); ++i) {
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (pthread_create(&HousekeepingThread, &attr,
+ (void* (*)(void*)) worker_thread, NULL) != 0) {
+ lprintf(1, "Can't create worker thead: %s\n",
+ strerror(errno));
+ }
+ }
+
+ /* Now this thread can become a worker as well. */
+ worker_thread();
+
+ return(0);
+}
+
+
+
+
+
+
+
+/*
+ * This loop just keeps going and going and going...
+ */
+void worker_thread(void) {
+ int i;
+ char junk;
+ int numselect = 0;
+ int highest;
+ struct CitContext *ptr;
+ struct CitContext *bind_me = NULL;
+ fd_set readfds;
+ int retval;
+ struct CitContext *con= NULL; /* Temporary context pointer */
+ struct sockaddr_in fsin; /* Data for master socket */
+ int alen; /* Data for master socket */
+ int ssock; /* Descriptor for master socket */
+
while (!time_to_die) {
- /* we need to check if a signal has been delivered. because
- * syscalls may be restartable across signals, we call
- * select with a timeout of 1 second and repeatedly check for
- * time_to_die... */
+
+ /*
+ * In a stupid environment, we would have all idle threads
+ * calling select() and then they'd all wake up at once. We
+ * solve this problem by putting the select() in a critical
+ * section, so only one thread has the opportunity to wake
+ * up. If we wake up on the master socket, create a new
+ * session context; otherwise, just bind the thread to the
+ * context we want and go on our merry way.
+ */
+
+ begin_critical_section(S_I_WANNA_SELECT);
+ lprintf(9, "Worker thread %2d woke up\n", getpid());
+
+SETUP_FD:
FD_ZERO(&readfds);
FD_SET(msock, &readfds);
- tv.tv_sec = 1;
- tv.tv_usec = 0;
- if (select(msock + 1, &readfds, NULL, NULL, &tv) <= 0)
- continue;
- alen = sizeof fsin;
- ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
- if (ssock < 0) {
- lprintf(2, "citserver: accept() failed: %s\n",
- strerror(errno));
+ highest = msock;
+ FD_SET(rescan[0], &readfds);
+ if (rescan[0] > highest) highest = rescan[0];
+ numselect = 2;
+
+ begin_critical_section(S_SESSION_TABLE);
+ for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
+ if (ptr->state == CON_IDLE) {
+ FD_SET(ptr->client_socket, &readfds);
+ if (ptr->client_socket > highest)
+ highest = ptr->client_socket;
+ ++numselect;
}
- else {
- lprintf(7, "citserver: Client socket %d\n", ssock);
- con = CreateNewContext();
- con->client_socket = ssock;
-
- /* Set the SO_REUSEADDR socket option */
- i = 1;
- setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
- &i, sizeof(i));
-
- /* set attributes for the new thread */
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr,
- PTHREAD_CREATE_DETACHED);
-
- /* now create the thread */
- if (pthread_create(&SessThread, &attr,
- (void* (*)(void*)) sd_context_loop,
- con)
- != 0) {
- lprintf(1,
- "citserver: can't create thread: %s\n",
+ }
+ end_critical_section(S_SESSION_TABLE);
+
+ lprintf(9, "Thread %2d can wake up on %d different fd's\n",
+ getpid(), numselect);
+ retval = select(highest + 1, &readfds, NULL, NULL, NULL);
+ lprintf(9, "select() returned %d\n", retval);
+
+ /* Now figure out who made this select() unblock.
+ * First, check for an error or exit condition.
+ */
+ if (retval < 0) {
+ end_critical_section(S_I_WANNA_SELECT);
+ lprintf(9, "Exiting (%s)\n", errno);
+ time_to_die = 1;
+ }
+
+ /* Next, check to see if it's a new client connecting
+ * on the master socket.
+ */
+ else if (FD_ISSET(msock, &readfds)) {
+ lprintf(9, "It's the master socket!\n");
+ alen = sizeof fsin;
+ ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
+ if (ssock < 0) {
+ lprintf(2, "citserver: accept() failed: %s\n",
strerror(errno));
+ }
+ else {
+ lprintf(7, "citserver: New client socket %d\n",
+ ssock);
+
+ /* New context will be created already set up
+ * in the CON_EXECUTING state.
+ */
+ con = CreateNewContext();
+
+ /* Assign our new socket number to it. */
+ con->client_socket = ssock;
+
+ /* Set the SO_REUSEADDR socket option */
+ i = 1;
+ setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR,
+ &i, sizeof(i));
+
+ pthread_setspecific(MyConKey, (void *)con);
+ begin_session(con);
+ /* do_command_loop(); */
+ pthread_setspecific(MyConKey, (void *)NULL);
+ con->state = CON_IDLE;
+ goto SETUP_FD;
+ }
+ }
+
+ /* If the rescan pipe went active, someone is telling this
+ * thread that the &readfds needs to be refreshed with more
+ * current data.
+ */
+ else if (FD_ISSET(rescan[0], &readfds)) {
+ lprintf(9, "rescanning\n");
+ read(rescan[0], &junk, 1);
+ goto SETUP_FD;
+ }
+
+ /* It must be a client socket. Find a context that has data
+ * waiting on its socket *and* is in the CON_IDLE state.
+ */
+ else {
+ bind_me = NULL;
+ begin_critical_section(S_SESSION_TABLE);
+ for (ptr = ContextList;
+ ( (ptr != NULL) && (bind_me == NULL) );
+ ptr = ptr->next) {
+ if ( (FD_ISSET(ptr->client_socket, &readfds))
+ && (ptr->state == CON_IDLE) ) {
+ bind_me = con;
}
+ }
+ if (bind_me != NULL) {
+ /* Found one. Stake a claim to it before
+ * letting anyone else touch the context list.
+ */
+ bind_me->state = CON_EXECUTING;
+ }
+ end_critical_section(S_SESSION_TABLE);
+ end_critical_section(S_I_WANNA_SELECT);
+
+ /* We're bound to a session, now do *one* command */
+ if (bind_me != NULL) {
+ lprintf(9, "Binding thread to session %d\n",
+ bind_me->client_socket);
+ pthread_setspecific(MyConKey, (void *)bind_me);
+ do_command_loop();
+ pthread_setspecific(MyConKey, (void *)NULL);
+ if (bind_me->state == CON_DYING) {
+ RemoveContext(bind_me);
+ }
+ else {
+ bind_me->state = CON_IDLE;
+ }
+ write(rescan[1], &junk, 1);
+ }
+ else {
+ lprintf(9, "Thread %02d found nothing to do!\n",
+ getpid());
}
+
}
- master_cleanup();
- return 0;
+
}
+ pthread_exit(NULL);
+}
+