Index: libmilter/Makefile.m4 diff -pur libmilter-orig/Makefile.m4 libmilter/Makefile.m4 --- libmilter-orig/Makefile.m4 2006-07-30 16:11:14.000000000 +0300 +++ libmilter/Makefile.m4 2006-07-30 16:12:29.000000000 +0300 @@ -9,11 +9,11 @@ define(`confMT', `true') SMSRCDIR= ifdef(`confSMSRCDIR', `confSMSRCDIR', `${SRCDIR}/sendmail') PREPENDDEF(`confINCDIRS', `-I${SMSRCDIR} ') -bldPRODUCT_START(`library', `libmilter') +bldPRODUCT_START(`library', `libmilter-fork') define(`bldINSTALLABLE', `true') define(`LIBMILTER_EXTRAS', `errstring.c strl.c') APPENDDEF(`confENVDEF', `-DNOT_SENDMAIL -Dsm_snprintf=snprintf') -define(`bldSOURCES', `main.c engine.c listener.c handler.c comm.c smfi.c signal.c sm_gethost.c LIBMILTER_EXTRAS ') +define(`bldSOURCES', `main.c engine.c listener.c handler.c comm.c smfi.c sm_gethost.c LIBMILTER_EXTRAS ') define(`confBEFORE', `LIBMILTER_EXTRAS') bldPUSH_INSTALL_TARGET(`install-mfapi') bldPRODUCT_END Index: libmilter/handler.c diff -pur libmilter-orig/handler.c libmilter/handler.c --- libmilter-orig/handler.c 2006-07-30 16:11:14.000000000 +0300 +++ libmilter/handler.c 2006-07-30 16:12:29.000000000 +0300 @@ -13,7 +13,6 @@ SM_RCSID("@(#)$Id: handler.c,v 8.36 2003 #include "libmilter.h" - /* ** HANDLE_SESSION -- Handle a connected session in its own context ** @@ -34,15 +33,8 @@ mi_handle_session(ctx) return MI_FAILURE; ctx->ctx_id = (sthread_t) sthread_get_id(); - /* - ** Detach so resources are free when the thread returns. - ** If we ever "wait" for threads, this call must be removed. - */ - - if (pthread_detach(ctx->ctx_id) != 0) - ret = MI_FAILURE; - else - ret = mi_engine(ctx); + ret = mi_engine(ctx); + if (ValidSocket(ctx->ctx_sd)) { (void) closesocket(ctx->ctx_sd); Index: libmilter/libmilter.h diff -pur libmilter-orig/libmilter.h libmilter/libmilter.h --- libmilter-orig/libmilter.h 2006-07-30 16:11:14.000000000 +0300 +++ libmilter/libmilter.h 2006-07-30 16:12:29.000000000 +0300 @@ -39,15 +39,7 @@ SM_IDSTR(MilterlId, "@(#)$Id: libmilter. # define MI_SOCK_READ_FAIL(x) ((x) < 0) # define MI_SOCK_WRITE(s, b, l) write(s, b, l) -# define thread_create(ptid,wr,arg) pthread_create(ptid, NULL, wr, arg) -# define sthread_get_id() pthread_self() - -typedef pthread_mutex_t smutex_t; -# define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) -# define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) -# define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) -# define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) -# define smutex_trylock(mp) (pthread_mutex_trylock(mp) == 0) +# define sthread_get_id() getpid() #if SM_CONF_POLL Index: libmilter/listener.c diff -pur libmilter-orig/listener.c libmilter/listener.c --- libmilter-orig/listener.c 2006-07-30 16:11:14.000000000 +0300 +++ libmilter/listener.c 2006-07-30 17:10:53.000000000 +0300 @@ -12,7 +12,7 @@ SM_RCSID("@(#)$Id$") /* -** listener.c -- threaded network listener +** listener.c -- a network listener */ #include "libmilter.h" @@ -26,7 +26,6 @@ SM_RCSID("@(#)$Id: listener.c,v 8.115 20 # include # endif /* NETINET || NETINET6 */ -static smutex_t L_Mutex; static int L_family; static SOCKADDR_LEN_T L_socksize; static socket_t listenfd = INVALID_SOCKET; @@ -69,15 +68,12 @@ mi_opensocket(conn, backlog, dbg, rmsock "%s: Opening listen socket on conn %s", smfi->xxfi_name, conn); } - (void) smutex_init(&L_Mutex); - (void) smutex_lock(&L_Mutex); listenfd = mi_milteropen(conn, backlog, rmsocket, smfi->xxfi_name); if (!ValidSocket(listenfd)) { smi_log(SMI_LOG_FATAL, "%s: Unable to create listening socket on conn %s", smfi->xxfi_name, conn); - (void) smutex_unlock(&L_Mutex); return MI_FAILURE; } #if !SM_CONF_POLL @@ -85,11 +81,9 @@ mi_opensocket(conn, backlog, dbg, rmsock { smi_log(SMI_LOG_ERR, "%s: fd %d is larger than FD_SETSIZE %d", smfi->xxfi_name, listenfd, FD_SETSIZE); - (void) smutex_unlock(&L_Mutex); return MI_FAILURE; } #endif /* !SM_CONF_POLL */ - (void) smutex_unlock(&L_Mutex); return MI_SUCCESS; } @@ -549,22 +543,6 @@ mi_milteropen(conn, backlog, rmsocket, n L_family = addr.sa.sa_family; return sock; } -/* -** MI_THREAD_HANDLE_WRAPPER -- small wrapper to handle session -** -** Parameters: -** arg -- argument to pass to mi_handle_session() -** -** Returns: -** results from mi_handle_session() -*/ - -static void * -mi_thread_handle_wrapper(arg) - void *arg; -{ - return (void *) mi_handle_session(arg); -} /* ** MI_CLOSENER -- close listen socket @@ -579,7 +557,6 @@ mi_thread_handle_wrapper(arg) void mi_closener() { - (void) smutex_lock(&L_Mutex); if (ValidSocket(listenfd)) { #if NETUNIX @@ -624,7 +601,6 @@ mi_closener() } #endif /* NETUNIX */ } - (void) smutex_unlock(&L_Mutex); } /* @@ -693,6 +669,23 @@ mi_closener() #else /* BROKEN_PTHREAD_SLEEP */ # define MI_SLEEP(s) sleep((s)) #endif /* BROKEN_PTHREAD_SLEEP */ + +int +start_subprocess(int (*handler)(SMFICTX_PTR ctx), SMFICTX_PTR ctx) +{ + pid_t pid = fork(); + if (pid == -1) + return -1; + if (pid != 0) + return 0; + + /* Child */ + close(listenfd); + listenfd = INVALID_SOCKET; + reset_signals(); + exit(handler(ctx)); +} + int mi_listener(conn, dbg, smfi, timeout, backlog) @@ -714,7 +707,6 @@ mi_listener(conn, dbg, smfi, timeout, ba int acnt = 0; /* error count for accept() failures */ int scnt = 0; /* error count for select() failures */ int save_errno = 0; - sthread_t thread_id; _SOCK_ADDR cliaddr; SOCKADDR_LEN_T clilen; SMFICTX_PTR ctx; @@ -727,14 +719,12 @@ mi_listener(conn, dbg, smfi, timeout, ba clilen = L_socksize; while ((mistop = mi_stop()) == MILTER_CONT) { - (void) smutex_lock(&L_Mutex); if (!ValidSocket(listenfd)) { ret = MI_FAILURE; smi_log(SMI_LOG_ERR, "%s: listenfd=%d corrupted, terminating, errno=%d", smfi->xxfi_name, listenfd, errno); - (void) smutex_unlock(&L_Mutex); break; } @@ -745,13 +735,11 @@ mi_listener(conn, dbg, smfi, timeout, ba r = FD_RD_READY(listenfd, rds, excs, &chktime); if (r == 0) /* timeout */ { - (void) smutex_unlock(&L_Mutex); continue; /* just check mi_stop() */ } if (r < 0) { save_errno = errno; - (void) smutex_unlock(&L_Mutex); if (save_errno == EINTR) continue; scnt++; @@ -771,7 +759,6 @@ mi_listener(conn, dbg, smfi, timeout, ba { /* some error: just stop for now... */ ret = MI_FAILURE; - (void) smutex_unlock(&L_Mutex); smi_log(SMI_LOG_ERR, "%s: %s() returned exception for socket, abort", smfi->xxfi_name, MI_POLLSELECT); @@ -783,7 +770,6 @@ mi_listener(conn, dbg, smfi, timeout, ba connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); save_errno = errno; - (void) smutex_unlock(&L_Mutex); /* ** If remote side closes before @@ -920,18 +906,18 @@ mi_listener(conn, dbg, smfi, timeout, ba if (smfi->xxfi_body == NULL) ctx->ctx_pflags |= SMFIP_NOBODY; - if ((r = thread_create(&thread_id, - mi_thread_handle_wrapper, - (void *) ctx)) != 0) + r = start_subprocess(mi_handle_session, ctx); + (void) closesocket(connfd); + free(ctx); + + if (r != 0) { tcnt++; smi_log(SMI_LOG_ERR, - "%s: thread_create() failed: %d, %s", - smfi->xxfi_name, r, + "%s: start_subprocess() failed: %d, %s", + smfi->xxfi_name, errno, tcnt >= MAX_FAILS_T ? "abort" : "try again"); MI_SLEEP(tcnt); - (void) closesocket(connfd); - free(ctx); if (tcnt >= MAX_FAILS_T) { ret = MI_FAILURE; @@ -950,6 +936,7 @@ mi_listener(conn, dbg, smfi, timeout, ba smfi->xxfi_name, mistop); mi_closener(); } - (void) smutex_destroy(&L_Mutex); return ret; } + + Index: libmilter/main.c diff -pur libmilter-orig/main.c libmilter/main.c --- libmilter-orig/main.c 2006-07-30 16:11:14.000000000 +0300 +++ libmilter/main.c 2006-07-30 16:12:29.000000000 +0300 @@ -15,7 +15,8 @@ SM_RCSID("@(#)$Id: main.c,v 8.79 2003/10 #include "libmilter.h" #include #include - +#include +#include static smfiDesc_ptr smfi = NULL; @@ -200,6 +201,76 @@ smfi_setbacklog(obacklog) return MI_SUCCESS; } +static int MilterStop = MILTER_CONT; + +int +mi_stop() +{ + return MilterStop; +} + +void +mi_stop_milters(int v) +{ + if (MilterStop < v) + MilterStop = v; + mi_closener(); + kill(0, SIGKILL); + /* FIXME: Wait for subprocesses to finish? */ +} + +static void +sig_stop(sig) + int sig; +{ + MilterStop = MILTER_STOP; +} + +static void +sig_child(sig) + int sig; +{ + pid_t pid; + int status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + if (WIFEXITED(status)) { + if (WEXITSTATUS(status)) + smi_log(SMI_LOG_WARN, + "Child %lu exited with status %d", + (unsigned long) pid, + WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) + smi_log(SMI_LOG_WARN, + "Child %lu terminated on signal %d", + WTERMSIG(status)); + else + smi_log(SMI_LOG_WARN, + "Child %lu terminated, reason unknown", + WTERMSIG(status)); + } + signal (sig, sig_child); +} + +void +setup_signals() +{ + signal(SIGPIPE, SIG_IGN); + signal(SIGCHLD, sig_child); + signal(SIGHUP, sig_stop); + signal(SIGTERM, sig_stop); + signal(SIGINT, sig_stop); +} + +void +reset_signals() +{ + signal(SIGPIPE, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGINT, SIG_DFL); +} /* ** SMFI_MAIN -- setup milter connnection and start listener. @@ -216,7 +287,9 @@ smfi_main() { int r; - (void) signal(SIGPIPE, SIG_IGN); + setup_signals(); + setsid(); + if (conn == NULL) { smi_log(SMI_LOG_FATAL, "%s: missing connection information", @@ -224,14 +297,6 @@ smfi_main() return MI_FAILURE; } - (void) atexit(mi_clean_signals); - if (mi_control_startup(smfi->xxfi_name) != MI_SUCCESS) - { - smi_log(SMI_LOG_FATAL, - "%s: Couldn't start signal thread", - smfi->xxfi_name); - return MI_FAILURE; - } r = MI_SUCCESS; /* Startup the listener */