The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Long;
use IO::Async::Loop;
use IO::Async::Stream 0.54; # ->new_close_future
use IO::Async::SSL;

my $DUMPCERT;
my $NO_VERIFY;
my $FAMILY;
GetOptions(
   'd|dumpcert'   => \$DUMPCERT,
   'nv|no-verify' => \$NO_VERIFY,
   '4|ipv4'       => sub { $FAMILY = "inet" },
   '6|ipv6'       => sub { $FAMILY = "inet6" },
) or exit 1;

my $HOST = shift @ARGV or die "Need HOST";
my $PORT = shift @ARGV or die "Need PORT";

my $loop = IO::Async::Loop->new;

my ( $socketstream, $stdiostream );
my $peeraddr;

$socketstream = IO::Async::Stream->new(
   on_read => sub {
      my ( undef, $buffref, $closed ) = @_;

      # Turn CRLFs into plain \n by stripping \r
      $$buffref =~ s/\r//g;
      $stdiostream->write( $$buffref );
      $$buffref = "";

      return 0;
   },

   on_closed => sub {
      print STDERR "Closed connection to $peeraddr\n";
      $stdiostream->close_when_empty;
   },
);
$loop->add( $socketstream );

$stdiostream = IO::Async::Stream->new(
   read_handle  => \*STDIN,
   write_handle => \*STDOUT,

   on_read => sub {
      my ( undef, $buffref, $closed ) = @_;

      # Turn plain \n into CRLFs
      $$buffref =~ s/\n/\x0d\x0a/g;
      $socketstream->write( $$buffref );
      $$buffref = "";

      return 0;
   },

   on_closed => sub {
      $socketstream->close_when_empty;
   },
);
$loop->add( $stdiostream );

$loop->SSL_connect(
   host    => $HOST,
   service => $PORT,
   family  => $FAMILY,

   handle => $socketstream,
   ( $NO_VERIFY ? ( SSL_verify_mode => 0 ) : () ),
)->get;

my $socket = $socketstream->read_handle;
$peeraddr = $socket->peerhost . ":" . $socket->peerport;

print STDERR "Connected to $peeraddr\n";

if( $DUMPCERT ) {
   print STDERR Net::SSLeay::PEM_get_string_X509($socket->peer_certificate) . "\n";
}

$loop->await( $socketstream->new_close_future, $stdiostream->new_close_future );