#include <errno.h>       /* obligatory includes */
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORTNUM 12345 /* random port number, we need something */
#define MAXHOSTNAME 80

  void fireman(), do_something();

  main()
  { int s, t;

    if ((s= establish(PORTNUM)) < 0) {  /* plug in the phone */
      perror("establish");
      exit(1);
    }

    signal(SIGCHLD, fireman);           /* this eliminates zombies */

    while(1) {                          /* loop for phone calls */
      if ((t= get_connection(s)) < 0) { /* get a connection */
        if (errno == EINTR)             /* EINTR might happen on accept(), */
          continue;                     /* try again */
        perror("accept");               /* bad */
        exit(1);
      }
      switch(fork()) {                  /* try to handle connection */
      case -1 :                         /* bad news.  scream and die */
        perror("fork");
        close(s);
        close(t);
        exit(1);
      case 0 :                          /* we're the child, do something */
        do_something(t);
        exit(0);
      default :                         /* we're the parent so look for */
        close(t);                       /* another connection */
        continue;
      }
    }
  }


void fireman()
{ union wait wstatus;
  
  while(wait3(&wstatus,WNOHANG,NULL) >= 0);
}


void do_something(s)
     int s;
{
  int a;
  char from_s;
  while((a=read_data(s,&from_s,1))!=-1) {
    putchar((char)from_s);
  }
}


int read_data(s,buf,n)
     int  s;                /* connected socket */
     char *buf;             /* pointer to the buffer */
     int  n;                /* number of characters (bytes) we want */
{ int bcount,          /* counts bytes read */
    br;              /* bytes read this pass */
  
  bcount= 0;
  br= 0;
  while (bcount < n) {             /* loop until full buffer */

    if ((br=read(s,buf,n-bcount)) > 0) {
      puts("read");
      bcount += br;      
      buf += br;           
    }

    if (br < 1)                    /* signal an error to the caller */
      return(-1);

  }
  return(bcount);
}



int establish(portnum)
     u_short portnum;
{ char   myname[MAXHOSTNAME+1];
  int    s;
  struct sockaddr_in sa;
  struct hostent *hp;

  bzero(&sa,sizeof(struct sockaddr_in));      /* clear our address */
  gethostname(myname,MAXHOSTNAME);            /* who are we? */
  hp= gethostbyname(myname);                  /* get our address info */
  if (hp == NULL)                             /* we don't exist !? */
    return(-1);
  sa.sin_family= hp->h_addrtype;              /* this is our host address */
  sa.sin_port= htons(portnum);                /* this is our port number */
  if ((s= socket(AF_INET,SOCK_STREAM,0)) < 0) /* create socket */
    return(-1);
  if (bind(s,&sa,sizeof sa,0) < 0) {
    close(s);
    return(-1);                               /* bind address to socket */
  }
  listen(s, 3);                               /* max # of queued connects */
  return(s);
}


int get_connection(s)
     int s;                    /* socket created with establish() */
{ struct sockaddr_in isa; /* address of socket */
  int i;                  /* size of address */
  int t;                  /* socket of connection */
  
  i = sizeof(isa);                   /* find socket's address */
  getsockname(s,&isa,&i);            /* for accept() */
  
  if ((t = accept(s,&isa,&i)) < 0)   /* accept connection if there is one */
    return(-1);
  return(t);
}

