Пример #1
0
int main()
{
  char *x;
  int udp53;

  x = env_get("IP");
  if (!x)
    strerr_die2x(111,fatal,"$IP not set");
  if (!ip4_scan(x,ip))
    strerr_die3x(111,fatal,"unable to parse IP address ",x);

  udp53 = socket_udp();
  if (udp53 == -1)
    strerr_die2sys(111,fatal,"unable to create UDP socket: ");
  if (socket_bind4_reuse(udp53,ip,53) == -1)
    strerr_die2sys(111,fatal,"unable to bind UDP socket: ");

  droproot(fatal);

  initialize();
  
  ndelay_off(udp53);
  socket_tryreservein(udp53,65536);

  buffer_putsflush(buffer_2,starting);

  for (;;) {
    len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
    if (len < 0) continue;
    if (!doit()) continue;
    if (response_len > 512) response_tc();
    socket_send4(udp53,response,response_len,ip,port);
    /* may block for buffer space; if it fails, too bad */
  }
}
Пример #2
0
static void ot_try_bind( char ip[4], uint16 port, int is_tcp ) {
  int64 s = is_tcp ? socket_tcp4( ) : socket_udp4();

  if( socket_bind4_reuse( s, ip, port ) == -1 )
    panic( "socket_bind4_reuse" );

  if( is_tcp && ( socket_listen( s, SOMAXCONN) == -1 ) )
    panic( "socket_listen" );

  if( !io_fd( s ) )
    panic( "io_fd" );

  io_setcookie( s, is_tcp ? FLAG_TCP : FLAG_UDP );

  io_wantread( s );
}
Пример #3
0
static int make_connection(char* ip,uint16 port,uint32 scope_id) {
  int v6=byte_diff(ip,12,V4mappedprefix);
  int s;
  if (v6) {
    s=socket_tcp6();
    if (s==-1)
      panic("socket_tcp6()");
    ndelay_off(s);
    if (bindport) {
      for (;;) {
	int r=socket_bind6_reuse(s,V6any,bindport,0);
	if (++bindport<1024) bindport=1024;
	if (r==0) break;
	if (errno!=EADDRINUSE)
	  panic("socket_bind6");
      }
    }
    if (socket_connect6(s,ip,port,scope_id)==-1) {
      carp("socket_connect6");
      close(s);
      return -1;
    }
  } else {
    s=socket_tcp4();
    if (s==-1)
      panic("socket_tcp4()");
    ndelay_off(s);
    if (bindport) {
      for (;;) {
	int r=socket_bind4_reuse(s,V6any,bindport);
	if (++bindport<1024) bindport=1024;
	if (r==0) break;
	if (errno!=EADDRINUSE)
	  panic("socket_bind4");
      }
    }
    if (socket_connect4(s,ip+12,port)==-1) {
      carp("socket_connect4");
      close(s);
      return -1;
    }
  }
  return s;
}
Пример #4
0
int
main (int argc, char *argv[])
{
    time_t t = 0;
    char *x = NULL;
    struct sigaction sa;
    iopause_fd *iop = NULL;
    int i = 0, n = 0, *udp53 = NULL;

    prog = strdup ((x = strrchr (argv[0], '/')) != NULL ? x + 1 : argv[0]);

    sa.sa_handler = handle_term;
    sigaction (SIGINT, &sa, NULL);
    sigaction (SIGTERM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction (SIGPIPE, &sa, NULL);

    i = check_option (argc, argv);
    argc -= i;
    argv += i;

    if (mode & DAEMON)
    {
        i = fork ();
        if (i == -1)
            err (-1, "could not fork a daemon process");
        if (i > 0)
            return 0;
    }

    time (&t);
    memset (buf, 0, sizeof (buf));
    strftime (buf, sizeof (buf), "%b-%d %Y %T %Z", localtime (&t));
    warnx ("version %s: starting: %s\n", VERSION, buf);

    set_timezone ();
    if (debug_level)
        warnx ("TIMEZONE: %s", env_get ("TZ"));

    initialize ();
    if (!debug_level)
        if ((x = env_get ("DEBUG_LEVEL")))
            debug_level = atol (x);
    warnx ("DEBUG_LEVEL set to `%d'", debug_level);

    if ((x = env_get ("DATALIMIT")))
    {
        struct rlimit r;
        unsigned long dlimit = atol (x);

        if (getrlimit (RLIMIT_DATA,  &r) != 0)
            err (-1, "could not get resource RLIMIT_DATA");

        r.rlim_cur = (dlimit <= r.rlim_max) ? dlimit : r.rlim_max;

        if (setrlimit (RLIMIT_DATA, &r) != 0)
            err (-1, "could not set resource RLIMIT_DATA");

        if (debug_level)
            warnx ("DATALIMIT set to `%ld' bytes", r.rlim_cur);
    }

    if (!(x = env_get ("IP")))
        err (-1, "$IP not set");
    for (i = 0; (unsigned)i < strlen (x); i++)
        n = (x[i] == ',') ? n+1 : n;
    if (!(udp53 = calloc (n+1, sizeof (int))))
        err (-1, "could not allocate enough memory for udp53");
    if (!(iop = calloc (n+1, sizeof (iopause_fd))))
        err (-1, "could not allocate enough memory for iop");

    i = n = 0;
    while (x[i])
    {
        unsigned int l = 0;

        if (!(l = ip4_scan(x+i, ip)))
            errx (-1, "could not parse IP address `%s'", x + i);

        udp53[n] = socket_udp();
        if (udp53[n] == -1)
            errx (-1, "could not open UDP socket");
        if (socket_bind4_reuse (udp53[n], ip, server_port) == -1)
            errx (-1, "could not bind UDP socket");

        ndelay_off (udp53[n]);
        socket_tryreservein (udp53[n], 65536);

        iop[n].fd = udp53[n];
        iop[n].events = IOPAUSE_READ;

        n++;
        i += (x[i + l] == ',') ? l + 1 : l;
    }

    droproot ();
    while (1)
    {
        struct taia stamp;
        struct in_addr odst; /* original destination IP */
        struct taia deadline;

        taia_now (&stamp);
        taia_uint (&deadline, 300);
        taia_add (&deadline, &deadline, &stamp);
        iopause (iop, n, &deadline, &stamp);

        for (i = 0; i < n; i++)
        {
            if (!iop[i].revents)
                continue;

            len = socket_recv4 (udp53[i], buf, sizeof (buf), ip, &port, &odst);
            if (len < 0)
                continue;
            if (!doit ())
                continue;
            if (response_len > 512)
                response_tc ();

            /* may block for buffer space; if it fails, too bad */
            len = socket_send4 (udp53[i], response,
                                response_len, ip, port, &odst);
            if (len < 0)
                continue;
            if (debug_level > 1)
                log_querydone(qnum, response, response_len);
        }
    }

    return 0;
}
Пример #5
0
int
main (int argc, char *argv[])
{
    int i = 0;
    time_t t = 0;
    struct sigaction sa;
    unsigned long cachesize = 0;
    char *x = NULL, char_seed[128];

    sa.sa_handler = handle_term;
    sigaction (SIGINT, &sa, NULL);
    sigaction (SIGTERM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction (SIGPIPE, &sa, NULL);

    seed_addtime ();
    seed_adduint32 (getpid ());
    seed_adduint32 (getppid ());
    seed_adduint32 (getuid ());
    seed_adduint32 (getgid ());

    seed_addtime ();
    prog = strdup ((x = strrchr (argv[0], '/')) != NULL ?  x + 1 : argv[0]);
    i = check_option (argc, argv);
    argc -= i;
    argv += i;

    if (mode & DAEMON)
    {
        i = fork ();
        if (i == -1)
            err (-1, "could not fork a daemon process");
        if (i > 0)
            return 0;
    }

    time (&t);
    strftime (char_seed, sizeof (char_seed), "%b-%d %Y %T %Z", localtime (&t));
    warnx ("version %s: starting: %s\n", VERSION, char_seed);

    set_timezone ();
    if (debug_level)
        warnx ("TIMEZONE: %s", env_get ("TZ"));

    read_conf (CFGFILE);
    if (!debug_level)
        if ((x = env_get ("DEBUG_LEVEL")))
            debug_level = atol (x);
    warnx ("DEBUG_LEVEL set to `%d'", debug_level);

    if ((x = env_get ("DATALIMIT")))
    {
        struct rlimit r;
        unsigned long dlimit = atol (x);

        if (getrlimit (RLIMIT_DATA,  &r) != 0)
            err (-1, "could not get resource RLIMIT_DATA");

        r.rlim_cur = (dlimit <= r.rlim_max) ? dlimit : r.rlim_max;

        if (setrlimit (RLIMIT_DATA, &r) != 0)
            err (-1, "could not set resource RLIMIT_DATA");

        if (debug_level)
            warnx ("DATALIMIT set to `%ld' bytes", r.rlim_cur);
    }

    if (!(x = env_get ("IP")))
        err (-1, "$IP not set");
    if (!ip4_scan (x, myipincoming))
        err (-1, "could not parse IP address `%s'", x);

    seed_addtime ();
    udp53 = socket_udp ();
    if (udp53 == -1)
        err (-1, "could not open UDP socket");
    if (socket_bind4_reuse (udp53, myipincoming, 53) == -1)
        err (-1, "could not bind UDP socket");

    seed_addtime ();
    tcp53 = socket_tcp ();
    if (tcp53 == -1)
        err (-1, "could not open TCP socket");
    if (socket_bind4_reuse (tcp53, myipincoming, 53) == -1)
        err (-1, "could not bind TCP socket");

    if (mode & DAEMON)
    {
        /* redirect stdout & stderr to a log file */
        redirect_to_log (LOGFILE, STDOUT_FILENO | STDERR_FILENO);

        write_pid (PIDFILE);
    }

    seed_addtime ();
    droproot ();
    if (mode & DAEMON)
        /* crerate a new session & detach from controlling tty */
        if (setsid () < 0)
            err (-1, "could not start a new session for the daemon");

    seed_addtime ();
    socket_tryreservein (udp53, 131072);

    memset (char_seed, 0, sizeof (char_seed));
    for (i = 0, x = (char *)seed; (unsigned)i < sizeof (char_seed); i++, x++)
        char_seed[i] = *x;
    dns_random_init (char_seed);

    if (!(x = env_get ("IPSEND")))
        err (-1, "$IPSEND not set");
    if (!ip4_scan (x, myipoutgoing))
        err (-1, "could not parse IP address `%s'", x);

    if (!(x = env_get ("CACHESIZE")))
        err (-1, "$CACHESIZE not set");
    scan_ulong (x, &cachesize);
    if (!cache_init (cachesize))
        err (-1, "could not allocate `%ld' bytes for cache", cachesize);

    if (env_get ("HIDETTL"))
        response_hidettl ();
    if (env_get ("FORWARDONLY"))
        query_forwardonly ();
    if (env_get ("MERGEQUERIES"))
        dns_enable_merge (log_merge);
    if (!roots_init ())
        err (-1, "could not read servers");
    if (debug_level > 3)
        roots_display();
    if (socket_listen (tcp53, 20) == -1)
        err (-1, "could not listen on TCP socket");
    if (!dbl_init() && debug_level > 1)
        warnx ("could not read dnsbl.cdb");

    doit ();

    return 0;
}
Пример #6
0
int main(int argc,char **argv)
{
 char *hostname, *x;
 int c, s, t;
 unsigned int u;
 unsigned int cpid = 0;

 opterr = 0;

 while ((c = getopt(argc, argv, "dDoOC:k:c:")) != -1)
  switch (c) {
	case 'c':
	 limit = atoi(optarg);
	 if (limit == 0) usage();
	 break;
	case 'd': flagdelay = 1; break;
	case 'D': flagdelay = 0; break;
	case 'O': flagkillopts = 1; break;
	case 'o': flagkillopts = 0; break;
	case 'C': cacheprogram = 1; break;
	case 'k':
	 autokill = atoi(optarg);
	 if (autokill == 0) usage();
	 break;
	default: abort();
  }
 argc -= optind;
 argv += optind;

 hostname = *argv++;
 if (!hostname) usage();

 x = *argv++;
 if (!x) usage();
 u = 0;
 u = atoi(x);
 if (u != 0) localport = u;
 else usage();

 if (!*argv) usage();

 sig_block(sig_child);
 sig_catch(sig_child,sigchld);
 sig_catch(sig_term,sigterm);
 sig_catch(sig_int,sigint);
 sig_ignore(sig_pipe);

 inet_aton(hostname, (struct in_addr *) &localip);

 if (autokill != 0) pt = ptable_init(limit);

 s = socket_tcp();
 if (s == -1) die(111, "unable to create socket");
 if (socket_bind4_reuse(s,localip,localport) == -1) die(111, "unable to bind");
 if (socket_local4(s,localip,&localport) == -1) die(111, "unable to get local address");
 if (socket_listen(s,20) == -1) die(111, "unable to listen");
 ndelay_off(s);

 fprintf(stderr, "bind: %s:%d\n", hostname, localport);

 close(0);
 close(1);
 printstatus();

 if (cacheprogram) {

   FILE *fp1;
   int fp2;
   char path[1024];
   ssize_t n;

   fp1 = popen(*argv, "r");
   if (fp1 == NULL) {
     fprintf(stderr, "Failed to run command\n");
     exit(1);
   }

   fp2 = open("/var/tmp/tcpd.cache", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
   if (fp2 == -1) {
     fprintf(stderr, "Can't open cache file\n");
     exit(1);
   }

   while ((n = fgets(path, sizeof(path)-1, fp1)) != NULL) {
     if (write(fp2, path, n) == n) {
       fprintf(stderr, "Error occured while creating cache\n");
       exit(1);
     }
   }

   /* close */
   pclose(fp1);
   close(fp2);

   // read cache file into memory
   FILE *f = fopen("/var/tmp/tcpd.cache", "rb");
   fseek(f, 0, SEEK_END);
   cachesize = ftell(f);
   fseek(f, 0, SEEK_SET);  //same as rewind(f);
   cache = malloc(cachesize + 1);
   n = fread(cache, cachesize, 1, f);
   fclose(f);
   cache[cachesize] = 0;
 }

 for (;;) {
   while (numchildren >= limit) {
    if (autokill != 0) ptable_autokill(pt, limit, autokill);
    sig_pause();
   }

   sig_unblock(sig_child);
   t = socket_accept4(s,remoteip,&remoteport);
   sig_block(sig_child);

   if (t == -1) continue;
   ++numchildren; printstatus();
   fprintf(stderr, "inbound connection from %d.%d.%d.%d:%d\n", (unsigned char) remoteip[0], (unsigned char) remoteip[1], (unsigned char) remoteip[2], (unsigned char) remoteip[3], remoteport);

   if (autokill != 0) ptable_autokill(pt,limit,autokill);

   cpid = fork();
   switch(cpid) {
	case 0:
	 close(s);
	 if(flagkillopts) socket_ipoptionskill(t);
	 if(!flagdelay) socket_tcpnodelay(t);
	 if((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) die(111,"unable to setup descriptors");
	 sig_uncatch(sig_child);
	 sig_unblock(sig_child);
	 sig_uncatch(sig_term);
	 sig_uncatch(sig_int);
	 sig_uncatch(sig_pipe);

	 if (cacheprogram) {
	   printf("%s", cache);
	   close(t);
	   exit(0);
	 } else {
	   if(execve(*argv,argv,NULL) == 0) {
	     close(t);
	     exit(0);
	   } else {
	     die(111, "unable to run argv");
	   }
	 }
	 break;
	case -1:
	 // unable to fork
	 eprint(P_WARN,"unable to fork");
	 --numchildren; printstatus();
	 break;
	default:
	 fprintf(stderr, "fork: child pid %d\n", cpid);
	 if (autokill != 0) ptable_set(pt, limit, cpid, time(NULL));
	 break;
   }
   close(t);
 }
}
Пример #7
0
int main(int argc, char **argv) {
  int opt;
  char *user =0;
  char *host;
  unsigned long port;
  int pid;
  int s;
  int conn;
  int delim;

  progname =*argv;
  phccmax =0;

#ifdef SSLSVD
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
#else
  while ((opt =getopt(argc, (const char **)argv,
                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
#endif
    switch(opt) {
    case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
    case 'C':
      delim =scan_ulong(optarg, &phccmax);
      if (phccmax < 1) usage();
      if (optarg[delim] == ':') {
        if (ipsvd_fmt_msg(&msg, optarg +delim +1) == -1) die_nomem();
        if (! stralloc_0(&msg)) die_nomem();
        phccmsg =msg.s;
      }
      break;
    case 'i': if (instructs) usage(); instructs =optarg; break;
    case 'x': if (instructs) usage(); instructs =optarg; iscdb =1; break;
    case 'u': user =(char*)optarg; break;
    case 'l':
      if (! stralloc_copys(&local_hostname, optarg)) die_nomem();
      if (! stralloc_0(&local_hostname)) die_nomem();
      break;
    case 'E': ucspi =0; break;
    case 'b': scan_ulong(optarg, &backlog); break;
    case 'h': lookuphost =1; break;
    case 'p': lookuphost =1; paranoid =1; break;
    case 't': scan_ulong(optarg, &timeout); break;
    case 'v': ++verbose; break;
#ifdef SSLSVD
    case 'U': ssluser =(char*)optarg; break;
    case '/': root =(char*)optarg; break;
    case 'Z': cert =(char*)optarg; break;
    case 'K': key =(char*)optarg; break;
#endif
    case 'V': strerr_warn1(VERSION, 0);
    case '?': usage();
    }
  }
  argv +=optind;

  if (! argv || ! *argv) usage();
  host =*argv++;
  if (! argv || ! *argv) usage();
  local_port =*argv++;
  if (! argv || ! *argv) usage();
  prog =(const char **)argv;
  if (phccmax > cmax) phccmax =cmax;

  if (user)
    if (! uidgids_get(&ugid, user)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", user, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", user);
    }
#ifdef SSLSVD
  svuser =user;
  client =0;
  if ((getuid() == 0) && (! ssluser))
    strerr_die2x(100, FATAL, "-U ssluser must be set when running as root");
  if (ssluser)
    if (! uidgids_get(&sslugid, ssluser)) {
      if (errno)
        strerr_die4sys(111, FATAL, "unable to get user/group: ", ssluser, ": ");
      strerr_die3x(100, FATAL, "unknown user/group: ", ssluser);
    }
  if (! cert) cert ="./cert.pem";
  if (! key) key =cert;
  if (matrixSslOpen() < 0) fatal("unable to initialize ssl");
  if (matrixSslReadKeys(&keys, cert, key, 0, ca) < 0) {
    if (client) fatal("unable to read cert, key, or ca file");
    fatal("unable to read cert or key file");
  }
  if (matrixSslNewSession(&ssl, keys, 0, SSL_FLAGS_SERVER) < 0)
    strerr_die2x(111, FATAL, "unable to create ssl session");
#endif

  dns_random_init(seed);
  sig_block(sig_child);
  sig_catch(sig_child, sig_child_handler);
  sig_catch(sig_term, sig_term_handler);
  sig_ignore(sig_pipe);

  if (phccmax) if (ipsvd_phcc_init(cmax) == -1) die_nomem();

  if (str_equal(host, "")) host ="0.0.0.0";
  if (str_equal(host, "0")) host ="0.0.0.0";

  if (! ipsvd_scan_port(local_port, "tcp", &port))
    strerr_die3x(100, FATAL, "unknown port number or name: ", local_port);

  if (! stralloc_copys(&sa, host)) die_nomem();
  if ((dns_ip4(&ips, &sa) == -1) || (ips.len < 4))
    if (dns_ip4_qualify(&ips, &fqdn, &sa) == -1)
      fatal2("unable to look up ip address", host);
  if (ips.len < 4)
    strerr_die3x(100, FATAL, "unable to look up ip address: ", host);
  ips.len =4;
  if (! stralloc_0(&ips)) die_nomem();
  local_ip[ipsvd_fmt_ip(local_ip, ips.s)] =0;

  if (! lookuphost) {
    if (! stralloc_copys(&remote_hostname, "")) die_nomem();
    if (! stralloc_0(&remote_hostname)) die_nomem();
  }

  if ((s =socket_tcp()) == -1) fatal("unable to create socket");
  if (socket_bind4_reuse(s, ips.s, port) == -1)
    fatal("unable to bind socket");
  if (listen(s, backlog) == -1) fatal("unable to listen");
  ndelay_off(s);

#ifdef SSLSVD
#else
  if (user) {
    /* drop permissions */
    if (setgroups(ugid.gids, ugid.gid) == -1) fatal("unable to set groups");
    if (setgid(*ugid.gid) == -1) fatal("unable to set gid");
    if (prot_uid(ugid.uid) == -1) fatal("unable to set uid");
  }
#endif
  close(0);

  if (verbose) {
    out(INFO); out("listening on "); outfix(local_ip); out(":");
    outfix(local_port);
#ifdef SSLSVD
#else
    if (user) {
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.uid)] =0;
      out(", uid "); out(bufnum);
      bufnum[fmt_ulong(bufnum, (unsigned long)ugid.gid)] =0;
      out(", gid "); out(bufnum);
    }
#endif
    flush(", starting.\n");
  }
  for (;;) {
    while (cnum >= cmax) sig_pause();
    socka_size =sizeof(socka);

    sig_unblock(sig_child);
    conn =accept(s, (struct sockaddr *)&socka, &socka_size);
    sig_block(sig_child);

    if (conn == -1) {
      if (errno != error_intr) warn("unable to accept connection");
      continue;
    }
    cnum++;

    if (verbose) connection_status();
    if (phccmax) phcc =ipsvd_phcc_add((char*)&socka.sin_addr);
    if ((pid =fork()) == -1) {
      warn2("drop connection", "unable to fork");
      close(conn);
      continue;
    }
    if (pid == 0) {
      /* child */
      close(s);
#ifdef SSLSVD
      if (*progname) *progname ='\\';
#endif
      connection_accept(conn);
    }
    if (phccmax) ipsvd_phcc_setpid(pid);
    close(conn);
  }
  _exit(0);
}
Пример #8
0
int main(int argc,char* argv[]) {
  int s,t;
  uint16 port=2342;
  uint32 scope_id=0;
  char ip[16];
  char buf[8192];
  int i;
  struct pollfd p[2];

  if (argc<3) {
usage:
    __write2("usage: server ip port\n\nexample: server 0 8000 | restore x -f -\n");
    return 0;
  }
  if (!strcmp(argv[1],"0"))
    byte_zero(ip,16);
  else
    if (argv[1][i=scan_ip6if(argv[1],ip,&scope_id)]) {
      __write2("server: error: invalid ip address!\n");
      goto usage;
    }
  if (argv[2][scan_ushort(argv[2],&port)]) {
    __write2("server: error: invalid port number!\n");
    goto usage;
  }
  if (byte_equal(ip,12,V4mappedprefix)) {
    s=socket_tcp4b();
    if (s==-1) panic("server: error: socket() failed");
    if (socket_bind4_reuse(s,ip+12,port)==-1) panic("server: error: bind() failed");
    if (socket_listen(s,1)==-1) panic("server: error: listen() failed");
    ndelay_off(s);
    if ((t=socket_accept4(s,0,0))==-1) panic("server: error: accept() failed");
  } else {
    s=socket_tcp6b();
    if (s==-1) panic("server: error: socket() failed");
    if (socket_bind6_reuse(s,ip,port,scope_id)==-1) panic("server: error: bind() failed");
    if (socket_listen(s,1)==-1) panic("server: error: listen() failed");
    ndelay_off(s);
    if ((t=socket_accept6(s,0,0,0))==-1) panic("server: error: accept() failed");
  }
  close(s);
  p[0].fd=0; p[0].events=POLLIN;
  p[1].fd=t; p[1].events=POLLIN;
  while (poll(p,2,5000)) {
    if (p[0].revents) {
      int j;
      if (p[0].revents&POLLERR)
	panic("server: error: poll() signals POLLERR\n");
      i=read(0,buf,sizeof(buf));
      if (i==0) { shutdown(t,SHUT_WR); blockingcopy(t,1); }
      for (j=0; j<i; ) {
	int k=write(t,buf+j,i-j);
	if (k==-1) panic("server: error: write() failed");
	if (k==0) panic("server: error: short write!\n");
	j+=k;
      }
    }
    if (p[1].revents) {
      int j;
      if (p[1].revents&POLLERR)
	panic("server: error: poll() signals POLLERR\n");
      i=read(t,buf,sizeof(buf));
      if (i==0) { shutdown(1,SHUT_WR); blockingcopy(0,t); }
      for (j=0; j<i; ) {
	int k=write(1,buf+j,i-j);
	if (k==-1) panic("server: error: write() failed");
	if (k==0) panic("server: error: short write!\n");
	j+=k;
      }
    }
  }
  return 0;
}