using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net.Sockets; using System.IO; using ComponentAce.Compression.Libs.zlib; using ProxyCore; namespace ProxyMud.Network { internal class NetworkBase { protected NetworkBase(Socket socket, NetworkServer server, int inBufferSize) { Server = server; Socket = socket; inStream = new MemoryStream(inBufferSize); Socket.Blocking = false; } #region Variables protected readonly NetworkServer Server; protected Socket Socket; protected MemoryStream inStream; protected TelnetPacket telnetPacket; protected ZStream zStream; protected static int zStream_Length; protected static byte[] zStream_Out = new byte[65536]; protected static int inIndex; protected static int inMaxIndex; protected static byte[] inData = new byte[65536]; #endregion #region Networking internal bool Receive() { if(Socket == null) return false; SocketError err; inMaxIndex = Socket.Receive(inData, 0, inData.Length, SocketFlags.None, out err); if(err != SocketError.WouldBlock && inMaxIndex == 0) { Socket.Close(); Socket = null; return false; } if(inMaxIndex == 0) return true; inIndex = 0; HandlePacket(); return true; } internal void Send(byte[] Data) { if(Socket == null) return; if(zStream != null && this is NetworkClient) { Compress(Data, zlibConst.Z_FULL_FLUSH); if(zStream_Length > 0) Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); } else Socket.Send(Data, SocketFlags.None); } internal void Send(TelnetPacket pkt) { if(Socket == null) return; if(pkt.Header == TelnetOpcodes.SB && pkt.Data.Length != 0) Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)pkt.Type }.Concat( pkt.Data.ToArray()).Concat(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }).ToArray()); else Send(new[] { (byte)TelnetOpcodes.IAC, (byte)pkt.Header, (byte)pkt.Type }); } internal void Disconnect() { if(Socket == null) return; Socket.Close(); Socket = null; } #endregion #region Compression protected bool StartCompression(TelnetOpcodes type) { if(this is NetworkAardwolf) throw new Exception("Trying to start compression on Aardwolf connection!"); if(zStream != null) return false; if(type == TelnetOpcodes.MCCP_V1) Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V1, (byte)TelnetOpcodes.WILL, (byte)TelnetOpcodes.SE }); else Send(new[] { (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SB, (byte)TelnetOpcodes.MCCP_V2, (byte)TelnetOpcodes.IAC, (byte)TelnetOpcodes.SE }); zStream = new ZStream(); zStream.deflateInit(6); return true; } protected void EndCompression() { if(this is NetworkAardwolf) throw new Exception("Trying to end compression on Aardwolf connection!"); if(zStream == null) return; byte[] d = new byte[0]; Compress(d, zlibConst.Z_FINISH); if(zStream_Length > 0) Socket.Send(zStream_Out, zStream_Length, SocketFlags.None); zStream.deflateEnd(); zStream.free(); zStream = null; } private void StartDecompression() { if(this is NetworkClient) throw new Exception("Trying to start decompression on Client connection!"); if(zStream != null) return; zStream = new ZStream(); zStream.inflateInit(); } internal void Compress(byte[] Data, int type) { if(this is NetworkAardwolf) throw new Exception("Trying to compress data on Aardwolf connection!"); zStream_Length = 0; zStream.avail_in = Data.Length; zStream.next_in = Data; zStream.next_in_index = 0; zStream.next_out = zStream_Out; zStream.next_out_index = 0; zStream.avail_out = zStream_Out.Length; switch(zStream.deflate(type)) { case zlibConst.Z_OK: //inIndex = zStream.next_in_index; zStream_Length = (int)zStream.total_out; zStream.total_out = 0; zStream.next_in = null; break; case zlibConst.Z_STREAM_END: //inIndex = zStream.next_in_index; zStream_Length = (int)zStream.total_out; zStream.deflateEnd(); zStream.free(); zStream = null; break; default: //case zlibConst.Z_STREAM_ERROR: throw new Exception("Error while compressing: " + (zStream.msg ?? "unknown error") + "!"); } } internal void Decompress(int type) { if(this is NetworkClient) throw new Exception("Trying to decompress data on Client connection!"); zStream_Length = 0; zStream.avail_in = inMaxIndex - inIndex; zStream.next_in = inData; zStream.next_in_index = inIndex; zStream.next_out = zStream_Out; zStream.next_out_index = 0; zStream.avail_out = zStream_Out.Length; switch(zStream.inflate(type)) { case zlibConst.Z_OK: inIndex = zStream.next_in_index; zStream_Length = (int)zStream.total_out; zStream.total_out = 0; break; case zlibConst.Z_STREAM_END: inIndex = zStream.next_in_index; zStream_Length = (int)zStream.total_out; zStream.inflateEnd(); zStream.free(); zStream = null; break; default: //case zlibConst.Z_STREAM_ERROR: throw new Exception("Error while decompressing: " + (zStream.msg ?? "unknown error") + "!"); } } #endregion #region Packet protected virtual void HandlePacket() { } protected virtual void HandlePacket(TelnetPacket pkt) { } protected int HandlePacket(byte[] Buf, int Index, int MaxIndex) { if(Index >= MaxIndex) return MaxIndex; if(telnetPacket != null) { switch(telnetPacket.State) { case TelnetStates.None: telnetPacket.Header = (TelnetOpcodes)Buf[Index]; telnetPacket.State = TelnetStates.Header; return HandlePacket(Buf, Index + 1, MaxIndex); case TelnetStates.Header: telnetPacket.Type = (TelnetOpcodes)Buf[Index]; telnetPacket.State = telnetPacket.Header == TelnetOpcodes.SB ? TelnetStates.Data : TelnetStates.End; if(telnetPacket.State == TelnetStates.End) { HandlePacket(telnetPacket); telnetPacket = null; } else telnetPacket.Data = new MemoryStream(512); return HandlePacket(Buf, Index + 1, MaxIndex); case TelnetStates.Data: { for(int i = Index; i < MaxIndex; i++) { if(telnetPacket.HadIAC && Buf[i] == (byte)TelnetOpcodes.SE) { telnetPacket.State = TelnetStates.End; HandlePacket(telnetPacket); if(zStream == null && (telnetPacket.Type == TelnetOpcodes.MCCP_V1 || telnetPacket.Type == TelnetOpcodes.MCCP_V2)) { telnetPacket = null; StartDecompression(); return i + 1; } telnetPacket = null; return HandlePacket(Buf, i + 1, MaxIndex); } if(Buf[i] == (byte)TelnetOpcodes.IAC || (Buf[i] == (byte)TelnetOpcodes.WILL && telnetPacket.Type == TelnetOpcodes.MCCP_V1)) { if(!telnetPacket.HadIAC) { if(i - Index > 0) { telnetPacket.Data.Write(Buf, Index, i - Index); Index = i; } telnetPacket.HadIAC = true; } else telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); } else { if(telnetPacket.HadIAC) { telnetPacket.HadIAC = false; telnetPacket.Data.Write(new[] { (byte)TelnetOpcodes.IAC }, 0, 1); } } } if(Index < MaxIndex) { if(Buf[MaxIndex - 1] != (byte)TelnetOpcodes.IAC) telnetPacket.Data.Write(Buf, Index, MaxIndex - Index); } return MaxIndex; } } } for(int i = Index; i < MaxIndex; i++) { if(Buf[i] == (byte)TelnetOpcodes.IAC) { if(i - Index > 0) WriteInStream(Buf, Index, i); telnetPacket = new TelnetPacket(); return HandlePacket(Buf, i + 1, MaxIndex); } } if(MaxIndex - Index > 0) WriteInStream(Buf, Index, MaxIndex); return MaxIndex; } protected virtual void WriteInStream(byte[] Buf, int Index, int MaxIndex) { } protected virtual void OnReceived(string Msg, bool bigPacket) { } #endregion protected long LastMSTime; internal virtual void Update(long msTime) { LastMSTime = msTime; } } }