3

I'm writing an application that takes a Wireshark File (Pcap, Snopp, Pcapng...), opens it and reads all the packets.

My base class:

public abstract class WiresharkFile
{
   ...
}

And all the sub classes implemented IEnumerable:

public class Libpcap : WiresharkFile, IDisposable, IEnumerable<WiresharkFilePacket>
{
    ....
}

Now when I create the object my code recognizes it automatically and then creates the current object type, for example:

wiresharkFile = new Libpcap(file);

And then when I want to loop over my file and read packets:

foreach (var packet in wiresharkFile)
{
   ...
}

I get this error:

foreach statement cannot operate on variables of type WiresharkFile' because WiresharkFile' does not contain a public definition for 'GetEnumerator'

So I added this function inside WiresharkFile base class:

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    return GetEnumerator();
}

And now I get this error StackOverflowException:

Cannot evaluate expression because the current thread is in a stack overflow state.

Edit

public class Libpcap : WiresharkFile, IDisposable, IEnumerable<WiresharkFilePacket>
{
    private BinaryReader binaryReader;
    private Version version;
    private uint snaplen;
    private int thiszone;
    private uint sigfigs;
    private LibpcapLinkType linktype;
    private long basePos;
    private bool byteSwap;
    private static uint MAGIC = 0xa1b2c3d4;
    private static uint MAGIC_ENDIAN = 0xd4c3b2a1;

    public Libpcap(string path) : this(new FileStream(path, FileMode.Open, FileAccess.Read))
    {
        FileName = path;
        binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read));
    }        

    public void Close()
    {
        binaryReader.Close();
    }

    public enum LibpcapLinkType
    {
        Null,
        Ethernet,
        ExpEthernet,
        AX25,
        ProNet,
        Chaos,
        TokenRing,
        ArcNet,
        Slip,
        Ppp,
        Fddi
    }

    public Libpcap(Stream s)
    {
        binaryReader = new BinaryReader(s);
        uint magic = binaryReader.ReadUInt32();

        ushort major = binaryReader.ReadUInt16();
        ushort minor = binaryReader.ReadUInt16();

        thiszone = binaryReader.ReadInt32();
        sigfigs = binaryReader.ReadUInt32();
        snaplen = binaryReader.ReadUInt32();
        uint ltype = binaryReader.ReadUInt32();

        if (byteSwap)
        {
            major = ByteSwap.Swap(major);
            minor = ByteSwap.Swap(minor);
            thiszone = ByteSwap.Swap(thiszone);
            snaplen = ByteSwap.Swap(snaplen);
            ltype = ByteSwap.Swap(ltype);
        }

        version = new Version(major, minor);
        linktype = (LibpcapLinkType)((int)ltype);
        basePos = binaryReader.BaseStream.Position;

        protected override WiresharkFilePacket ReadPacket()
        {
            if (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
            {
                int secs = binaryReader.ReadInt32();
                int usecs = binaryReader.ReadInt32();
                uint caplen = binaryReader.ReadUInt32();
                uint len = binaryReader.ReadUInt32();
                if (byteSwap)
                {
                    secs = ByteSwap.Swap(secs);
                    usecs = ByteSwap.Swap(usecs);
                    caplen = ByteSwap.Swap(caplen);
                    len = ByteSwap.Swap(len);
                }

                DateTime timeStamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds((Double)secs).AddMilliseconds((Double)usecs / 1000);
                byte[] data = binaryReader.ReadBytes((int)caplen);

                return new WiresharkFilePacket(timeStamp, data);
            }
            else
                return null;
        }

        public Version Version
        {
            get
            {
                return version;
            }
        }

        public uint MaximumCaptureLength
        {
            get
            {
                return snaplen;
            }
        }

        public int TimezoneOffset
        {
            get
            {
                return thiszone;
            }
        }

        public uint SignificantFigures
        {
            get
            {
                return sigfigs;
            }
        }

        public LibpcapLinkType LinkType
        {
            get
            {
                return linktype;
            }
        }

        public void Rewind()
        {
            binaryReader.BaseStream.Position = basePos;
        }

        public override string ToString()
        {
            string endianness;

            if (BitConverter.IsLittleEndian)
            {
                if (byteSwap)
                    endianness = "Big";
                else
                    endianness = "Little";
            }
            else
            {
                if (byteSwap)
                    endianness = "Little";
                else
                    endianness = "Big";
            }

            return String.Format("{0}-endian {1} capture, pcap version {2}", endianness, linktype.ToString(), version.ToString());
        }

        public void Dispose()
        {
            binaryReader.Close();
        }

        public class PacketEnumerator : IEnumerator<WiresharkFilePacket>
        {
            private Libpcap file;
            private WiresharkFilePacket currentPacket = null;

            public PacketEnumerator(Libpcap file)
            {
                this.file = file;
            }

            #region IEnumerator<PcapPacket> Members

            public WiresharkFilePacket Current
            {
                get { return currentPacket; }
            }

            #endregion

            #region IDisposable Members

            public void Dispose()
            {
            }

            #endregion

            #region IEnumerator Members

            object System.Collections.IEnumerator.Current
            {
                get { return currentPacket; }
            }

            public bool MoveNext()
            {
                currentPacket = file.ReadPacket();
                return currentPacket != null;
            }

            public void Reset()
            {
                file.Rewind();
            }

            #endregion
        }

        #region IEnumerable<PcapPacket> Members

        public IEnumerator<WiresharkFilePacket> GetEnumerator()
        {
            return new PacketEnumerator(this);
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new PacketEnumerator(this);
        }

        #endregion
    }
Palle Due
  • 5,929
  • 4
  • 17
  • 32
david hol
  • 1,272
  • 7
  • 22
  • 44

2 Answers2

0

You are seeing StackOverflowException because you're calling yourself

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    return GetEnumerator();
}

You need to properly implement an iterator for this to work. For example:

public IEnumerator<WiresharkFilePacket> GetEnumerator()
{
    for (int i = 0; i < 10; i++)
        yield return new WiresharkFilePacket();
}

Your WiresharkFile should have some internal collection it can iterate over. Be it a packets that you parse out of the pcap and return. Simply creating a GetEnumerator method will do nothing. For more, perhaps you want to read How do I implement IEnumerable<T>

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Please see my edit, my class implement this IEnumerable with private class so, how to convert it to normal IEnumerable ? – david hol Nov 15 '15 at 13:28
0

If all derived classes provide a GetEnumerator() method, and you have no problem requiring this of any future derived classes, but your base class cannot meaningfully define one, that's when you mark it abstract.

public abstract IEnumerator<WiresharkFilePacket> GetEnumerator();

Thus is enough to implement IEnumerable on your base class, you don't need the full definition there yet.

  • Please see my edit, my class implement this IEnumerable with private class so, how to convert it to normal IEnumerable ? – david hol Nov 15 '15 at 13:28