Files
SuperVPN/.history/desktop_global/InOutSocketSimple_20251009103145.cs
2025-10-12 10:59:34 +09:00

407 lines
15 KiB
C#

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<byte[]> outbuffer = new ConcurrentQueue<byte[]>();
private BinaryWriter bw;
private ConcurrentQueue<byte[]> output = new ConcurrentQueue<byte[]>();
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)");
}
}
}