/*daemon to return a few lines of html to requesting browsers*/
/*compile with -lnsl -lsocket*/
/*this is a work in progress*/

/*give us socket(),setsockopt(),bind(),accept()*/
#include <sys/types.h> /*and htons()*/
#include <sys/socket.h>
/*give us htons*/
#include <netinet/in.h>
/*give us perror()*/
#include <stdio.h>
/*give us errno*/
#include <errno.h> /*necc???*/
/*give us signal()*/
#include <signal.h>
/*give us select(),FD_SET(),FD_CLR(),FD_ISSET(),FD_ZERO()*/
#include <sys/time.h> /*and wait3()*/
#include <sys/types.h>
/*give us sysconf(),alarm()*/
#include <unistd.h>
/*give us wait3()*/
#include <sys/wait.h>
#include <sys/resource.h>

#define LINES 5
#define BUFLEN 512

static void sighandler(){
  while(waitpid((pid_t)-1,0,(WNOHANG|WUNTRACED))>0);
  (void)signal(SIGCHLD,sighandler);
}

void processreq(int s){
  FILE *fd; /*IO stream*/
  char buf[LINES][BUFLEN];
  int i;

  if((fd=fdopen(s,"a+"))==NULL)perror("plaind fdopen()"),exit(1);
  for(i=0;i<LINES;i++)
    if(fgets(buf[i],sizeof(buf[i]),fd)==NULL||strlen(buf[i])<2)break;
  rewind(fd);
  fprintf(fd,"HTTP/1.0 200\nSet-Cookie: Penut = Butter\n");
  fprintf(fd,"Content-type: text/html\nContent-length: %d\n\n",
	  (LINES+2)*BUFLEN);
  /*len is actually header+footer+strlen(buf[i])*/
  fprintf(fd,"<HTML><HEAD><TITLE>Hi!</TITLE></HEAD><BODY><PRE>\n");
  fprintf(fd,"The first %d things your browser said were:\n\n",LINES,buf);
  for(i=0;i<LINES;i++)fprintf(fd,"(%d) %s",i+1,buf[i]);
  fprintf(fd,"\nThen I stopped listening.\n",buf);
  fprintf(fd,"</PRE></BODY></HTML>\n");
  fflush(fd);
  printf("\a\nplaind is sending its page.\n");
}

int main(int argc,char**argv){
  /*decl*/
  int port; /*port to listen on*/
  int s; /*socket handle*/
  int maxopenfiles; /*duh*/
  struct sockaddr_in addr,from; /*another mystery*/
  fd_set readfds; /*beats me what this is*/
  int rc; /*select retval for error check*/
  int fromlen; /*I think this is useless*/
  int ns; /*socket descriptor*/
  int pid; /*guess*/
  int one;

  /*set up socket*/
  port=3701;
  maxopenfiles=sysconf(_SC_OPEN_MAX); /*sysconf(3C): find max # of open files*/
  s=socket(PF_INET,SOCK_STREAM,0); /*socket(3N): get socket*/
  if(s==-1||s==0)perror("plaind socket()"),exit(1);
  one=1;
  if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&one,sizeof(one))!=0)/*necc?*/
    perror("plaind setsockopt()"),exit(1);
  addr.sin_family=AF_INET;
  addr.sin_addr.s_addr=INADDR_ANY;
  addr.sin_port=htons(port); /*byteorder(3N): endian conversion*/
  if(bind(s,(struct sockaddr*)&addr,sizeof(addr))) /*bind(3N): name to socket*/
    perror("plaind bind()"),exit(1);
  if(listen(s,3)==-1)perror("plaind listen()"),exit(1);/*listen(3N):queue len*/
  /*reap kids*/
  (void)signal(SIGCHLD,sighandler); /*signal(3C): set disposition*/
  for(;;){
    FD_ZERO(&readfds);
    FD_SET(s,&readfds);
    rc=select(maxopenfiles,&readfds,0,0,0); /*select(3C): check if can read*/
    if(rc==-1||rc==0)continue;
    if(!FD_ISSET(s,&readfds))continue;
    fromlen=sizeof(from);
    /*accept(3N): socket connection*/
    if((ns=accept(s,(struct sockaddr*)&from,&fromlen))==-1)continue;
    switch(pid=fork()){
    case -1: /*failed*/
      perror("plaind fork()");
      break;
    case 0: /*child*/
      close(s);
      alarm(10); /*alarm(2): set alarm clock (why???)*/
      processreq(ns);
      break;
    default: /*parent*/
      close(ns);
    }
  }
}
