예제 #1
0
        public unsafe IList <ArraySegment <byte> > CreateBuffer(IList <ArraySegment <byte> > appendTo)
        {
            // key size
            byte[] keyData   = BinaryConverter.EncodeKey(this.Key);
            int    keyLength = keyData == null ? 0 : keyData.Length;

            if (keyLength > 0xffff)
            {
                throw new InvalidOperationException("KeyTooLong");
            }

            // extra size
            ArraySegment <byte> extras = this.Extra;
            int extraLength            = extras.Array == null ? 0 : extras.Count;

            if (extraLength > 0xff)
            {
                throw new InvalidOperationException("ExtraTooLong");
            }

            // body size
            ArraySegment <byte> body = this.Data;
            int bodyLength           = body.Array == null ? 0 : body.Count;

            // total payload size
            int totalLength = extraLength + keyLength + bodyLength;

            //build the header
            byte[] header = new byte[24];

            fixed(byte *buffer = header)
            {
                buffer[0x00] = 0x80;                 // magic
                buffer[0x01] = this.Operation;

                // key length
                buffer[0x02] = (byte)(keyLength >> 8);
                buffer[0x03] = (byte)(keyLength & 255);

                // extra length
                buffer[0x04] = (byte)(extraLength);

                // 5 -- data type, 0 (RAW)
                // 6,7 -- reserved, always 0

                buffer[0x06] = (byte)(this.Reserved >> 8);
                buffer[0x07] = (byte)(this.Reserved & 255);

                // body length
                buffer[0x08] = (byte)(totalLength >> 24);
                buffer[0x09] = (byte)(totalLength >> 16);
                buffer[0x0a] = (byte)(totalLength >> 8);
                buffer[0x0b] = (byte)(totalLength & 255);

                buffer[0x0c] = (byte)(this.CorrelationId >> 24);
                buffer[0x0d] = (byte)(this.CorrelationId >> 16);
                buffer[0x0e] = (byte)(this.CorrelationId >> 8);
                buffer[0x0f] = (byte)(this.CorrelationId & 255);

                ulong cas = this.Cas;

                // CAS
                if (cas > 0)
                {
                    // skip this if no cas is specfied
                    buffer[0x10] = (byte)(cas >> 56);
                    buffer[0x11] = (byte)(cas >> 48);
                    buffer[0x12] = (byte)(cas >> 40);
                    buffer[0x13] = (byte)(cas >> 32);
                    buffer[0x14] = (byte)(cas >> 24);
                    buffer[0x15] = (byte)(cas >> 16);
                    buffer[0x16] = (byte)(cas >> 8);
                    buffer[0x17] = (byte)(cas & 255);
                }
            }

            var retval = appendTo ?? new List <ArraySegment <byte> >(4);

            retval.Add(new ArraySegment <byte>(header));

            if (extraLength > 0)
            {
                retval.Add(extras);
            }

            // NOTE key must be already encoded and should not contain any invalid characters which are not allowed by the protocol
            if (keyLength > 0)
            {
                retval.Add(new ArraySegment <byte>(keyData));
            }
            if (bodyLength > 0)
            {
                retval.Add(body);
            }

#if DEBUG_PROTOCOL
            if (log.IsDebugEnabled)
            {
                log.Debug("Building binary request");
                StringBuilder sb = new StringBuilder(128).AppendLine();

                for (int i = 0; i < header.Length; i++)
                {
                    byte value = header[i];
                    sb.Append(value < 16 ? "0x0" : "0x").Append(value.ToString("X"));

                    if (i % 4 == 3)
                    {
                        sb.AppendLine();
                    }
                    else
                    {
                        sb.Append(" ");
                    }
                }

                log.Debug(sb.ToString());
            }
#endif

            return(retval);
        }