private static void AddTunnelMessage(List <TunnelMessage> result, TunnelDataFragment initialfragment, byte[] buf)
        {
            switch (initialfragment.Delivery)
            {
            case TunnelMessage.DeliveryTypes.Local:
                result.Add(new TunnelMessageLocal(I2NPMessage.ReadHeader16(new BufRef(buf))));
                break;

            case TunnelMessage.DeliveryTypes.Router:
                result.Add(new TunnelMessageRouter(I2NPMessage.ReadHeader16(new BufRef(buf)),
                                                   new I2PIdentHash((BufRefLen)initialfragment.ToHash)));
                break;

            case TunnelMessage.DeliveryTypes.Tunnel:
                result.Add(new TunnelMessageTunnel(I2NPMessage.ReadHeader16(new BufRef(buf)),
                                                   new I2PIdentHash((BufRefLen)initialfragment.ToHash), initialfragment.Tunnel));
                break;
            }
        }
        public IEnumerable <TunnelMessage> Process(IEnumerable <TunnelDataMessage> tdmsgs)
        {
            var result = new List <TunnelMessage>();

            RemoveUnmatchedFragments.Do(() =>
            {
                lock ( MessageFragments )
                {
                    var remove = MessageFragments.Where(p => p.Value.Created.DeltaToNow.ToMinutes > RememberUnmatchedFragmentsForMinutes).
                                 Select(p => p.Key).ToArray();
                    foreach (var key in remove)
                    {
                        Logging.LogDebug("TunnelDataFragmentReassembly: Removing old unmatched fragment for " + key.ToString());
                        MessageFragments.Remove(key);
                    }
                }
            });

            foreach (var msg in tdmsgs)
            {
                var hash = I2PHashSHA256.GetHash(msg.TunnelDataPayload, msg.IV);
                var eq   = BufUtils.Equal(msg.Checksum.PeekB(0, 4), 0, hash, 0, 4);
                if (!eq)
                {
                    // Do not stop processing, just throw away faulty data
                    // throw new SignatureCheckFailureException( "TunnelDataFragmentReassembly: SHA256 check failed in TunnelData" );
                    Logging.LogDebug("TunnelDataFragmentReassembly: SHA256 check failed in TunnelData");
                    continue;
                }

                var reader = (BufRefLen)msg.TunnelDataPayload;

                while (reader.Length > 0)
                {
                    var frag = new TunnelDataFragment(reader);

                    if (frag.FollowOnFragment)
                    {
                        List <TunnelDataFragment> fragments;

                        if (!MessageFragments.ContainsKey(frag.MessageId))
                        {
                            fragments = new List <TunnelDataFragment>();
                            MessageFragments[frag.MessageId] = new TunnelDataFragmentList(fragments);
                        }
                        else
                        {
                            fragments = MessageFragments[frag.MessageId].List;
                        }

                        if (fragments.Count <= frag.FragmentNumber)
                        {
                            fragments.AddRange(new TunnelDataFragment[frag.FragmentNumber - fragments.Count + 1]);
                        }
                        fragments[frag.FragmentNumber] = frag;

                        CheckForAllFragmentsFound(result, frag.MessageId, fragments);
                    }
                    else
                    {
                        if (frag.Fragmented)
                        {
                            List <TunnelDataFragment> fragments;

                            if (!MessageFragments.ContainsKey(frag.MessageId))
                            {
                                fragments = new List <TunnelDataFragment>();
                                MessageFragments[frag.MessageId] = new TunnelDataFragmentList(fragments);
                            }
                            else
                            {
                                fragments = MessageFragments[frag.MessageId].List;
                            }

                            if (fragments.Count == 0)
                            {
                                fragments.AddRange(new TunnelDataFragment[1]);
                            }
                            fragments[0] = frag;

                            CheckForAllFragmentsFound(result, frag.MessageId, fragments);
                        }
                        else
                        {
                            AddTunnelMessage(result, frag, frag.Payload.ToByteArray());
                        }
                    }
                }
            }

            return(result);
        }