public void Unmarshal(TransportPacket input, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { // <item>Message fits within the transport packet length, so sent unmodified // <pre>[byte:message-type] [byte:channelId] [uint32:packet-size] // [bytes:content]</pre> // </item> // <item> if the message is the first fragment, then the high-bit is // set on the message-type; the number of fragments is encoded using // the adaptive <see cref="ByteUtils.EncodeLength(int)"/> format. // <pre>[byte:message-type'] [byte:channelId] [uint32:packet-size] // [byte:seqno] [bytes:encoded-#-fragments] [bytes:frag]</pre> // </item> // <item> for all subsequent fragments; seqno' = seqno | 128; // the number of fragments is encoded using the adaptive // <see cref="ByteUtils.EncodeLength(int)"/> format. // <pre>[byte:message-type'] [byte:channelId] [uint32:packet-size] // [byte:seqno'] [bytes:encoded-fragment-#] [bytes:frag]</pre> // Fastpath: if the message-type doesn't have the high-bit set, // then this is a non-fragmented message if ((input.ByteAt(0) & 128) == 0) { // If the submarshaller uses LWMCFv1.1 then we would have just // sent the packet as-is; if not, then we'll have prefixed a // LWMCFv1.1 header which must be first removed if (!subMarshallerIsLwmcf11) { input.RemoveBytes(0, (int)LWMCFv11.HeaderSize); } subMarshaller.Unmarshal(input, tdc, messageAvailable); return; } MessageType type; byte channelId; uint contentLength; Stream s = input.AsReadStream(); LWMCFv11.DecodeHeader(out type, out channelId, out contentLength, s); byte seqNo = (byte)s.ReadByte(); TransportPacket subPacket; if ((seqNo & 128) == 0) { // This starts a new message uint numFrags = (uint)ByteUtils.DecodeLength(s); subPacket = UnmarshalFirstFragment(seqNo, numFrags, input.SplitOut((int)(s.Length - s.Position)), tdc); } else { // This is a message in progress seqNo = (byte)(seqNo & ~128); uint fragNo = (uint)ByteUtils.DecodeLength(s); subPacket = UnmarshalFragInProgress(seqNo, fragNo, input.SplitOut((int)(s.Length - s.Position)), tdc); } if (subPacket != null) { subMarshaller.Unmarshal(subPacket, tdc, messageAvailable); subPacket.Dispose(); } }
public void Unmarshal(TransportPacket packet, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { Debug.Assert(messageAvailable != null, "callers must provide a messageAvailable handler"); Stream input = packet.AsReadStream(); int encoderId = DataConverter.Converter.ToInt32(ByteUtils.Read(input, 4), 0); uint length = ByteUtils.DecodeLength(input); byte[] decoded = Decode(encoderId, ByteUtils.Read(input, length)); TransportPacket subPacket = TransportPacket.On(decoded); input.Close(); subMarshaller.Unmarshal(subPacket, tdc, (sender, mea) => messageAvailable(this, mea)); }
public void TestStreams() { byte[] source = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; TransportPacket packet = new TransportPacket(source); Stream rs = packet.AsReadStream(); Assert.AreEqual(source[0], rs.ReadByte()); Assert.AreEqual(source[1], rs.ReadByte()); Assert.AreEqual(source.Length - 2, rs.Length - rs.Position); Assert.AreEqual(source.Length - 2, packet.Length); // causes stream changes to be committed Assert.AreEqual(0, rs.Position); Assert.AreEqual(packet.Length, rs.Length); Assert.AreEqual(source[2], rs.ReadByte()); Assert.AreEqual(source[3], rs.ReadByte()); Assert.IsTrue(rs == packet.AsReadStream()); Stream ws = packet.AsWriteStream(); try { rs.ReadByte(); Assert.Fail("read stream should have been automatically closed"); } catch (ObjectDisposedException) { /* expected */ } rs = packet.AsReadStream(); try { ws.ReadByte(); Assert.Fail("read stream should have been automatically closed"); } catch (ObjectDisposedException) { /* expected */ } CheckDisposed(packet); CheckForUndisposedSegments(); }
public void TestReadStream() { byte[] source = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int sourceStart = 1; int sourceCount = 6; TransportPacket packet = new TransportPacket(); packet.Append(source, sourceStart, sourceCount); packet.Append(source, sourceStart, sourceCount); packet.Append(source, sourceStart, sourceCount); Stream s = packet.AsReadStream(); int packetLength = packet.Length; Assert.AreEqual(3 * sourceCount, packetLength); for (int i = 0; i < packetLength; i++) { Assert.AreEqual(source[sourceStart + (i % sourceCount)], s.ReadByte()); Assert.AreEqual(packetLength - i - 1, s.Length - s.Position); } Assert.AreEqual(s.Length, s.Position); CheckDisposed(packet); CheckForUndisposedSegments(); }
public virtual void Unmarshal(TransportPacket tp, ITransportDeliveryCharacteristics tdc, EventHandler<MessageEventArgs> messageAvailable) { Debug.Assert(messageAvailable != null, "callers must provide a messageAvailale handler"); Stream input = tp.AsReadStream(); MessageType type; byte channelId; uint length; LWMCFv11.DecodeHeader(out type, out channelId, out length, input); Message m = UnmarshalContent(channelId, type, new WrappedStream(input, length), length); if (m == null) { throw new MarshallingException(String.Format( "Cannot unmarshal the provided content: channel={0}, type={1}, len={2}", channelId, type, length)); } messageAvailable(this, new MessageEventArgs(tdc as ITransport, m)); }
/// <summary> /// Handle incoming packets from previously-unknown remote endpoints. /// We check if the packet indicates a handshake and, if so, negotiate. /// Otherwise we send a GT error message and disregard the packet. /// </summary> /// <param name="ep">the remote endpoint</param> /// <param name="packet">the first packet</param> protected void PreviouslyUnseenUdpEndpoint(EndPoint ep, TransportPacket packet) { TransportPacket response; Stream ms; // This is the GT (UDP) protocol 1.0: // bytes 0 - 3: the protocol version (the result from ProtocolDescriptor) // bytes 4 - n: the number of bytes in the capability dictionary (see ByteUtils.EncodeLength) // bytes n+1 - end: the capability dictionary // The # bytes in the dictionary isn't actually necessary in UDP, but oh well foreach(TransportFactory<UdpHandle> factory in factories) { if(packet.Length >= factory.ProtocolDescriptor.Length && ByteUtils.Compare(packet.ToArray(0, factory.ProtocolDescriptor.Length), factory.ProtocolDescriptor)) { packet.RemoveBytes(0, factory.ProtocolDescriptor.Length); ms = packet.AsReadStream(); Dictionary<string, string> dict = null; try { uint count = ByteUtils.DecodeLength(ms); // we don't use it dict = ByteUtils.DecodeDictionary(ms); if(ms.Position != ms.Length) { byte[] rest = packet.ToArray(); log.Info(String.Format( "{0} bytes still left at end of UDP handshake packet: {1} ({2})", rest.Length, ByteUtils.DumpBytes(rest, 0, rest.Length), ByteUtils.AsPrintable(rest, 0, rest.Length))); } ITransport result = factory.CreateTransport(UdpHandle.Bind(udpMultiplexer, ep)); if (ShouldAcceptTransport(result, dict)) { // Send confirmation // NB: following uses the format specified by LWMCF v1.1 response = new TransportPacket(LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.Acknowledged, (uint)factory.ProtocolDescriptor.Length)); response.Append(factory.ProtocolDescriptor); udpMultiplexer.Send(response, ep); NotifyNewTransport(result, dict); } else { // NB: following follows the format specified by LWMCF v1.1 response = new TransportPacket(LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.IncompatibleVersion, 0)); udpMultiplexer.Send(response, ep); result.Dispose(); } return; } catch(Exception e) { log.Warn(String.Format("Error decoding handshake from remote {0}", ep), e); } } } // If we can figure out some way to say: the packet is an invalid form: // response = new TransportPacket(); // ms = response.AsWriteStream(); // log.Info("Undecipherable packet (ignored)"); // // NB: following follows the format specified by LWMCF v1.1 // LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.UnknownConnexion, // (uint)ProtocolDescriptor.Length, ms); // ms.Write(ProtocolDescriptor, 0, ProtocolDescriptor.Length); // ms.Flush(); // udpMultiplexer.Send(response, ep); response = new TransportPacket(); ms = response.AsWriteStream(); log.Info("Unknown protocol version: " + ByteUtils.DumpBytes(packet.ToArray(), 0, 4) + " [" + ByteUtils.AsPrintable(packet.ToArray(), 0, 4) + "]"); // NB: following follows the format specified by LWMCF v1.1 LWMCFv11.EncodeHeader(MessageType.System, (byte)SystemMessageType.IncompatibleVersion, 0, ms); ms.Flush(); udpMultiplexer.Send(response, ep); }