additions
This commit is contained in:
414
desktop_global/InOutSocketSimple.cs
Normal file
414
desktop_global/InOutSocketSimple.cs
Normal file
@@ -0,0 +1,414 @@
|
||||
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}");
|
||||
|
||||
// Send authorization bytes (as per original protocol)
|
||||
DetailedLogger.LogDebug("Sending authorization bytes...");
|
||||
networkStream.WriteByte(0); // Receiver type
|
||||
networkStream.WriteByte((byte)config.Channel); // Channel number
|
||||
networkStream.Flush();
|
||||
DetailedLogger.LogConnection($"Authorization sent: ReceiverType=0, Channel={config.Channel}");
|
||||
|
||||
// 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)");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user