socket = @stream_socket_client("tcp://{$this->host}:{$this->port}", $errorNumber, $errorMessage, $this->timeout); if (! is_resource($this->socket)) { throw new RuntimeException('TELNET_UNREACHABLE: koneksi Telnet HSGQ port 23 gagal.'); } stream_set_timeout($this->socket, $this->timeout); $this->readUntil('/(?:login|username|user\s*name)\s*:\s*$/i'); $this->write($username); $this->readUntil('/password\s*:\s*$/i'); $this->write($password); $output = $this->readPrompt(); if (! preg_match('/[>#]\s*$/', trim($output))) { throw new RuntimeException('AUTHENTICATION_FAILED: login Telnet HSGQ ditolak.'); } } public function command(string $command): string { $this->write($command); $output = $this->readPrompt(); $isHelpCommand = in_array(trim($command), ['?', 'help', 'list'], true); if (! $isHelpCommand && preg_match('/(?:Error|Invalid|Failed|failure|unknown command|Command incomplete|There is no matched command)/i', $output)) { preg_match('/^(?!.*user\s+(?:add|password)).*(?:Error|Invalid|Failed|failure|unknown command|Command incomplete|There is no matched command).*$/mi', $output, $detail); throw new RuntimeException('COMMAND_REJECTED: '.str($detail[0] ?? 'HSGQ menolak perintah CLI Telnet.')->trim()->limit(180)); } return $output; } public function enterEnable(string $password): void { $this->write('enable'); $output = $this->readUntil('/(?:Password\s*:|#\s*$)/i'); if (preg_match('/Password\s*:/i', $output)) { $this->write($password); $output = $this->readPrompt(); } if (! str_ends_with(trim($output), '#')) { throw new RuntimeException('ENABLE_FAILED: gagal masuk privileged mode Telnet HSGQ.'); } } public function disconnect(): void { if (is_resource($this->socket)) { fclose($this->socket); } $this->socket = null; } private function write(string $value): void { if (! is_resource($this->socket) || fwrite($this->socket, $value."\r\n") === false) { throw new RuntimeException('CONNECTION_CLOSED: sesi Telnet HSGQ terputus.'); } } private function readPrompt(): string { return $this->readUntil('/(?:\([^\r\n]+\))?[#>]\s*$/'); } private function readUntil(string $pattern): string { if (! is_resource($this->socket)) { throw new RuntimeException('CONNECTION_CLOSED: sesi Telnet HSGQ belum tersambung.'); } $output = ''; $startedAt = microtime(true); while (microtime(true) - $startedAt < $this->timeout) { $chunk = fread($this->socket, 4096); if ($chunk === false || ($chunk === '' && feof($this->socket))) { throw new RuntimeException('CONNECTION_CLOSED: sesi Telnet HSGQ ditutup perangkat.'); } if ($chunk !== '') { $output .= $this->stripNegotiation($chunk); if (preg_match($pattern, $output)) { return $output; } } $metadata = stream_get_meta_data($this->socket); if ($metadata['timed_out']) { break; } } throw new RuntimeException('CONNECTION_TIMEOUT: prompt Telnet HSGQ tidak diterima.'); } private function stripNegotiation(string $data): string { $clean = ''; $length = strlen($data); for ($index = 0; $index < $length; $index++) { if (ord($data[$index]) !== 255) { $clean .= $data[$index]; continue; } if ($index + 2 >= $length) { break; } $command = ord($data[++$index]); $option = ord($data[++$index]); if (in_array($command, [251, 252], true)) { fwrite($this->socket, pack('CCC', 255, 254, $option)); } elseif (in_array($command, [253, 254], true)) { fwrite($this->socket, pack('CCC', 255, 252, $option)); } } return str_replace("\0", '', $clean); } }