Autodetect Telnet IAC modes, and if in binary mode esc 0xff chars
This commit is contained in:
parent
52961e2403
commit
b1eaec3271
@ -936,6 +936,107 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface
|
|||||||
if (static::DEBUG)
|
if (static::DEBUG)
|
||||||
Log::debug(sprintf('%s:- Got [%x] (%c)',self::LOGKEY,$ch,$ch));
|
Log::debug(sprintf('%s:- Got [%x] (%c)',self::LOGKEY,$ch,$ch));
|
||||||
|
|
||||||
|
// Look for Telnet IAC, if binary mode we'll need to handle IAC IAC => IAC
|
||||||
|
if ($ch === 0xff) {
|
||||||
|
Log::info(sprintf('%s:- TELNET IAC',self::LOGKEY));
|
||||||
|
|
||||||
|
$iaccmd = NULL;
|
||||||
|
// Peek for the next chars
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
$iac = $this->client->read(1,1,MSG_PEEK);
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s: - IAC LOOP',self::LOGKEY),['iac'=>ord($iac),'cmd'=>$iaccmd]);
|
||||||
|
|
||||||
|
switch (ord($iac)) {
|
||||||
|
// Binary Mode
|
||||||
|
case 0x00:
|
||||||
|
if ($iaccmd === 0xfb) {
|
||||||
|
Log::debug(sprintf('%s: - IAC WILL BINARY [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
// Config with DO
|
||||||
|
$this->client->send(chr(0xff).chr(0xfd).$iac,10);
|
||||||
|
|
||||||
|
} elseif ($iaccmd === 0xfd) {
|
||||||
|
Log::debug(sprintf('%s: - IAC DO BINARY [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
// Config with WILL
|
||||||
|
if (! $this->client->iac_bin) {
|
||||||
|
$this->client->send(chr(0xff).chr(0xfb).$iac,10);
|
||||||
|
$this->client->iac_bin = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$iaccmd = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Suppress Go Ahead
|
||||||
|
case 0x03:
|
||||||
|
if ($iaccmd === 0xfb) {
|
||||||
|
Log::debug(sprintf('%s: - IAC WILL SUPPRESS-GO-AHEAD [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
// Config with DO
|
||||||
|
$this->client->send(chr(0xff).chr(0xfd).$iac,10);
|
||||||
|
|
||||||
|
} elseif ($iaccmd === 0xfd) {
|
||||||
|
Log::debug(sprintf('%s: - IAC DO SUPPRESS-GO-AHEAD [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
// Config with WILL
|
||||||
|
$this->client->send(chr(0xff).chr(0xfb).$iac,10);
|
||||||
|
}
|
||||||
|
|
||||||
|
$iaccmd = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Will
|
||||||
|
case 0xfb:
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s: - IAC WILL [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
$iaccmd = ord($iac);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Do
|
||||||
|
case 0xfd:
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s: - IAC DO [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
$iaccmd = ord($iac);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// IAC
|
||||||
|
case 0xff:
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s: - IAC [%02x]',self::LOGKEY,ord($iac)));
|
||||||
|
|
||||||
|
$iaccmd = ord($iac);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log::alert(sprintf('%s: - IAC Unhandled [%02x]',self::LOGKEY,ord($iac)),['iac'=>$iac,'iaccmd'=>$iaccmd,'ch'=>ord($iac)]);
|
||||||
|
|
||||||
|
$ch = ord($iac);
|
||||||
|
$iac = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($iaccmd) {
|
||||||
|
$iac = ord($this->client->read_ch(10));
|
||||||
|
$ch = NULL;
|
||||||
|
|
||||||
|
} elseif (is_null($ch)) {
|
||||||
|
$ch = ord($this->client->read_ch(10));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SocketException $e) {
|
||||||
|
Log::debug(sprintf('%s:! SocketException: %s',self::LOGKEY,$e->getMessage()),['class'=>get_class($e),'code'=>$e->getCode()]);
|
||||||
|
$iac = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (! is_null($iac));
|
||||||
|
|
||||||
|
Log::debug(sprintf('%s:- Leaving IAC with [%02x]',self::LOGKEY,$ch),['ch'=>serialize($ch)]);
|
||||||
|
}
|
||||||
|
|
||||||
if (($ch != self::TIMEOUT) && ($ch < 0))
|
if (($ch != self::TIMEOUT) && ($ch < 0))
|
||||||
return $ch;
|
return $ch;
|
||||||
|
|
||||||
|
@ -1147,7 +1147,7 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
private function ls_zrecvdata32(string &$data,int &$len,int $timeout): int
|
private function ls_zrecvdata32(string &$data,int &$len,int $timeout): int
|
||||||
{
|
{
|
||||||
if (static::DEBUG)
|
if (static::DEBUG)
|
||||||
Log::debug(sprintf('%s:+ ls_zrecvdata32',self::LOGKEY),['d'=>$data]);
|
Log::debug(sprintf('%s:+ ls_zrecvdata32',self::LOGKEY),['d'=>$data,'len'=>$len,'timeout'=>$timeout]);
|
||||||
|
|
||||||
$got = 0; /* Bytes total got */
|
$got = 0; /* Bytes total got */
|
||||||
$crc = 0; /* Received CRC */
|
$crc = 0; /* Received CRC */
|
||||||
@ -1165,6 +1165,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
return self::LSZ_BADCRC;
|
return self::LSZ_BADCRC;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s:- ls_zrecvdata32 c>32 [%x] (%c)',self::LOGKEY,$c,($c<31 ? 32 : $c)),['c'=>serialize($c)]);
|
||||||
|
|
||||||
switch ($c) {
|
switch ($c) {
|
||||||
case self::LSZ_CRCE:
|
case self::LSZ_CRCE:
|
||||||
case self::LSZ_CRCG:
|
case self::LSZ_CRCG:
|
||||||
@ -1277,6 +1280,8 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case self::LSZ_BADCRC:
|
case self::LSZ_BADCRC:
|
||||||
|
$this->rxbuf = '';
|
||||||
|
|
||||||
case self::TIMEOUT:
|
case self::TIMEOUT:
|
||||||
if ($this->ls_rxAttnStr) {
|
if ($this->ls_rxAttnStr) {
|
||||||
$this->client->buffer_add($this->ls_rxAttnStr);
|
$this->client->buffer_add($this->ls_rxAttnStr);
|
||||||
@ -1305,6 +1310,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
$needzdata = 1;
|
$needzdata = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (static::DEBUG)
|
||||||
|
Log::debug(sprintf('%s:- ls_zrecvfile RC [%s]',self::LOGKEY,$rc),['needzdata'=>$needzdata]);
|
||||||
|
|
||||||
/* We need new position -- ZDATA (and may be ZEOF) */
|
/* We need new position -- ZDATA (and may be ZEOF) */
|
||||||
} else {
|
} else {
|
||||||
Log::debug(sprintf('%s:- ls_zrecvfile Want ZDATA/ZEOF at [%d]',self::LOGKEY,$rxpos));
|
Log::debug(sprintf('%s:- ls_zrecvfile Want ZDATA/ZEOF at [%d]',self::LOGKEY,$rxpos));
|
||||||
@ -1335,7 +1343,7 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
return self::OK;
|
return self::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log::debug(sprintf('%s:- ls_zrecvfile ZDATA',self::LOGKEY));
|
Log::debug(sprintf('%s:- ls_zrecvfile ZDATA',self::LOGKEY),['newpos'=>$newpos]);
|
||||||
$needzdata = 0;
|
$needzdata = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1928,6 +1936,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface
|
|||||||
$this->ls_zsendhhdr(self::ZNAK,$this->ls_storelong(0));
|
$this->ls_zsendhhdr(self::ZNAK,$this->ls_storelong(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sleep between tries
|
||||||
|
sleep(5);
|
||||||
|
|
||||||
} while (++$trys < 10);
|
} while (++$trys < 10);
|
||||||
|
|
||||||
Log::error(sprintf('%s:? ls_zrecvnewpos Something strange or timeout [%d]',self::LOGKEY,$rc));
|
Log::error(sprintf('%s:? ls_zrecvnewpos Something strange or timeout [%d]',self::LOGKEY,$rc));
|
||||||
|
@ -197,6 +197,7 @@ final class SocketClient {
|
|||||||
return match ($key) {
|
return match ($key) {
|
||||||
'address_remote', 'port_remote' => $this->{$key},
|
'address_remote', 'port_remote' => $this->{$key},
|
||||||
'cps', 'speed' => Arr::get($this->session,$key),
|
'cps', 'speed' => Arr::get($this->session,$key),
|
||||||
|
'iac_bin' => Arr::get($this->session,$key),
|
||||||
'rx_free' => self::RX_BUF_SIZE-$this->rx_left,
|
'rx_free' => self::RX_BUF_SIZE-$this->rx_left,
|
||||||
'rx_left' => strlen($this->rx_buf),
|
'rx_left' => strlen($this->rx_buf),
|
||||||
'tx_free' => self::TX_BUF_SIZE-strlen($this->tx_buf),
|
'tx_free' => self::TX_BUF_SIZE-strlen($this->tx_buf),
|
||||||
@ -210,6 +211,7 @@ final class SocketClient {
|
|||||||
switch ($key) {
|
switch ($key) {
|
||||||
case 'cps':
|
case 'cps':
|
||||||
case 'speed':
|
case 'speed':
|
||||||
|
case 'iac_bin':
|
||||||
$this->session[$key] = $value;
|
$this->session[$key] = $value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -428,11 +430,45 @@ final class SocketClient {
|
|||||||
Log::debug(sprintf('%s:- Returning [%d] chars from the RX buffer',self::LOGKEY,$len));
|
Log::debug(sprintf('%s:- Returning [%d] chars from the RX buffer',self::LOGKEY,$len));
|
||||||
|
|
||||||
$result = substr($this->rx_buf,0,$len);
|
$result = substr($this->rx_buf,0,$len);
|
||||||
$this->rx_buf = substr($this->rx_buf,strlen($result));
|
if ($flags !== MSG_PEEK)
|
||||||
|
$this->rx_buf = substr($this->rx_buf,strlen($result));
|
||||||
|
|
||||||
return $result;
|
// In case we are in Telnet Binary Mode
|
||||||
|
if ($this->iac_bin) {
|
||||||
|
if (self::DEBUG)
|
||||||
|
Log::debug(sprintf('%s:- Telnet IAC Binary Mode, looking for ff ff',self::LOGKEY),['result'=>hex_dump($result)]);
|
||||||
|
|
||||||
|
// if the last char is ff, we need to get the next char
|
||||||
|
if (str_ends_with($result,"\xff")) {
|
||||||
|
if (self::DEBUG)
|
||||||
|
Log::debug(sprintf('%s: - We have a hit',self::LOGKEY));
|
||||||
|
|
||||||
|
// If we have it in our buffer, just get it
|
||||||
|
if ($this->rx_left) {
|
||||||
|
$result .= substr($this->rx_buf,0,1);
|
||||||
|
$this->rx_buf = substr($this->rx_buf,1);
|
||||||
|
|
||||||
|
// Else put everything back into rx_buf, and increase len by 1
|
||||||
|
} else {
|
||||||
|
$this->rx_buf = $result;
|
||||||
|
$len++;
|
||||||
|
$result = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($result) > 1)
|
||||||
|
$result = str_replace("\xff\xff","\xff",$result);
|
||||||
|
|
||||||
|
if (strlen($result))
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
} else
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self::DEBUG)
|
||||||
|
Log::debug(sprintf('%s:- Buffer doesnt have [%d] chars, it only has [%d], or it ends with 0xff',self::LOGKEY,$len,strlen($this->rx_buf)),['rx_buf'=>hex_dump($this->rx_buf)]);
|
||||||
|
|
||||||
if ($timeout && (! $this->hasData($timeout)))
|
if ($timeout && (! $this->hasData($timeout)))
|
||||||
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
||||||
|
|
||||||
@ -486,13 +522,19 @@ final class SocketClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($flags === MSG_PEEK) {
|
||||||
|
Log::debug(sprintf('%s:- Returning [%d] chars as a result of a PEEK operation, buffer would have [%d], but still has [%d]',self::LOGKEY,$len,strlen($this->rx_buf.$buf),strlen($this->rx_buf)),['rx_buf'=>hex_dump($this->rx_buf),'buf'=>hex_dump($buf)]);
|
||||||
|
|
||||||
|
return substr($this->rx_buf.$buf,0,$len);
|
||||||
|
}
|
||||||
|
|
||||||
$this->rx_buf .= $buf;
|
$this->rx_buf .= $buf;
|
||||||
|
|
||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
Log::debug(sprintf('%s:- Added [%d] chars to the RX buffer',self::LOGKEY,strlen($buf)),['rx_buf'=>hex_dump($this->rx_buf)]);
|
Log::debug(sprintf('%s:- Added [%d] chars to the RX buffer',self::LOGKEY,strlen($buf)),['rx_buf'=>hex_dump($this->rx_buf)]);
|
||||||
|
|
||||||
// Loop again and return the data, now that it is in the RX buffer
|
// Loop again and return the data, now that it is in the RX buffer
|
||||||
return $this->read($timeout,$len);
|
return $this->read($timeout,$len,$flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -511,6 +553,9 @@ final class SocketClient {
|
|||||||
else
|
else
|
||||||
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
throw new SocketException(SocketException::SOCKET_TIMEOUT,$timeout);
|
||||||
|
|
||||||
|
if (self::DEBUG)
|
||||||
|
Log::debug(sprintf('%s:+ read_ch [%c] (%x)',self::LOGKEY,$ch,ord($ch)));
|
||||||
|
|
||||||
return ord($ch);
|
return ord($ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +594,11 @@ final class SocketClient {
|
|||||||
if (self::DEBUG)
|
if (self::DEBUG)
|
||||||
Log::debug(sprintf('%s:- Sending [%d] chars [%s]',self::LOGKEY,strlen($message),Str::limit($message,15)));
|
Log::debug(sprintf('%s:- Sending [%d] chars [%s]',self::LOGKEY,strlen($message),Str::limit($message,15)));
|
||||||
|
|
||||||
|
if ($this->iac_bin) {
|
||||||
|
Log::debug(sprintf('%s:- IAC_BIN mode, looking for 0xff',self::LOGKEY));
|
||||||
|
$message = str_replace("\xff","\xff\xff",$message);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($this->type) {
|
switch ($this->type) {
|
||||||
case SOCK_STREAM:
|
case SOCK_STREAM:
|
||||||
return socket_write($this->connection,$message,strlen($message));
|
return socket_write($this->connection,$message,strlen($message));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user