#  Copyright (c) 1997-2005
#  Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
#  http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de
#
#  This program is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by the
#  Free Software Foundation; either version 2, or (at your option) any
#  later version: http://www.gnu.org/licenses/gpl.txt.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#-----------------------------------------------------------------------------
#  $Project: polymake $$Id: Sockets.pm,v 1.3 2005/12/21 19:15:43 gawrilow Exp $

use strict;
use namespaces;

package Poly::ServerSocket;
use Poly::Pipe;
use Socket;
use Errno;
use Fcntl;
use POSIX qw(:errno_h);

use Struct (
   [ new => ';$' ],
   [ '$handle' => 'undef' ],
   [ '$port' => '#1' ],
);

# Constructor: new ServerSocket([ port ])
sub new {
   my $self=&_new;
   socket $self->handle, PF_INET, SOCK_STREAM, getprotobyname('tcp')
      or die "socket failed: $!\n";
   fcntl $self->handle, F_SETFD, 0		# keep opened in the client
      or die "fcntl(F_SETFD) failed: $!\n";
   if (defined $self->port) {
      bind $self->handle, sockaddr_in($self->port, INADDR_LOOPBACK)
         or die "bind failed: $!\n";
   } else {
      my $port;
      for ($port=30000; $port<65536; ++$port) {
	 last if bind $self->handle, sockaddr_in($port, INADDR_LOOPBACK);
	 die "bind failed: $!\n" if $! != EADDRINUSE;
      }	
      if ($port==65536) {
	 die "bind failed: all ports seem occupied\n";
      }
      $self->port=$port;
   }
   listen $self->handle, 1
      or die "listen failed: $!\n";
   $self;
}

sub DESTROY {
   close($_[0]->handle);
}

sub fileno { fileno($_[0]->handle) }

sub accept {
   my ($self)=@_;
   accept my $s, $self->handle
      or die "accept failed: $!\n";
   new Pipe($s);
}

####################################################################################
package Poly::ClientSocket;
use Socket;

# Constructor: new ClientSocket(hostname, port)
sub new {
   my ($class, $hostname, $port)=@_;
   my $hostaddr=inet_aton($hostname)
      or die "unknown host name $hostname\n";
   socket(my $socket, PF_INET, SOCK_STREAM, getprotobyname('tcp'))
      or die "can't create socket: $!\n";
   connect($socket, sockaddr_in($port, $hostaddr))
      or die "can't connect to $hostname: $!\n";
   new Pipe($socket);
}

1
