home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / inetray / rpcntryd.c < prev    next >
C/C++ Source or Header  |  1992-06-30  |  14KB  |  575 lines

  1. /*======================================================================
  2.                     R P C . I N E T R A Y D . C 
  3.                     doc: Mon Feb 24 16:24:35 1992
  4.                     dlm: Wed Jul  1 11:45:19 1992
  5.                     (c) 1992 ant@julia
  6.                     uE-Info: 351 32 T 0 0 72 2 2 8 ofnI
  7. ======================================================================*/
  8.  
  9. /*#define        VERBOSE         /* babble */
  10. /*#define        DEBUG            /* syslog appears on stderr */
  11.  
  12. #ifdef DEBUG
  13. #    define syslog(level,msg)    fprintf(stderr,"syslog: %s\n",msg)
  14. #endif
  15.  
  16. #include    <string.h>        /* The long and sad inclusion story */
  17. #include    <signal.h>
  18. #include    </usr/include/netdb.h>    /* Prefer system over rpc/netdb.h */
  19. #include    <stdio.h>
  20. #include    <syslog.h>
  21. #include    <pwd.h>
  22. #include    <errno.h>
  23. #include    <unistd.h>
  24. #ifdef NOASYNCIO_QUIRK
  25. #include    <fcntl.h>
  26. #endif
  27. #include    <sys/file.h>        /* A/UX wants that */
  28. #include    <sys/types.h>
  29. #include    <sys/socket.h>
  30. #include    <sys/param.h>
  31. #include    <sys/wait.h>
  32. #ifndef INADDR_ANY
  33. #include    <netinet/in.h>
  34. #endif
  35. #include    <rpc/rpc.h>
  36. #include    "inetray.h"
  37. #include     "common.h"
  38. #include    "rayshade.h"
  39. #include    "picture.h"
  40. #include    "irtrace.h"
  41. #include    "config.h"
  42. #include    "utils.h"
  43. #ifdef AUX_QUIRK
  44. #include    "aux_quirk.h"
  45. #endif
  46.  
  47. #define MAXARGS    256            /* max # of args allowed */
  48. #define ARGBUFSZE 8192            /* max buffer for args */
  49.  
  50. #define    IN    0            /* files */
  51. #define    OUT    1
  52. #define    ERR    2
  53.  
  54. #define    READBUF    128            /* read buffer size */
  55.  
  56. extern int errno;            /* for stderr2syslog */
  57.  
  58. int     argc;                /* argcount */
  59. char     *argv[MAXARGS];            /* argvector */
  60. char     argbuf[ARGBUFSZE];        /* buffer for argv */
  61. int    pid = -1;            /* pid of child */
  62. char    rName[MAXHOSTNAMELEN];        /* remote hostname */
  63. int    lSize;                /* size of scanline */
  64. int    sock = -1;            /* result socket */
  65. XDR    xdrs;                /* result XDR stream */
  66. int    key;                /* session key */
  67. int     progNum;            /* program number (INETRAY + wid) */
  68. uid_t    uid;                /* user id (ideal) */
  69. int    ep[2];                /* error pipe */
  70. char    initialized = FALSE;        /* files read */
  71. char    chkClntOk = TRUE;        /* may check dispatcher */
  72. int    firstFrame;            /* deferred startframe number */
  73.  
  74. /*----------------------------------------------------------------------*/
  75.  
  76. static void parseQuote(s,spp,bpp)        /* parse quoted arg */
  77. char s[]; int *spp,*bpp;
  78. {
  79.     argv[argc] = &argbuf[*bpp];
  80.     (*spp)++;
  81.     while (s[*spp] != '\'')    {    /* copy simply */
  82.         argbuf[(*bpp)++] = s[(*spp)++];
  83.     }
  84.     argbuf[(*bpp)++] = '\0';
  85.     (*spp)++;                /* skip quote char */
  86. }
  87.  
  88. static void parseArgs(s)            /* break up s into argv */
  89. char s[];
  90. {
  91.     int bufp,sp,sl;
  92.  
  93.     argc = bufp = sp = 0;
  94.     sl = strlen(s);
  95.     while (sp < sl) {
  96.         if (s[sp] != '\'') {
  97.             sp++;
  98.             continue;
  99.         }
  100.         parseQuote(s,&sp,&bufp);
  101.         argc++;
  102.     }
  103.     argv[argc] = NULL;
  104. }
  105.     
  106. /*----------------------------------------------------------------------*/
  107.  
  108. static void killSelf()            /* received SIGINT(kill) signal */
  109. {
  110.     if (!xdrrec_endofrecord(&xdrs,TRUE)) {
  111.         syslog(LOG_ERR,"xdrrec_endofrecord() failed");
  112.         exit(1);
  113.     } 
  114.     exit(0);
  115. }
  116.  
  117. /*----------------------------------------------------------------------*/
  118.  
  119. static void stderr2syslog()            /* stderr -> syslog */
  120. {
  121.     int    nByte,i;
  122.     char    buf[READBUF];
  123.     static char    line[READBUF];
  124.     static int    lPos = 0;
  125.  
  126.     do {                     /* read everything */
  127.         nByte = read(ep[IN],buf,READBUF);/* read (must be ready) */
  128.         if (nByte == 0) continue; 
  129.         if (nByte < 0) {
  130.             if (errno == EWOULDBLOCK) continue; 
  131.             syslog(LOG_ERR,"read: %m");
  132.             exit(1);
  133.         }
  134.         for (i=0; i<nByte; i++)    {    /* copy message part */
  135.             if (buf[i] == '\0')    /* skip \0 */
  136.                 continue;
  137.             if (buf[i] == '\n') {    /* terminate line */
  138.                 line[lPos] = '\0';
  139.                 syslog(LOG_ERR,"%s",line);
  140.                 lPos = 0;
  141.                 continue;
  142.             }
  143.             line[lPos++] = buf[i];
  144.         }
  145.     } while (nByte > 0); 
  146.     signal(SIGIO,stderr2syslog);        /* reenable sysV signal */
  147. }
  148.  
  149. /*----------------------------------------------------------------------*/
  150.  
  151. static writeit(dummy,buf,nbyte)            /* XDR write routine */
  152. char *dummy,*buf; int nbyte;
  153. {
  154.     int writ;
  155.  
  156.     writ = write(sock,buf,nbyte);
  157.     if (writ < 0) {
  158.         syslog(LOG_ERR,"write: %m");
  159.     }
  160.     return writ;
  161. }
  162.  
  163. static void abort()                /* if disp dead */
  164. {
  165.     if (pid > 0) kill(pid,SIGKILL);        /* kill worker */
  166.     syslog(LOG_ERR,"Dispatcher disappeared");
  167.     exit(1);
  168. }
  169.  
  170. static void chkClnt()                /* check if disp. running */
  171. {
  172.     fd_set    resSock;
  173.     
  174.     signal(SIGALRM,chkClnt);        /* system V */
  175.     if (!chkClntOk) return;            /* only if does not disturb */
  176.  
  177.     if (sock == -1)                /* not yet initialized */
  178.         abort();
  179.  
  180.     FD_ZERO(&resSock);            /* check connection */
  181.     FD_SET(sock,&resSock);
  182.     if (select(sock+1,&resSock,NULL,NULL,&now) < 0) {
  183.         syslog(LOG_ERR,"select(): %m");
  184.         exit(1);
  185.     }
  186.     if (FD_ISSET(sock,&resSock)) abort();    /* read would return 0 */
  187. }
  188.  
  189. static void sendResult(lNr,bSz,block)        /* send whole resultblock back */
  190. int lNr,bSz; Scanline *block;
  191. {
  192.     pixArr    res;
  193.     int    i;
  194.     
  195.     if (!xdr_int(&xdrs,&lNr)) {
  196.         syslog(LOG_ERR,"xdr_int() failed");
  197.         exit(1);
  198.     }
  199.     res.pixArr_len = lSize;
  200.     for (i=1; i<=bSz; i++) {
  201.         res.pixArr_val = (xdrPix *)block[i].pix;
  202.         if (!xdr_pixArr(&xdrs,&res)) {
  203.             syslog(LOG_ERR,"xdr_pixArr() failed");
  204.             exit(1);
  205.         }
  206.     }
  207.     if (!xdrrec_endofrecord(&xdrs,TRUE)) {
  208.         syslog(LOG_ERR,"xdrrec_endofrecord() failed");
  209.         exit(1);
  210.     }
  211. }
  212.  
  213. /*----------------------------------------------------------------------*/
  214.  
  215. void *init_1(param)                    /* init self */
  216. iPrm *param;
  217. {
  218.     int    wid,wpid;
  219.     char    wd[MAXPATHLEN],*cp,*getwd();
  220.     struct passwd        *p;
  221.     struct hostent        *host;
  222.     struct sockaddr_in    name;
  223.     
  224. #ifdef VERBOSE
  225.     syslog(LOG_NOTICE,"INIT:");
  226. #endif
  227.     if (pid != -1)                    /* only once */
  228.         return (void *)NULL;        
  229.     signal(SIGINT,SIG_IGN);                /* ignore kill signal */
  230.  
  231.     strncpy(rName,param->rName,MAXHOSTNAMELEN);
  232.     key = param->key;                /* session key */
  233.  
  234.     if (uid == 0) {                    /* set default uid */
  235.         if (setreuid(-1,param->uid) < 0) {
  236.             syslog(LOG_NOTICE,"setreuid: %m");
  237.         }
  238.         uid = geteuid();            /* get effective uid */
  239.         if (uid == 0) {
  240.             syslog(LOG_ERR,"can't run as root");
  241.             exit(1);
  242.         }
  243.     }
  244.     p = getpwuid(uid);            /* get user info */
  245.     if (p == NULL) {
  246.         syslog(LOG_ERR,"user %d non-existent");
  247.         exit(1);
  248.     }
  249.     
  250.     addHome(uid,param->cwd,wd);            /* get right dir */
  251.     if (chdir(wd) < 0) {                /* try to get there */
  252.         syslog(LOG_NOTICE,"WARNING: chdir(%s): %m",wd);
  253.     }
  254.  
  255.     if (key != 0) {                    /* only pinged */
  256.         parseArgs(param->cmdLine);
  257.     }
  258.     pid = 0;                    /* initialized */
  259.                             /* init socket */
  260.     if ((host = gethostbyname(rName)) == NULL) {
  261.         syslog(LOG_ERR,"gethostbyname() failed!");
  262.         exit(1);
  263.     }
  264.     name.sin_family = AF_INET;
  265.     name.sin_port = htons(param->rPort);
  266.     bcopy(host->h_addr_list[0],(char *)&name.sin_addr,host->h_length);
  267.  
  268.     if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
  269.         syslog(LOG_ERR,"socket: %m");
  270.         exit(1);
  271.     }
  272.     if (connect(sock,&name,sizeof(name)) < 0) {
  273.         if (errno == ECONNREFUSED) {        /* retry once */
  274.             close(sock);
  275.             sleep((rand()%2)+1);        /* wait random time */
  276.                 if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
  277.                         syslog(LOG_ERR,"socket: %m");
  278.                         exit(1);
  279.                 }
  280.             if (connect(sock,&name,sizeof(name)) < 0) {
  281.                         syslog(LOG_ERR,"connect: %m");
  282.                 exit(1);
  283.             }
  284.         } else {
  285.                     syslog(LOG_ERR,"connect: %m");
  286.             exit(1);
  287.         }
  288.     }
  289.  
  290.     xdrrec_create(&xdrs,0,0,NULL,NULL,writeit);    /* create XDR */
  291.     xdrs.x_op = XDR_ENCODE;
  292.     wid = progNum - INETRAY;            /* send back info */
  293.     if (!xdr_int(&xdrs,&wid)) {            /* worker id */
  294.         syslog(LOG_ERR,"xdr_int() failed");
  295.         exit(1);
  296.     }
  297.     wpid = getpid();
  298.     if (!xdr_int(&xdrs,&wpid)) {            /* pid */
  299.         syslog(LOG_ERR,"xdr_int() failed");
  300.         exit(1);
  301.     }
  302.     cp = p->pw_name;                /* user name */
  303.     if (!xdr_string(&xdrs,&cp,32)) {
  304.         syslog(LOG_ERR,"xdr_string() failed");
  305.         exit(1);
  306.     }
  307.     getwd(wd);                    /* working dir */
  308.     stripHome(uid,wd); 
  309.     cp = wd;
  310.     if (!xdr_string(&xdrs,&cp,MAXPATHLEN)) {
  311.         syslog(LOG_ERR,"xdr_string() failed");
  312.         exit(1);
  313.     }
  314.     if (!xdrrec_endofrecord(&xdrs,TRUE)) {
  315.         syslog(LOG_ERR,"xdrrec_endofrecord() failed");
  316.         exit(1);
  317.     }
  318.     chkClntOk = TRUE;                /* check client */
  319.  
  320. #ifdef VERBOSE
  321.     syslog(LOG_NOTICE,"INIT done");
  322. #endif
  323.     return (void *)NULL;                /* dont reply rpc */
  324. }
  325.  
  326. int *wait_1(keyP)                /* wait 4 worker 2 die */
  327. int *keyP;
  328. {
  329.     int    status,dPid;
  330.     static int res = 0;
  331.     
  332. #ifdef VERBOSE
  333.     syslog(LOG_NOTICE,"WAITING FOR: %d",pid);
  334. #endif
  335.     if (pid < 0) exit(0);            /* not initialized */
  336.     if (*keyP != key) {             /* authorize */
  337.         return (int *)NULL;
  338.     }
  339.     if (pid > 0) {                /* one has been started */
  340.         if ((dPid = wait(&status)) < 0) {     /* wait for it */
  341.             syslog(LOG_ERR,"wait: %m");
  342.             exit(1);
  343.         }
  344.         if (status != 0) {
  345.             syslog(LOG_NOTICE,"worker exit status %d",status);
  346.             /* earlier versions exited here */
  347.         }
  348.         if (dPid != pid) {        /* what happened ? */
  349.             kill(pid,SIGKILL);    /* abort ! */
  350.             syslog(LOG_ERR,"pid of dead %d instead of %d",dPid,pid);
  351.             exit(1);
  352.         }
  353. #ifdef VERBOSE
  354.     syslog(LOG_NOTICE,"pid %d returned %d",dPid,status);
  355. #endif
  356.         pid = 0;
  357.     }
  358.     return &res; 
  359. }        
  360.  
  361. int *startframe_1(param)            /* start new frame */
  362. sfPrm *param;
  363. {
  364.     static int res = 0;
  365.     int    status;
  366.  
  367.     if (pid < 0) exit(0);            /* not initialized */
  368.     if (param->key != key) {        /* authorize */
  369.         return (int *)NULL;
  370.     }
  371.     wait_1(&(param->key));
  372.     if (initialized)            /* start new frame */
  373.         RSStartFrame(param->fNr);
  374.     else                    /* defer */
  375.         firstFrame = param->fNr;
  376.     return &res;
  377. }
  378.  
  379. void *traceblock_1(param)            /* trace block of lines */
  380. tbPrm *param;
  381. {
  382.     int    pgrp,status;    
  383.     Scanline *resBlock,*Raytrace();
  384.  
  385.     if (pid < 0) exit(0);            /* not initialized */
  386.     if (param->key != key) {        /* authorize */
  387.         return (void *)NULL;
  388.     }
  389.     if (!initialized) {            /* deferred stuff */
  390.         lSize = RaytraceInit(argc,argv);
  391.         RSStartFrame(firstFrame);
  392.         initialized = TRUE;
  393.         wait(NULL);            /* get status */
  394.     }
  395.     wait_1(&(param->key));
  396.     chkClntOk = FALSE;            /* child doesn't check */
  397.     pid = fork();                /* make new */
  398.     if (pid < 0) {
  399.         syslog(LOG_ERR,"fork: %m");
  400.         exit(1);
  401.     }
  402.     if (pid == 0) {                /* child */
  403.         signal(SIGINT,killSelf);    /* custom kill */
  404.         nice(NICEDAEMON);        /* run nicely */
  405.         resBlock = Raytrace(param->bSz,    /* do trace */
  406.                     param->lNr);
  407.         signal(SIGINT,SIG_IGN);        /* don't disturb xdr */
  408.         sendResult(param->bNr,        /* send result */
  409.                param->bSz,
  410.                resBlock);
  411.         exit(0);
  412.     }
  413. #ifdef VERBOSE
  414.     syslog(LOG_NOTICE,"pid %d forked",pid);
  415. #endif
  416.     chkClntOk = TRUE;            /* father continues checking */
  417.     return NULL;                /* don't block */
  418. }
  419.  
  420. int *kill_1(keyP)                /* kill worker */
  421. int *keyP;
  422. {
  423.     static int res = 0;
  424.     
  425. #ifdef VERBOSE
  426.     syslog(LOG_NOTICE,"KILLING: %d",pid);
  427. #endif
  428.     if (pid < 0) exit(0);            /* not initialized */
  429.     if (*keyP != key) {            /* authorize */
  430.         return (int *)NULL;
  431.     }
  432.     if (pid > 0) kill(pid,SIGINT);
  433.     return &res;
  434. }
  435.  
  436. void *terminate_1(keyP)                /* terminate */
  437. int *keyP;
  438. {
  439. #ifdef VERBOSE
  440.     syslog(LOG_NOTICE,"TERMINATE:");
  441. #endif
  442.     if (pid < 0) exit(0);            /* not initialized */
  443.     if (*keyP != key) {            /* authorize */
  444.         return (void *)NULL;
  445.     }
  446.     if (pid > 0) {                /* force */
  447.         kill(pid,SIGKILL);
  448.         wait_1(keyP);
  449.     }
  450.     close(sock);
  451. #ifdef VERBOSE
  452.     syslog(LOG_NOTICE,"TERMINATE done");
  453. #endif
  454.     closelog();
  455.     exit(0);
  456. }
  457.  
  458. /*======================================================================*/
  459.  
  460. extern void inetray_1();    /* generated dispatch routine */
  461. int _rpcpmstart = 0;        /* Started by a port monitor ? */
  462. int _rpcfdtype = SOCK_DGRAM;    /* Whether Stream or Datagram ? */
  463.  
  464. main(ac,av)
  465. int ac; char *av[];
  466. {
  467.     register SVCXPRT *transp;
  468.     int     sock, proto, pgrp;
  469.     struct sockaddr_in     saddr;
  470.     struct itimerval    chkClntT;
  471.     int asize = sizeof(saddr);
  472.     int ssize = sizeof(int);
  473.     int     fd;
  474.     char    *name;
  475.  
  476. #ifdef LOG_DAEMON
  477.     openlog(av[0], LOG_PID, LOG_DAEMON);
  478. #else
  479.     openlog(av[0],LOG_PID);
  480. #endif
  481. #ifdef VERBOSE
  482.     syslog(LOG_NOTICE,"started!");
  483. #endif
  484.     chkClntT.it_interval.tv_sec = chkClntT.it_value.tv_sec = CHKCLNT;
  485.     chkClntT.it_interval.tv_usec = chkClntT.it_value.tv_usec = 0;
  486.     signal(SIGALRM,chkClnt);
  487.     if (setitimer(ITIMER_REAL,&chkClntT,NULL) < 0) {
  488.         syslog(LOG_ERR,"setitimer: %m");
  489.         exit(1);
  490.     }
  491. #ifndef DEBUG
  492. #ifdef NOASYNCIO_QUIRK
  493.     name = tempnam(NULL,"inetray.");        /* /tmp file */
  494.     ep[OUT] = open(name,O_WRONLY|O_CREAT,0666);
  495.     if (ep[OUT] < 0) {
  496.         syslog(LOG_ERR,"open(%s): %m",name);
  497.         exit(1);
  498.     }
  499. #else
  500.     if (socketpair(PF_UNIX,SOCK_STREAM,0,ep) < 0) {    /* make pipe */
  501.         syslog(LOG_ERR,"socketpair: %m");
  502.         exit(1);
  503.     }
  504.     if (fcntl(ep[IN],F_SETFL,FASYNC|FNDELAY) < 0) { /* async mode */
  505.         syslog(LOG_ERR,"fcntl F_SETFL: %m");
  506.         exit(1);
  507.     }
  508.     pgrp = getpgrp(0);                /* set prgp */
  509.     if (fcntl(ep[IN],F_SETOWN,pgrp) < 0) {
  510.         syslog(LOG_ERR,"fcntl F_SETOWN: %m");
  511.         exit(1);
  512.     }
  513.     if ((int)signal(SIGIO,stderr2syslog) < 0) {    /* async read */
  514.         syslog(LOG_ERR,"signal: %m");
  515.         exit(1);
  516.     }
  517. #endif
  518.     if (dup2(ep[OUT],ERR) < 0) {            /* stderr */
  519.         syslog(LOG_ERR,"dup2 ERR: %m");
  520.         exit(1);
  521.     }
  522. #endif
  523. #ifdef VERBOSE
  524.     syslog(LOG_NOTICE,"testing stderr");
  525.     fprintf(stderr,"stderr redirected");
  526. #endif
  527.     
  528.     if (ac == 1) {                    /* inetd */
  529.         _rpcpmstart = 1;
  530.         sock = 0;
  531.         proto = 0;
  532.         progNum = INETRAY;
  533.         if (getsockname(sock, (struct sockaddr *)&saddr, &asize) < 0) {
  534.             syslog(LOG_ERR,"socket: %m");
  535.             exit(1);
  536.         }
  537.         if (saddr.sin_family != AF_INET) {
  538.             syslog(LOG_ERR,"illegal protocol");
  539.             exit(1);
  540.         }
  541.         if (getsockopt(0, SOL_SOCKET, SO_TYPE,
  542.                 (char *)&_rpcfdtype, &ssize) == -1) {
  543.             syslog(LOG_ERR,"getsockopt: %m");
  544.             exit(1);
  545.         }
  546.     } else {                /* inetray.starter */
  547.         sock = RPC_ANYSOCK;
  548.         proto = IPPROTO_UDP;
  549.         progNum = INETRAY + atoi(av[1]);
  550.         uid = (uid_t)atoi(av[2]);
  551.         (void)setreuid(-1,uid);        /* no big deal if fails */
  552.         (void)pmap_unset(progNum, IRV1);
  553.     }
  554.  
  555.     uid = geteuid();
  556.     transp = svcudp_create(sock);
  557.     if (transp == NULL) {
  558.         syslog(LOG_ERR,"cannot create udp service.");
  559.         exit(1);
  560.     }
  561.     if (!svc_register(transp, progNum, IRV1, inetray_1, proto)) {
  562.         syslog(LOG_ERR,"unable to register (progNum, VER, udp).");
  563.         exit(1);
  564.     }
  565.  
  566. #ifdef VERBOSE
  567.     syslog(LOG_NOTICE,"waiting for request...");
  568. #endif
  569.     svc_run();
  570.     syslog(LOG_ERR,"svc_run returned");
  571.     exit(1);
  572.     /* NOTREACHED */
  573. }
  574.  
  575.