2026-03-26 02:35:43 +08:00
|
|
|
using System;
|
2026-07-18 21:37:52 +03:00
|
|
|
using System.IO;
|
2019-04-29 22:30:43 +02:00
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using MinecraftClient.Crypto;
|
|
|
|
|
|
|
|
|
|
namespace MinecraftClient.Protocol.Handlers
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wrapper for handling unencrypted & encrypted socket
|
|
|
|
|
/// </summary>
|
2024-09-01 20:42:39 +02:00
|
|
|
public class SocketWrapper
|
2019-04-29 22:30:43 +02:00
|
|
|
{
|
2022-10-02 18:31:08 +08:00
|
|
|
readonly TcpClient c;
|
|
|
|
|
AesCfb8Stream? s;
|
2019-04-29 22:30:43 +02:00
|
|
|
bool encrypted = false;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initialize a new SocketWrapper
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="client">TcpClient connected to the server</param>
|
|
|
|
|
public SocketWrapper(TcpClient client)
|
|
|
|
|
{
|
2022-10-02 18:31:08 +08:00
|
|
|
c = client;
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check if the socket is still connected
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>TRUE if still connected</returns>
|
|
|
|
|
/// <remarks>Silently dropped connection can only be detected by attempting to read/write data</remarks>
|
|
|
|
|
public bool IsConnected()
|
|
|
|
|
{
|
refactor: convert == null / != null to is null / is not null in 31 files
Replace old-style null comparisons with modern C# pattern matching
syntax across Commands, Protocol, Mapping, ChatBots, Physics,
Inventory, Logger, CommandHandler, Scripting, Crypto, and other modules.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 00:42:59 +00:00
|
|
|
return c.Client is not null && c.Connected;
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check if the socket has data available to read
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>TRUE if data is available to read</returns>
|
|
|
|
|
public bool HasDataAvailable()
|
|
|
|
|
{
|
|
|
|
|
return c.Client.Available > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Switch network reading/writing to an encrypted stream
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="secretKey">AES secret key</param>
|
|
|
|
|
public void SwitchToEncrypted(byte[] secretKey)
|
|
|
|
|
{
|
|
|
|
|
if (encrypted)
|
|
|
|
|
throw new InvalidOperationException("Stream is already encrypted!?");
|
2022-10-02 18:31:08 +08:00
|
|
|
s = new AesCfb8Stream(c.GetStream(), secretKey);
|
|
|
|
|
encrypted = true;
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Network reading method. Read bytes from the socket or encrypted socket.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void Receive(byte[] buffer, int start, int offset, SocketFlags f)
|
|
|
|
|
{
|
|
|
|
|
int read = 0;
|
|
|
|
|
while (read < offset)
|
|
|
|
|
{
|
2026-07-18 21:37:52 +03:00
|
|
|
int received;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (encrypted)
|
|
|
|
|
received = s!.Read(buffer, start + read, offset - read);
|
|
|
|
|
else
|
|
|
|
|
received = c.Client.Receive(buffer, start + read, offset - read, f);
|
|
|
|
|
}
|
|
|
|
|
catch (SocketException)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
catch (ObjectDisposedException)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
catch (IOException)
|
|
|
|
|
{
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (received <= 0)
|
|
|
|
|
throw new IOException("Socket closed while reading from the server.");
|
|
|
|
|
|
|
|
|
|
read += received;
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Read some data from the server.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="length">Amount of bytes to read</param>
|
|
|
|
|
/// <returns>The data read from the network as an array</returns>
|
|
|
|
|
public byte[] ReadDataRAW(int length)
|
|
|
|
|
{
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
byte[] cache = new byte[length];
|
|
|
|
|
Receive(cache, 0, length, SocketFlags.None);
|
|
|
|
|
return cache;
|
|
|
|
|
}
|
2022-08-15 23:55:44 +08:00
|
|
|
return Array.Empty<byte>();
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Send raw data to the server.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="buffer">data to send</param>
|
|
|
|
|
public void SendDataRAW(byte[] buffer)
|
|
|
|
|
{
|
2026-03-26 02:35:43 +08:00
|
|
|
if (!IsConnected())
|
|
|
|
|
throw new SocketException((int)SocketError.NotConnected);
|
|
|
|
|
|
2019-04-29 22:30:43 +02:00
|
|
|
if (encrypted)
|
2022-10-02 18:31:08 +08:00
|
|
|
s!.Write(buffer, 0, buffer.Length);
|
|
|
|
|
else
|
|
|
|
|
c.Client.Send(buffer);
|
2019-04-29 22:30:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Disconnect from the server
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Disconnect()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
c.Close();
|
|
|
|
|
}
|
|
|
|
|
catch (SocketException) { }
|
|
|
|
|
catch (System.IO.IOException) { }
|
|
|
|
|
catch (NullReferenceException) { }
|
|
|
|
|
catch (ObjectDisposedException) { }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|