From 59e68c837eaa393a3fa0bb979b9b1da23a93e841 Mon Sep 17 00:00:00 2001 From: jongfoster Date: Sat, 16 Mar 2002 23:54:06 +0000 Subject: [PATCH 1/1] Adding graceful termination feature, to help look for memory leaks. If you enable this (which, by design, has to be done by hand editing config.h) and then go to http://i.j.b/die, then the program will exit cleanly after the *next* request. It should free all the memory that was used. --- actions.c | 33 ++++++++++++++++++++++++-- actions.h | 8 ++++++- cgi.c | 10 +++++++- cgisimple.c | 47 ++++++++++++++++++++++++++++++++++++- cgisimple.h | 11 ++++++++- jcc.c | 52 +++++++++++++++++++++++++++++++++++++++-- jcc.h | 9 ++++++- loadcfg.c | 29 ++++++++++++++++++++++- loadcfg.h | 13 ++++++++++- loaders.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++----- loaders.h | 11 ++++++++- 11 files changed, 272 insertions(+), 18 deletions(-) diff --git a/actions.c b/actions.c index e58b6a85..9e3f24d7 100644 --- a/actions.c +++ b/actions.c @@ -1,4 +1,4 @@ -const char actions_rcs[] = "$Id: actions.c,v 1.22 2002/01/21 00:27:02 jongfoster Exp $"; +const char actions_rcs[] = "$Id: actions.c,v 1.23 2002/03/07 03:46:16 oes Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actions.c,v $ @@ -33,6 +33,9 @@ const char actions_rcs[] = "$Id: actions.c,v 1.22 2002/01/21 00:27:02 jongfoster * * Revisions : * $Log: actions.c,v $ + * Revision 1.23 2002/03/07 03:46:16 oes + * Fixed compiler warnings + * * Revision 1.22 2002/01/21 00:27:02 jongfoster * Allowing free_action(NULL). * Moving the functions that #include actionlist.h to the end of the file, @@ -804,6 +807,33 @@ void free_current_action (struct current_action_spec *src) } +static struct file_list *current_actions_file = NULL; + + +#ifdef FEATURE_GRACEFUL_TERMINATION +/********************************************************************* + * + * Function : unload_current_actions_file + * + * Description : Unloads current actions file - reset to state at + * beginning of program. + * + * Parameters : None + * + * Returns : N/A + * + *********************************************************************/ +void unload_current_actions_file(void) +{ + if (current_actions_file) + { + current_actions_file->unloader = unload_actions_file; + current_actions_file = NULL; + } +} +#endif /* FEATURE_GRACEFUL_TERMINATION */ + + /********************************************************************* * * Function : unload_actions_file @@ -874,7 +904,6 @@ void free_alias_list(struct action_alias *alias_list) *********************************************************************/ int load_actions_file(struct client_state *csp) { - static struct file_list *current_actions_file = NULL; /* * Parser mode. diff --git a/actions.h b/actions.h index e2f99631..46758c0e 100644 --- a/actions.h +++ b/actions.h @@ -1,6 +1,6 @@ #ifndef ACTIONS_H_INCLUDED #define ACTIONS_H_INCLUDED -#define ACTIONS_H_VERSION "$Id: actions.h,v 1.5 2001/10/14 21:58:22 jongfoster Exp $" +#define ACTIONS_H_VERSION "$Id: actions.h,v 1.6 2001/10/23 21:30:30 jongfoster Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actions.h,v $ @@ -35,6 +35,9 @@ * * Revisions : * $Log: actions.h,v $ + * Revision 1.6 2001/10/23 21:30:30 jongfoster + * Adding error-checking to selected functions. + * * Revision 1.5 2001/10/14 21:58:22 jongfoster * Adding support for the CGI-based editor: * - Exported get_actions() @@ -112,6 +115,9 @@ extern jb_err get_action_token(char **line, char **name, char **value); extern void unload_actions_file(void *file_data); extern int load_actions_file(struct client_state *csp); +#ifdef FEATURE_GRACEFUL_TERMINATION +void unload_current_actions_file(void); +#endif /* Revision control strings from this header and associated .c file */ diff --git a/cgi.c b/cgi.c index e1960974..98d05cdc 100644 --- a/cgi.c +++ b/cgi.c @@ -1,4 +1,4 @@ -const char cgi_rcs[] = "$Id: cgi.c,v 1.48 2002/03/08 17:47:07 jongfoster Exp $"; +const char cgi_rcs[] = "$Id: cgi.c,v 1.49 2002/03/13 00:27:04 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgi.c,v $ @@ -38,6 +38,9 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.48 2002/03/08 17:47:07 jongfoster Exp $"; * * Revisions : * $Log: cgi.c,v $ + * Revision 1.49 2002/03/13 00:27:04 jongfoster + * Killing warnings + * * Revision 1.48 2002/03/08 17:47:07 jongfoster * Adding comments * @@ -330,6 +333,11 @@ static const struct cgi_dispatcher cgi_dispatchers[] = { { "", cgi_default, "Junkbuster main page" }, +#ifdef FEATURE_GRACEFUL_TERMINATION + { "die", + cgi_die, + "Shut down - Do not deploy this build in a production environment, this is a one click Denial Of Service attack!!!" }, +#endif { "show-status", cgi_show_status, "Show information about the current configuration" }, diff --git a/cgisimple.c b/cgisimple.c index 401065c2..1621baa2 100644 --- a/cgisimple.c +++ b/cgisimple.c @@ -1,4 +1,4 @@ -const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.17 2002/03/08 16:43:18 oes Exp $"; +const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.18 2002/03/12 01:44:49 oes Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgisimple.c,v $ @@ -36,6 +36,9 @@ const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.17 2002/03/08 16:43:18 oes Ex * * Revisions : * $Log: cgisimple.c,v $ + * Revision 1.18 2002/03/12 01:44:49 oes + * Changed default for "blocked" image from jb logo to checkboard pattern + * * Revision 1.17 2002/03/08 16:43:18 oes * Added choice beween GIF and PNG built-in images * @@ -253,6 +256,48 @@ jb_err cgi_error_404(struct client_state *csp, } +#ifdef FEATURE_GRACEFUL_TERMINATION +/********************************************************************* + * + * Function : cgi_die + * + * Description : CGI function to shut down JunkBuster. + * NOTE: Turning this on in a production build + * would be a BAD idea. An EXTREMELY BAD idea. + * In short, don't do it. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : rsp = http_response data structure for output + * 3 : parameters = map of cgi parameters + * + * CGI Parameters : none + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory error. + * + *********************************************************************/ +jb_err cgi_die (struct client_state *csp, + struct http_response *rsp, + const struct map *parameters) +{ + assert(csp); + assert(rsp); + assert(parameters); + + /* quit */ + g_terminate = 1; + + /* + * I don't really care what gets sent back to the browser. + * Take the easy option - "out of memory" page. + */ + + return JB_ERR_MEMORY; +} +#endif /* def FEATURE_GRACEFUL_TERMINATION */ + + /********************************************************************* * * Function : cgi_show_request diff --git a/cgisimple.h b/cgisimple.h index afa06cab..adb14f16 100644 --- a/cgisimple.h +++ b/cgisimple.h @@ -1,6 +1,6 @@ #ifndef CGISIMPLE_H_INCLUDED #define CGISIMPLE_H_INCLUDED -#define CGISIMPLE_H_VERSION "$Id: cgisimple.h,v 1.6 2002/03/07 03:48:59 oes Exp $" +#define CGISIMPLE_H_VERSION "$Id: cgisimple.h,v 1.7 2002/03/08 16:43:59 oes Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgisimple.h,v $ @@ -38,6 +38,9 @@ * * Revisions : * $Log: cgisimple.h,v $ + * Revision 1.7 2002/03/08 16:43:59 oes + * Renamed cgi_transparent_png to cgi_transparent_image + * * Revision 1.6 2002/03/07 03:48:59 oes * - Changed built-in images from GIF to PNG * (with regard to Unisys patent issue) @@ -107,6 +110,12 @@ extern jb_err cgi_transparent_image (struct client_state *csp, struct http_response *rsp, const struct map *parameters); +#ifdef FEATURE_GRACEFUL_TERMINATION +extern jb_err cgi_die (struct client_state *csp, + struct http_response *rsp, + const struct map *parameters); +#endif + /* Revision control strings from this header and associated .c file */ extern const char cgisimple_rcs[]; extern const char cgisimple_h_rcs[]; diff --git a/jcc.c b/jcc.c index bdb26a32..4e28e4f1 100644 --- a/jcc.c +++ b/jcc.c @@ -1,4 +1,4 @@ -const char jcc_rcs[] = "$Id: jcc.c,v 1.81 2002/03/12 01:42:50 oes Exp $"; +const char jcc_rcs[] = "$Id: jcc.c,v 1.82 2002/03/13 00:27:05 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.c,v $ @@ -33,6 +33,9 @@ const char jcc_rcs[] = "$Id: jcc.c,v 1.81 2002/03/12 01:42:50 oes Exp $"; * * Revisions : * $Log: jcc.c,v $ + * Revision 1.82 2002/03/13 00:27:05 jongfoster + * Killing warnings + * * Revision 1.81 2002/03/12 01:42:50 oes * Introduced modular filters * @@ -583,6 +586,9 @@ int urls_read = 0; /* total nr of urls read inc rejected */ int urls_rejected = 0; /* total nr of urls rejected */ #endif /* def FEATURE_STATISTICS */ +#ifdef FEATURE_GRACEFUL_TERMINATION +int g_terminate = 0; +#endif static void listen_loop(void); static void chat(struct client_state *csp); @@ -1974,7 +1980,11 @@ static void listen_loop(void) bfd = bind_port_helper(config); +#ifdef FEATURE_GRACEFUL_TERMINATION + while (!g_terminate) +#else for (;;) +#endif { #if !defined(FEATURE_PTHREAD) && !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) while (waitpid(-1, NULL, WNOHANG) > 0) @@ -2202,7 +2212,45 @@ static void listen_loop(void) serve(csp); } } - /* NOTREACHED */ + + /* NOTREACHED unless FEATURE_GRACEFUL_TERMINATION is defined */ + + /* Clean up. Aim: free all memory (no leaks) */ +#ifdef FEATURE_GRACEFUL_TERMINATION + + log_error(LOG_LEVEL_ERROR, "Graceful termination requested"); + + unload_current_config_file(); + unload_current_actions_file(); + unload_current_re_filterfile(); +#ifdef FEATURE_TRUST + unload_current_trust_file(); +#endif + + if (config->multi_threaded) + { + int i = 60; + do + { + sleep(1); + sweep(); + } while ((clients->next != NULL) && (--i > 0)); + + if (i <= 0) + { + log_error(LOG_LEVEL_ERROR, "Graceful termination failed - still some live clients after 1 minute wait."); + } + } + sweep(); + sweep(); + +#if defined(_WIN32) && !defined(_WIN_CONSOLE) + /* Cleanup - remove taskbar icon etc. */ + TermLogWindow(); +#endif + + exit(0); +#endif /* FEATURE_GRACEFUL_TERMINATION */ } diff --git a/jcc.h b/jcc.h index c233a1a0..15784400 100644 --- a/jcc.h +++ b/jcc.h @@ -1,6 +1,6 @@ #ifndef JCC_H_INCLUDED #define JCC_H_INCLUDED -#define JCC_H_VERSION "$Id: jcc.h,v 1.8 2002/03/04 18:19:49 oes Exp $" +#define JCC_H_VERSION "$Id: jcc.h,v 1.9 2002/03/07 03:52:44 oes Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/jcc.h,v $ @@ -35,6 +35,9 @@ * * Revisions : * $Log: jcc.h,v $ + * Revision 1.9 2002/03/07 03:52:44 oes + * Set logging to tty for --no-daemon mode + * * Revision 1.8 2002/03/04 18:19:49 oes * Added extern const char *pidfile * @@ -98,6 +101,10 @@ extern const char *pidfile; #endif extern int no_daemon; +#ifdef FEATURE_GRACEFUL_TERMINATION +extern int g_terminate; +#endif + /* Functions */ #ifdef __MINGW32__ diff --git a/loadcfg.c b/loadcfg.c index 98814659..77b12d39 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -1,4 +1,4 @@ -const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.35 2002/03/07 03:52:44 oes Exp $"; +const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.36 2002/03/13 00:27:05 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.c,v $ @@ -35,6 +35,9 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.35 2002/03/07 03:52:44 oes Exp $" * * Revisions : * $Log: loadcfg.c,v $ + * Revision 1.36 2002/03/13 00:27:05 jongfoster + * Killing warnings + * * Revision 1.35 2002/03/07 03:52:44 oes * Set logging to tty for --no-daemon mode * @@ -455,6 +458,30 @@ void unload_configfile (void * data) } +#ifdef FEATURE_GRACEFUL_TERMINATION +/********************************************************************* + * + * Function : unload_current_config_file + * + * Description : Unloads current config file - reset to state at + * beginning of program. + * + * Parameters : None + * + * Returns : N/A + * + *********************************************************************/ +void unload_current_config_file(void) +{ + if (current_configfile) + { + current_configfile->unloader = unload_configfile; + current_configfile = NULL; + } +} +#endif + + /********************************************************************* * * Function : load_config diff --git a/loadcfg.h b/loadcfg.h index 5c7e2f00..85c3ab66 100644 --- a/loadcfg.h +++ b/loadcfg.h @@ -1,6 +1,6 @@ #ifndef LOADCFG_H_INCLUDED #define LOADCFG_H_INCLUDED -#define LOADCFG_H_VERSION "$Id: loadcfg.h,v 1.7 2001/07/30 22:08:36 jongfoster Exp $" +#define LOADCFG_H_VERSION "$Id: loadcfg.h,v 1.8 2001/12/30 14:07:32 steudten Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loadcfg.h,v $ @@ -37,6 +37,14 @@ * * Revisions : * $Log: loadcfg.h,v $ + * Revision 1.8 2001/12/30 14:07:32 steudten + * - Add signal handling (unix) + * - Add SIGHUP handler (unix) + * - Add creation of pidfile (unix) + * - Add action 'top' in rc file (RH) + * - Add entry 'SIGNALS' to manpage + * - Add exit message to logfile (unix) + * * Revision 1.7 2001/07/30 22:08:36 jongfoster * Tidying up #defines: * - All feature #defines are now of the form FEATURE_xxx @@ -150,6 +158,9 @@ extern short int MustReload; extern struct configuration_spec * load_config(void); +#ifdef FEATURE_GRACEFUL_TERMINATION +void unload_current_config_file(void); +#endif /* Revision control strings from this header and associated .c file */ extern const char loadcfg_rcs[]; diff --git a/loaders.c b/loaders.c index 5a81363c..a2dd8047 100644 --- a/loaders.c +++ b/loaders.c @@ -1,4 +1,4 @@ -const char loaders_rcs[] = "$Id: loaders.c,v 1.43 2002/03/16 20:28:34 oes Exp $"; +const char loaders_rcs[] = "$Id: loaders.c,v 1.44 2002/03/16 21:51:00 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loaders.c,v $ @@ -35,6 +35,9 @@ const char loaders_rcs[] = "$Id: loaders.c,v 1.43 2002/03/16 20:28:34 oes Exp $" * * Revisions : * $Log: loaders.c,v $ + * Revision 1.44 2002/03/16 21:51:00 jongfoster + * Fixing free(NULL). + * * Revision 1.43 2002/03/16 20:28:34 oes * Added descriptions to the filters so users will know what they select in the cgi editor * @@ -948,18 +951,46 @@ char *read_config_line(char *buf, size_t buflen, FILE *fp, unsigned long *linenu *********************************************************************/ static void unload_trustfile(void *f) { - struct block_spec *b = (struct block_spec *)f; - if (b == NULL) return; + struct block_spec *cur = (struct block_spec *)f; + struct block_spec *next; - unload_trustfile(b->next); /* Stack is cheap, isn't it? */ + while (cur != NULL) + { + next = cur->next; - free_url_spec(b->url); + free_url_spec(cur->url); + free(cur); - freez(b); + cur = next; + } } +#ifdef FEATURE_GRACEFUL_TERMINATION +/********************************************************************* + * + * Function : unload_current_trust_file + * + * Description : Unloads current trust file - reset to state at + * beginning of program. + * + * Parameters : None + * + * Returns : N/A + * + *********************************************************************/ +void unload_current_trust_file(void) +{ + if (current_trustfile) + { + current_trustfile->unloader = unload_trustfile; + current_trustfile = NULL; + } +} +#endif /* FEATURE_GRACEFUL_TERMINATION */ + + /********************************************************************* * * Function : load_trustfile @@ -1133,6 +1164,30 @@ static void unload_re_filterfile(void *f) } +#ifdef FEATURE_GRACEFUL_TERMINATION +/********************************************************************* + * + * Function : unload_current_re_filterfile + * + * Description : Unloads current re_filter file - reset to state at + * beginning of program. + * + * Parameters : None + * + * Returns : N/A + * + *********************************************************************/ +void unload_current_re_filterfile(void) +{ + if (current_re_filterfile) + { + current_re_filterfile->unloader = unload_re_filterfile; + current_re_filterfile = NULL; + } +} +#endif + + /********************************************************************* * * Function : load_re_filterfile diff --git a/loaders.h b/loaders.h index 0637f7c6..8b6e29b0 100644 --- a/loaders.h +++ b/loaders.h @@ -1,6 +1,6 @@ #ifndef LOADERS_H_INCLUDED #define LOADERS_H_INCLUDED -#define LOADERS_H_VERSION "$Id: loaders.h,v 1.15 2002/01/22 23:46:18 jongfoster Exp $" +#define LOADERS_H_VERSION "$Id: loaders.h,v 1.16 2002/03/07 03:46:17 oes Exp $" /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/loaders.h,v $ @@ -37,6 +37,9 @@ * * Revisions : * $Log: loaders.h,v $ + * Revision 1.16 2002/03/07 03:46:17 oes + * Fixed compiler warnings + * * Revision 1.15 2002/01/22 23:46:18 jongfoster * Moving edit_read_line() and simple_read_line() to loaders.c, and * extending them to support reading MS-DOS, Mac and UNIX style files @@ -193,6 +196,12 @@ extern int load_re_filterfile(struct client_state *csp); extern int load_trustfile(struct client_state *csp); #endif /* def FEATURE_TRUST */ +#ifdef FEATURE_GRACEFUL_TERMINATION +#ifdef FEATURE_TRUST +void unload_current_trust_file(void); +#endif +void unload_current_re_filterfile(void); +#endif /* FEATURE_GRACEFUL_TERMINATION */ extern void add_loader(int (*loader)(struct client_state *), -- 2.39.2