home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Photo CD Demo 1
/
Demo.bin
/
inetray
/
rpcntryd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-30
|
14KB
|
575 lines
/*======================================================================
R P C . I N E T R A Y D . C
doc: Mon Feb 24 16:24:35 1992
dlm: Wed Jul 1 11:45:19 1992
(c) 1992 ant@julia
uE-Info: 351 32 T 0 0 72 2 2 8 ofnI
======================================================================*/
/*#define VERBOSE /* babble */
/*#define DEBUG /* syslog appears on stderr */
#ifdef DEBUG
# define syslog(level,msg) fprintf(stderr,"syslog: %s\n",msg)
#endif
#include <string.h> /* The long and sad inclusion story */
#include <signal.h>
#include </usr/include/netdb.h> /* Prefer system over rpc/netdb.h */
#include <stdio.h>
#include <syslog.h>
#include <pwd.h>
#include <errno.h>
#include <unistd.h>
#ifdef NOASYNCIO_QUIRK
#include <fcntl.h>
#endif
#include <sys/file.h> /* A/UX wants that */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/wait.h>
#ifndef INADDR_ANY
#include <netinet/in.h>
#endif
#include <rpc/rpc.h>
#include "inetray.h"
#include "common.h"
#include "rayshade.h"
#include "picture.h"
#include "irtrace.h"
#include "config.h"
#include "utils.h"
#ifdef AUX_QUIRK
#include "aux_quirk.h"
#endif
#define MAXARGS 256 /* max # of args allowed */
#define ARGBUFSZE 8192 /* max buffer for args */
#define IN 0 /* files */
#define OUT 1
#define ERR 2
#define READBUF 128 /* read buffer size */
extern int errno; /* for stderr2syslog */
int argc; /* argcount */
char *argv[MAXARGS]; /* argvector */
char argbuf[ARGBUFSZE]; /* buffer for argv */
int pid = -1; /* pid of child */
char rName[MAXHOSTNAMELEN]; /* remote hostname */
int lSize; /* size of scanline */
int sock = -1; /* result socket */
XDR xdrs; /* result XDR stream */
int key; /* session key */
int progNum; /* program number (INETRAY + wid) */
uid_t uid; /* user id (ideal) */
int ep[2]; /* error pipe */
char initialized = FALSE; /* files read */
char chkClntOk = TRUE; /* may check dispatcher */
int firstFrame; /* deferred startframe number */
/*----------------------------------------------------------------------*/
static void parseQuote(s,spp,bpp) /* parse quoted arg */
char s[]; int *spp,*bpp;
{
argv[argc] = &argbuf[*bpp];
(*spp)++;
while (s[*spp] != '\'') { /* copy simply */
argbuf[(*bpp)++] = s[(*spp)++];
}
argbuf[(*bpp)++] = '\0';
(*spp)++; /* skip quote char */
}
static void parseArgs(s) /* break up s into argv */
char s[];
{
int bufp,sp,sl;
argc = bufp = sp = 0;
sl = strlen(s);
while (sp < sl) {
if (s[sp] != '\'') {
sp++;
continue;
}
parseQuote(s,&sp,&bufp);
argc++;
}
argv[argc] = NULL;
}
/*----------------------------------------------------------------------*/
static void killSelf() /* received SIGINT(kill) signal */
{
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
syslog(LOG_ERR,"xdrrec_endofrecord() failed");
exit(1);
}
exit(0);
}
/*----------------------------------------------------------------------*/
static void stderr2syslog() /* stderr -> syslog */
{
int nByte,i;
char buf[READBUF];
static char line[READBUF];
static int lPos = 0;
do { /* read everything */
nByte = read(ep[IN],buf,READBUF);/* read (must be ready) */
if (nByte == 0) continue;
if (nByte < 0) {
if (errno == EWOULDBLOCK) continue;
syslog(LOG_ERR,"read: %m");
exit(1);
}
for (i=0; i<nByte; i++) { /* copy message part */
if (buf[i] == '\0') /* skip \0 */
continue;
if (buf[i] == '\n') { /* terminate line */
line[lPos] = '\0';
syslog(LOG_ERR,"%s",line);
lPos = 0;
continue;
}
line[lPos++] = buf[i];
}
} while (nByte > 0);
signal(SIGIO,stderr2syslog); /* reenable sysV signal */
}
/*----------------------------------------------------------------------*/
static writeit(dummy,buf,nbyte) /* XDR write routine */
char *dummy,*buf; int nbyte;
{
int writ;
writ = write(sock,buf,nbyte);
if (writ < 0) {
syslog(LOG_ERR,"write: %m");
}
return writ;
}
static void abort() /* if disp dead */
{
if (pid > 0) kill(pid,SIGKILL); /* kill worker */
syslog(LOG_ERR,"Dispatcher disappeared");
exit(1);
}
static void chkClnt() /* check if disp. running */
{
fd_set resSock;
signal(SIGALRM,chkClnt); /* system V */
if (!chkClntOk) return; /* only if does not disturb */
if (sock == -1) /* not yet initialized */
abort();
FD_ZERO(&resSock); /* check connection */
FD_SET(sock,&resSock);
if (select(sock+1,&resSock,NULL,NULL,&now) < 0) {
syslog(LOG_ERR,"select(): %m");
exit(1);
}
if (FD_ISSET(sock,&resSock)) abort(); /* read would return 0 */
}
static void sendResult(lNr,bSz,block) /* send whole resultblock back */
int lNr,bSz; Scanline *block;
{
pixArr res;
int i;
if (!xdr_int(&xdrs,&lNr)) {
syslog(LOG_ERR,"xdr_int() failed");
exit(1);
}
res.pixArr_len = lSize;
for (i=1; i<=bSz; i++) {
res.pixArr_val = (xdrPix *)block[i].pix;
if (!xdr_pixArr(&xdrs,&res)) {
syslog(LOG_ERR,"xdr_pixArr() failed");
exit(1);
}
}
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
syslog(LOG_ERR,"xdrrec_endofrecord() failed");
exit(1);
}
}
/*----------------------------------------------------------------------*/
void *init_1(param) /* init self */
iPrm *param;
{
int wid,wpid;
char wd[MAXPATHLEN],*cp,*getwd();
struct passwd *p;
struct hostent *host;
struct sockaddr_in name;
#ifdef VERBOSE
syslog(LOG_NOTICE,"INIT:");
#endif
if (pid != -1) /* only once */
return (void *)NULL;
signal(SIGINT,SIG_IGN); /* ignore kill signal */
strncpy(rName,param->rName,MAXHOSTNAMELEN);
key = param->key; /* session key */
if (uid == 0) { /* set default uid */
if (setreuid(-1,param->uid) < 0) {
syslog(LOG_NOTICE,"setreuid: %m");
}
uid = geteuid(); /* get effective uid */
if (uid == 0) {
syslog(LOG_ERR,"can't run as root");
exit(1);
}
}
p = getpwuid(uid); /* get user info */
if (p == NULL) {
syslog(LOG_ERR,"user %d non-existent");
exit(1);
}
addHome(uid,param->cwd,wd); /* get right dir */
if (chdir(wd) < 0) { /* try to get there */
syslog(LOG_NOTICE,"WARNING: chdir(%s): %m",wd);
}
if (key != 0) { /* only pinged */
parseArgs(param->cmdLine);
}
pid = 0; /* initialized */
/* init socket */
if ((host = gethostbyname(rName)) == NULL) {
syslog(LOG_ERR,"gethostbyname() failed!");
exit(1);
}
name.sin_family = AF_INET;
name.sin_port = htons(param->rPort);
bcopy(host->h_addr_list[0],(char *)&name.sin_addr,host->h_length);
if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
syslog(LOG_ERR,"socket: %m");
exit(1);
}
if (connect(sock,&name,sizeof(name)) < 0) {
if (errno == ECONNREFUSED) { /* retry once */
close(sock);
sleep((rand()%2)+1); /* wait random time */
if ((sock = socket(PF_INET,SOCK_STREAM,0)) < 0) {
syslog(LOG_ERR,"socket: %m");
exit(1);
}
if (connect(sock,&name,sizeof(name)) < 0) {
syslog(LOG_ERR,"connect: %m");
exit(1);
}
} else {
syslog(LOG_ERR,"connect: %m");
exit(1);
}
}
xdrrec_create(&xdrs,0,0,NULL,NULL,writeit); /* create XDR */
xdrs.x_op = XDR_ENCODE;
wid = progNum - INETRAY; /* send back info */
if (!xdr_int(&xdrs,&wid)) { /* worker id */
syslog(LOG_ERR,"xdr_int() failed");
exit(1);
}
wpid = getpid();
if (!xdr_int(&xdrs,&wpid)) { /* pid */
syslog(LOG_ERR,"xdr_int() failed");
exit(1);
}
cp = p->pw_name; /* user name */
if (!xdr_string(&xdrs,&cp,32)) {
syslog(LOG_ERR,"xdr_string() failed");
exit(1);
}
getwd(wd); /* working dir */
stripHome(uid,wd);
cp = wd;
if (!xdr_string(&xdrs,&cp,MAXPATHLEN)) {
syslog(LOG_ERR,"xdr_string() failed");
exit(1);
}
if (!xdrrec_endofrecord(&xdrs,TRUE)) {
syslog(LOG_ERR,"xdrrec_endofrecord() failed");
exit(1);
}
chkClntOk = TRUE; /* check client */
#ifdef VERBOSE
syslog(LOG_NOTICE,"INIT done");
#endif
return (void *)NULL; /* dont reply rpc */
}
int *wait_1(keyP) /* wait 4 worker 2 die */
int *keyP;
{
int status,dPid;
static int res = 0;
#ifdef VERBOSE
syslog(LOG_NOTICE,"WAITING FOR: %d",pid);
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return (int *)NULL;
}
if (pid > 0) { /* one has been started */
if ((dPid = wait(&status)) < 0) { /* wait for it */
syslog(LOG_ERR,"wait: %m");
exit(1);
}
if (status != 0) {
syslog(LOG_NOTICE,"worker exit status %d",status);
/* earlier versions exited here */
}
if (dPid != pid) { /* what happened ? */
kill(pid,SIGKILL); /* abort ! */
syslog(LOG_ERR,"pid of dead %d instead of %d",dPid,pid);
exit(1);
}
#ifdef VERBOSE
syslog(LOG_NOTICE,"pid %d returned %d",dPid,status);
#endif
pid = 0;
}
return &res;
}
int *startframe_1(param) /* start new frame */
sfPrm *param;
{
static int res = 0;
int status;
if (pid < 0) exit(0); /* not initialized */
if (param->key != key) { /* authorize */
return (int *)NULL;
}
wait_1(&(param->key));
if (initialized) /* start new frame */
RSStartFrame(param->fNr);
else /* defer */
firstFrame = param->fNr;
return &res;
}
void *traceblock_1(param) /* trace block of lines */
tbPrm *param;
{
int pgrp,status;
Scanline *resBlock,*Raytrace();
if (pid < 0) exit(0); /* not initialized */
if (param->key != key) { /* authorize */
return (void *)NULL;
}
if (!initialized) { /* deferred stuff */
lSize = RaytraceInit(argc,argv);
RSStartFrame(firstFrame);
initialized = TRUE;
wait(NULL); /* get status */
}
wait_1(&(param->key));
chkClntOk = FALSE; /* child doesn't check */
pid = fork(); /* make new */
if (pid < 0) {
syslog(LOG_ERR,"fork: %m");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGINT,killSelf); /* custom kill */
nice(NICEDAEMON); /* run nicely */
resBlock = Raytrace(param->bSz, /* do trace */
param->lNr);
signal(SIGINT,SIG_IGN); /* don't disturb xdr */
sendResult(param->bNr, /* send result */
param->bSz,
resBlock);
exit(0);
}
#ifdef VERBOSE
syslog(LOG_NOTICE,"pid %d forked",pid);
#endif
chkClntOk = TRUE; /* father continues checking */
return NULL; /* don't block */
}
int *kill_1(keyP) /* kill worker */
int *keyP;
{
static int res = 0;
#ifdef VERBOSE
syslog(LOG_NOTICE,"KILLING: %d",pid);
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return (int *)NULL;
}
if (pid > 0) kill(pid,SIGINT);
return &res;
}
void *terminate_1(keyP) /* terminate */
int *keyP;
{
#ifdef VERBOSE
syslog(LOG_NOTICE,"TERMINATE:");
#endif
if (pid < 0) exit(0); /* not initialized */
if (*keyP != key) { /* authorize */
return (void *)NULL;
}
if (pid > 0) { /* force */
kill(pid,SIGKILL);
wait_1(keyP);
}
close(sock);
#ifdef VERBOSE
syslog(LOG_NOTICE,"TERMINATE done");
#endif
closelog();
exit(0);
}
/*======================================================================*/
extern void inetray_1(); /* generated dispatch routine */
int _rpcpmstart = 0; /* Started by a port monitor ? */
int _rpcfdtype = SOCK_DGRAM; /* Whether Stream or Datagram ? */
main(ac,av)
int ac; char *av[];
{
register SVCXPRT *transp;
int sock, proto, pgrp;
struct sockaddr_in saddr;
struct itimerval chkClntT;
int asize = sizeof(saddr);
int ssize = sizeof(int);
int fd;
char *name;
#ifdef LOG_DAEMON
openlog(av[0], LOG_PID, LOG_DAEMON);
#else
openlog(av[0],LOG_PID);
#endif
#ifdef VERBOSE
syslog(LOG_NOTICE,"started!");
#endif
chkClntT.it_interval.tv_sec = chkClntT.it_value.tv_sec = CHKCLNT;
chkClntT.it_interval.tv_usec = chkClntT.it_value.tv_usec = 0;
signal(SIGALRM,chkClnt);
if (setitimer(ITIMER_REAL,&chkClntT,NULL) < 0) {
syslog(LOG_ERR,"setitimer: %m");
exit(1);
}
#ifndef DEBUG
#ifdef NOASYNCIO_QUIRK
name = tempnam(NULL,"inetray."); /* /tmp file */
ep[OUT] = open(name,O_WRONLY|O_CREAT,0666);
if (ep[OUT] < 0) {
syslog(LOG_ERR,"open(%s): %m",name);
exit(1);
}
#else
if (socketpair(PF_UNIX,SOCK_STREAM,0,ep) < 0) { /* make pipe */
syslog(LOG_ERR,"socketpair: %m");
exit(1);
}
if (fcntl(ep[IN],F_SETFL,FASYNC|FNDELAY) < 0) { /* async mode */
syslog(LOG_ERR,"fcntl F_SETFL: %m");
exit(1);
}
pgrp = getpgrp(0); /* set prgp */
if (fcntl(ep[IN],F_SETOWN,pgrp) < 0) {
syslog(LOG_ERR,"fcntl F_SETOWN: %m");
exit(1);
}
if ((int)signal(SIGIO,stderr2syslog) < 0) { /* async read */
syslog(LOG_ERR,"signal: %m");
exit(1);
}
#endif
if (dup2(ep[OUT],ERR) < 0) { /* stderr */
syslog(LOG_ERR,"dup2 ERR: %m");
exit(1);
}
#endif
#ifdef VERBOSE
syslog(LOG_NOTICE,"testing stderr");
fprintf(stderr,"stderr redirected");
#endif
if (ac == 1) { /* inetd */
_rpcpmstart = 1;
sock = 0;
proto = 0;
progNum = INETRAY;
if (getsockname(sock, (struct sockaddr *)&saddr, &asize) < 0) {
syslog(LOG_ERR,"socket: %m");
exit(1);
}
if (saddr.sin_family != AF_INET) {
syslog(LOG_ERR,"illegal protocol");
exit(1);
}
if (getsockopt(0, SOL_SOCKET, SO_TYPE,
(char *)&_rpcfdtype, &ssize) == -1) {
syslog(LOG_ERR,"getsockopt: %m");
exit(1);
}
} else { /* inetray.starter */
sock = RPC_ANYSOCK;
proto = IPPROTO_UDP;
progNum = INETRAY + atoi(av[1]);
uid = (uid_t)atoi(av[2]);
(void)setreuid(-1,uid); /* no big deal if fails */
(void)pmap_unset(progNum, IRV1);
}
uid = geteuid();
transp = svcudp_create(sock);
if (transp == NULL) {
syslog(LOG_ERR,"cannot create udp service.");
exit(1);
}
if (!svc_register(transp, progNum, IRV1, inetray_1, proto)) {
syslog(LOG_ERR,"unable to register (progNum, VER, udp).");
exit(1);
}
#ifdef VERBOSE
syslog(LOG_NOTICE,"waiting for request...");
#endif
svc_run();
syslog(LOG_ERR,"svc_run returned");
exit(1);
/* NOTREACHED */
}