919 lines
24 KiB
PHP
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 = '';
|
|
}
|