diff --git a/app/Classes/Protocol/EMSI.php b/app/Classes/Protocol/EMSI.php index b8ea5bf..961161b 100644 --- a/app/Classes/Protocol/EMSI.php +++ b/app/Classes/Protocol/EMSI.php @@ -936,6 +936,107 @@ final class EMSI extends BaseProtocol implements CRCInterface,ZmodemInterface if (static::DEBUG) 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)) return $ch; diff --git a/app/Classes/Protocol/Zmodem.php b/app/Classes/Protocol/Zmodem.php index a642064..40be618 100644 --- a/app/Classes/Protocol/Zmodem.php +++ b/app/Classes/Protocol/Zmodem.php @@ -1147,7 +1147,7 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface private function ls_zrecvdata32(string &$data,int &$len,int $timeout): int { 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 */ $crc = 0; /* Received CRC */ @@ -1165,6 +1165,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface return self::LSZ_BADCRC; } 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) { case self::LSZ_CRCE: case self::LSZ_CRCG: @@ -1277,6 +1280,8 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface break; case self::LSZ_BADCRC: + $this->rxbuf = ''; + case self::TIMEOUT: if ($this->ls_rxAttnStr) { $this->client->buffer_add($this->ls_rxAttnStr); @@ -1305,6 +1310,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface $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) */ } else { 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; } - Log::debug(sprintf('%s:- ls_zrecvfile ZDATA',self::LOGKEY)); + Log::debug(sprintf('%s:- ls_zrecvfile ZDATA',self::LOGKEY),['newpos'=>$newpos]); $needzdata = 0; } } @@ -1928,6 +1936,9 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface $this->ls_zsendhhdr(self::ZNAK,$this->ls_storelong(0)); } + // sleep between tries + sleep(5); + } while (++$trys < 10); Log::error(sprintf('%s:? ls_zrecvnewpos Something strange or timeout [%d]',self::LOGKEY,$rc)); diff --git a/app/Classes/Sock/SocketClient.php b/app/Classes/Sock/SocketClient.php index 77a5887..6176af0 100644 --- a/app/Classes/Sock/SocketClient.php +++ b/app/Classes/Sock/SocketClient.php @@ -197,6 +197,7 @@ final class SocketClient { return match ($key) { 'address_remote', 'port_remote' => $this->{$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_left' => strlen($this->rx_buf), 'tx_free' => self::TX_BUF_SIZE-strlen($this->tx_buf), @@ -210,6 +211,7 @@ final class SocketClient { switch ($key) { case 'cps': case 'speed': + case 'iac_bin': $this->session[$key] = $value; break; @@ -428,11 +430,45 @@ final class SocketClient { Log::debug(sprintf('%s:- Returning [%d] chars from the RX buffer',self::LOGKEY,$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))) 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; 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)]); // 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 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); } @@ -549,6 +594,11 @@ final class SocketClient { if (self::DEBUG) 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) { case SOCK_STREAM: return socket_write($this->connection,$message,strlen($message));