Ejemplo n.º 1
0
        public bool GetFixedSize(ref int size)
        {
            if (size < 0)
            {
                return(false);
            }

            if (data.Length == 0)
            {
                return(true);
            }

            // Sensible?
            size = Protocol.Padded(size, Alignment);

            if (data.Length == 1)
            {
                int valueSize = GetSize(this[0]);

                if (valueSize == -1)
                {
                    return(false);
                }

                size += valueSize;
                return(true);
            }

            if (IsStructlike)
            {
                foreach (Signature sig in GetParts())
                {
                    if (!sig.GetFixedSize(ref size))
                    {
                        return(false);
                    }
                }
                return(true);
            }

            if (IsArray || IsDict)
            {
                return(false);
            }

            if (IsStruct)
            {
                foreach (Signature sig in GetFieldSignatures())
                {
                    if (!sig.GetFixedSize(ref size))
                    {
                        return(false);
                    }
                }
                return(true);
            }

            // Any other cases?
            throw new Exception();
        }
Ejemplo n.º 2
0
        /*
         * public void ReadPad (int alignment)
         * {
         *      pos = Protocol.Padded (pos, alignment);
         * }
         */

        public void ReadPad(int alignment)
        {
            for (int endPos = Protocol.Padded(pos, alignment); pos != endPos; pos++)
            {
                if (data[pos] != 0)
                {
                    throw new Exception("Read non-zero byte at position " + pos + " while expecting padding");
                }
            }
        }
Ejemplo n.º 3
0
        public object ReadVariant()
        {
            var sig      = ReadSignature();
            int startPos = Protocol.Padded(pos, sig.Alignment);
            var v        = ReadValue(sig);
            int endPos   = pos;

            if (v != null && v.GetType().BaseType == typeof(DValue))
            {
                SetDValueFields(v, sig, startPos, endPos);
            }

            return(v);
        }
Ejemplo n.º 4
0
        public IEnumerable <Signature> StepInto(Signature sig)
        {
            if (sig == Signature.VariantSig)
            {
                Signature valueSig = ReadSignature();
                yield return(valueSig);

                yield break;
            }

            // No need to handle dicts specially. IsArray does the job
            if (sig.IsArray)
            {
                Signature elemSig = sig.GetElementSignature();
                uint      ln      = ReadUInt32();
                ReadPad(elemSig.Alignment);
                int endPos = pos + (int)ln;
                while (pos < endPos)
                {
                    yield return(elemSig);
                }
                yield break;
            }

            if (sig.IsDictEntry)
            {
                pos = Protocol.Padded(pos, sig.Alignment);
                Signature sigKey, sigValue;
                sig.GetDictEntrySignatures(out sigKey, out sigValue);
                yield return(sigKey);

                yield return(sigValue);

                yield break;
            }

            if (sig.IsStruct)
            {
                pos = Protocol.Padded(pos, sig.Alignment);
                foreach (Signature fieldSig in sig.GetFieldSignatures())
                {
                    yield return(fieldSig);
                }
                yield break;
            }

            throw new Exception("Can't step into '" + sig + "'");
            //yield break;
        }
 public void WritePad(int alignment)
 {
     stream.Position = Protocol.Padded((int)stream.Position, alignment);
 }
Ejemplo n.º 6
0
        /*
         * Queue<Message> Outbound = new Queue<Message> ();
         *
         * public void Flush ()
         * {
         *      //should just iterate the enumerator here
         *      while (Outbound.Count != 0) {
         *              Message msg = Outbound.Dequeue ();
         *              WriteMessage (msg);
         *      }
         * }
         *
         * public bool ReadWrite (int timeout_milliseconds)
         * {
         *      //TODO
         *
         *      return true;
         * }
         *
         * public bool ReadWrite ()
         * {
         *      return ReadWrite (-1);
         * }
         *
         * public bool Dispatch ()
         * {
         *      //TODO
         *      Message msg = Inbound.Dequeue ();
         *      //HandleMessage (msg);
         *
         *      return true;
         * }
         *
         * public bool ReadWriteDispatch (int timeout_milliseconds)
         * {
         *      //TODO
         *      return Dispatch ();
         * }
         *
         * public bool ReadWriteDispatch ()
         * {
         *      return ReadWriteDispatch (-1);
         * }
         */

        internal Message ReadMessage()
        {
            //FIXME: fix reading algorithm to work in one step
            //this code is a bit silly and inefficient
            //hopefully it's at least correct and avoids polls for now

            int read;

            byte[] buf = new byte[16];
            read = ns.Read(buf, 0, 16);

            if (read == 0)
            {
                return(null);
            }

            if (read != 16)
            {
                throw new Exception("Header read length mismatch: " + read + " of expected " + "16");
            }

            MemoryStream ms = new MemoryStream();

            ms.Write(buf, 0, 16);

            EndianFlag    endianness = (EndianFlag)buf[0];
            MessageReader reader     = new MessageReader(endianness, buf);

            //discard the endian byte as we've already read it
            byte tmp;

            reader.GetValue(out tmp);

            //discard message type and flags, which we don't care about here
            reader.GetValue(out tmp);
            reader.GetValue(out tmp);

            byte version;

            reader.GetValue(out version);

            if (version < Protocol.MinVersion || version > Protocol.MaxVersion)
            {
                throw new NotSupportedException("Protocol version '" + version.ToString() + "' is not supported");
            }

            if (Protocol.Verbose)
            {
                if (version != Protocol.Version)
                {
                    Console.Error.WriteLine("Warning: Protocol version '" + version.ToString() + "' is not explicitly supported but may be compatible");
                }
            }

            uint bodyLength, serial, headerLength;

            reader.GetValue(out bodyLength);
            reader.GetValue(out serial);
            reader.GetValue(out headerLength);

            //TODO: remove this limitation
            if (bodyLength > Int32.MaxValue || headerLength > Int32.MaxValue)
            {
                throw new NotImplementedException("Long messages are not yet supported");
            }

            int bodyLen = (int)bodyLength;
            int toRead  = (int)headerLength;

            toRead = Protocol.Padded((int)toRead, 8);

            buf = new byte[toRead];

            read = ns.Read(buf, 0, toRead);

            if (read != toRead)
            {
                throw new Exception("Read length mismatch: " + read + " of expected " + toRead);
            }

            ms.Write(buf, 0, buf.Length);

            Message msg = new Message();

            msg.Connection = this;
            msg.HeaderData = ms.ToArray();

            //read the body
            if (bodyLen != 0)
            {
                //FIXME
                //msg.Body = new byte[(int)msg.Header->Length];
                byte[] body = new byte[bodyLen];

                //int len = ns.Read (msg.Body, 0, msg.Body.Length);
                int len = ns.Read(body, 0, bodyLen);

                //if (len != msg.Body.Length)
                if (len != bodyLen)
                {
                    throw new Exception("Message body size mismatch");
                }

                //msg.Body = new MemoryStream (body);
                msg.Body = body;
            }

            //this needn't be done here
            msg.ParseHeader();

            return(msg);
        }
Ejemplo n.º 7
0
        /*
         * Queue<Message> Outbound = new Queue<Message> ();
         *
         * public void Flush ()
         * {
         *      //should just iterate the enumerator here
         *      while (Outbound.Count != 0) {
         *              Message msg = Outbound.Dequeue ();
         *              WriteMessage (msg);
         *      }
         * }
         *
         * public bool ReadWrite (int timeout_milliseconds)
         * {
         *      //TODO
         *
         *      return true;
         * }
         *
         * public bool ReadWrite ()
         * {
         *      return ReadWrite (-1);
         * }
         *
         * public bool Dispatch ()
         * {
         *      //TODO
         *      Message msg = Inbound.Dequeue ();
         *      //HandleMessage (msg);
         *
         *      return true;
         * }
         *
         * public bool ReadWriteDispatch (int timeout_milliseconds)
         * {
         *      //TODO
         *      return Dispatch ();
         * }
         *
         * public bool ReadWriteDispatch ()
         * {
         *      return ReadWriteDispatch (-1);
         * }
         */

        internal Message ReadMessage()
        {
            byte[] header;
            byte[] body = null;

            int read;

            //16 bytes is the size of the fixed part of the header
            byte[] hbuf = new byte[16];
            read = ns.Read(hbuf, 0, 16);

            if (read == 0)
            {
                return(null);
            }

            if (read != 16)
            {
                throw new Exception("Header read length mismatch: " + read + " of expected " + "16");
            }

            EndianFlag    endianness = (EndianFlag)hbuf[0];
            MessageReader reader     = new MessageReader(endianness, hbuf);

            //discard the endian byte as we've already read it
            reader.ReadByte();

            //discard message type and flags, which we don't care about here
            reader.ReadByte();
            reader.ReadByte();

            byte version = reader.ReadByte();

            if (version < Protocol.MinVersion || version > Protocol.MaxVersion)
            {
                throw new NotSupportedException("Protocol version '" + version.ToString() + "' is not supported");
            }

            if (Protocol.Verbose)
            {
                if (version != Protocol.Version)
                {
                    Console.Error.WriteLine("Warning: Protocol version '" + version.ToString() + "' is not explicitly supported but may be compatible");
                }
            }

            uint bodyLength = reader.ReadUInt32();

            //discard serial
            reader.ReadUInt32();
            uint headerLength = reader.ReadUInt32();

            //this check may become relevant if a future version of the protocol allows larger messages

            /*
             * if (bodyLength > Int32.MaxValue || headerLength > Int32.MaxValue)
             *      throw new NotImplementedException ("Long messages are not yet supported");
             */

            int bodyLen = (int)bodyLength;
            int toRead  = (int)headerLength;

            //we fixup to include the padding following the header
            toRead = Protocol.Padded(toRead, 8);

            long msgLength = toRead + bodyLen;

            if (msgLength > Protocol.MaxMessageLength)
            {
                throw new Exception("Message length " + msgLength + " exceeds maximum allowed " + Protocol.MaxMessageLength + " bytes");
            }

            header = new byte[16 + toRead];
            Array.Copy(hbuf, header, 16);

            read = ns.Read(header, 16, toRead);

            if (read != toRead)
            {
                throw new Exception("Message header length mismatch: " + read + " of expected " + toRead);
            }

            //read the body
            if (bodyLen != 0)
            {
                body = new byte[bodyLen];
                read = ns.Read(body, 0, bodyLen);

                if (read != bodyLen)
                {
                    throw new Exception("Message body length mismatch: " + read + " of expected " + bodyLen);
                }
            }

            Message msg = new Message();

            msg.Connection = this;
            msg.Body       = body;
            msg.SetHeaderData(header);

            return(msg);
        }
Ejemplo n.º 8
0
        // Note: This method doesn't support aggregate signatures
        public bool StepOver(Signature sig)
        {
            if (sig == Signature.VariantSig)
            {
                Signature valueSig = ReadSignature();
                return(StepOver(valueSig));
            }

            if (sig == Signature.StringSig)
            {
                uint valueLength = ReadUInt32();
                pos += (int)valueLength;
                pos++;
                return(true);
            }

            if (sig == Signature.SignatureSig)
            {
                byte valueLength = ReadByte();
                pos += valueLength;
                pos++;
                return(true);
            }

            // No need to handle dicts specially. IsArray does the job
            if (sig.IsArray)
            {
                Signature elemSig = sig.GetElementSignature();
                uint      ln      = ReadUInt32();
                pos  = Protocol.Padded(pos, elemSig.Alignment);
                pos += (int)ln;
                return(true);
            }

            int endPos = pos;

            if (sig.GetFixedSize(ref endPos))
            {
                pos = endPos;
                return(true);
            }

            if (sig.IsDictEntry)
            {
                pos = Protocol.Padded(pos, sig.Alignment);
                Signature sigKey, sigValue;
                sig.GetDictEntrySignatures(out sigKey, out sigValue);
                if (!StepOver(sigKey))
                {
                    return(false);
                }
                if (!StepOver(sigValue))
                {
                    return(false);
                }
                return(true);
            }

            if (sig.IsStruct)
            {
                pos = Protocol.Padded(pos, sig.Alignment);
                foreach (Signature fieldSig in sig.GetFieldSignatures())
                {
                    if (!StepOver(fieldSig))
                    {
                        return(false);
                    }
                }
                return(true);
            }

            throw new Exception("Can't step over '" + sig + "'");
            //return false;
        }
Ejemplo n.º 9
0
        public static void GenReadArrayFixed(ILGenerator ilg, Type t, int knownElemSize)
        {
            //Console.Error.WriteLine ("GenReadArrayFixed " + t);
            LocalBuilder readerLocal = ilg.DeclareLocal(typeof(MessageReader));

            ilg.Emit(OpCodes.Stloc, readerLocal);

            Type      tElem               = t.GetElementType();
            Signature sigElem             = Signature.GetSig(tElem);
            int       alignElem           = sigElem.Alignment;
            int       knownElemSizePadded = Protocol.Padded(knownElemSize, sigElem.Alignment);
            Type      tUnder              = tElem.IsEnum ? Enum.GetUnderlyingType(tElem) : tElem;
            int       managedElemSize     = System.Runtime.InteropServices.Marshal.SizeOf(tUnder);

            /*
             * Console.WriteLine ("managedElemSize: " + managedElemSize);
             * Console.WriteLine ("elemSize: " + knownElemSize);
             * Console.WriteLine ("elemSizePadded: " + knownElemSizePadded);
             */

            // Read the array's byte length
            ilg.Emit(OpCodes.Ldloc, readerLocal);
            MethodInfo exactMethod = GetReadMethod(typeof(uint));

            ilg.Emit(exactMethod.IsFinal ? OpCodes.Call : OpCodes.Callvirt, exactMethod);
            LocalBuilder sizeLocal = ilg.DeclareLocal(typeof(uint));

            ilg.Emit(OpCodes.Stloc, sizeLocal);

            /*
             * // Take the array's byte length
             * ilg.Emit (OpCodes.Ldloc, sizeLocal);
             * // Divide by the known element size
             * //ilg.Emit (OpCodes.Ldc_I4, knownElemSizePadded);
             * ilg.Emit (OpCodes.Ldc_I4, knownElemSize);
             * ilg.Emit (OpCodes.Div_Un);
             */

            // Create a new array of the correct element length
            ilg.Emit(OpCodes.Ldloc, sizeLocal);
            if (knownElemSizePadded > 1)
            {
                ilg.Emit(OpCodes.Ldc_I4, alignElem);
                MethodInfo paddedMethod = typeof(Protocol).GetMethod("Padded");
                ilg.Emit(OpCodes.Call, paddedMethod);
                // Divide by the known element size
                ilg.Emit(OpCodes.Ldc_I4, knownElemSizePadded);
                ilg.Emit(OpCodes.Div_Un);
            }
            ilg.Emit(OpCodes.Newarr, tElem);
            LocalBuilder aryLocal = ilg.DeclareLocal(t);

            ilg.Emit(OpCodes.Stloc, aryLocal);

            Label nonBlitLabel = ilg.DefineLabel();
            Label endLabel     = ilg.DefineLabel();

            // Skip read or blit for zero-length arrays.
            ilg.Emit(OpCodes.Ldloc, sizeLocal);
            ilg.Emit(OpCodes.Brfalse, endLabel);

            // WARNING: This may skew pos when we later increment it!
            if (alignElem > 4)
            {
                // Align to element if alignment requirement is higher than 4 (since we just read a uint)
                ilg.Emit(OpCodes.Ldloc, readerLocal);
                ilg.Emit(OpCodes.Ldc_I4, alignElem);
                ilg.Emit(OpCodes.Call, messageReaderReadPad);
            }

            // Blit where possible

            // shouldBlit: Blit if endian is native
            // mustBlit: Blit regardless of endian (ie. byte or structs containing only bytes)

            bool shouldBlit = tElem.IsValueType && knownElemSizePadded == managedElemSize && !sigElem.IsStruct;

            //bool shouldBlit = tElem.IsValueType && knownElemSizePadded == managedElemSize;

            // bool and char are not reliably blittable, so we don't allow blitting in these cases.
            // Their exact layout varies between runtimes, platforms and even data types.
            shouldBlit &= tElem != typeof(bool) && tElem != typeof(char);

            bool mustBlit = shouldBlit && knownElemSizePadded == 1;

            if (shouldBlit)
            {
                //Console.Error.WriteLine ("Blit read array " + tElem);

                if (!mustBlit)
                {
                    // Check to see if we can blit the data structures
                    FieldInfo nativeEndianField = typeof(MessageReader).GetField("IsNativeEndian");
                    ilg.Emit(OpCodes.Ldloc, readerLocal);
                    ilg.Emit(OpCodes.Ldfld, nativeEndianField);
                    ilg.Emit(OpCodes.Brfalse_S, nonBlitLabel);
                }

                // Get the destination address
                ilg.Emit(OpCodes.Ldloc, aryLocal);
                ilg.Emit(OpCodes.Ldc_I4_0);
                ilg.Emit(OpCodes.Ldelema, tElem);

                // Get the source address
                FieldInfo dataField = typeof(MessageReader).GetField("data");
                FieldInfo posField  = typeof(MessageReader).GetField("pos");
                ilg.Emit(OpCodes.Ldloc, readerLocal);
                ilg.Emit(OpCodes.Ldfld, dataField);
                {
                    ilg.Emit(OpCodes.Ldloc, readerLocal);
                    ilg.Emit(OpCodes.Ldfld, posField);
                }
                ilg.Emit(OpCodes.Ldelema, typeof(byte));

                // The number of bytes to copy
                ilg.Emit(OpCodes.Ldloc, sizeLocal);

                // Blit the array
                ilg.Emit(OpCodes.Cpblk);

                // pos += bytesRead
                ilg.Emit(OpCodes.Ldloc, readerLocal);
                ilg.Emit(OpCodes.Ldloc, readerLocal);
                ilg.Emit(OpCodes.Ldfld, posField);
                ilg.Emit(OpCodes.Ldloc, sizeLocal);
                ilg.Emit(OpCodes.Add);
                ilg.Emit(OpCodes.Stfld, posField);

                ilg.Emit(OpCodes.Br, endLabel);
            }

            if (!mustBlit)
            {
                ilg.MarkLabel(nonBlitLabel);

                // for (int i = 0 ; i < ary.Length ; i++)
                LocalBuilder indexLocal = ilg.DeclareLocal(typeof(int));
                ilg.Emit(OpCodes.Ldc_I4_0);
                ilg.Emit(OpCodes.Stloc, indexLocal);

                Label loopStartLabel = ilg.DefineLabel();
                Label loopEndLabel   = ilg.DefineLabel();

                ilg.Emit(OpCodes.Br, loopEndLabel);

                ilg.MarkLabel(loopStartLabel);

                {
                    // Read and store an element to the array
                    ilg.Emit(OpCodes.Ldloc, aryLocal);
                    ilg.Emit(OpCodes.Ldloc, indexLocal);

                    ilg.Emit(OpCodes.Ldloc, readerLocal);
                    GenReader(ilg, tElem);

                    ilg.Emit(OpCodes.Stelem, tElem);
                }

                // i++
                ilg.Emit(OpCodes.Ldloc, indexLocal);
                ilg.Emit(OpCodes.Ldc_I4_1);
                ilg.Emit(OpCodes.Add);
                ilg.Emit(OpCodes.Stloc, indexLocal);

                ilg.MarkLabel(loopEndLabel);
                ilg.Emit(OpCodes.Ldloc, indexLocal);
                ilg.Emit(OpCodes.Ldloc, aryLocal);
                ilg.Emit(OpCodes.Ldlen);
                ilg.Emit(OpCodes.Blt, loopStartLabel);
            }

            ilg.MarkLabel(endLabel);

            // Return the new array
            ilg.Emit(OpCodes.Ldloc, aryLocal);
        }