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 } }