home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3543 / tcpserver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  7.2 KB  |  308 lines

  1. /* Public domain. */
  2.  
  3. #include <stdio.h>
  4. #include <signal.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <sys/stat.h>
  8. #include <sys/wait.h>
  9. #include <sys/file.h>
  10. #include <netinet/in.h>
  11. #include <netdb.h>
  12. #include <arpa/inet.h>
  13. #include <sys/time.h>
  14. #include <sys/param.h>
  15. #include "dupdup.h"
  16. #include "malloc.h"
  17. #include "errno.h"
  18. #include "username.h"
  19. #include "hostname.h"
  20. #include "portname.h"
  21. #include "env.h"
  22. #include "getopt.h"
  23. #include "authuser.h"
  24. #include "numfiles.h"
  25.  
  26. #ifndef MAXHOSTNAMELEN
  27. #define MAXHOSTNAMELEN 64
  28. #endif
  29.  
  30. static int flagdo931 = 1;
  31. static int flagprintlocal = 0;
  32. static int flagverbose = 1;
  33. static struct sockaddr_in sabind;
  34.  
  35. static char *fnrecord;
  36.  
  37. int record(uid,host,port,pid)
  38. int uid;
  39. char *host;
  40. int port;
  41. int pid;
  42. {
  43.  char *home;
  44.  char pidstr[50];
  45.  int fd;
  46.  /* The idea is to record our pid in $HOME/.tcpserver.host.uid.port. */
  47.  /* Then tcpkiller can read the pid from there, and send us a signal. */
  48.  /* TCPHOME overrides HOME if it is set. */
  49.  /* XXX: should we choose a signal that won't hurt ordinary processes? */
  50.  /* XXX: anything good to do if $HOME is undefined or unwritable? */
  51.  
  52.  home = env_get("TCPHOME");
  53.  if (!home)
  54.   {
  55.    home = env_get("HOME");
  56.    if (!home)
  57.      return -1;
  58.   }
  59.  fnrecord = malloc(strlen(home) + strlen(host) + 100);
  60.  if (!fnrecord)
  61.    return -1;
  62.  sprintf(fnrecord,"%s/.tcpserver.%s.%d.%d",home,host,uid,port);
  63.  
  64.  unlink(fnrecord); /* XXX */
  65.  
  66.  fd = open(fnrecord,O_WRONLY | O_CREAT | O_EXCL,0400);
  67.  if (fd == -1)
  68.   {
  69.    /* XXX */
  70.    return -1;
  71.   }
  72.  
  73.  sprintf(pidstr,"%d",pid);
  74.  
  75.  write(fd,pidstr,strlen(pidstr) + 1); /* XXX: check for partial writes */
  76.  
  77.  close(fd);
  78.  return 0;
  79. }
  80.  
  81. SIGRET sigterm()
  82. {
  83.  if (fnrecord)
  84.    unlink(fnrecord); /*XXX*/
  85.  exit(0);
  86. }
  87.  
  88. SIGRET sigchld()
  89. {
  90.  wait((union wait *) 0); /*XXX*/
  91. }
  92.  
  93. static char errbuf[500];
  94. void die(n,s) int n; char *s;
  95. { if (flagverbose) fprintf(stderr,"tcpserver: fatal: %s\n",s); exit(n); }
  96. void dies(n,s,t) int n; char *s; char *t;
  97. { if (flagverbose) fprintf(stderr,"tcpserver: fatal: %s%s\n",s,t); exit(n); }
  98. void diep(n,s) int n; char *s;
  99. { if (flagverbose) sprintf(errbuf,"tcpserver: fatal: %s",s); perror(errbuf); exit(n); }
  100. void warnp(s) char *s;
  101. { if (flagverbose) sprintf(errbuf,"tcpserver: warning: %s",s); perror(errbuf); }
  102. void warnsp(s,t) char *s; char *t;
  103. { if (flagverbose) sprintf(errbuf,"tcpserver: warning: %s%s",s,t); perror(errbuf); }
  104.  
  105. main(argc,argv,envp)
  106. int argc;
  107. char *argv[];
  108. char *envp[];
  109. {
  110.  int s;
  111.  int dummy;
  112.  int t;
  113.  int *d;
  114.  int tdup;
  115.  int numfiles;
  116.  static struct sockaddr_in sa;
  117.  int uid;
  118.  int i;
  119.  char lochost[MAXHOSTNAMELEN];
  120.  struct in_addr locinaddr;
  121.  char tcplocal[300]; /*XXX*/
  122.  char tcpremote[300]; /*XXX*/
  123.  int locport;
  124.  int remport;
  125.  char *remhost;
  126.  char *ruser;
  127.  char *uname;
  128.  int opt;
  129.  
  130.  while ((opt = getopt(argc,argv,"qQ4rR")) != EOF)
  131.    switch(opt)
  132.     {
  133.      case 'q':
  134.        flagverbose = 0;
  135.        break;
  136.      case 'Q':
  137.        flagverbose = 1;
  138.        break;
  139.      case '4':
  140.        flagprintlocal = 1;
  141.        break;
  142.      case 'r':
  143.        flagdo931 = 1;
  144.        break;
  145.      case 'R':
  146.        flagdo931 = 0;
  147.        break;
  148.      case '?':
  149.        break; /*XXX*/
  150.      default:
  151.        break; /*XXX*/
  152.     }
  153.  argc -= optind; argv += optind;
  154.  
  155.  if (argc < 3)
  156.    die(1,"need at least three arguments");
  157.  
  158.  uid = getuid();
  159.  if (uid2username(uid,&uname) == -1) /* will never happen */
  160.    die(2,"cannot figure out my own username");
  161.  
  162.  gethostname(lochost,sizeof(lochost));
  163.  if (hostname2inaddr(lochost,&locinaddr) == -1)
  164.    die(2,"cannot figure out my own hostname");
  165.  
  166.  if ((argv[0][0] == '0') && (argv[0][1] == 0))
  167.    sabind.sin_addr.s_addr = INADDR_ANY; /* special case "0" */
  168.  else
  169.   {
  170.    if (hostname2inaddr(argv[0],&sabind.sin_addr) == -1)
  171.      dies(2,"cannot figure out hostname ",argv[0]);
  172.    /* XXX: check whether sabind.sin_addr matches locinaddr? */
  173.   }
  174.  
  175.  if (portname2port(argv[1],&locport,"tcp") == -1)
  176.    dies(2,"cannot figure out portname ",argv[1]);
  177.  locport = locport & 65535;
  178.  sabind.sin_port = htons((short) locport);
  179.  
  180.  close(6);
  181.  close(7); /* XXX: these have implications that should be documented */
  182.  signal(SIGTERM,sigterm);
  183.  signal(SIGINT,sigterm);
  184.  signal(SIGCHLD,sigchld);
  185.  signal(SIGPIPE,SIG_IGN);
  186.  
  187.  numfiles = NUMFILES;
  188.  d = (int *) malloc(numfiles * sizeof(int));
  189.  if (!d)
  190.    die(6,"cannot malloc");
  191.  for (i = 0;i < numfiles;++i)
  192.    d[i] = -1;
  193.  
  194.  s = socket(AF_INET,SOCK_STREAM,0);
  195.  if (s == -1)
  196.    diep(7,"cannot create server socket");
  197.  sabind.sin_family = AF_INET;
  198.  if (bind(s,(struct sockaddr *) &sabind,sizeof(sabind)) == -1)
  199.    diep(9,"cannot bind server socket");
  200.  if (listen(s,5) == -1) 
  201.    diep(10,"cannot listen on server socket");
  202.  dummy = sizeof(sabind);
  203.  if (getsockname(s,&sabind,&dummy) == -1)
  204.    diep(9,"cannot figure out local connection address");
  205.  locport = ntohs(sabind.sin_port);
  206.  
  207.  if (env_init() == -1)
  208.    die(11,"cannot init environment");
  209.  if (env_put("PROTO=TCP") == -1)
  210.    die(11,"out of memory putting PROTO into environment");
  211.  sprintf(tcplocal,"TCPLOCAL=%s@%s(%s):%d"
  212.    ,uname
  213.    ,inet_ntoa(locinaddr) /* could use sabind.sin_addr */
  214.    ,lochost
  215.    ,locport
  216.   );
  217.  if (env_put(tcplocal) == -1)
  218.    die(11,"out of memory putting TCPLOCAL into environment");
  219.  
  220.  if (flagprintlocal)
  221.   {
  222.    FILE *fd4;
  223.    fd4 = fdopen(4,"w");
  224.    if (!fd4)
  225.      die(1,"cannot print TCPLOCAL on fd 4");
  226.    fprintf(fd4,"%s@%s(%s):%d\n"
  227.      ,uname
  228.      ,inet_ntoa(locinaddr) /* could use sabind.sin_addr */
  229.      ,lochost
  230.      ,locport
  231.     );
  232.    fclose(fd4);
  233.    close(4); /* just in case */
  234.   }
  235.  
  236.  if (record(uid,lochost,locport,getpid()) == -1)
  237.    die(1,"cannot record process id for tcpkiller");
  238.    /* XXX: could use argv[0] instead of lochost here... hmmm */
  239.  
  240.  for (;;)
  241.   {
  242.    /* XXX: don't accept too many requests at once? */
  243.    dummy = sizeof(sa);
  244.    t = accept(s,(struct sockaddr *) &sa,&dummy);
  245.    if (t == -1) /* so when can this happen? */
  246.     {
  247.      switch(errno)
  248.       {
  249.        case SIGCHLD: break; /*XXX*/
  250.        case EINTR: break; /*XXX*/
  251.        case EMFILE: sleep(1); break; /*XXX*/
  252.        case ENFILE: sleep(1); break; /*XXX*/
  253.        default: ; /*XXX*/
  254.       }
  255.      continue;
  256.     }
  257.  
  258.    switch(fork())
  259.     {
  260.      case -1:
  261.        warnp("cannot fork");
  262.        break;
  263.  
  264.      case 0:
  265.  
  266.        remport = ntohs(sa.sin_port);
  267.        ruser = "";
  268.        if (flagdo931)
  269.         {
  270.          ruser = auth_tcpuser((unsigned long) sa.sin_addr.s_addr
  271.                  ,(unsigned short) locport
  272.                   ,(unsigned short) remport);
  273.          if (!ruser)
  274.            ruser = ""; /* XXX: any other suggestions? */
  275.         }
  276.        if (inaddr2hostname(sa.sin_addr,&remhost) == -1) /* will never happen */
  277.      die(1,"cannot find hostname");
  278.        sprintf(tcpremote,"TCPREMOTE=%s@%s(%s):%d"
  279.          ,ruser
  280.          ,inet_ntoa(sa.sin_addr)
  281.      ,remhost
  282.      ,remport
  283.         );
  284.        if (env_put(tcpremote) == -1)
  285.      die(1,"out of memory putting TCPREMOTE into environment");
  286.  
  287.        tdup = dup(t);
  288.        if (tdup == -1)
  289.      diep(1,"cannot dup connection to client");
  290.  
  291.        /* Now put t into descriptor 6 and tdup into descriptor 7. */
  292.        /* XXX: should check that t and tdup are small enough */
  293.        d[t] = 6;
  294.        d[tdup] = 7;
  295.        if (dupdup(d,numfiles) == -1)
  296.      diep(1,"cannot dup connection to client");
  297.  
  298.        signal(SIGPIPE,SIG_DFL);
  299.        execvp(argv[2],argv + 2);
  300.        warnsp("cannot exec ",argv[2]);
  301.        exit(1);
  302.  
  303.      default:
  304.        close(t);
  305.     }
  306.   }
  307. }
  308.