Back to index

courier  0.68.2
perlfilter.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2000-2002 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 #include      <stdio.h>
00006 #include      "courier.h"
00007 
00008 #if    HAVE_UNISTD_H
00009 #include      <unistd.h>
00010 #endif
00011 #include      <sys/types.h>
00012 #include      <sys/stat.h>
00013 #if TIME_WITH_SYS_TIME
00014 #include      <sys/time.h>
00015 #include      <time.h>
00016 #else
00017 #if HAVE_SYS_TIME_H
00018 #include      <sys/time.h>
00019 #else
00020 #include      <time.h>
00021 #endif
00022 #endif
00023 #include      "libfilter/libfilter.h"
00024 #include      "filtersocketdir.h"
00025 #include      "waitlib/waitlib.h"
00026 #include      "wrapperpl.h"
00027 
00028 
00029 int listen_sock;     /* Filter connection socket */
00030 char *filter; /* The Perl filter */
00031 
00032 unsigned nchildren=5;       /* Number of child perlfilter processes */
00033 pid_t  *children;
00034 
00035 /*
00036 ** This is, basically, persistent.c from perlembed, with a couple of changes
00037 */
00038 
00039 #undef PACKAGE
00040 #undef VERSION
00041 
00042 #include "xsinit.c"
00043  
00044 static void perlfilter()
00045 {
00046 char *embedding[] = { "", WRAPPERPL };
00047 char *args[] = { "", "0", NULL, NULL, NULL};
00048 int exitstatus = 0;
00049 int    sock;
00050 PerlInterpreter *my_perl;
00051  
00052        if((my_perl = perl_alloc()) == NULL)
00053        {
00054               fprintf(stderr, "no memory!");
00055               exit(1);
00056        }
00057        perl_construct(my_perl);
00058  
00059        exitstatus = perl_parse(my_perl, xs_init, 2, embedding, NULL);
00060  
00061        if (exitstatus || (exitstatus=perl_run(my_perl)) != 0)
00062        {
00063               fprintf(stderr, "Cannot parse " WRAPPERPL "\n");
00064               exit(exitstatus);
00065        }
00066 
00067        while ((sock=lf_accept(listen_sock)) >= 0)
00068        {
00069        char   sockbuf[100];
00070 
00071               args[0]=filter;
00072               sprintf(sockbuf, "%d", sock);
00073               args[2]=sockbuf;
00074 
00075               {
00076               dSP ;
00077               ENTER ;
00078               SAVETMPS ;
00079 
00080               perl_call_argv("Embed::Persistent::eval_file",
00081                      G_VOID | G_DISCARD | G_EVAL, args);
00082 
00083 #ifdef ERRSV
00084               if(SvTRUE(ERRSV))
00085 #else
00086               if(SvTRUE(GvSV(errgv)))
00087 #endif
00088               {
00089                      clog_open_syslog("perlfilter");
00090                      clog_msg_str("ERR: eval error: ");
00091 
00092 #ifdef ERRSV
00093                      clog_msg_str(SvPV(ERRSV,PL_na));
00094 #else
00095                      clog_msg_str(SvPV(GvSV(errgv),na));
00096 #endif
00097                      clog_msg_send();
00098               }
00099               FREETMPS ;
00100               LEAVE ;
00101               }
00102 
00103               close(sock);  /* Just in case */
00104        }
00105 #ifdef perl_destruct_level
00106        perl_destruct_level=0;
00107 #else
00108        PL_perl_destruct_level=0;
00109 #endif
00110        perl_destruct(my_perl);
00111        perl_free(my_perl);
00112        exit(0);
00113 }
00114 
00115 static void reap_child(pid_t pid, int exit_status)
00116 {
00117        int    n;
00118        fd_set fd0;
00119        struct timeval tv;
00120 
00121        FD_ZERO(&fd0);
00122        FD_SET(0, &fd0);
00123 
00124        tv.tv_sec=0;
00125        tv.tv_usec=0;
00126 
00127        if (select(1, &fd0, 0, 0, &tv) >= 0)
00128        {
00129               if (FD_ISSET(0, &fd0))
00130                      return;
00131        }
00132 
00133        n=wait_reforkchild(nchildren, children, pid);
00134 
00135        if (n < 0)
00136        {
00137        unsigned u;
00138 
00139               clog_open_syslog("perlfilter");
00140               clog_msg_str("ERR: Unable to restart a child process"
00141                             " - aborting.");
00142               clog_msg_send();
00143               for (u=0; u<nchildren; u++)
00144                      if (children[u] >= 0)
00145                             kill(children[u], SIGKILL);
00146               exit(0);
00147        }
00148 
00149        if (n > 0)
00150        {
00151               wait_restore();
00152               if (exit_status)
00153               {
00154                      clog_open_syslog("perlfilter");
00155                      clog_msg_str("ERR: Child process ");
00156                      clog_msg_uint(pid);
00157                      clog_msg_str(" terminated - restarting.");
00158                      clog_msg_send();
00159               }
00160               perlfilter();
00161        }
00162 }
00163 
00164 static RETSIGTYPE    reap_children(int signum)
00165 {
00166        wait_reap(reap_child, reap_children);
00167 
00168 #if     RETSIGTYPE != void
00169         return (0);
00170 #endif
00171 }
00172 
00173 
00174 int main(int argc, char **argv, char **env)
00175 {
00176 char   *fn, *f;
00177 int    rc;
00178 char   buffer[1];
00179 int    waitstat;
00180 struct stat   stat_buf;
00181 
00182        fn=config_localfilename("filters/perlfilter-numprocs");
00183        if ( (f=config_read1l(fn)) != 0)
00184        {
00185               sscanf(f, "%u", &nchildren);
00186               free(f);
00187        }
00188        free(fn);
00189        if (nchildren <= 0)  nchildren=1;
00190 
00191        fn=config_localfilename("filters/perlfilter");
00192        if ( (f=config_read1l(fn)) == 0)
00193        {
00194               fprintf(stderr, "filters/perlfilter: not defined.\n");
00195               exit(1);
00196        }
00197 
00198        filter=f;
00199 
00200        if (stat(filter, &stat_buf))
00201        {
00202               perror(filter);
00203               exit(1);
00204        }
00205 
00206        listen_sock=lf_init("filters/perlfilter-mode",
00207               ALLFILTERSOCKETDIR "/perlfilter",
00208               ALLFILTERSOCKETDIR "/.perlfilter",
00209               FILTERSOCKETDIR "/perlfilter",
00210               FILTERSOCKETDIR "/.perlfilter");
00211 
00212        if (listen_sock < 0)
00213        {
00214               perror("socket");
00215               exit(1);
00216        }
00217 
00218        rc=wait_startchildren(nchildren, &children);
00219 
00220        if (rc < 0)
00221        {
00222               perror("fork");
00223               exit(1);
00224        }
00225 
00226        if (rc > 0)
00227        {
00228               lf_init_completed(listen_sock);
00229               perlfilter();
00230        }
00231 
00232        signal(SIGCHLD, reap_children);
00233        lf_init_completed(listen_sock);
00234 
00235        while (read(0, &buffer, 1) != 0)
00236        {
00237               ;
00238        }
00239        wait_restore();
00240 
00241        /* Wait for all child processes to terminate */
00242 
00243        while (wait(&waitstat) > 0)
00244               ;
00245        exit(0);
00246        return (0);
00247 }