#!/bin/perl -w
# $Id: client,v 2.12 1999/01/20 14:55:19 hasegawa Exp $
# copyright (c)1997-1999 Yoshinori Hasegawa <hasegawa@madoka.org>

if ($] < 5) {
  foreach $inc (@INC) {
    if (-r "$inc/sys/socket.ph") {
      eval 'require "sys/socket.ph"';
      $SOCKET = "$inc/sys/socket.ph" unless $@;
      last;
    }
    if (-r "$inc/socket.ph") {
      eval 'require "socket.ph"';
      $SOCKET = "$inc/socket.ph" unless $@;
      last;
    }
  }
} else {
  eval 'use Socket';
  $SOCKET = 'Socket.pm' unless $@;
}

$NIL = $;;

$READSIZE = 1024;
$SOCKADDR = 'S n N x8';

$PROTO = (getprotobyname('tcp'))[2];

$AF_INET = eval '&AF_INET' || 2;
$PF_INET = eval '&PF_INET' || 2;
$SOCK_STREAM = eval '&SOCK_STREAM' || 1;

$'rin = '';

$handle = 0;

select((select(STDOUT), $| = 1)[0]);

$SIG{'PIPE'} = 'IGNORE' if &'exist(&'list(keys(%SIG)), 'PIPE');

&main(@ARGV);

sub main {
  local(@args) = @_;
  local($rout, $sno, $stdin, $socket, $nf, $tmp);
  if (@args < 2) {
    &usage();
    exit(1);
  }
  $sno = &'connect($args[0], $args[1]) || die "cannot connect to server\n";
  $socket = $'socket[$sno];
  $stdin = fileno(STDIN);
  vec($'rin, $stdin, 1) = 1;
  for (;;) {
    $nf = select($rout = $'rin, undef, undef, undef);
    if (vec($rout, $sno, 1)) {
      $tmp = '';
      if (sysread($socket, $tmp, $READSIZE)) {
        print STDOUT $tmp;
      } else {
        &'close($sno);
        exit(0);
      }
    } elsif (vec($rout, $stdin, 1)) {
      $tmp = '';
      if (sysread(STDIN, $tmp, $READSIZE)) {
        print $socket $tmp;
      } else {
        &'close($sno);
        exit(0);
      }
    }
  }
}

sub usage {
  print 'usage: perl client <server> <port>', "\n";
}

sub 'connect {
  local($host, $port) = @_;
  local($serverno, $socket, $ip, @addr, $name);
  if ($host =~ /^\d+$/) {
    $ip = $host;
  } elsif ($host =~ /^[\d\.]+$/) {
    @addr = split(/\./, $host);
    $ip = unpack('N', pack('C4', @addr, 0, 0, 0));
  } else {
    $ip = unpack('N', (gethostbyname($host))[4] || "\0\0\0\0");
  }
  return 0 unless $ip;
  $socket = '\'S' . ++$handle;
  socket($socket, $PF_INET, $SOCK_STREAM, $PROTO) || return 0;
  $name = pack($SOCKADDR, $AF_INET, $port, $ip);
  connect($socket, $name) || return 0;
  binmode($socket);
  $serverno = fileno($socket);
  vec($'rin, $serverno, 1) = 1;
  $'socket[$serverno] = $socket;
  select((select($socket), $| = 1)[0]);
  return $serverno;
}

sub 'close {
  local($no) = @_;
  close($'socket[$no]);
  vec($'rin, $no, 1) = 0;
}

sub 'exist {
  local($list, @items) = @_;
  return 0 unless $list;
  $list .= $NIL;
  foreach $item (@items) {
    return 1 if index("\L$list\E", $NIL . "\L$item\E" . $NIL) != -1;
  }
  return 0;
}

sub 'list {
  local(@array) = @_;
  return join($NIL, '', @array);
}
