using System;
using System.Net.Sockets;
using Hang.Messages;
using Hang.Util;
using Hang.Core;
namespace Hang.Net
{
///
/// Represents a TCP network connection accepted by an IonTcpConnectionListener. Provides methods for sending and receiving data, aswell as disconnecting the connection.
///
internal class TcpConnection : Socket, IDisposable
{
#region Fields
private bool mDisposed = false;
///
/// The ID of this connection as a 32 bit unsigned integer.
///
private readonly uint mID;
///
/// The byte array holding the buffer for receiving data from client.
///
private byte[] mDataBuffer;
///
/// The AsyncCallback instance for the thread for receiving data asynchronously.
///
private AsyncCallback mDataReceivedCallback;
private AsyncCallback mDataSentCallback;
///
/// The RouteReceivedDataCallback to route received data to another object.
///
private RouteReceivedDataCallback mRouteReceivedDataCallback;
#endregion
#region Members
internal delegate void RouteReceivedDataCallback(ref byte[] Data);
#endregion
#region Properties
///
/// Gets the ID of this connection as a 32 bit unsigned integer.
///
//internal uint ID
//{
// get { return mID; }
//}
private string mIP;
///
/// Gets the IP address of this connection as a string.
///
internal string ipAddress
{
get
{
return mIP;
}
}
#endregion
#region Constructors
///
/// Constructs a new instance of IonTcpConnection for a given connection identifier and socket.
///
/// The unique ID used to identify this connection in the environment.
/// The System.Net.Sockets.Socket of the new connection.
//internal TcpConnection(uint ID, Socket pSocket)
internal TcpConnection(uint pSockID, SocketInformation pSockInfo)
: base(pSockInfo)
{
mID = pSockID;
mIP = RemoteEndPoint.ToString().Split(':')[0];
}
#endregion
#region Methods
///
/// Starts the connection, prepares the received data buffer and waits for data.
///
internal void Start(RouteReceivedDataCallback dataRouter)
{
mDataBuffer = new byte[1024];
mDataReceivedCallback = new AsyncCallback(DataReceived);
mDataSentCallback = new AsyncCallback(DataSent);
mRouteReceivedDataCallback = dataRouter;
WaitForData();
}
internal void ConnectionDead()
{
try
{
Disposes();
HangEnvironment.GetGame().GetClientManager().StopClient(mID);
}
catch { }
}
public void SendData(byte[] Data)
{
if (mDisposed)
return;
try
{
//base.Send(Data);
//Logging.LogPacketException("Data sent to client: [" + System.Text.Encoding.Default.GetString(Data, 0, Data.Length) + "]", "");
int DataLength = Data.Length;
mDataSent += DataLength;
if (base.Connected)
base.BeginSend(Data, 0, Data.Length, SocketFlags.Partial, mDataSentCallback, this);
}
catch
{
HangEnvironment.GetGame().GetClientManager().AddGameClient(this);
ConnectionDead();
}
}
private static int mDataSent = 0;
private static int mDataReceived = 0;
internal static int GetNumberOfSentBytes()
{
int Tmp = mDataSent;
mDataSent = 0;
return Tmp;
}
internal static int GetNumberOfReceivedBytes()
{
int Tmp = mDataReceived;
mDataReceived = 0;
return Tmp;
}
private void DataSent(IAsyncResult Iar)
{
if (mDisposed)
return;
try
{
base.EndSend(Iar);
}
catch { ConnectionDead(); }
}
internal void SendData(string sData)
{
//Logging.WriteLine("[PACKET SENDED]" + sData);
SendData(HangEnvironment.GetDefaultEncoding().GetBytes(sData));
}
internal void SendMessage(ServerMessage Message)
{
if (Message == null)
return;
//Logging.WriteLine("[PACKET SENDED]" + Message.ToString());
SendData(Message.GetBytes());
}
///
/// Starts the asynchronous wait for new data.
///
private void WaitForData()
{
if (mDisposed)
return;
try
{
BeginReceive(mDataBuffer, 0, 1024, SocketFlags.None, mDataReceivedCallback, this);
}
catch (Exception)
{
//Logging.WriteLine("IonTcpConnection.WaitForData - " + ex.ToString(), LogLevel.Error);
//Logging.LogCriticalException(ex.ToString());
ConnectionDead();
}
}
private void DataReceived(IAsyncResult iAr)
{
if (mDisposed)
return;
try
{
// How many bytes has server received?
int numReceivedBytes = 0;
try
{
numReceivedBytes = base.EndReceive(iAr);
mDataReceived += numReceivedBytes;
}
catch
{
ConnectionDead();
return;
}
if (numReceivedBytes > 0)
{
// Copy received data buffer
//Logging.LogPacketException("Data received from client: [" + System.Text.Encoding.Default.GetString(mDataBuffer, 0, numReceivedBytes) + "]", "");
byte[] dataToProcess = ByteUtil.ChompBytes(mDataBuffer, 0, numReceivedBytes);
// Route data to GameClient to parse and process messages
RouteData(ref dataToProcess);
//Environment.GetHabboHotel().GetClients().GetClient(this.ID).HandleConnectionData(ref dataToProcess);
}
else
{
ConnectionDead();
return;
}
// Wait for new data
WaitForData();
}
catch
{
ConnectionDead();
return;
}
}
///
/// Routes a byte array passed as reference to another object.
///
/// The byte array to route.
private void RouteData(ref byte[] Data)
{
if (mRouteReceivedDataCallback != null)
mRouteReceivedDataCallback.Invoke(ref Data);
}
#endregion
#region IDisposable members
public void Disposes()
{
Disposes(true);
GC.SuppressFinalize(this);
}
///
/// Stops the connection, disconnects the socket and disposes used resources.
///
private void Disposes(bool Disposing)
{
if (!this.mDisposed)
{
if (Disposing)
{
mDisposed = true;
try
{
base.Shutdown(SocketShutdown.Both);
base.Close();
base.Dispose();
}
catch { }
Array.Clear(mDataBuffer, 0, mDataBuffer.Length);
mDataBuffer = null;
mDataReceivedCallback = null;
mRouteReceivedDataCallback = null;
HangEnvironment.GetConnectionManager().DropConnection(this.mID);
TcpAuthorization.FreeConnection(mIP);
//¿Whatf? más basura lol!
//Console.WriteLine("[" + this.mID + "] -> Disposed");
}
}
}
#endregion
}
}