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();
            }
        }
示例#2
0
 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));
 }
示例#3
0
        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();
        }
示例#4
0
        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();
        }
示例#5
0
 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));
 }
示例#6
0
        /// <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);
        }