コード例 #1
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
authenticate_client(void)
{
    u_char secretlen;
    u_short userid;

    if (read(compat_sock, (char *)&userid, sizeof(userid)) != sizeof(userid))
	efatal("server read");
    userid = ntohs(userid);
    if (debug)
	diag("read userid %d", userid);
    if (read(compat_sock, &secretlen, sizeof(secretlen)) != sizeof(secretlen))
	efatal("server read");
    if (debug)
	diag("read secretlen %d", secretlen);
    if (secretlen != 0)
	efatal("non-zero secretlen");
    if (read(compat_sock, &secretlen, sizeof(secretlen)) != sizeof(secretlen))
	efatal("server read");
    if (secretlen <= 0 || secretlen >= ANAME_SZ)
	fatal("bad local name length");
    if (read(compat_sock, lname, secretlen) != secretlen)
	efatal("server read??");
    if (debug)
	diag("local name %s", lname);
}
コード例 #2
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
setup_control(void)
{
    char buf2[BUFSIZ];
    int pid;
    int pv[2];
    long ready, readfrom;
    char sig;
    int i;

    (void) signal(SIGINT, SIG_DFL);
    (void) signal(SIGQUIT, SIG_DFL);
    (void) signal(SIGTERM, SIG_DFL);

    if (pipe(pv) < 0)
	efatal("pipe failed");
    pid = fork();
    if (pid == -1)
	efatal("fork failed");
    if (pid == 0) {
    (void) setsid();
	(void) close(sigsock);
	(void) close(pv[0]);
	dup2(pv[1], 2);
	(void) close(pv[1]);
	return;
    }
    (void) close(0);
    (void) close(1);
    (void) close(2);
    (void) close(pv[1]);
    readfrom = (1L<<sigsock) | (1L<<pv[0]);
    i = 1;
    ioctl(pv[0], FIONBIO, (char *)&i);
    do {
	ready = readfrom;
	if (select(16, (fd_set *)&ready, (fd_set *)0,
		   (fd_set *)0, (struct timeval *)0) < 0)
	    break;
	if (ready & (1L<<sigsock)) {
	    if (read(sigsock, &sig, 1) <= 0)
		readfrom &= ~(1L<<sigsock);
	    else
#ifdef NO_KILLPG
		kill(pid, sig);
#else
		killpg(pid, sig);
#endif
	}
	if (ready & (1L<<pv[0])) {
	    i = read(pv[0], buf2, sizeof (buf2));
	    if (i <= 0) {
		shutdown(sigsock, 1+1);
		readfrom &= ~(1L<<pv[0]);
	    } else
		(void) write(sigsock, buf2, i);
	}
    } while (readfrom);
    exit(0);
}
コード例 #3
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
read_config_info (void)
{
    u_char len;
    if (read(datasock, &len, sizeof(len)) != sizeof(len))
	efatal("server read");
    if (read(datasock, uniq_str, len) != len)
	efatal("server read??");
} /* end read_config_info */
コード例 #4
0
ファイル: strutil.c プロジェクト: yath/spdroxy
str *str_new(void) {
    str *ret = malloc(sizeof(str));
    if (!ret)
        efatal("malloc");
    ret->pos = ret->buf = NULL;
    ret->size = ret->space = 0;
    return ret;
}
コード例 #5
0
ファイル: strutil.c プロジェクト: yath/spdroxy
static void ensure_total_space(str *s, size_t space) {
    //debug("ensure total: %d", space);
    size_t before = s->space;
    if (!s->space)
        s->space = space < 5 ? 5 : space;
    while (s->space < space)
        s->space *= ALLOC_FACTOR;
    if (s->space != before) {
        if (!(s->buf = realloc(s->buf, s->space)))
            efatal("realloc");
        s->pos = s->buf + s->size;
    }
}
コード例 #6
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
put_buffer ( char * buffer, int len, int * len2, int fd )
{
  int error;
        if ((*len2 = write(datasock, buffer, len)) != len) {
            error = errno;
            (void) close(fd);
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            errno = error;
            efatal("write", error);
        }

}
コード例 #7
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
get_buffer ( char * buffer, int * len, int readsize, int fd )
{
  int error;
        if ((*len = read(datasock, buffer, readsize)) <= 0) {
            error = errno;
            (void) close(fd);
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            if (len == 0)
                fatal("premature EOF");
            errno = error;
            efatal("server read", error);
        }
}
コード例 #8
0
ファイル: odexm.c プロジェクト: andreiw/ode4linux
/*VARARGS1*/
void
diag(const char * fmt, ... )
{
    char buf[BUFSIZ];
    char *ptr;
    va_list vargs;
    struct timeval tv;

    if (gettimeofday(&tv, (struct timezone *)0) < 0)
        efatal("gettimeofday failed");
    (void) sprintf(buf, "%d.%d: ", tv.tv_sec, tv.tv_usec);
    ptr = buf + strlen(buf);
    va_start(vargs,fmt);
    ptr += vsprintf(ptr, fmt, vargs);
    va_end(vargs);
    *ptr++ = '\n';
    (void) write(errdesc, buf, ptr-buf);
}
コード例 #9
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
transmit_status(void)
{
    unsigned int status;
    int op;

    if (debug)
	diag("sending status %d", exit_status);
    if ( batch ) {
      (*header).count = 0;
      (*header).status = htonl (exit_status);
      op=1;
      setsockopt(datasock, IPPROTO_TCP, TCP_NODELAY, (char *)&op ,
                 sizeof(op) );
      write ( datasock, buf, sizeof(*header) );
      op=0;
      setsockopt(datasock, IPPROTO_TCP, TCP_NODELAY, (char *)&op ,
                 sizeof(op) );
    } else {
      status = htonl((unsigned int)exit_status);
      if (write(datasock, (char *)&status, sizeof(status)) != sizeof(status))
  	efatal("write failed");
    } /* if */
}
コード例 #10
0
ファイル: odexm.c プロジェクト: andreiw/ode4linux
void
transmit_data(void)
{
    unsigned int count;
    u_short perm;
    char *buffer;
    int bufsize;
    int fd;
    struct stat st;
    int len, len2;
    int error;
    char exists;

    if (debug)
        diag("sending data");
    if ((tempmode&WANT_BACK) == 0) {
        (void) unlink(tempfile);
        if (debug)
            diag("not wanted back");
        return;
    }
    if (lstat(tempfile, &st) < 0) {
        if (errno != ENOENT) {
            error = errno;
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            errno = error;
            efatal("lstat", error);
        }
        exists = 0;
    } else {
        if ((st.st_mode&S_IFMT) != S_IFREG) {
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            fatal("tempfile no longer a regular file");
        }
        exists = 1;
    }
    if (debug)
        diag("exists %d", exists);
    if ( ! put_exists ( &exists ) ) {
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        efatal("write failed");
    }
    if (!exists) {
        (void) unlink(tempfile);
        return;
    }
    perm = st.st_mode&0777;
    if (debug)
        diag("perm %#o", perm);
    if ( ! put_perm ( &perm ) ) {
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        efatal("write failed");
    }
    count = st.st_size;
    if (debug)
        diag("count %d", count);
    if ( ! put_count ( &count ) ) {
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        efatal("write failed");
    }
    count = st.st_size;
    if (count == 0) {
        (void) unlink(tempfile);
#ifdef notdef
        (void) rmdir(tempdir);
#endif
        return;
    }
    if ((fd = open(tempfile, O_RDONLY, 0)) < 0) {
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        efatal("open failed");
    }
    if ((bufsize = count) > 10*1024)
        buffer = (char *) malloc(bufsize = 10*1024);
    else
        buffer = (char *) malloc(bufsize);
    if (buffer == NULL) {
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        fatal("malloc failed");
    }
    if (debug)
        diag("bufsize %d", bufsize);
    while (count != 0) {
        if (debug)
            diag("loop count %d", count);
        if ((len = read(fd, buffer, bufsize)) <= 0) {
            error = errno;
            (void) close(fd);
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            if (len == 0)
                fatal("1 premature EOF");
            errno = error;
            efatal("server read", error);
        }
        if (debug)
            diag("read %d bytes", len);
        put_buffer ( buffer, len, &len2, fd );
        if (debug)
            diag("wrote %d bytes", len2);
        count -= len;
        if (count < bufsize)
            bufsize = count;
    }
    if (close(fd) < 0) {
        error = errno;
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        errno = error;
        efatal("close");
    }
    (void) free(buffer);
    (void) unlink(tempfile);
    if (debug)
        diag("transfer complete");
}
コード例 #11
0
ファイル: odexm.c プロジェクト: andreiw/ode4linux
void
receive_data (void)
{
    unsigned int count;
    u_short perm;
    char *buffer;
    int bufsize;
    int fd;
    int len, len2;
    int error;
    char exists;
    int readsize;

    if (debug)
        diag("receiving data");
    if ((tempmode&SEND_OVER) == 0)
        exists = 0;
    else if ( ! get_exists ( &exists ) )
        efatal("server read failed");
    if (debug)
        diag("exists %d", exists);
    if (exists) {
        if ( ! get_perm ( &perm ) )
            efatal("server read failed");
        if ( ! get_count ( &count ) )
            efatal("server read failed");
    } else {
        perm = 0600;
        count = 0;
    }
    concat ( temppath, sizeof(temppath), tempdir, "/", tempfile, NULL );
    tempfile = temppath;
    if (debug) {
        diag("perm %#o, count %d", perm, count);
        diag("d: %s f: %s p: %s", tempdir, tempfile, temppath );
    }
    fd = open ( tempfile, O_CREAT | O_RDWR, 0600 );
    if (debug)
        diag("tempfile %s", tempfile);
    if (fchmod(fd, (mode_t) (perm & ( S_IRWXU | S_IRWXG | S_IRWXO ) ) ) < 0)
        efatal("fchmod failed");
    if (!exists)
        (void) unlink(tempfile);
    if (count == 0) {
        (void) close(fd);
        return;
    }
    /*
     * should check for space on disk, but could be expensive and unreliable
     */
    if ((bufsize = count) > 10*1024)
        buffer = (char *) malloc(bufsize = 10*1024);
    else
        buffer = (char *) malloc(bufsize);
    if (buffer == NULL)
        fatal("malloc failed");
    while (count != 0) {
        if (debug)
            diag("loop count %d", count);
        if ( count > bufsize )
          readsize = bufsize;
        else
          readsize = count;
        /* if */
        get_buffer ( buffer, &len, readsize, fd );
        if ((len2 = write(fd, buffer, len)) != len) {
            error = errno;
            (void) close(fd);
            (void) unlink(tempfile);
            (void) rmdir(tempdir);
            errno = error;
            efatal("write", error);
        }
        count -= len;
        if (count < bufsize)
            bufsize = count;
    }
    if (close(fd) < 0) {
        error = errno;
        (void) unlink(tempfile);
        (void) rmdir(tempdir);
        errno = error;
        efatal("close");
    }
    (void) free(buffer);
    if (debug)
        diag("transfer complete");
} /* end receive_data */
コード例 #12
0
ファイル: odexm.c プロジェクト: andreiw/ode4linux
void
check_config(void)
{
  char buf[BUFSIZ];
  char aclfile[MAXPATHLEN];
  char *tools_dir=NULL;
  char *tree_owner=NULL;
  char *map_file=NULL;
  char *cmd;
  char *p;
  char *q=(char *)"";
  FILE *fp;
  int cmdfound;
  char *uniq_str_arg;
  struct stat st;
  struct passwd *pw;
  char * bufptr;
  BOOLEAN matched;
  int i;
  char * dummy;

  if (debug)
      diag("checking config");
  if ( !batch ) {
    tree_base = *arglist++;
    tree_owner = *arglist++;
  } /* if */
  cmd = *arglist;
  if (debug)
      diag("command: %s", cmd );
  if ( strcmp ( cmd, "odexm_begin") == 0 ) {
     start_batch = 1;
     return;
  } /* if */
  if ( strcmp ( cmd, "odexm_end") == 0 ) {
     end_batch = 1;
     return;
  } /* if */
  if ( first ) {
    first = FALSE;
    if ((fp = fopen( conf_file, "r")) == NULL)
      efatal("fopen %s", conf_file);
    matched = FALSE;
    while ( fgets( buf, sizeof(buf), fp ) != NULL) {
      rm_newline ( buf );
      bufptr = (char *) buf;
      uniq_str_arg = strdup ( nxtarg ( &bufptr, " \t" ) );
      if ( strcmp ( uniq_str_arg, uniq_str ) != 0 )
        continue;
      /* if */
      matched = TRUE;
      if ( batch )
        tree_base = strdup ( nxtarg ( &bufptr, " \t" ) );
      else
	/* Skip over argument */
        dummy = nxtarg ( &bufptr, " \t" );
      /* if */
      tools_dir = strdup ( nxtarg ( &bufptr, " \t" ) );
      if ( batch )
        tree_owner = strdup ( nxtarg ( &bufptr, " \t" ) );
      else
	/* Skip over argument */
        dummy = nxtarg ( &bufptr, " \t" );
      /* if */
      map_file = strdup ( nxtarg ( &bufptr, " \t" ) );
      break;
    } /* while */
    fclose ( fp );
    if ( ! matched ) {
      sprintf (buf, "No match for unique string %s\nin configuration file %s.\n", uniq_str, conf_file );
      fatal (buf);
    }
    if (debug)
      diag("map file %s", map_file );
    if (lstat(map_file, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG) {
      sprintf(buf, "Invalid odexm map file: %s\n", map_file);
      fatal(buf);
    }
    if (debug)
      diag("map file mode ok");
    if ((pw = getpwnam(tree_owner)) == NULL)
      fatal("Owner of directory not found");
    if (pw -> pw_uid == 0)
      fatal("Cannot run as root");
    if (setgid(pw->pw_gid) < 0)
      efatal("setgid");
    if (setuid(pw->pw_uid) < 0)
      efatal("setuid");
    if (chdir(tree_base) < 0)
      efatal("chdir");
    if (debug)
      diag("setuid/chdir ok");
    (void) concat ( exec_path, sizeof (exec_path), tools_dir,
                    ":/bin:/usr/bin:/usr/ucb", NULL );
    if ((fp = fopen(map_file, "r")) == NULL)
        efatal("map file fopen");
    i = 0;
    while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
      if ((q  = strrchr (p, '\n')) != NULL)
          *q = '\0';
      q = nxtarg(&p, " \t");
      strcpy ( map_data [i].cmd, q );
      q = nxtarg(&p, " \t");
      strcpy ( map_data [i].bin, q );
      q = nxtarg(&p, " \t");
      strcpy ( map_data [i].acl, q );
      i++;
    }
    map_entries = i;
    (void) fclose(fp);
  } /* if */
  if ( tempslot != 0 && !made_temp_dir ) {
    made_temp_dir = TRUE;
    concat ( tempdir, sizeof(tempdir), tree_base, "/#odexmXXXXXX", NULL);
    if ( opentemp(tempdir, tempdir ) < 0) {
    	efatal("opentemp %s failed", tree_base); 
    }
  } /* if */
  cmdfound = FALSE;
  if ( strcmp ( cmd, "odexm_cp" ) != 0 ) {
    for ( i = 0; i < map_entries; i++ ) {
      if (strcmp( map_data [i].cmd, cmd) == 0) {
        cmdfound = TRUE;
        (void) strcpy(aclfile, q);
        strcpy ( cmdbuf, map_data [i].bin );
      } /* if */
    } /* for */
    if (!cmdfound) {
      sprintf (buf, "No match for command %s in map file %s.\n", cmd, map_file );
      fatal("%s", buf);
    }
    if (debug)
      diag("command %s acl %s temp %s", cmdbuf, aclfile, tempdir);
    /* if */
  } /* if */
  if ( !batch )
    authenticate_client ();
  /* if */
}
コード例 #13
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
read_arglist(void)
{
    int i;
    u_char byte;
    u_short count;
    u_short length;
    char *sp;
    char *ep;
    unsigned int checksum;

    if (read(compat_sock, &byte, sizeof(byte)) != sizeof(byte))
	efatal("read needsecret failed");
    if (byte)
	efatal("request for secret");
    if (debug)
	diag("reading arglist");
    if (read(compat_sock, (char *)&count, sizeof(count)) != sizeof(count))
	efatal("server read");
    count = ntohs(count);
    if (debug)
	diag("arglist count %d", count);
    if ( ( batch && count < 1) || ( !batch && count < 3 ) || count > MAXARGC - 1)
	fatal("Invalid arg count");
    if (read(compat_sock, (char *)&length, sizeof(length)) != sizeof(length))
	efatal("server read");
    length = ntohs(length);
    if (debug)
	diag("arglist length %d", length);
    if ((int)length > NCARGS)
	fatal("Arglist too long");
    if (read(compat_sock, (char *)&tempslot, sizeof(tempslot)) != sizeof(tempslot))
	efatal("server read");
    tempslot = ntohs(tempslot);
    if (debug)
	diag("tempslot %d", tempslot);
    if ( ( batch && tempslot >= count) ||
         (!batch && tempslot >= count - 2 ) )
	fatal("Invalid temp file index");
    if (tempslot != 0) {
	if (read(compat_sock, (char *)&tempmode, sizeof(tempmode)) != sizeof(tempmode))
	    efatal("server read");
	if (debug)
	    diag("tempmode %d", tempmode);
    }
    if (read(compat_sock, (char *)&checksum, sizeof(checksum)) != sizeof(checksum))
	efatal("server read");
    checksum = ntohl(checksum);
    if (debug)
	diag("checksum %x", checksum);
    memset (args, 0, sizeof(args));
    sp = args;
    ep = args + length;
    while (ep > sp) {
	i = ep - sp;
	i = read(compat_sock, sp, i);
	if (i < 0)
	    efatal("server read");
	else if (i == 0)
	    fatal("read (eof)");
	sp += i;
    }
    check_arglist ( count, ep, sp, checksum);
}
コード例 #14
0
ファイル: odexm_tcp.c プロジェクト: andreiw/ode4linux
void
setup_connections(void)
{
    int i;
    struct linger linger;
    struct sockaddr_in s_in;
    u_short port;
    u_short sigport;
    u_short dataport;

    header = (odexm_header *) buf;

    /*
     * setup file descriptors
     */
    for (;;) {
	errno = 0;
	i = dup(0);
	if (i == -1) {
	    efatal("dup failed");
	}
	if (i > 2)
	    break;
    }
    errdesc = i;
    if (dup2(i, 0) < 0)
	efatal("dup2 #0 failed");
    if (dup2(i, 1) < 0)
	efatal("dup2 #1 failed");
    if (dup2(i, 2) < 0)
	efatal("dup2 #2 failed");
    (void) close(i);
    errdesc = 2;

    /*
     * setup main (command) connection
     */
    i = 1;
    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i)) < 0)
	ewarn("setsockopt (SO_KEEPALIVE)");
#ifdef DONT_SO_LINGER
    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&i, sizeof(i)) < 0 )
#else
    linger.l_onoff = 1;
    linger.l_linger = 60;
    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger))
                   < 0)
#endif
	ewarn("setsockopt (SO_LINGER)");
    i = sizeof(peername);
    if (getpeername(0, (struct sockaddr *)&peername, &i) < 0)
	efatal("getpeername");
    i = sizeof(sockname);
    if (getsockname(0, (struct sockaddr *)&sockname, &i) < 0)
	efatal("getsockname");
    if (debug)
	diag("connection from %s (%d)",
	     inet_ntoa(peername.sin_addr), ntohs(peername.sin_port));

    /*
     * get flags
     */
    if (read(0, &flags, sizeof(flags)) != sizeof(flags))
	efatal("server read");

    if ( flags == 1 || flags == 3 )
      debug = 1;
    /* if */
    if ( flags > 1 )
      batch = 1;
    /* if */

    /*
     * setup control (signal) connection
     */
    if (read(0, (char *)&sigport, sizeof(sigport)) != sizeof(sigport))
	efatal("server read");
    sigsock = socket(AF_INET, SOCK_STREAM, 0);
    if (sigsock < 0)
	efatal("socket");
    memcpy (&s_in, &sockname, sizeof(s_in));
    s_in.sin_port = 0;
    if (bind(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("bind");
    i = sizeof(s_in);
    if (getsockname(sigsock, (struct sockaddr *)&s_in, &i) < 0)
	efatal("getsockname");
    port = s_in.sin_port;
    if (write(1, (char *)&port, sizeof(port)) != sizeof(port))
	efatal("write");
    memcpy(&s_in, &peername, sizeof(s_in));
    s_in.sin_port = sigport;
    if (connect(sigsock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("connect");

    /*
     * start control process (actually parent)
     */
    setup_control();
    /*
     * safe now for debugging
     */

    /*
     * setup data transfer connection
     */
    if (debug)
	diag("reading data port");
    if (read(0, (char *)&dataport, sizeof(dataport)) != sizeof(dataport))
	efatal("server read");
    if (debug)
	diag("data port %d", ntohs(dataport));
    datasock = socket(AF_INET, SOCK_STREAM, 0);
    if (datasock < 0)
	efatal("socket");
    memcpy(&s_in, &sockname, sizeof(s_in));
    s_in.sin_port = 0;
    if (bind(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("bind");
    i = sizeof(s_in);
    if (getsockname(datasock, (struct sockaddr *)&s_in, &i) < 0)
	efatal("getsockname");
    port = s_in.sin_port;
    if (debug)
	diag("sending data port %d", ntohs(port));
    if (write(1, (char *)&port, sizeof(port)) != sizeof(port))
	efatal("write");
    memcpy(&s_in, &peername, sizeof(s_in));
    s_in.sin_port = dataport;
    if (connect(datasock, (struct sockaddr *)&s_in, sizeof(s_in)) < 0)
	efatal("connect");
    if (debug)
	diag("connected to dataport");
    if ( batch )
      compat_sock = datasock;
    else
      compat_sock = 0;
    /* if */
}
コード例 #15
0
ファイル: parastreamd.c プロジェクト: vnaybhat/emulab
int main(int argc,char **argv) {
    int i,srv_sock,j,retval,ptype;
    struct sockaddr_in srv_sa;
    int clientfds[MAX_CLIENTS];
    char *clientsas[MAX_CLIENTS];
    int client_cnt = 0;
    int block_size = 1024;
    int maxfd = 0;
    int c;
    char *srvhost = NULL;
    short srvport = DEF_SRV_PORT;
    int proto = DEF_PROTO;
    int debug = 0;
    char *buf = NULL;
    fd_set rfds;
    fd_set static_rfds;

    /* grab some quick args, hostname, port, tcp, udp... */
    while ((c = getopt(argc,argv,"h:p:tudb:")) != -1) {
	switch(c) {
	case 'h':
	    srvhost = optarg;
	    break;
	case 'p':
	    srvport = atoi(optarg);
	    break;
	case 't':
	    proto = SOCK_STREAM;
	    break;
	case 'u':
	    proto = SOCK_DGRAM;
	    fatal("no udp support yet!");
	    break;
	case 'd':
	    ++debug;
	    break;
	case 'b':
	    block_size = atoi(optarg);
	    break;
	default:
	    break;
	}
    }

    if ((buf = (char *)malloc(sizeof(char)*block_size)) == NULL) {
	efatal("no memory for data buf");
    }
    
    if ((retval = fill_sockaddr(srvhost,srvport,&srv_sa)) != 0) {
	if (retval == -1) {
	    fatal("bad port");
	}
	else {
	    efatal("host lookup failed");
	}
    }

    /* startup server... */
    if ((srv_sock = socket(AF_INET,proto,0)) == -1) {
	efatal("could not get socket");
    }

    if (bind(srv_sock,
	     (struct sockaddr *)&srv_sa,
	     sizeof(struct sockaddr_in)
	     ) < 0) {
	efatal("could not bind");
    }

    if (proto == PROTO_TCP) {
	if (listen(srv_sock,8) < 0) {
	    efatal("could not listen");
	}
    }

    /* daemonize... */
    if (!debug) {
	daemon(0,0);
    }

    for (i = 0; i < MAX_CLIENTS; ++i) {
	clientfds[i] = -1;
	clientsas[i] = (char *)malloc(MAX_NAME_LEN + 1);
    }

    FD_ZERO(&static_rfds);
    FD_SET(srv_sock,&static_rfds);
    maxfd = srv_sock;
    
    /* listen and read forever */
    while (1) {
	/* reset fdsets */
	memcpy(&rfds,&static_rfds,sizeof(static_rfds));

	retval = select(maxfd+1,&rfds,NULL,NULL,NULL);
	
	if (retval > 0) {
	    if (FD_ISSET(srv_sock,&rfds)) {
		struct sockaddr_in client_sin;
		socklen_t slen;
		int client_fd;

		slen = sizeof(client_sin);

		if ((client_fd = accept(srv_sock,
					(struct sockaddr *)&client_sin,
					&slen)) < 0) {
		    warn("accept failed");
		}
		else if (client_cnt >= MAX_CLIENTS) {
		    warn("already at max clients");
		}
		else {
		    /* add new client... */
		    for (i = 0; i < MAX_CLIENTS; ++i) {
			if (clientfds[i] == -1) {
			    break;
			}
		    }
		    
		    clientfds[i] = client_fd;
		    if (client_fd > maxfd) {
			maxfd = client_fd;
		    }
		    
		    FD_SET(client_fd,&static_rfds);
		    
		    if (debug) {
			fprintf(stdout,
				"connect from %s:%d\n",
				inet_ntoa(client_sin.sin_addr),
				ntohs(client_sin.sin_port));
		    }
		    
		    char *addr = inet_ntoa(client_sin.sin_addr);
		    int addrlen = strlen(addr);
		    
		    strncpy(clientsas[i],
			    addr,
			    (addrlen > MAX_NAME_LEN)?MAX_NAME_LEN:addrlen);
		    /* null term if strncpy couldn't */
		    if (addrlen > MAX_NAME_LEN) {
			clientsas[i][MAX_NAME_LEN] = '\0';
		    }
		    
		    ++client_cnt;
		}
	    }
	    else {
		for (i = 0; i < MAX_CLIENTS; ++i) {
		    if (clientfds[i] > -1) {
			if (FD_ISSET(clientfds[i],&rfds)) {
			    /* read a block, or as much as possible */
			    retval = read(clientfds[i],buf,block_size);

			    /* dead client, pretty much */
			    if (retval <= 0) {
				if (debug) {
				    fprintf(stdout,
					    "disconnect from %s\n",
					    clientsas[i]);
				}

				close(clientfds[i]);
				FD_CLR(clientfds[i],&static_rfds);
				clientfds[i] = -1;

				--client_cnt;
			    }
			    else if (debug > 2 ) {
				fprintf(stdout,
					"DEBUG: read %d bytes from %s\n",
					retval,
					clientsas[i]);
			    }
			}
		    }
		}
	    }
	}
	else if (retval < 0) {
	    /* error... */
	    ewarn("error in select");
	}
    }

    return -1;
}