clrghouz/app/Classes/TTY.php
2021-06-13 01:32:22 +10:00

919 lines
24 KiB
PHP

<?php
namespace App\Classes;
use Illuminate\Support\Facades\Log;
use App\Classes\Sock\SocketClient;
/**
* Class TTY
* @package App\Classes
*
* This base class handles all the comms with the remote
*/
class TTY
{
protected SocketClient $client; /* Our incoming client socket */
private const RX_BUF_SIZE = (0x8100);
private const TX_BUF_SIZE = (0x8100);
private const MSG_BUFFER = 2048;
protected const OK = 0;
private const EOF = -1;
protected const TIMEOUT = -2;
protected const RCDO = -3;
protected const GCOUNT = -4;
protected const ERROR = -5;
private const TTY_SUCCESS = self::OK;
private const TTY_TIMEOUT = self::TIMEOUT;
private const TTY_HANGUP = self::RCDO;
private const TTY_ERROR = self::ERROR;
protected const QC_RECVD = 'c';
protected const QC_SENDD = 'd';
protected const QC_EMSID = 'g';
private const QR_POLL = 'A';
private const QR_REQ = 'B';
private const QR_SEND = 'D';
private const QR_STS = 'E';
private const QR_CONF = 'F';
private const QR_QUIT = 'G';
private const QR_INFO = 'H';
private const QR_SCAN = 'I';
private const QR_KILL = 'J';
private const QR_QUEUE = 'K';
private const QR_SKIP = 'L';
private const QR_REFUSE = 'M';
private const QR_HANGUP = 'N';
private const QR_RESTMR = 'O';
private const QR_CHAT = 'P';
private const QR_SET = 'S';
private const QR_STYPE = 'T';
private const HUP_NONE = 0;
private const HUP_LINE = 1;
private const HUP_OPERATOR = 2;
private const HUP_SESLIMIT = 3;
private const HUP_CPS = 4;
// @tod these FOP has been duplicated from Protocol - added back here for optimising EMSI
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 int $tty_rx_left = 0; /* Number of bytes in receive buffer */
private string $tty_tx_buf = ''; /* Data in the buffer to send */
private int $tty_tx_ptr = 0; /* Pointer to next byte to send out in transmit buffer */
private int $tty_tx_free = self::TX_BUF_SIZE;/* Number of byte left in transmit buffer */
private int $tty_status = self::TTY_SUCCESS;
private int $tty_gothup = 0;
//protected int $rxstatus = 0;
public function __construct()
{
$this->sendf = new FileSend; // @todo these should be delcared private if they are staying here
$this->recvf = new FileReceive;
$this->rnode = new rnode;
}
protected function check_cps(): void
{
Log::debug('- Start',['m'=>__METHOD__]);
$cpsdelay=10; // $cpsdelay=cfgi(CFG_MINCPSDELAY);
$ncps = 38400/1000; $this->speed/1000;
$r=1; //$r=cfgi(CFG_REALMINCPS);
if(!($this->sendf->cps=time()-$this->sendf->start)) {
$this->sendf->cps=1;
} else {
$this->sendf->cps=($this->sendf->foff-$this->sendf->soff)/$this->sendf->cps;
}
if(!($this->recvf->cps=time()-$this->recvf->start)) {
$this->recvf->cps=1;
} else {
$this->recvf->cps=($this->recvf->foff-$this->recvf->soff)/$this->recvf->cps;
}
if($this->sendf->start&&(true ? 0 : cfgi(CFG_MINCPSOUT))>0&&(time()-$this->sendf->start)>$cpsdelay&&$this->sendf->cps<($r?$cci:$cci*$ncps)) {
//write_log("mincpsout=%d reached, aborting session",r?cci:cci*ncps);
$tty_gothup = self::HUP_CPS;
}
if($this->recvf->start&&(true ? 0 : cfgi(CFG_MINCPSIN))>0&&(time()-$this->recvf->start)>$cpsdelay&&$this->recvf->cps<($r?$cci:$cci*$ncps)) {
//write_log("mincpsin=%d reached, aborting session",r?cci:cci*ncps);
$tty_gothup = self::HUP_CPS;
}
$this->getevt();
Log::debug('- End',['m'=>__METHOD__]);
}
// @todo no longer used?
protected function getevt(): void
{
Log::debug('+ Start', ['m' => __METHOD__]);
$qsndbuflen = 0;
while($this->qrecvpkt($qrcv_buf)) {
Log::debug(' - qrecvpkt Returned', ['m' => __METHOD__,'qrcv_buf'=>$qrcv_buf]);
switch($qrcv_buf[2]) { // @todo this doesnt seem right?
case self::QR_SKIP:
//$this->rxstatus=self::RX_SKIP;
break;
case self::QR_REFUSE:
//$this->rxstatus=self::RX_SUSPEND;
break;
case self::QR_HANGUP:
$tty_gothup = self::HUP_OPERATOR;
break;
case self::QR_CHAT:
/*
if($qrcv_buf[3]) {
xstrcpy((qsnd_buf+qsndbuflen),(qrcv_buf+3),self::CHAT_BUF-$qsndbuflen);
$qsndbuflen+=strlen((qrcv_buf+3));
if($qsndbuflen>self::CHAT_BUF-128) {
$qsndbuflen=self::CHAT_BUF-128;
}
} else {
$i=$chatprot;
$chatprot=-1;
chatsend(qsnd_buf);
if($chatlg) {
chatlog_done();
}
$chatlg=0;
$chatprot=i;
xstrcat($qsnd_buf,"\n * Chat closed\n",CHAT_BUF);
chatsend($qsnd_buf);
if($chattimer>1) {
qlcerase();
}
$qsndbuflen=0;
$chattimer=1;
}
*/
break;
}
$qsnd_buf[$qsndbuflen]=0;
}
if ($qsndbuflen>0)
if(! $this->chatsend($qsnd_buf)) {
$qsndbuflen=0;
}
Log::debug('- End', ['m' => __METHOD__]);
}
protected function qrecvpkt(&$str): int
{
Log::debug('+ Start',['m'=>__METHOD__,'str'=>$str]);
/*
if (! $this->xsend_cb) {
return 0;
}
*/
$rc = $this->xrecv($this->client->connection,$str,self::MSG_BUFFER-1,0);
Log::debug(sprintf(' - qrecvpkt Got [%x] (%d)',$rc,$rc),['m'=>__METHOD__]);
if ( $rc < 0 && $this->errno != 11 /*MSG_EAGAIN*/ ) {
if ($this->errno == self::ECONNREFUSED) {
$xsend_cb = NULL;
}
//DEBUG(('I',1,"can't recv (fd=%d): %s",ssock,strerror(errno)));
}
Log::debug(sprintf(' - qrecvpkt Got [%x] (%d)',$rc,$rc),['m'=>__METHOD__,'str'=>$str,'len'=>strlen($str)]);
if ($rc < 3 || ! substr($str,0,2)) {
Log::debug('+ End',['m'=>__METHOD__,'rc'=>0]);
return 0;
}
//str[rc] = '\0';
if (! $rc)
$str = '';
Log::debug('+ End',['m'=>__METHOD__,'rc'=>$rc]);
return $rc;
}
protected function rxclose(&$f, int $what): int
{
Log::debug('+ Start',['m'=>__METHOD__,'what'=>$what,'f'=>$f]);
$cps=time()-$this->recvf->start;
$ss = '';
if(!$f || !$f) {
Log::debug('= End',['m'=>__METHOD__,'rc'=>self::FOP_ERROR]);
return self::FOP_ERROR;
}
$this->recvf->toff+=$this->recvf->foff;
$this->recvf->stot+=$this->recvf->soff;
$p2=0;
if(! $cps) {
$cps=1;
}
$cps=($this->recvf->foff-$this->recvf->soff)/$cps;
/*
IFPerl(if((ss=perl_end_recv(what))) {
if(!$ss) {
$what=self::FOP_SKIP;
} else {
$p2 = $ss; //xstrcpy(p2,ss,MAX_PATH);
}
});
*/
switch($what) {
case self::FOP_SUSPEND:
$ss="suspended";
break;
case self::FOP_SKIP:
$ss="skipped";
break;
case self::FOP_ERROR:
$ss="error";
break;
case self::FOP_OK:
$ss="ok";
break;
default:
$ss="";
}
Log::debug(' -',['m'=>__METHOD__,'soff'=>$this->recvf->soff,'ss'=>$ss]);
if($this->recvf->soff) {
//write_log("rcvd: %s, %lu bytes (from %lu), %ld cps [%s]",
// recvf.fname, (long) recvf.foff, (long) recvf.soff, cps, ss);
} else {
//write_log("rcvd: %s, %lu bytes, %ld cps [%s]",
// recvf.fname, (long) recvf.foff, cps, ss);
}
fclose($f);
$f='';
/*
snprintf(p, MAX_PATH, "%s/tmp/%s", cfgs(CFG_INBOUND), recvf.fname);
if($p2) {
if($p2!='/'&&*$p2=='.') {
$ss=xstrdup($p2);
snprintf($p2,MAX_PATH,"%s/%s",cfgs(CFG_INBOUND),$ss);
xfree($ss);
}
} else {
snprintf(p2, MAX_PATH, "%s/%s", cfgs(CFG_INBOUND), recvf.fname);
}
*/
//$ut->actime=$ut->modtime=$this->recvf->mtime;
$this->recvf->foff=0;
switch($what) {
case self::FOP_SKIP:
unlink($p);
break;
case self::FOP_SUSPEND:
case self::FOP_ERROR:
/*
if($this->whattype($p)==self::IS_PKT&&cfgi(self::CFG_KILLBADPKT)) {
unlink($p);
} else {
//utime(p,&ut);
touch ($this->recvf->name,octdec($this->recvf->mtime));
}
*/
break;
case self::FOP_OK:
$rc=isset($receive_callback)?receive_callback($p):0;
if($rc) {
//lunlink(p);
} else {
$ss=$p2+strlen($p2)-1;
$overwrite=0;
/*
for(i=cfgsl(CFG_ALWAYSOVERWRITE); i; i=i->next)
if(!xfnmatch(i->str,recvf.fname,FNM_PATHNAME)) {
$overwrite=1;
}
while(!$overwrite&&!stat(p2, &sb)&&p2[0]) {
if(sifname(ss)) {
ss--;
while('.' == *ss && ss >= p2) {
ss--;
}
if(ss < p2) {
write_log("can't find suitable name for %s: leaving in temporary directory",p);
p2[0] = '\x00';
}
}
}
if(p2[0]) {
if(overwrite) {
lunlink(p2);
}
if(rename(p, p2)) {
write_log("can't rename %s to %s: %s",p,p2,strerror(errno));
} else {
utime(p2,&ut);
chmod(p2,cfgi(CFG_DEFPERM));
}
}
*/
Log::debug(sprintf('Recevied [%s] with mtime [%s]',$this->f->name,$this->recvf->mtime),['m'=>__METHOD__]);
touch('/tmp/tmp/'.$this->f->name,$this->recvf->mtime);
}
break;
}
if($what==self::FOP_SKIP||$what==self::FOP_SUSPEND) {
$skipiftic=$what;
}
$this->recvf->start=0;
$this->recvf->ftot=0;
//$this->rxstatus=0;
Log::debug('= End',['m'=>__METHOD__,'rc'=>$what]);
return $what;
}
protected function rxopen(string $name,int $rtime,int $rsize,string &$f): int
{
Log::debug('+ Start',['m'=>__METHOD__,'name'=>$name,'rtime'=>$rtime,'rsize'=>$rsize,'f'=>$f]);
$ccs = '/tmp'; // @todo Base path needs to be a config item
$this->speed = 38400;
$prevcps = ($this->recvf->start&&(time()-$this->recvf->start>2))?$this->recvf->cps:$this->speed/10;
if(! $name) {
return self::FOP_ERROR;
}
$bn = basename($name);//xstrcpy($bn, qbasename($name), self::MAX_PATH);
Log::debug(sprintf(' - bn[%s]',$bn),['m'=>__METHOD__]);
//mapname((char*)bn, cfgs(CFG_MAPIN), MAX_PATH);
//$this->recvf->start=(int)decoct(time());
$this->recvf->start=time();
//xfree(recvf.fname);
$this->recvf->fname=$bn; //xstrdup($bn);
//dd(['rtime'=>$rtime,'start'=>$this->recvf->start]);
$this->recvf->mtime=$rtime; //-gmtoff($this->recvf->start);
$this->recvf->ftot=$rsize;
if($this->recvf->toff+$rsize > $this->recvf->ttot) {
$this->recvf->ttot+=$rsize;
}
$this->recvf->nf++;
if($this->recvf->nf > $this->recvf->allf) {
$this->recvf->allf++;
}
//IFPerl(if((rc=perl_on_recv())!=FOP_OK)return rc);
/*
if($this->whattype($name)==self::IS_PKT&&($rsize==60||!$rsize)&&cfgi(self::CFG_KILLBADPKT)) {
return self::FOP_SKIP;
}
*/
$rc=$skipiftic = 0; // @todo
$skipiftic=0;
if($rc&&istic($bn)&&cfgi(self::CFG_AUTOTICSKIP)) {
//write_log($rc==self::FOP_SKIP?$weskipstr:$wesusstr,$this->recvf->fname,"auto");
return $rc;
}
// @todo
/*
for($i=cfgsl(self::CFG_AUTOSKIP); $i; $i=$i->next)
if(!$this->xfnmatch($i->str,$bn, self::FNM_PATHNAME)) {
//write_log(weskipstr,$this->recvf.fname,"");
$skipiftic=self::FOP_SKIP;
return self::FOP_SKIP;
}
for($i=cfgsl(self::CFG_AUTOSUSPEND); $i; $i=$i->next)
if(!$this->xfnmatch($i->str, $bn, self::FNM_PATHNAME)) {
//write_log(wesusstr,$this->recvf->fname,"");
$skipiftic=self::FOP_SUSPEND;
return self::FOP_SUSPEND;
}
*/
$p = '/tmp/tmp/'; //@todo snprintf(p, MAX_PATH, "%s/tmp/", cfgs(CFG_INBOUND));
//if ($sb = stat($p)) // if(stat($p, &sb))
if(! is_dir($p) AND ! mkdir($p)) { // && $errno!=EEXIST
Log::debug(sprintf(' - dir doesnt exist and cannot make it? [%s]',$p),['m'=>__METHOD__,'rc'=>self::FOP_SUSPEND]);
//write_log("can't make directory %s: %s", p, strerror(errno));
//write_log(wesusstr,$this->recvf.fname,"");
$skipiftic=self::FOP_SUSPEND;
return self::FOP_SUSPEND;
}
$p = sprintf('%s/%s',$ccs,$bn);// snprintf($p, self::MAX_PATH, "%s/%s", $ccs, $bn);
if(file_exists($p) AND ($sb=stat($p)) && $sb['size']==$rsize) {//if(!stat(p, &sb) && sb.st_size==rsize) {
Log::debug(sprintf(' - file exists and size is same? [%s]',$p),['m'=>__METHOD__,'sb'=>$sb,'rsize'=>$rsize,'rc'=>self::FOP_SKIP]);
//write_log(weskipstr,$this->recvf.fname,"");
$skipiftic=self::FOP_SKIP;
return self::FOP_SKIP;
}
//dd(['maxpath'=>self::MAX_PATH,'bn'=>$bn]);
//snprintf($p, self::MAX_PATH, "%s/tmp/%s", $ccs, $bn);
$p = sprintf('%s/tmp/%s',$ccs,$bn);
// If the file exists
if (file_exists($p) AND $sb=stat($p)) {//if(!stat(p, &sb)) {
Log::debug(sprintf(' - file exists... [%s]',$p),['m'=>__METHOD__,'sb'=>$sb,'rsize'=>$rsize,
'mtime'=>$this->recvf->mtime,
//'mtime-decopt'=>(int)decoct($this->recvf->mtime),
//'mtime-octdec'=>(int)octdec($this->recvf->mtime),
'sbmtime'=>$sb['mtime'],
'sbmtime-decopt'=>(int)decoct($sb['mtime']),
//'sbmtime-octdec'=>(int)octdec($sb['mtime']),
]);
// @todo binkp doesnt use octal.
if($sb['size']<$rsize && $sb['mtime']==(int)$this->recvf->mtime) {
Log::debug(sprintf(' - attempt open for append [%s]',$p),['m'=>__METHOD__]);
$f=fopen($p, "ab");
if(!$f) {
Log::debug(sprintf(' - attempt open for append FAILED [%s]',$p),['m'=>__METHOD__,'rc'=>self::FOP_SUSPEND]);
//write_log("can't open file %s for writing: %s", p,strerror(errno));
//write_log(wesusstr,$this->recvf.fname,"");
$skipiftic=self::FOP_SUSPEND;
return self::FOP_SUSPEND;
}
Log::debug(sprintf(' - FTELL REPORTS [%s]',serialize(ftell($f))),['m'=>__METHOD__]);
// ftell() gives undefined results for append-only streams (opened with "a" flag).
$this->recvf->foff = $this->recvf->soff = $sb['size']; //ftell($f);
Log::debug(sprintf(' - open for append [%s] at [%d]',$p,$this->recvf->soff),['m'=>__METHOD__,'rc'=>self::FOP_CONT]);
//if(cfgi(self::CFG_ESTIMATEDTIME)) {
//write_log("start recv: %s, %lu bytes (from %lu), estimated time %s",
// $this->recvf.fname, (long) rsize, (long) $this->recvf.soff, estimatedtime(rsize-$this->recvf.soff,prevcps,effbaud));
//}
return self::FOP_CONT;
}
}
$f=fopen($p, "wb");
if(!$f) {
//write_log("can't open file %s for writing: %s", p,strerror(errno));
//write_log(wesusstr,$this->recvf.fname,"");
$skipiftic=self::FOP_SUSPEND;
return self::FOP_SUSPEND;
}
//dd(['sb'=>$sb,'recvf'=>$this->recvf]);
Log::debug(sprintf(' - new file created [%s]',$p),['m'=>__METHOD__,'rc'=>self::FOP_OK]);
$this->recvf->foff = $this->recvf->soff = 0;
//if(cfgi(self::CFG_ESTIMATEDTIME)) {
//write_log("start recv: %s, %lu bytes, estimated time %s",
// $this->recvf.fname, (long) rsize, estimatedtime(rsize,prevcps,effbaud));
//}
return self::FOP_OK;
}
public function setClient(SocketClient $client): void
{
$this->client = $client;
}
public function timer_expired(int $timer): int
{
return (time()>=$timer);
}
public function timer_rest(int $timer): int
{
return (($timer)-time());
}
public function timer_set(int $expire): int
{
return (time()+$expire);
}
protected function txclose(&$f, int $what):int
{
$cps=time()-$this->sendf->start;
if(!$f) {
return self::FOP_ERROR;
}
$this->sendf->toff+=$this->sendf->foff;
$this->sendf->stot+=$this->sendf->soff;
if(!$cps) {
$cps=1;
}
$cps=($this->sendf->foff-$this->sendf->soff)/$cps;
//IFPerl(perl_end_send(what));
switch($what) {
case self::FOP_SUSPEND:
$ss="suspended";
break;
case self::FOP_SKIP:
$ss="skipped";
break;
case self::FOP_ERROR:
$ss="error";
break;
case self::FOP_OK:
$ss="ok";
break;
default:
$ss="";
}
if($this->sendf->soff) {}
//write_log("sent: %s, %lu bytes (from %lu), %ld cps [%s]", sendf.fname, (long) sendf.foff, (long) sendf.soff, cps, ss);
else {}
//write_log("sent: %s, %lu bytes, %ld cps [%s]",sendf.fname, (long) sendf.foff, cps, ss);
$this->sendf->foff=0;
$this->sendf->ftot=0;
$this->sendf->start=0;
fclose($f);
$f=NULL;
return $what;
}
protected function xrecv($sock,&$buf,int $len,int $wait):int
{
Log::debug('+ Start',['m'=> __METHOD__]);
$l = 0;
if (! $sock) {
$this->errno = self::EBADF;
return -1;
}
if (! $wait) {
Log::debug(' - Not wait',['m'=> __METHOD__]);
$tv_tv_sec = 0;
$tv_tv_usec = 0;
$rfd = 0; //FD_ZERO(&rfd);
//FD_SET(sock, &rfd);
$read = [$sock];
$write = [];
$except = [];
$rc = socket_select($read,$write,$except,0,0);
//$foo = '';
//$rc = socket_recv($this->client->connection,$foo,1,MSG_PEEK | MSG_DONTWAIT);
Log::debug(' - socket_select',['m'=> __METHOD__,'rc'=>$rc,'read'=>$read,'write'=>$write,'except'=>$except]);
//$rc = $this->client->hasData(0);
if ($rc < 1) {
if (! $rc) {
$this->errno = 11; //MSG_EAGAIN;
}
return -1;
}
}
Log::debug(sprintf(' - doing a read now for [%d].',$len));
$rc = socket_recv($read[0],$l,$len,MSG_PEEK | MSG_DONTWAIT);
Log::debug(' - socket_recv PEEK', ['m' => __METHOD__,'l'=>$l,'rc'=>$rc]);
if ($rc <= 0) {
return $rc;
}
if ($rc == 2) {
return 2;
//l = I2H16(l);
// $l = unpack('s',$l);
$l = ((ord($l[0])&0x7f)<<8)+ord($l[1]);
// dd(['l'=>$l,'0'=>ord($l[0])&0xf,'00'=>((ord($l[0])&0x7f)<<8)+ord($l[1]),'1'=>ord($l[1]),'hex'=>sprintf('%x',unpack('v',$l)),'len'=>$len]);
if (! $l) {
return 0;
}
if ($l > $len) {
$l = $len;
}
Log::debug(' - L is ',['m' => __METHOD__,'l'=>min($l+$rc,$len)]);
$rc = socket_recv($sock,$buf,min($l+$rc,$len),MSG_WAITALL);
Log::debug(' - socket_recv GOT', ['m' => __METHOD__,'buf'=>$buf,'len'=>strlen($buf),'rc'=>$rc]);
if ($rc <= 0) {
return $rc;
}
$rc = min($rc - 2, strlen($buf));
if ($rc < 1) {
return 0;
}
if ($rc >= $len) {
$rc = $len - 2;
}
$buf = substr($buf,2,$rc); //memcpy(buf, buf + 2, rc);
return $rc;
}
return 0;
}
private function tty_bufc(int $ch): int
{
return $this->tty_bufblock( chr($ch), 1 );
}
// SocketClient::buffer_add()
public function tty_bufblock(string $data, int $nbytes): int
{
Log::debug(sprintf('%s: + Start [%s] (%d)',__METHOD__,$data,$nbytes));
$rc = self::OK;
$txptr = self::TX_BUF_SIZE - $this->tty_tx_free;
$nptr = 0;
$this->tty_status = self::TTY_SUCCESS;
while ( $nbytes ) {
Log::debug(sprintf(' - Num Bytes [%d]: TX Free [%d]',$nbytes,$this->tty_tx_free));
if ( $nbytes > $this->tty_tx_free ) {
do {
$this->tty_bufflush( 5 );
if ( $this->tty_status == self::TTY_SUCCESS ) {
$n = min($this->tty_tx_free,$nbytes);
$this->tty_tx_buf = substr($data,$nptr,$n);
$this->tty_tx_free -= $n;
$nbytes -= $n;
$nptr += $n;
}
} while ( $this->tty_status != self::TTY_SUCCESS );
} else {
Log::debug(sprintf(' -'),['data'=>$data,'nptr'=>$nptr,'txptr'=>$txptr,'tx_buff'=>substr($data,$nptr+$txptr,$nbytes)]);
$this->tty_tx_buf .= $data;// memcpy( (void *) (tty_tx_buf + txptr), nptr, nbytes );
$this->tty_tx_free -= $nbytes;
$nbytes = 0;
}
}
Log::debug('= End',['m'=>__METHOD__,'rc'=>$rc]);
return $rc;
}
private function tty_bufclear(): void
{
$this->tty_tx_ptr = 0;
$this->tty_tx_free = self::TX_BUF_SIZE;
$this->tty_tx_buf = '';
}
protected function tty_bufflush(int $tsec): int
{
Log::debug('+ Start',['m'=>__METHOD__,'tsec'=>$tsec,'txfree'=>$this->tty_tx_free,'txptr'=>$this->tty_tx_ptr,'txbuff'=>$this->tty_tx_buf]);
$rc = self::OK;
$restsize = self::TX_BUF_SIZE - $this->tty_tx_free - $this->tty_tx_ptr;
$tm = $this->timer_set( $tsec );
while (self::TX_BUF_SIZE != $this->tty_tx_free ) {
$wd = true;
$tv = $this->timer_rest( $tm );
if (( $rc = $this->client->canSend($tv) > 0 && $wd )) {
Log::debug(sprintf(' - Sending [%d]: Buffer [%s] Size [%d]',substr($this->tty_tx_buf,$this->tty_tx_ptr,$restsize),$this->tty_tx_buf,$restsize));
$rc = $this->client->send(substr($this->tty_tx_buf,$this->tty_tx_ptr,$restsize),0,$restsize);
Log::debug(sprintf(' - Sent [%d]: Buffer [%s] Size [%d]',$rc,$this->tty_tx_buf,$restsize));
if ($rc == $restsize ) {
$this->tty_bufclear();
} else if ( $rc > 0 ) {
$this->tty_tx_ptr += $rc;
$restsize -= $rc;
} else if ( $rc < 0 && $this->tty_status != self::TTY_TIMEOUT ) {
return self::ERROR;
}
} else {
return $rc;
}
if ($this->timer_expired( $tm )) {
return self::ERROR;
}
}
Log::debug('= End',['m'=>__METHOD__,'rc'=>$rc]);
return $rc;
}
public function tty_getc(int $timeout): int
{
Log::debug(sprintf('%s: + Start [%d]',__METHOD__,$timeout),['rx_left'=>$this->tty_rx_left]);
if ($this->tty_rx_left == 0 ) {
if ($this->client->hasData($timeout) > 0) {
if (! ($this->tty_rx_buf = $this->client->read(0,self::RX_BUF_SIZE))) {
Log::debug(sprintf('%s: - Nothing read',__METHOD__));
return ($this->EWBOEA()) ? self::TTY_TIMEOUT : self::ERROR;
}
Log::info(sprintf('%s: - Read [%d]',__METHOD__,strlen($this->tty_rx_buf)));
$this->tty_rx_ptr = 0;
$this->tty_rx_left = strlen($this->tty_rx_buf);
} else {
return ( $this->tty_gothup ? self::TTY_HANGUP : self::TTY_TIMEOUT );
}
}
$rc = ord(substr($this->tty_rx_buf,$this->tty_rx_ptr,1)); //tty_rx_buf[tty_rx_ptr++];
$this->tty_rx_left--;
$this->tty_rx_ptr++;
Log::debug(sprintf('%s: = Return [%x] (%c)',__METHOD__,$rc,$rc));
return $rc;
}
private function tty_getc_timed(int $timeout): int
{
$t = time();
$rc = $this->tty_getc($timeout);
$timeout -= (time() - $t);
return $rc;
}
protected function tty_purge(): void
{
//DEBUG(('M',3,"tty_purge"));
$this->tty_rx_ptr = $this->tty_rx_left = 0;
/*
if ( isatty( tty_fd )) {
tio_flush_queue( tty_fd, TIO_Q_IN );
}
*/
}
private function tty_purgeout(): void
{
//DEBUG(('M',3,"tty_purgeout"));
$this->tty_bufclear();
/*
if ( isatty( tty_fd )) {
tio_flush_queue( tty_fd, TIO_Q_OUT );
}
*/
}
private function tty_putc(string $ch):int
{
$this->tty_bufblock($ch,1);
return $this->tty_bufflush(5);
}
protected function tty_select($rd,$wd,int $tval): int
{
//DEBUG(('T',2,"tty_select"));
$rfd = $this->client->connection;
$wfd = $this->client->connection;
//dump($rfd,$wfd);
//FD_ZERO( &rfd );
//FD_ZERO( &wfd );
//if ($rd && $rd) {
//FD_SET($tty_fd,$rfd);
$rd = FALSE;
//}
//if ($wd && $wd ) {
//FD_SET($tty_fd,$wfd);
$wd = FALSE;
//}
$tty_error = 0;
$read = [$this->client->connection];
$write = [$this->client->connection];
$except = [];
dump('calling socket_select',['timeout'=>$tval,'read'=>$read,'write'=>$write]);
$rc = socket_select($read, $write, $except,($tval ?: NULL));
dump('done socket_select',$tval);
$tty_error = socket_last_error();
$tty_status = self::TTY_SUCCESS;
if ($rc < 0 ) {
if (EWBOEA()) {
$tty_status = self::TTY_TIMEOUT;
} else if ($errno == self::EINTR) {
$tty_status = ($tty_online && $tty_gothup ) ? self::TTY_HANGUP : self::TTY_TIMEOUT;
} else if ($errno == self::EPIPE) {
$tty_gothup = self::HUP_LINE;
$tty_status = self::TTY_HANGUP;
} else {
$tty_status = self::TTY_ERROR;
}
} else if ($rc == 0) {
$tty_status = self::TTY_TIMEOUT;
/*
} else {
if ($rd /*&& FD_ISSET( tty_fd, &rfd )*) {
$rd = TRUE;
}
if ($wd /*&& FD_ISSET( tty_fd, &wfd )*) {
$wd = TRUE;
}
*/
}
//DEBUG(('T',2,"tty_select: fd=%d rc=%i (rd=%s, wd=%s)", tty_fd, rc, FDS( rd ), FDS( wd )));
return $rc;
}
protected function BUFCHAR(int $c)
{
$this->tty_bufc($c);
}
protected function BUFFLUSH(int $tsec): int
{
return $this->tty_bufflush($tsec);
}
// @todo this should go into SocketCLient?
protected function EWBOEA(): bool
{
$errno = socket_last_error($this->client->connection);
Log::debug('+ Start',['m'=> __METHOD__,'errno'=>$errno]);
return $errno === 11 /*MSG_EAGAIN*/;
}
protected function GETCHAR(int $t): int
{
return $this->tty_getc($t);
}
protected function GETCHART($t): int
{
return $this->tty_getc_timed($t);
}
public function NOTTO(string $ch): int
{
return (($ch)==self::ERROR || ($ch)==self::RCDO || ($ch)==self::EOF);
}
protected function PUTSTR(string $s):void
{
$this->tty_bufblock($s,strlen($s));
$this->BUFFLUSH( 5);
}
protected function PURGEALL(): void
{
$this->tty_purge();
$this->tty_purgeout();
}
protected function PUTCHAR(string $c)
{
$this->tty_putc( $c );
}
protected function PUTSTRCR(string $str)
{
$this->tty_bufblock($str."\r",strlen($str)+1);
return $this->tty_bufflush(5);
}
}
class rnode
{
public $starttime = 0;
public $options = 0;
public $netmail = 0;
public $files = 0;
public $ewboea = 0;
public $phone = '';
}