public SystemPacket(Header header, IMessage message, ushort ConnectionId, OperationalSocket OpSocket)
 {
     this.Header = header;
     this.Message = message;
     this.ConnectionId = ConnectionId;
     this.OpSocket = OpSocket;
 }
        /// <summary>
        /// Send data to the established connection
        /// </summary>
        /// <param name="Message">The data to send</param>
        /// <param name="Header">The Header to use for adding additional information</param>
        /// <param name="feature">The Feature that has been used for this Message</param>
        /// <param name="OpSocket">The OperationalSocket that has been used for this Message</param>
        internal int SendMessage(IMessage Message, Header Header, Feature feature = null, OperationalSocket OpSocket = null)
        {
            lock (SendLock)
            {
                if (!Connected)
                    return -1;

                if (Message == null)
                    throw new ArgumentException("Message cannot be null");
                if (Header == null)
                    throw new ArgumentException("Header cannot be null");

                ushort HeaderId = OpSocket != null ? OpSocket.Headers.GetHeaderId(Header) : Headers.GetHeaderId(Header);
                byte[] SerializedHeader = Header.Serialize(Header);

                uint messageId = OpSocket != null ? OpSocket.MessageHandler.GetMessageId(Message.GetType()) : messageHandler.GetMessageId(Message.GetType());

                if (SerializedHeader.Length >= MAX_PACKET_SIZE)
                    throw new ArgumentException("Header length cannot be greater then " + MAX_PAYLOAD);

                using (MemoryStream outStream = new MemoryStream())
                using (PayloadWriter pw = new PayloadWriter(outStream))
                {
                    pw.WriteBytes(new byte[HEADER_SIZE], 0, HEADER_SIZE); //reserve space

                    pw.WriteBytes(SerializedHeader);
                    pw.WriteUInteger(messageId);

                    int packetSize = messageHandler.EncryptMessage(this, Message, outStream);

                    if (pw.Length > MAX_PACKET_SIZE)
                        throw new OverflowException("Message size cannot be greater then " + MAX_PACKET_SIZE);

                    int PayloadLength = pw.Length - Connection.HEADER_SIZE;
                    byte CurPacketId = 0;
                    int FeatureId = feature != null ? feature.GetFeatureId() : -1;
                    ushort ConnectionId = OpSocket != null ? OpSocket.ConnectionId : (ushort)0;

                    byte checksum = 0;
                    checksum += (byte)PayloadLength;
                    checksum += CurPacketId;
                    checksum += (byte)ConnectionId;
                    checksum += (byte)HeaderId;
                    checksum += (byte)FeatureId;

                    pw.Position = 0;
                    pw.WriteThreeByteInteger(PayloadLength); //length
                    pw.WriteByte(CurPacketId); //cur packet id
                    pw.WriteUShort(ConnectionId); //Connection Id
                    pw.WriteUShort(HeaderId); //Header Id
                    pw.WriteByte(checksum);
                    pw.WriteInteger(FeatureId);

                    //encrypt the header
                    lock (HeaderEncryption)
                    {
                        HeaderEncryption.Encrypt(pw.GetBuffer(), 0, HEADER_SIZE);

                        byte[] temp = pw.GetBuffer();
                        headerConfuser.Obfuscate(ref temp, 0);
                    }

                    int SendNum = 0;

                    try
                    {
                        for (int i = 0; i < outStream.Length;)
                        {
                            int len = i + 65535 < outStream.Length ? 65535 : (int)outStream.Length - i;
                            Handle.Send(outStream.GetBuffer(), i, len, SocketFlags.None);
                            i += len;
                            SendNum += len;
                        }
                    }
                    catch (Exception ex)
                    {
                        Disconnect();
                        return -1;
                    }

                    SysLogger.Log("Send " + outStream.Length, SysLogType.Network);

                    PacketsOut++;
                    DataOut += (ulong)outStream.Length;
                    this.LastPacketSendSW = Stopwatch.StartNew();
                    return SendNum;
                }

                /*using (OptimizedPayloadStream ms = new OptimizedPayloadStream(SerializedHeader, HeaderId, feature, OpSocket))
                {
                    ms.Write(BitConverter.GetBytes(messageId), 0, 4);

                    MemoryStream stream = ms.PayloadFrames[ms.PayloadFrames.Count - 1];

                    int ReservedPos = (int)stream.Position;
                    ms.Write(new byte[3], 0, 3); //reserve space

                    ms.WritingMessage = true;
                    Serializer.Serialize(ms, Message);
                    ms.WritingMessage = false;

                    using (PayloadWriter pw = new PayloadWriter(new MemoryStream(stream.GetBuffer())))
                    {
                        pw.Position = ReservedPos; //skip MessageId data
                        pw.WriteThreeByteInteger(ms.MessageLength);//Reserved Space + MessageId = 7
                    }
                    ms.Commit(this);

                    for (int i = 0; i < ms.PayloadFrames.Count; i++)
                    {
                        stream = ms.PayloadFrames[i];

                        lock (HeaderEncryption)
                        {
                            HeaderEncryption.Encrypt(stream.GetBuffer(), 0, HEADER_SIZE);

                            byte[] temp = stream.GetBuffer();
                            headerConfuser.Obfuscate(ref temp, 0);
                        }
                        //lock (PayloadEncryption)
                        //{
                        //    PayloadEncryption.Encrypt(stream.GetBuffer(), HEADER_SIZE, (int)stream.Length - HEADER_SIZE);
                        //}

                        Handle.Send(stream.GetBuffer(), 0, (int)stream.Length, SocketFlags.None);
                    }
                }*/
            }
        }
 /// <summary>
 /// Send a message to the other side
 /// </summary>
 /// <param name="Message">The message to send</param>
 /// <param name="Header">The header that is being used for this message</param>
 protected void SendMessage(IMessage Message, Header Header)
 {
     Client.Connection.SendMessage(Message, new ConnectionHeader(Header, this, 0), null, this);
 }
 internal void InternalSendMessage(IMessage Message, Header Header)
 {
     Client.Connection.SendMessage(Message, Header);
 }
 public abstract void onReceiveMessage(IMessage Message, Header header);
        /// <summary>
        /// Serialize the Message to output stream
        /// </summary>
        /// <param name="message"></param>
        /// <param name="TargetStream"></param>
        /// <returns>The size of the serialzed message</returns>
        internal int EncryptMessage(Connection conn, IMessage message, MemoryStream TargetStream)
        {
            PayloadWriter pw = new PayloadWriter(TargetStream);
            int PayloadPos = pw.Position;

            Serializer.Serialize(TargetStream, message);

            //return (int)TargetStream.Length;

            #region Security
            //compress data
            if (CompressionAlgorithm.QuickLZ == (conn.CompressionAlgorithm & CompressionAlgorithm.QuickLZ))
            {
                UnsafeQuickLZ quickLz = new UnsafeQuickLZ();
                byte[] compressed = quickLz.compress(TargetStream.GetBuffer(), (uint)Connection.HEADER_SIZE, (uint)TargetStream.Length - Connection.HEADER_SIZE);

                if (compressed != null &&
                    compressed.Length + Connection.HEADER_SIZE < TargetStream.Length) //only apply compression if it's smaller then the original data
                {
                    TargetStream.Position = Connection.HEADER_SIZE;
                    TargetStream.Write(compressed, 0, compressed.Length);

                    if (TargetStream.Length != compressed.Length + Connection.HEADER_SIZE)
                        TargetStream.SetLength(compressed.Length + Connection.HEADER_SIZE);
                }
            }

            //encrypt all the data
            if (EncAlgorithm.HwAES == (conn.EncryptionAlgorithm & EncAlgorithm.HwAES))
            {
                lock (conn.EncAES)
                {
                    //no need to re-size the stream here, AES will encrypt at the same size or bigger then the stream, so data will be overwritten
                    byte[] encrypted = conn.EncAES.Encrypt(TargetStream.GetBuffer(), Connection.HEADER_SIZE, (int)TargetStream.Length - Connection.HEADER_SIZE);
                    TargetStream.Position = Connection.HEADER_SIZE;
                    TargetStream.Write(encrypted, 0, encrypted.Length);
                }
            }
            if (EncAlgorithm.WopEx == (conn.EncryptionAlgorithm & EncAlgorithm.WopEx))
            {
                lock (conn.PayloadEncryption)
                {
                    conn.PayloadEncryption.Encrypt(TargetStream.GetBuffer(), Connection.HEADER_SIZE, (int)TargetStream.Length - Connection.HEADER_SIZE);
                }
            }
            #endregion

            return pw.Length - PayloadPos;
        }
        /*public override void onReceiveData(byte[] Data, Header header)
        {
            bench.Bench(new BenchCallback(() => { }));

            if (bench.PastASecond)
            {
                Console.WriteLine("Speed:" + bench.SpeedPerSec + ", raw size: " + Math.Round( ((((ulong)(Data.Length + 28) * bench.SpeedPerSec) / 1000F) / 1000F) / 1000F, 2)    + "GBps");
            }
        }*/
        public override void onReceiveMessage(IMessage Message, Header header)
        {
            //base.SendMessage(new TestMessage() { Buffer = new byte[] { 1, 3, 3, 7 } }, header);
        }
 public override void onReceiveMessage(IMessage Message, Header header)
 {
 }