### Client.pm  -*- Perl -*-
## Client implementation for the logical testing interface protocol.

### Ivan Shmakov, 2022

## To the extent possible under law, the author(s) have dedicated
## all copyright and related and neighboring rights to this software
## to the public domain worldwide.  This software is distributed
## without any warranty.

## You should have received a copy of the CC0 Public Domain Dedication
## along with this software.  If not, see
## <http://creativecommons.org/publicdomain/zero/1.0/>.

### History:

## 0.1  2022-10-08 16:37Z
##      Initial revision, split off client.perl.

### Code:
package Lotei::Client;

use common::sense;

our $VERSION = "0.1";

sub fletcher {
    my ($s) = @_;
    my ($s1, $s0)
        = (0, 0);
    foreach my $x (unpack ("C*", $s)) {
        $s0 += $x; 
        $s1 += $s0; 
    }
    ## .
    pack ("C*", $s1 % 255, $s0 % 255);
}

sub frame {
    my ($s) = @_;
    substr ($s, 1, 0, pack ("C", -1 + length ($s)));
    my $ck
        = fletcher ($s);
    ## .
    $s .= $ck;
}

sub read_1 {
    my ($eh, $z) = @_[0, 2];
    do {
        my $rd
            = $eh->sysread ($_[1], $z - length ($_[1]), length ($_[1]));
        ## .
        die (($rd < 0 ? $! : "EOF") . " after reading " . xdump ($_[1]))
            if ($rd <= 0);
    } while (length ($_[1]) < $z);
    ## .
    $_[1];
}

sub read_response {
    my ($eh) = @_;

    my $s
        = "";
    read_1 ($eh, $s, 2);
    my ($z)
        = 4 + unpack ("C", substr ($s, 1));
    read_1 ($eh, $s, $z);

    my $ck
        = fletcher (substr ($s, 0, -2));
    ## .
    die (sprintf ("Checksum error; computed: %s, message: %s\n",
                  xdump ($ck), xdump ($s)))
        if ($ck ne substr ($s, -2));

    ## .
    $s;
}

sub with_timeout (&$;$) {
    my ($code, $to, $to_x) = @_;
    $to_x
        //= "*timeout*\n";
    local $SIG{"ALRM"}
        = sub { die ($to_x); };
    ## FIXME: it is likely possible to use select(2) instead
    alarm ($to);
    my $r
        = $code->();
    alarm (0);
    ## .
    $r;
}

sub xdump {
    ## .
    unpack ("H*", $_[0])
        =~ s/../$& /rg;
}

## .
1;

### Client.pm ends here
