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(); }
/* * 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"); } } }
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); }
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); }
/* * 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); }
/* * 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); }
// 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; }
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); }