Some BINKP optimisation, implemented crypt, implemented receiving compressed transfers

This commit is contained in:
2023-07-02 23:40:08 +10:00
parent f9f9fb5345
commit 6f298d778f
28 changed files with 1614 additions and 904 deletions

View File

@@ -17,12 +17,12 @@ abstract class Protocol
private const LOGKEY = 'P--';
/* CONSTS */
// Return constants
protected const OK = 0;
protected const EOF = -1;
protected const TIMEOUT = -2;
protected const RCDO = -3;
protected const GCOUNT = -4;
protected const ERROR = -5;
// Our sessions Types
@@ -33,24 +33,57 @@ abstract class Protocol
protected const MAX_PATH = 1024;
/* 9 most right bits are zeros */
private const O_BASE = 9; /* First 9 bits are protocol */
protected const O_NRQ = (1<<self::O_BASE); /* 0000 0000 0000 0000 0010 0000 0000 BOTH - No file requests accepted by this system */
protected const O_HRQ = (1<<(self::O_BASE+1)); /* 0000 0000 0000 0000 0100 0000 0000 BOTH - Hold file requests (not processed at this time). */
protected const O_FNC = (1<<(self::O_BASE+2)); /* 0000 0000 0000 0000 1000 0000 0000 - Filename conversion, transmitted files must be 8.3 */
protected const O_XMA = (1<<(self::O_BASE+3)); /* 0000 0000 0000 0001 0000 0000 0000 - Supports other forms of compressed mail */
protected const O_HAT = (1<<(self::O_BASE+4)); /* 0000 0000 0000 0010 0000 0000 0000 BOTH - Hold ALL files (Answering System) */
protected const O_HXT = (1<<(self::O_BASE+5)); /* 0000 0000 0000 0100 0000 0000 0000 BOTH - Hold Mail traffic */
protected const O_NPU = (1<<(self::O_BASE+6)); /* 0000 0000 0000 1000 0000 0000 0000 - No files pickup desired (Calling System) */
protected const O_PUP = (1<<(self::O_BASE+7)); /* 0000 0000 0001 0000 0000 0000 0000 - Pickup files for primary address only */
protected const O_PUA = (1<<(self::O_BASE+8)); /* 0000 0000 0010 0000 0000 0000 0000 EMSI - Pickup files for all presented addresses */
protected const O_PWD = (1<<(self::O_BASE+9)); /* 0000 0000 0100 0000 0000 0000 0000 BINK - Node needs to be password validated */
protected const O_BAD = (1<<(self::O_BASE+10)); /* 0000 0000 1000 0000 0000 0000 0000 BOTH - Node invalid password presented */
protected const O_RH1 = (1<<(self::O_BASE+11)); /* 0000 0001 0000 0000 0000 0000 0000 EMSI - Use RH1 for Hydra (files-after-freqs) */
protected const O_LST = (1<<(self::O_BASE+12)); /* 0000 0010 0000 0000 0000 0000 0000 BOTH - Node is nodelisted */
protected const O_INB = (1<<(self::O_BASE+13)); /* 0000 0100 0000 0000 0000 0000 0000 BOTH - Inbound session */
protected const O_TCP = (1<<(self::O_BASE+14)); /* 0000 1000 0000 0000 0000 0000 0000 BOTH - TCP session */
protected const O_EII = (1<<(self::O_BASE+15)); /* 0001 0000 0000 0000 0000 0000 0000 EMSI - Remote understands EMSI-II */
/* O_ options - [First 9 bits are protocol P_* (Interfaces/ZModem)] */
/** 0000 0000 0000 0000 0010 0000 0000 BOTH - No file requests accepted by this system */
protected const O_NRQ = 1<<9;
/** 0000 0000 0000 0000 0100 0000 0000 BOTH - Hold file requests (not processed at this time). */
protected const O_HRQ = 1<<10;
/** 0000 0000 0000 0000 1000 0000 0000 - Filename conversion, transmitted files must be 8.3 */
protected const O_FNC = 1<<11;
/** 0000 0000 0000 0001 0000 0000 0000 - Supports other forms of compressed mail */
protected const O_XMA = 1<<12;
/** 0000 0000 0000 0010 0000 0000 0000 BOTH - Hold ALL files (Answering System) */
protected const O_HAT = 1<<13;
/** 0000 0000 0000 0100 0000 0000 0000 BOTH - Hold Mail traffic */
protected const O_HXT = 1<<14;
/** 0000 0000 0000 1000 0000 0000 0000 - No files pickup desired (Calling System) */
protected const O_NPU = 1<<15;
/** 0000 0000 0001 0000 0000 0000 0000 - Pickup files for primary address only */
protected const O_PUP = 1<<16;
/** 0000 0000 0010 0000 0000 0000 0000 EMSI - Pickup files for all presented addresses */
protected const O_PUA = 1<<17;
/** 0000 0000 0100 0000 0000 0000 0000 BINK - Node needs to be password validated */
protected const O_PWD = 1<<18;
/** 0000 0000 1000 0000 0000 0000 0000 BOTH - Node invalid password presented */
protected const O_BAD = 1<<19;
/** 0000 0001 0000 0000 0000 0000 0000 EMSI - Use RH1 for Hydra (files-after-freqs) */
protected const O_RH1 = 1<<20;
/** 0000 0010 0000 0000 0000 0000 0000 BOTH - Node is nodelisted */
protected const O_LST = 1<<21;
/** 0000 0100 0000 0000 0000 0000 0000 BOTH - Inbound session */
protected const O_INB = 1<<22;
/** 0000 1000 0000 0000 0000 0000 0000 BOTH - TCP session */
protected const O_TCP = 1<<23;
/** 0001 0000 0000 0000 0000 0000 0000 EMSI - Remote understands EMSI-II */
protected const O_EII = 1<<24;
/* Negotiation Options */
/** 00 0000 I/They dont want a capability? */
protected const O_NO = 0;
/** 00 0001 - I want a capability, but can be persuaded */
protected const O_WANT = 1<<0;
/** 00 0010 - They want a capability and we want it too */
protected const O_WE = 1<<1;
/** 00 0100 - They want a capability */
protected const O_THEY = 1<<2;
/** 00 1000 - I want a capability, and wont compromise */
protected const O_NEED = 1<<3;
/** 01 0000 - Extra options set */
protected const O_EXT = 1<<4;
/** 10 0000 - We agree on a capability and we are set to use it */
protected const O_YES = 1<<5;
// Session Status
protected const S_OK = 0;
@@ -66,24 +99,35 @@ abstract class Protocol
protected const S_ANYHOLD = (self::S_HOLDR|self::S_HOLDX|self::S_HOLDA);
// File transfer status
protected const FOP_OK = 0;
protected const FOP_CONT = 1;
protected const FOP_SKIP = 2;
protected const FOP_ERROR = 3;
protected const FOP_SUSPEND = 4;
protected const MO_CHAT = 4;
public const FOP_OK = 0;
public const FOP_CONT = 1;
public const FOP_SKIP = 2;
public const FOP_ERROR = 3;
public const FOP_SUSPEND = 4;
public const FOP_GOT = 5;
public const TCP_SPEED = 115200;
protected SocketClient $client; /* Our socket details */
protected ?Setup $setup; /* Our setup */
protected ?Setup $setup; /* Our setup */
protected Node $node; /* The node we are communicating with */
protected Send $send; /* The list of files we are sending */
protected Receive $recv; /* The list of files we are receiving */
/** The list of files we are sending */
protected Send $send;
/** The list of files we are receiving */
protected Receive $recv;
private int $options; /* Our options for a session */
private int $session; /* Tracks where we are up to with this session */
protected bool $originate; /* Are we originating a connection */
private array $comms; /* Our comms details */
/** @var int The active options for a session */
private int $options;
/** @var int Tracks the session state */
private int $session;
/** @var array Our negotiated capability for a protocol session */
protected array $capability; // @todo make private
/** @var bool Are we originating a connection */
protected bool $originate;
/** Our comms details */
private array $comms;
abstract protected function protocol_init(): int;
@@ -91,8 +135,8 @@ abstract class Protocol
public function __construct(Setup $o=NULL)
{
if ($o && ! $o->system->addresses->count())
throw new \Exception('We dont have any FTN addresses assigned');
if ($o && ! $o->system->akas->count())
throw new \Exception('We dont have any ACTIVE FTN addresses assigned');
$this->setup = $o;
}
@@ -105,7 +149,6 @@ abstract class Protocol
switch ($key) {
case 'ls_SkipGuard': /* double-skip protection on/off */
case 'rxOptions': /* Options from ZRINIT header */
case 'socket_error':
return $this->comms[$key] ?? 0;
case 'ls_rxAttnStr':
@@ -125,7 +168,6 @@ abstract class Protocol
case 'ls_rxAttnStr':
case 'ls_SkipGuard':
case 'rxOptions':
case 'socket_error':
$this->comms[$key] = $value;
break;
@@ -134,6 +176,55 @@ abstract class Protocol
}
}
/* Capabilities are what we negotitate with the remote and are valid for the session */
/**
* Clear a capability bit
*
* @param int $cap (F_*)
* @param int $val (O_*)
* @return void
*/
public function capClear(int $cap,int $val): void
{
if (! array_key_exists($cap,$this->capability))
$this->capability[$cap] = 0;
$this->capability[$cap] &= ~$val;
}
/**
* Get a session bit (SE_*)
*
* @param int $cap (F_*)
* @param int $val (O_*)
* @return bool
*/
protected function capGet(int $cap,int $val): bool
{
if (! array_key_exists($cap,$this->capability))
$this->capability[$cap] = 0;
if ($val === self::O_WE)
return $this->capGet($cap,self::O_WANT) && $this->capGet($cap,self::O_THEY);
return $this->capability[$cap] & $val;
}
/**
* Set a session bit (SE_*)
*
* @param int $cap (F_*)
* @param int $val (O_*)
*/
protected function capSet(int $cap,int $val): void
{
if (! array_key_exists($cap,$this->capability) || $val === 0)
$this->capability[$cap] = 0;
$this->capability[$cap] |= $val;
}
/**
* We got an error, close anything we are have open
*
@@ -162,22 +253,40 @@ abstract class Protocol
if ($pid === -1)
throw new SocketException(SocketException::CANT_ACCEPT,'Could not fork process');
Log::debug(sprintf('%s:= End [%d]',self::LOGKEY,$pid));
// Parent return ready for next connection
return $pid;
}
/* O_* determine what features processing is availabile */
/**
* Clear an option bit (O_*)
*
* @param int $key
* @return void
*/
protected function optionClear(int $key): void
{
$this->options &= ~$key;
}
/**
* Get an option bit (O_*)
*
* @param int $key
* @return int
*/
protected function optionGet(int $key): int
{
return ($this->options & $key);
}
/**
* Set an option bit (O_*)
*
* @param int $key
* @return void
*/
protected function optionSet(int $key): void
{
$this->options |= $key;
@@ -197,12 +306,12 @@ abstract class Protocol
$addresses = $addresses->unique();
Log::debug(sprintf('%s: - Presenting limited AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
Log::debug(sprintf('%s:- Presenting limited AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
} else {
$addresses = $this->setup->system->addresses;
Log::debug(sprintf('%s: - Presenting ALL our AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
Log::debug(sprintf('%s:- Presenting ALL our AKAs [%s]',self::LOGKEY,$addresses->pluck('ftn')->join(',')));
}
return $addresses;
@@ -214,19 +323,18 @@ abstract class Protocol
* @param int $type
* @param SocketClient $client
* @param Address|null $o
* @return int
* @return void
* @throws \Exception
*/
public function session(int $type,SocketClient $client,Address $o=NULL): int
public function session(int $type,SocketClient $client,Address $o=NULL): void
{
if ($o->exists)
Log::withContext(['ftn'=>$o->ftn]);
Log::debug(sprintf('%s:+ Start [%d]',self::LOGKEY,$type));
// This sessions options
$this->options = 0;
$this->session = 0;
$this->capability = [];
// Our files that we are sending/receive
$this->send = new Send;
@@ -240,7 +348,7 @@ abstract class Protocol
// If we are connecting to a node
if ($o->exists) {
Log::debug(sprintf('%s: + Originating a connection to [%s]',self::LOGKEY,$o->ftn));
Log::debug(sprintf('%s:+ Originating a connection to [%s]',self::LOGKEY,$o->ftn));
$this->node->originate($o);
} else {
@@ -255,38 +363,39 @@ abstract class Protocol
switch ($type) {
/** @noinspection PhpMissingBreakStatementInspection */
case self::SESSION_AUTO:
Log::debug(sprintf('%s: - Trying EMSI',self::LOGKEY));
Log::debug(sprintf('%s:- Trying EMSI',self::LOGKEY));
$rc = $this->protocol_init();
if ($rc < 0) {
Log::error(sprintf('%s:! Unable to start EMSI [%d]',self::LOGKEY,$rc));
return self::S_REDIAL | self::S_ADDTRY;
return;
}
case self::SESSION_EMSI:
Log::debug(sprintf('%s: - Starting EMSI',self::LOGKEY));
Log::debug(sprintf('%s:- Starting EMSI',self::LOGKEY));
$rc = $this->protocol_session();
break;
case self::SESSION_BINKP:
Log::debug(sprintf('%s: - Starting BINKP',self::LOGKEY));
Log::debug(sprintf('%s:- Starting BINKP',self::LOGKEY));
$rc = $this->protocol_session();
break;
case self::SESSION_ZMODEM:
Log::debug(sprintf('%s: - Starting ZMODEM',self::LOGKEY));
$this->client->speed = SocketClient::TCP_SPEED;
Log::debug(sprintf('%s:- Starting ZMODEM',self::LOGKEY));
$this->client->speed = self::TCP_SPEED;
$this->originate = FALSE;
$this->protocol_session();
return $this->protocol_session();
return;
default:
Log::error(sprintf('%s: ! Unsupported session type [%d]',self::LOGKEY,$type));
Log::error(sprintf('%s:! Unsupported session type [%d]',self::LOGKEY,$type));
return self::S_REDIAL | self::S_ADDTRY;
return;
}
// @todo Unlock outbounds
@@ -302,7 +411,7 @@ abstract class Protocol
if ($this->optionGet(self::O_HAT))
$rc |= self::S_HOLDA;
Log::info(sprintf('%s: Total: %s - %d:%02d:%02d online, (%d) %lu%s sent, (%d) %lu%s received - %s',
Log::info(sprintf('%s:= Total: %s - %d:%02d:%02d online, (%d) %lu%s sent, (%d) %lu%s received - %s',
self::LOGKEY,
$this->node->address ? $this->node->address->ftn : 'Unknown',
$this->node->session_time/3600,
@@ -343,12 +452,12 @@ abstract class Protocol
// @todo Optional after session includes mail event
// if ($this->node->start_time && $this->setup->cfg('CFG_AFTERMAIL')) {}
return ($rc & ~self::S_ADDTRY);
}
/* SE_* flags determine our session processing status, at any point in time */
/**
* Clear a session bit
* Clear a session bit (SE_*)
*
* @param int $key
*/
@@ -358,7 +467,8 @@ abstract class Protocol
}
/**
* Get a session bit
* Get a session bit (SE_*)
*
* @param int $key
* @return bool
*/
@@ -368,7 +478,7 @@ abstract class Protocol
}
/**
* Set a session bit (with SE_*)
* Set a session bit (SE_*)
*
* @param int $key
*/
@@ -381,6 +491,7 @@ abstract class Protocol
* Set our client that we are communicating with
*
* @param SocketClient $client
* @deprecated use __get()/__set()
*/
protected function setClient(SocketClient $client): void
{