PHP Classes

File: scripts/binkp_test_client.php

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   scripts/binkp_test_client.php   Download  
File: scripts/binkp_test_client.php
Role: Auxiliary script
Content type: text/plain
Description: Configuration script
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 11,052 bytes
 

Contents

Class file image Download
#!/usr/bin/env php <?php /** * Standalone Binkp Test Client * * Connects directly to a binkp server for testing and debugging. * Does not use the application's database or config files. */ // Frame command constants const M_NUL = 0; // Site information const M_ADR = 1; // List of addresses const M_PWD = 2; // Session password const M_FILE = 3; // File information const M_OK = 4; // Password accepted const M_EOB = 5; // End of batch const M_GOT = 6; // File received const M_ERR = 7; // Error const M_BSY = 8; // Busy const M_GET = 9; // Get file const M_SKIP = 10; // Skip file $commandNames = [ M_NUL => 'M_NUL', M_ADR => 'M_ADR', M_PWD => 'M_PWD', M_FILE => 'M_FILE', M_OK => 'M_OK', M_EOB => 'M_EOB', M_GOT => 'M_GOT', M_ERR => 'M_ERR', M_BSY => 'M_BSY', M_GET => 'M_GET', M_SKIP => 'M_SKIP', ]; function showUsage() { echo "Binkp Test Client - Standalone binkp connection tester\n"; echo "======================================================\n\n"; echo "Usage: php binkp_test_client.php [options]\n\n"; echo "Options:\n"; echo " --host=HOST Remote host to connect to (required)\n"; echo " --port=PORT Remote port (default: 24554)\n"; echo " --address=ADDR Our FTN address (default: 1:999/999)\n"; echo " --password=PWD Session password (default: empty)\n"; echo " --sysname=NAME Our system name (default: Test System)\n"; echo " --sysop=NAME Our sysop name (default: Test Sysop)\n"; echo " --location=LOC Our location (default: Test Location)\n"; echo " --timeout=SEC Connection timeout (default: 30)\n"; echo " --send-file=PATH Send a file to the remote system\n"; echo " --verbose Show detailed frame data\n"; echo " --help Show this help message\n\n"; echo "Examples:\n"; echo " php binkp_test_client.php --host=bbs.example.com --address=1:123/456\n"; echo " php binkp_test_client.php --host=localhost --port=24554 --password=secret\n"; echo " php binkp_test_client.php --host=bbs.example.com --send-file=packet.pkt\n\n"; } function log_msg($message, $level = 'INFO') { $timestamp = date('H:i:s'); echo "[$timestamp] [$level] $message\n"; } function createFrame($command, $data = '') { $dataLen = strlen($data); $frameLen = $dataLen + 1; // +1 for command byte // Set high bit to indicate command frame $header = pack('n', $frameLen | 0x8000); return $header . chr($command) . $data; } function createDataFrame($data) { $dataLen = strlen($data); $header = pack('n', $dataLen); // No high bit for data frame return $header . $data; } function readFrame($socket, $timeout = 30) { global $commandNames; // Set socket timeout stream_set_timeout($socket, $timeout); // Read 2-byte header $header = fread($socket, 2); if ($header === false || strlen($header) < 2) { return null; } $headerVal = unpack('n', $header)[1]; $isCommand = ($headerVal & 0x8000) !== 0; $length = $headerVal & 0x7FFF; if ($length === 0) { return ['is_command' => $isCommand, 'command' => null, 'data' => '']; } // Read frame data $data = ''; $remaining = $length; while ($remaining > 0) { $chunk = fread($socket, $remaining); if ($chunk === false || strlen($chunk) === 0) { break; } $data .= $chunk; $remaining -= strlen($chunk); } if ($isCommand && strlen($data) > 0) { $command = ord($data[0]); $commandData = substr($data, 1); return [ 'is_command' => true, 'command' => $command, 'command_name' => $commandNames[$command] ?? "UNKNOWN($command)", 'data' => $commandData ]; } return ['is_command' => false, 'command' => null, 'data' => $data]; } function sendFrame($socket, $command, $data = '') { global $commandNames; $frame = createFrame($command, $data); $written = fwrite($socket, $frame); $cmdName = $commandNames[$command] ?? "UNKNOWN($command)"; log_msg("SENT: $cmdName" . ($data ? " [$data]" : "")); return $written; } function sendDataFrame($socket, $data) { $frame = createDataFrame($data); return fwrite($socket, $frame); } // Parse command line arguments $options = [ 'host' => null, 'port' => 24554, 'address' => '1:999/999', 'password' => '', 'sysname' => 'Test System', 'sysop' => 'Test Sysop', 'location' => 'Test Location', 'timeout' => 30, 'send-file' => null, 'verbose' => false, 'help' => false, ]; for ($i = 1; $i < $argc; $i++) { $arg = $argv[$i]; if ($arg === '--help' || $arg === '-h') { $options['help'] = true; } elseif ($arg === '--verbose' || $arg === '-v') { $options['verbose'] = true; } elseif (preg_match('/^--(\w+(?:-\w+)*)=(.*)$/', $arg, $matches)) { $key = $matches[1]; $value = $matches[2]; if (array_key_exists($key, $options)) { $options[$key] = $value; } else { echo "Unknown option: --$key\n"; exit(1); } } elseif (preg_match('/^--(\w+(?:-\w+)*)$/', $arg, $matches)) { $key = $matches[1]; if (array_key_exists($key, $options)) { $options[$key] = true; } } } if ($options['help']) { showUsage(); exit(0); } if (!$options['host']) { echo "Error: --host is required\n\n"; showUsage(); exit(1); } // Main client logic log_msg("Binkp Test Client Starting"); log_msg("Connecting to {$options['host']}:{$options['port']}..."); $socket = @stream_socket_client( "tcp://{$options['host']}:{$options['port']}", $errno, $errstr, $options['timeout'] ); if (!$socket) { log_msg("Connection failed: $errstr ($errno)", 'ERROR'); exit(1); } log_msg("Connected successfully!"); stream_set_timeout($socket, $options['timeout']); // Send our system info log_msg("Sending system information..."); sendFrame($socket, M_NUL, "SYS {$options['sysname']}"); sendFrame($socket, M_NUL, "ZYZ {$options['sysop']}"); sendFrame($socket, M_NUL, "LOC {$options['location']}"); sendFrame($socket, M_NUL, "VER BinkpTestClient/1.0 binkp/1.0"); sendFrame($socket, M_NUL, "TIME " . gmdate('D, d M Y H:i:s') . " UTC"); // Send our address log_msg("Sending address: {$options['address']}"); sendFrame($socket, M_ADR, $options['address']); // Read frames from server log_msg("Waiting for server response..."); $authenticated = false; $remoteAddress = null; $gotRemoteAddress = false; $sessionComplete = false; while (!$sessionComplete && !feof($socket)) { $frame = readFrame($socket, $options['timeout']); if (!$frame) { log_msg("No frame received or timeout", 'WARNING'); break; } if ($frame['is_command']) { $cmdName = $frame['command_name']; $data = $frame['data']; log_msg("RECV: $cmdName" . ($data ? " [$data]" : "")); switch ($frame['command']) { case M_NUL: // Info frame, just log it if ($options['verbose']) { log_msg(" System info: $data", 'DEBUG'); } break; case M_ADR: $remoteAddress = $data; $gotRemoteAddress = true; log_msg("Remote address: $remoteAddress"); // Now send password log_msg("Sending password..."); sendFrame($socket, M_PWD, $options['password']); break; case M_OK: log_msg("Authentication successful!", 'SUCCESS'); $authenticated = true; // If we have a file to send, do it now if ($options['send-file'] && file_exists($options['send-file'])) { $filePath = $options['send-file']; $fileName = basename($filePath); $fileSize = filesize($filePath); $fileTime = filemtime($filePath); log_msg("Sending file: $fileName ($fileSize bytes)"); // Send M_FILE $fileInfo = "$fileName $fileSize $fileTime 0"; sendFrame($socket, M_FILE, $fileInfo); // Send file data $handle = fopen($filePath, 'rb'); $bytesSent = 0; while (!feof($handle)) { $chunk = fread($handle, 4096); if ($chunk !== false && strlen($chunk) > 0) { sendDataFrame($socket, $chunk); $bytesSent += strlen($chunk); } } fclose($handle); log_msg("Sent $bytesSent bytes of file data"); // Wait for M_GOT log_msg("Waiting for M_GOT..."); } else { // No file to send, send EOB log_msg("No files to send, sending EOB"); sendFrame($socket, M_EOB); } break; case M_GOT: log_msg("File received confirmation: $data"); // Send EOB after file is confirmed sendFrame($socket, M_EOB); break; case M_EOB: log_msg("End of batch received"); if ($authenticated) { log_msg("Session complete"); $sessionComplete = true; } break; case M_ERR: log_msg("Error from server: $data", 'ERROR'); $sessionComplete = true; break; case M_BSY: log_msg("Server busy: $data", 'WARNING'); $sessionComplete = true; break; case M_FILE: // Server wants to send us a file log_msg("Server sending file: $data"); // Parse file info: name size time offset $parts = explode(' ', $data); if (count($parts) >= 3) { $fileName = $parts[0]; $fileSize = (int)$parts[1]; log_msg("Receiving file $fileName ($fileSize bytes)..."); // For testing, we'll skip the file sendFrame($socket, M_SKIP, $data); log_msg("Skipped file (test mode)"); } break; default: log_msg("Unhandled command: $cmdName", 'WARNING'); } } else { // Data frame $dataLen = strlen($frame['data']); log_msg("RECV: DATA [$dataLen bytes]"); } } fclose($socket); log_msg("Connection closed"); log_msg("Session " . ($authenticated ? "succeeded" : "failed")); exit($authenticated ? 0 : 1);