using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ComponentAce.Compression.Libs.zlib;
using Newtonsoft.Json;
using OXGaming.TibiaAPI.Constants;
using OXGaming.TibiaAPI.Utilities;
namespace OXGaming.TibiaAPI.Network
{
///
/// The class is used to create a proxy between the Tibia client and the game server.
///
public class Connection : Communication, IDisposable
{
private const string LOGIN_WEB_SERVICE = "https://www.tibia.com/clientservices/loginservice.php";
private readonly object _clientSendLock = new object();
private readonly object _serverSendLock = new object();
private readonly object _clientSequenceNumberLock = new object();
private readonly object _ServerSequenceNumberLock = new object();
private readonly Client _client;
private readonly HttpListener _httpListener = new HttpListener();
private readonly NetworkMessage _clientInMessage;
private readonly NetworkMessage _clientOutMessage;
private readonly NetworkMessage _serverInMessage;
private readonly NetworkMessage _serverOutMessage;
private readonly Queue _clientSendQueue = new Queue();
private readonly Queue _serverSendQueue = new Queue();
private readonly Rsa _rsa = new Rsa();
private uint[] _xteaKey;
private ZStream _zStream = new ZStream();
private Socket _clientSocket;
private Socket _serverSocket;
private Thread _clientSendThread;
private Thread _serverSendThread;
private TcpListener _tcpListener;
private dynamic _loginData;
private string _loginWebService;
private uint _clientSequenceNumber = 1;
private uint _serverSequenceNumber = 1;
private bool _isResettingConnection = false;
private bool _isSendingToClient = false;
private bool _isSendingToServer = false;
private bool _isStarted;
public delegate void ReceivedMessageEventHandler(byte[] data);
public event ReceivedMessageEventHandler OnReceivedClientMessage;
public event ReceivedMessageEventHandler OnReceivedServerMessage;
public ConnectionState ConnectionState { get; set; } = ConnectionState.Disconnected;
public bool IsClientPacketDecryptionEnabled { get; set; } = true;
public bool IsClientPacketModificationEnabled { get; set; } = false;
public bool IsClientPacketParsingEnabled { get; set; } = true;
public bool IsServerPacketDecryptionEnabled { get; set; } = true;
public bool IsServerPacketCompressionEnabled { get; set; } = false;
public bool IsServerPacketModificationEnabled { get; set; } = false;
public bool IsServerPacketParsingEnabled { get; set; } = true;
///
/// Initializes a new instance of the class that acts as a proxy
/// between the Tibia client and the game server.
///
public Connection(Client client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
_clientInMessage = new NetworkMessage(_client);
_clientOutMessage = new NetworkMessage(_client);
_serverInMessage = new NetworkMessage(_client);
_serverOutMessage = new NetworkMessage(_client);
}
///
/// Starts the and objects that listen for incoming
/// connection requests from the Tibia client.
///
/// Returns true on success, or if already started. Returns false if an exception is thrown.
internal bool Start(int httpPort = 7171, string loginWebService = "")
{
if (_isStarted)
{
return true;
}
try
{
if (_tcpListener == null)
{
_tcpListener = new TcpListener(IPAddress.Loopback, 0);
}
var uriPrefix = $"http://127.0.0.1:{httpPort}/";
if (!_httpListener.Prefixes.Contains(uriPrefix))
{
_httpListener.Prefixes.Add(uriPrefix);
}
_zStream.deflateInit(zlibConst.Z_DEFAULT_COMPRESSION, -15);
_zStream.inflateInit(-15);
_httpListener.Start();
_httpListener.BeginGetContext(new AsyncCallback(BeginGetContextCallback), _httpListener);
_tcpListener.Start();
_tcpListener.BeginAcceptSocket(new AsyncCallback(BeginAcceptTcpClientCallback), _tcpListener);
_isStarted = true;
_loginWebService = loginWebService;
ConnectionState = ConnectionState.ConnectingStage1;
}
catch (Exception ex)
{
_isStarted = false;
_client.Logger.Error(ex.ToString());
}
return _isStarted;
}
///
/// Sends a packet to the Tibia client.
///
///
/// The object to be sent.
///
public void SendToClient(ServerPacket packet)
{
if (packet == null)
{
throw new ArgumentNullException(nameof(packet));
}
var message = new NetworkMessage(_client);
packet.AppendToNetworkMessage(message);
SendToClient(message);
}
///
/// Sends a packet to the Tibia client.
///
///
/// The object containing the data to be sent.
///
public void SendToClient(NetworkMessage message)
{
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
if (message.Size <= 8)
{
return;
}
if (message.SequenceNumber != 0)
{
lock (_clientSequenceNumberLock)
{
message.SequenceNumber = _clientSequenceNumber++;
}
}
message.PrepareToSend(_xteaKey, (IsServerPacketCompressionEnabled ? _zStream : null));
SendToClient(message.GetData());
}
///
/// Sends a packet to the Tibia client.
///
///
/// The raw byte-array containing the data to be sent.
///
public void SendToClient(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (data.Length <= 8)
{
return;
}
lock (_clientSendLock)
{
_clientSendQueue.Enqueue(data);
if (!_isSendingToClient)
{
try
{
_isSendingToClient = true;
_clientSendThread = new Thread(new ThreadStart(ClientSend));
_clientSendThread.Start();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
}
}
///
/// Sends a packet to the game server.
///
///
/// The to be sent.
///
public void SendToServer(ClientPacket packet)
{
if (packet == null)
{
throw new ArgumentNullException(nameof(packet));
}
var message = new NetworkMessage(_client);
packet.AppendToNetworkMessage(message);
SendToServer(message);
}
///
/// Sends a packet to the game server.
///
///
/// The object containing the data to be sent.
///
public void SendToServer(NetworkMessage message)
{
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
if (message.Size <= 8)
{
return;
}
if (message.SequenceNumber != 0)
{
lock (_ServerSequenceNumberLock)
{
message.SequenceNumber = _serverSequenceNumber++;
}
}
message.PrepareToSend(_xteaKey);
SendToServer(message.GetData());
}
///
/// Sends a packet to the game server.
///
///
/// Raw byte-array containing the data to be sent.
///
public void SendToServer(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (data.Length <= 8)
{
return;
}
lock (_serverSendLock)
{
_serverSendQueue.Enqueue(data);
if (!_isSendingToServer)
{
try
{
_isSendingToServer = true;
_serverSendThread = new Thread(new ThreadStart(ServerSend));
_serverSendThread.Start();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
}
}
///
/// Sets the XTEA key used for encrypting/decrypting both server and client packets.
///
/// List of unsigned integers to be used as the XTEA key.
/// Returns false if the length of the list is anything other than 4.
internal bool SetXteaKey(List key)
{
if (key.Count != 4)
{
return false;
}
_xteaKey = key.ToArray();
return true;
}
///
/// Closes any open connections between the Tibia client and game server, and stops listening for any
/// new incoming HTTP or TCP connection requests.
///
internal void Stop()
{
if (!_isStarted)
{
return;
}
try
{
_zStream.deflateEnd();
_zStream.inflateEnd();
_httpListener.Close();
if (_tcpListener != null)
{
_tcpListener.Stop();
}
if (_clientSocket != null)
{
_clientSocket.Close();
}
if (_serverSocket != null)
{
_serverSocket.Close();
}
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
_isStarted = false;
_xteaKey = null;
ConnectionState = ConnectionState.Disconnected;
}
///
/// Closes any open connections between the Tibia client and game server, and clears
/// any pending packets to be sent.
///
private void ResetConnection()
{
if (_isResettingConnection)
{
return;
}
_isResettingConnection = true;
lock (_clientSendLock)
{
_isSendingToClient = false;
_clientSendQueue.Clear();
}
if (_clientSocket != null)
{
_clientSocket.Close();
}
lock (_serverSendLock)
{
_isSendingToServer = false;
_serverSendQueue.Clear();
}
if (_serverSocket != null)
{
_serverSocket.Close();
}
_zStream.deflateEnd();
_zStream.inflateEnd();
_zStream = new ZStream();
_zStream.deflateInit(zlibConst.Z_DEFAULT_COMPRESSION, -15);
_zStream.inflateInit(-15);
_clientSequenceNumber = 1;
_serverSequenceNumber = 1;
_xteaKey = null;
_isResettingConnection = false;
ConnectionState = ConnectionState.ConnectingStage1;
}
///
/// Grabs the next packet in the queue and sends it ansychronously to the Tibia client.
///
private void ClientSend()
{
if (_clientSocket == null)
{
return;
}
try
{
byte[] data = null;
lock (_clientSendLock)
{
if (_clientSendQueue.Count > 0)
{
data = _clientSendQueue.Dequeue();
}
if (data == null)
{
_isSendingToClient = false;
return;
}
}
_clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(BeginSendClientCallback), _clientSocket);
}
catch (SocketException)
{
// This exception can happen if the client, forcefully, closes the connection (e.g., killing the client process).
ResetConnection();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
///
/// Grabs the next packet in the queue and sends it ansychronously to the game server.
///
private void ServerSend()
{
if (_serverSocket == null)
{
return;
}
try
{
byte[] data = null;
lock (_serverSendLock)
{
if (_serverSendQueue.Count > 0)
{
data = _serverSendQueue.Dequeue();
}
if (data == null)
{
_isSendingToServer = false;
return;
}
}
_serverSocket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(BeginSendServerCallback), _serverSocket);
}
catch (SocketException)
{
// This exception can happen if the server, forcefully, closes the connection.
ResetConnection();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
///
/// Handles a pending ansynchronous packet send to the Tibia client, and calls to send the next one.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginSendClientCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
if (socket == null)
{
throw new Exception("[Connection.BeginSendClientCallback] Client socket is null.");
}
try
{
socket.EndSend(ar);
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
ClientSend();
}
///
/// Handles a pending ansynchronous packet send to the game server, and calls to send the next one.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginSendServerCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
if (socket == null)
{
throw new Exception("[Connection.BeginSendServerCallback] Server socket is null.");
}
try
{
socket.EndSend(ar);
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
ServerSend();
}
///
/// Handles an incoming HTTP request, forwards it to CipSoft's web service, waits for a response,
/// modifies the response if it's the character list, then forwards it to the Tibia client.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginGetContextCallback(IAsyncResult ar)
{
try
{
var httpListener = (HttpListener)ar.AsyncState;
if (httpListener == null)
{
throw new Exception("[Connection.BeginGetContextCallback] HTTP listener is null.");
}
var context = httpListener.EndGetContext(ar);
var request = context.Request;
var clientRequest = string.Empty;
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
clientRequest = reader.ReadToEnd();
}
if (string.IsNullOrEmpty(clientRequest))
{
throw new Exception($"[Connection.BeginGetContextCallback] Invalid HTTP request data: {clientRequest ?? "null"}");
}
_client.Logger.Debug($"Client POST: {clientRequest}");
var data = PostAsync(clientRequest).Result;
var response = string.Empty;
using (var compressedStream = new MemoryStream(data))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
response = Encoding.UTF8.GetString(resultStream.ToArray());
}
if (string.IsNullOrEmpty(response))
{
// This can happen with Open-Tibia servers where their login service doesn't handle all
// types of requests from the client. Best to keep listening for a proper response.
_httpListener.BeginGetContext(new AsyncCallback(BeginGetContextCallback), _httpListener);
return;
}
_client.Logger.Debug($"Server response: {response}");
try
{
// Login data is the only thing we have to modify, everything else can be piped through.
dynamic loginData = JsonConvert.DeserializeObject(response);
if (loginData != null && loginData.session != null)
{
// Change the address and port of each game world to that of the TCP listener so that
// the Tibia client connects to the TCP listener instead of a game world.
var address = ((IPEndPoint)_tcpListener.LocalEndpoint).Address.ToString();
var port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
foreach (var world in loginData.playdata.worlds)
{
world.externaladdressprotected = address;
world.externaladdressunprotected = address;
world.externalportprotected = port;
world.externalportunprotected = port;
}
// Store the original login data so when the Tibia client tries to connect to a game world
// the server socket can recall the address and port to connect to.
_loginData = JsonConvert.DeserializeObject(response);
response = JsonConvert.SerializeObject(loginData);
}
}
catch (JsonReaderException)
{
// This exception can occur if the login server responds with something other than JSON.
// This is usually HTML when Tibia is down for maintenance. Ignore the exception and continue on.
}
catch
{
throw;
}
data = Encoding.UTF8.GetBytes(response);
context.Response.ContentLength64 = data.Length;
context.Response.OutputStream.Write(data, 0, data.Length);
context.Response.Close();
_httpListener.BeginGetContext(new AsyncCallback(BeginGetContextCallback), _httpListener);
}
catch (ObjectDisposedException)
{
// This exception can occur if Stop() is called.
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
///
/// Handles an incoming TCP connection and begins receiving incoming data.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginAcceptTcpClientCallback(IAsyncResult ar)
{
try
{
var tcpListener = (TcpListener)ar.AsyncState;
if (tcpListener == null)
{
throw new Exception("[Connection.BeginAcceptTcpClientCallback] TCP client is null.");
}
_clientSocket = tcpListener.EndAcceptSocket(ar);
_clientSocket.LingerState = new LingerOption(true, 2);
_clientSocket.BeginReceive(_clientInMessage.GetBuffer(), 0, 1, SocketFlags.None, new AsyncCallback(BeginReceiveWorldNameCallback), null);
_tcpListener.BeginAcceptSocket(new AsyncCallback(BeginAcceptTcpClientCallback), _tcpListener);
}
catch (ObjectDisposedException)
{
// This exception can occur if Stop() is called.
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
}
}
///
/// Handles the first packet the Tibia client sends to the game server; which is just the world name.
/// This is the only packet that doesn't conform to the normal packet structure that Tibia uses.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginReceiveWorldNameCallback(IAsyncResult ar)
{
try
{
if (_clientSocket == null)
{
return;
}
var count = _clientSocket.EndReceive(ar);
if (count <= 0)
{
ResetConnection();
return;
}
// The first message the client sends to the game server is the world name without a length.
// Read from the socket one byte at a time until the end of the string (\n) is read.
while (_clientInMessage.GetBuffer()[count - 1] != Convert.ToByte('\n'))
{
var read = _clientSocket.Receive(_clientInMessage.GetBuffer(), count, 1, SocketFlags.None);
if (read <= 0)
{
throw new Exception("[Connection.BeginReceiveWorldNameCallback] Client connection broken.");
}
count += read;
}
var worldName = Encoding.UTF8.GetString(_clientInMessage.GetBuffer(), 0, count - 1);
foreach (var world in _loginData.playdata.worlds)
{
var name = (string)world.name;
if (name.Equals(worldName, StringComparison.CurrentCultureIgnoreCase))
{
_clientSocket.BeginReceive(_clientInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveClientCallback), 0);
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Connect((string)world.externaladdressprotected, (int)world.externalportprotected);
_serverSocket.Send(_clientInMessage.GetBuffer(), 0, count, SocketFlags.None);
_serverSocket.BeginReceive(_serverInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveServerCallback), 0);
return;
}
}
throw new Exception($"[Connection.BeginReceiveWorldNameCallback] Login data not found for world: {worldName}.");
}
catch (SocketException)
{
// This exception can happen if the client, forcefully, closes the connection (e.g., killing the client process).
ResetConnection();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
_client.Logger.Error($"Data: {BitConverter.ToString(_clientInMessage.GetData()).Replace('-', ' ')}");
}
}
///
/// Handles all incoming data from the Tibia client (except the first packet).
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginReceiveClientCallback(IAsyncResult ar)
{
try
{
if (_clientSocket == null)
{
return;
}
var count = _clientSocket.EndReceive(ar);
if (count <= 0)
{
ResetConnection();
return;
}
_clientInMessage.Size = (uint)BitConverter.ToUInt16(_clientInMessage.GetBuffer(), 0) + 2;
while (count < _clientInMessage.Size)
{
var read = _clientSocket.Receive(_clientInMessage.GetBuffer(), count, (int)(_clientInMessage.Size - count), SocketFlags.None);
if (read <= 0)
{
throw new Exception("[Connection.BeginReceiveClientCallback] Client connection broken.");
}
count += read;
}
var protocol = (int)ar.AsyncState;
if (protocol == 0)
{
var rsaStartIndex = _client.VersionNumber >= 124010030 ? 31 : 18;
_rsa.OpenTibiaDecrypt(_clientInMessage, rsaStartIndex);
_clientInMessage.Seek(rsaStartIndex, SeekOrigin.Begin);
if (_clientInMessage.ReadByte() != 0)
{
throw new Exception("[Connection.BeginReceiveClientCallback] RSA decryption failed.");
}
OnReceivedClientMessage?.Invoke(_clientInMessage.GetData());
if (IsClientPacketParsingEnabled)
{
_clientOutMessage.Reset();
ParseClientMessage(_client, _clientInMessage, _clientOutMessage);
}
else
{
_xteaKey = new uint[4];
for (var i = 0; i < 4; ++i)
{
_xteaKey[i] = _clientInMessage.ReadUInt32();
}
}
if (string.IsNullOrEmpty(_loginWebService))
{
_rsa.TibiaEncrypt(_clientInMessage, rsaStartIndex);
}
else
{
// If the user supplied a login web service address,
// it's safe to assume it's an Open-Tibia server.
_rsa.OpenTibiaEncrypt(_clientInMessage, rsaStartIndex);
}
SendToServer(_clientInMessage.GetData());
}
else
{
if (IsClientPacketDecryptionEnabled)
{
_clientInMessage.PrepareToParse(_xteaKey);
OnReceivedClientMessage?.Invoke(_clientInMessage.GetData());
}
if (IsClientPacketParsingEnabled)
{
_clientOutMessage.Reset();
_clientOutMessage.SequenceNumber = _clientInMessage.SequenceNumber;
ParseClientMessage(_client, _clientInMessage, _clientOutMessage);
if (IsClientPacketModificationEnabled && _client.Logger.Level == Logger.LogLevel.Debug)
{
_client.Logger.Debug($"In Size: {_clientInMessage.Size}, Out Size: {_clientOutMessage.Size}");
_client.Logger.Debug($"In Data: {BitConverter.ToString(_clientInMessage.GetData()).Replace('-', ' ')}");
_client.Logger.Debug($"Out Data: {BitConverter.ToString(_clientOutMessage.GetData()).Replace('-', ' ')}");
}
SendToServer(IsClientPacketModificationEnabled ? _clientOutMessage : _clientInMessage);
}
else
{
if (IsClientPacketDecryptionEnabled)
{
_clientInMessage.PrepareToSend(_xteaKey);
}
SendToServer(_clientInMessage.GetData());
}
}
_clientSocket.BeginReceive(_clientInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveClientCallback), 1);
}
catch (ObjectDisposedException)
{
// This exception can occur when the player logs out of their character (e.g., Ctrl+L).
ResetConnection();
}
catch (SocketException)
{
// This exception can happen if the client, forcefully, closes the connection (e.g., killing the client process).
ResetConnection();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
_client.Logger.Error($"Data: {BitConverter.ToString(_clientInMessage.GetData()).Replace('-', ' ')}");
}
}
///
/// Handles all incoming data from the game server.
///
///
/// An object that indicates the status of the asynchronous operation.
///
private void BeginReceiveServerCallback(IAsyncResult ar)
{
try
{
if (_serverSocket == null)
{
return;
}
var count = _serverSocket.EndReceive(ar);
if (count <= 0)
{
ResetConnection();
return;
}
_serverInMessage.Size = (uint)BitConverter.ToUInt16(_serverInMessage.GetBuffer(), 0) + 2;
while (count < _serverInMessage.Size)
{
var read = _serverSocket.Receive(_serverInMessage.GetBuffer(), count, (int)(_serverInMessage.Size - count), SocketFlags.None);
if (read <= 0)
{
throw new Exception("[Connection.BeginReceiveServerCallback] Server connection broken.");
}
count += read;
}
if (IsServerPacketDecryptionEnabled)
{
_serverInMessage.PrepareToParse(_xteaKey, _zStream);
OnReceivedServerMessage?.Invoke(_serverInMessage.GetData());
}
if (IsServerPacketParsingEnabled)
{
_serverOutMessage.Reset();
_serverOutMessage.SequenceNumber = _serverInMessage.SequenceNumber;
ParseServerMessage(_client, _serverInMessage, _serverOutMessage);
if (IsServerPacketModificationEnabled && _client.Logger.Level == Logger.LogLevel.Debug)
{
_client.Logger.Debug($"In Size: {_serverInMessage.Size}, Out Size: {_serverOutMessage.Size}");
_client.Logger.Debug($"In Data: {BitConverter.ToString(_serverInMessage.GetData()).Replace('-', ' ')}");
_client.Logger.Debug($"Out Data: {BitConverter.ToString(_serverOutMessage.GetData()).Replace('-', ' ')}");
}
SendToClient(IsServerPacketModificationEnabled ? _serverOutMessage : _serverInMessage);
}
else
{
if (IsServerPacketDecryptionEnabled)
{
_serverInMessage.PrepareToSend(_xteaKey, IsServerPacketCompressionEnabled ? _zStream : null);
}
SendToClient(_serverInMessage.GetData());
}
_serverSocket.BeginReceive(_serverInMessage.GetBuffer(), 0, 2, SocketFlags.None, new AsyncCallback(BeginReceiveServerCallback), 1);
}
catch (ObjectDisposedException)
{
// This exception can occur if Stop() is called.
}
catch (SocketException)
{
// This exception can happen if the server, forcefully, closes the connection.
ResetConnection();
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
_client.Logger.Error($"Data: {BitConverter.ToString(_serverInMessage.GetData()).Replace('-', ' ')}");
}
}
///
/// Asynchronously sends an HTTP POST to CipSoft's web service.
///
///
/// The JSON data to POST.
///
///
/// The response from CipSoft's web service.
///
private async Task PostAsync(string content)
{
try
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0");
httpClient.DefaultRequestHeaders.Add("Connection", "Keep-Alive");
httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,*");
httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
var postContent = new StringContent(content, Encoding.UTF8, "application/json");
postContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
using (var response = await httpClient.PostAsync(new Uri(GetLoginWebService()), postContent).ConfigureAwait(false))
{
postContent.Dispose();
return await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
_client.Logger.Error(ex.ToString());
return Array.Empty();
}
}
private string GetLoginWebService()
{
return !string.IsNullOrEmpty(_loginWebService) ? _loginWebService : LOGIN_WEB_SERVICE;
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_httpListener.Close();
if (_clientSocket != null)
{
_clientSocket.Dispose();
}
if (_serverSocket != null)
{
_serverSocket.Dispose();
}
}
disposedValue = true;
}
}
~Connection()
{
Dispose(false);
}
///
/// Releases all the managed resources used by the .
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}