using System; using System.Collections.Concurrent; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace VideoReader { internal class InOutSocket { public int bitrateout = 0; public int bitratein = 0; private static byte[] keyByte = MD5("73!2#qweaSdzxc4r"); private static byte[] ivByte = MD5("0_=op[l:',./vf73"); private bool open; private ServerConfig config; private ConcurrentQueue outbuffer = new ConcurrentQueue(); private BinaryWriter bw; private ConcurrentQueue output = new ConcurrentQueue(); private bool noblock = true; // Новые поля для детального логгирования private TcpClient tcpClient; private NetworkStream networkStream; private Thread receiveThread; private Thread sendThread; private bool isRunning = false; private long packetCounter = 0; private DateTime connectionStartTime; public bool opened { get { return open; } set { open = value; } } public InOutSocket() { config = ServerConfig.LoadConfig(); DetailedLogger.LogConnection($"InOutSocket initialized with server: {config.ServerAddress}:{config.Port}"); DetailedLogger.LogDebug($"Encryption keys initialized - Key: {BitConverter.ToString(keyByte)}, IV: {BitConverter.ToString(ivByte)}"); } private static byte[] MD5(string input) { using (var md5 = System.Security.Cryptography.MD5.Create()) { return md5.ComputeHash(Encoding.UTF8.GetBytes(input)); } } public void Connect() { try { connectionStartTime = DateTime.Now; DetailedLogger.LogConnection($"Starting connection to {config.ServerAddress}:{config.Port}..."); // DNS Resolution DetailedLogger.LogDebug($"Resolving DNS for {config.ServerAddress}..."); var addresses = Dns.GetHostAddresses(config.ServerAddress); DetailedLogger.LogDebug($"DNS resolved to {addresses.Length} addresses: {string.Join(", ", addresses.Select(a => a.ToString()))}"); // TCP Connection tcpClient = new TcpClient(); tcpClient.ReceiveTimeout = 30000; // 30 seconds tcpClient.SendTimeout = 30000; var connectTask = tcpClient.ConnectAsync(config.ServerAddress, config.Port); var sw = Stopwatch.StartNew(); DetailedLogger.LogConnection($"Attempting TCP connection to {config.ServerAddress}:{config.Port}..."); connectTask.Wait(10000); // 10 second timeout if (!tcpClient.Connected) { throw new Exception($"Failed to connect within timeout"); } sw.Stop(); DetailedLogger.LogConnection($"TCP connection established in {sw.ElapsedMilliseconds}ms"); networkStream = tcpClient.GetStream(); DetailedLogger.LogDebug($"Network stream obtained, available: {networkStream.DataAvailable}"); // Start monitoring threads isRunning = true; receiveThread = new Thread(ReceiveLoop) { IsBackground = true, Name = "ReceiveThread" }; sendThread = new Thread(SendLoop) { IsBackground = true, Name = "SendThread" }; receiveThread.Start(); sendThread.Start(); DetailedLogger.LogConnection("Monitoring threads started"); // Send initial handshake SendInitialHandshake(); opened = true; DetailedLogger.LogConnection("Connection established successfully"); } catch (Exception ex) { DetailedLogger.LogError($"Connection failed: {ex.Message}", ex); opened = false; Cleanup(); throw; } } public void Disconnect() { DetailedLogger.LogConnection("Starting disconnect procedure..."); isRunning = false; opened = false; try { // Send disconnect packet if possible if (networkStream != null && tcpClient != null && tcpClient.Connected) { var disconnectPacket = Encoding.UTF8.GetBytes("DISCONNECT"); SendPacket(disconnectPacket, "Disconnect command"); } } catch (Exception ex) { DetailedLogger.LogError($"Error sending disconnect packet: {ex.Message}"); } Cleanup(); var totalTime = DateTime.Now - connectionStartTime; DetailedLogger.LogConnection($"Disconnected from server (session duration: {totalTime.TotalSeconds:F1}s, packets processed: {packetCounter})"); } private void Cleanup() { try { networkStream?.Close(); networkStream?.Dispose(); tcpClient?.Close(); tcpClient?.Dispose(); // Wait for threads to finish receiveThread?.Join(2000); sendThread?.Join(2000); DetailedLogger.LogDebug("Connection cleanup completed"); } catch (Exception ex) { DetailedLogger.LogError($"Error during cleanup: {ex.Message}"); } } private void SendInitialHandshake() { try { DetailedLogger.LogConnection("Sending initial handshake..."); // Создаем пакет авторизации var handshakeData = new byte[64]; var channelBytes = BitConverter.GetBytes(config.Channel); var serverTypeBytes = Encoding.UTF8.GetBytes(config.ServerType.PadRight(16).Substring(0, 16)); Array.Copy(channelBytes, 0, handshakeData, 0, 4); Array.Copy(serverTypeBytes, 0, handshakeData, 4, 16); // Добавляем timestamp var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); var timestampBytes = BitConverter.GetBytes(timestamp); Array.Copy(timestampBytes, 0, handshakeData, 20, 8); SendPacket(handshakeData, "Initial handshake"); } catch (Exception ex) { DetailedLogger.LogError($"Failed to send handshake: {ex.Message}", ex); } } private void SendPacket(byte[] data, string description) { try { var encryptedData = EncryptData(data); DetailedLogger.LogPacket("OUTGOING", encryptedData, description); networkStream.Write(encryptedData, 0, encryptedData.Length); networkStream.Flush(); Interlocked.Add(ref bitrateout, encryptedData.Length); Interlocked.Increment(ref packetCounter); DetailedLogger.LogDebug($"Packet sent successfully ({encryptedData.Length} bytes)"); } catch (Exception ex) { DetailedLogger.LogError($"Failed to send packet: {ex.Message}", ex); } } private void ReceiveLoop() { DetailedLogger.LogDebug("Receive thread started"); var buffer = new byte[8192]; while (isRunning && tcpClient?.Connected == true) { try { if (networkStream.DataAvailable) { var bytesRead = networkStream.Read(buffer, 0, buffer.Length); if (bytesRead > 0) { var receivedData = new byte[bytesRead]; Array.Copy(buffer, receivedData, bytesRead); ProcessReceivedPacket(receivedData); Interlocked.Add(ref bitratein, bytesRead); Interlocked.Increment(ref packetCounter); } } Thread.Sleep(10); // Небольшая задержка чтобы не грузить CPU } catch (Exception ex) { if (isRunning) // Только логгируем если не идет остановка { DetailedLogger.LogError($"Error in receive loop: {ex.Message}"); } break; } } DetailedLogger.LogDebug("Receive thread stopped"); } private void SendLoop() { DetailedLogger.LogDebug("Send thread started"); while (isRunning && tcpClient?.Connected == true) { try { if (outbuffer.TryDequeue(out byte[] dataToSend)) { SendPacket(dataToSend, "Queued data"); } Thread.Sleep(10); } catch (Exception ex) { if (isRunning) { DetailedLogger.LogError($"Error in send loop: {ex.Message}"); } break; } } DetailedLogger.LogDebug("Send thread stopped"); } private void ProcessReceivedPacket(byte[] rawData) { try { DetailedLogger.LogPacket("INCOMING", rawData, "Raw received data"); // Пытаемся расшифровать данные var decryptedData = DecryptData(rawData); if (decryptedData != null) { DetailedLogger.LogPacket("DECRYPTED", decryptedData, "Decrypted data"); AnalyzePacketContent(decryptedData); } else { DetailedLogger.LogDebug("Failed to decrypt packet, analyzing as plain data"); AnalyzePacketContent(rawData); } } catch (Exception ex) { DetailedLogger.LogError($"Error processing received packet: {ex.Message}", ex); } } private void AnalyzePacketContent(byte[] data) { try { var dataStr = Encoding.UTF8.GetString(data); // Проверяем на подключение телефона if (dataStr.Contains("PHONE") || dataStr.Contains("DEVICE") || dataStr.Contains("CONNECT")) { DetailedLogger.LogPhoneConnection(dataStr, "Phone connection detected in packet"); } // Проверяем другие типы пакетов if (dataStr.Contains("VIDEO")) { DetailedLogger.LogDebug("Video data packet detected"); } else if (dataStr.Contains("AUDIO")) { DetailedLogger.LogDebug("Audio data packet detected"); } else if (dataStr.Contains("HEARTBEAT") || dataStr.Contains("PING")) { DetailedLogger.LogDebug("Heartbeat/ping packet detected"); } else if (dataStr.Contains("AUTH") || dataStr.Contains("LOGIN")) { DetailedLogger.LogConnection("Authentication packet detected"); } // Логгируем содержимое пакета DetailedLogger.LogDebug($"Packet content analysis: {dataStr.Substring(0, Math.Min(100, dataStr.Length))}..."); } catch (Exception ex) { DetailedLogger.LogDebug($"Could not analyze packet as text: {ex.Message}"); } } private byte[] EncryptData(byte[] data) { try { using (var aes = Aes.Create()) { aes.Key = keyByte; aes.IV = ivByte; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (var encryptor = aes.CreateEncryptor()) using (var ms = new MemoryStream()) using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write)) { cs.Write(data, 0, data.Length); cs.FlushFinalBlock(); return ms.ToArray(); } } } catch (Exception ex) { DetailedLogger.LogError($"Encryption failed: {ex.Message}"); return data; // Возвращаем оригинальные данные если шифрование не удалось } } private byte[] DecryptData(byte[] data) { try { using (var aes = Aes.Create()) { aes.Key = keyByte; aes.IV = ivByte; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using (var decryptor = aes.CreateDecryptor()) using (var ms = new MemoryStream(data)) using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) using (var result = new MemoryStream()) { cs.CopyTo(result); return result.ToArray(); } } } catch (Exception ex) { DetailedLogger.LogDebug($"Decryption failed (data might not be encrypted): {ex.Message}"); return null; } } public void QueueDataForSending(byte[] data) { outbuffer.Enqueue(data); DetailedLogger.LogDebug($"Data queued for sending ({data.Length} bytes)"); } } }