Commit 136fbcc7 authored by Brickner_cp's avatar Brickner_cp

Code Analysis and Documentation - 185 warnings left.

parent 738f640a
......@@ -25,6 +25,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>1718</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
......
......@@ -11,6 +11,9 @@ namespace PcapDotNet.Base
/// </summary>
public static class MoreIEnumerable
{
/// <summary>
/// True iff the sequence has no elements.
/// </summary>
public static bool IsEmpty<T>(this IEnumerable<T> sequence)
{
return !sequence.GetEnumerator().MoveNext();
......
......@@ -2,11 +2,17 @@ using System.Reflection;
namespace PcapDotNet.Base
{
/// <summary>
/// Extension methods for PropertyInfo.
/// </summary>
public static class MorePropertyInfo
{
public static object GetValue(this PropertyInfo propertyInfo, object obj)
/// <summary>
/// Returns the value of the given instance's non-indexed property.
/// </summary>
public static object GetValue(this PropertyInfo propertyInfo, object instanceWithProperty)
{
return propertyInfo.GetValue(obj, null);
return propertyInfo.GetValue(instanceWithProperty, null);
}
}
}
\ No newline at end of file
......@@ -3,8 +3,14 @@ using System.Collections.Generic;
namespace PcapDotNet.Base
{
/// <summary>
/// Extension methods for Type.
/// </summary>
public static class MoreType
{
/// <summary>
/// Returns all the possible values for the given enum type.
/// </summary>
public static IEnumerable<T> GetEnumValues<T>(this Type type)
{
return (IEnumerable<T>)Enum.GetValues(type);
......
......@@ -34,9 +34,9 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.EchoReply:
return "Echo reply: " + ((TcpOptionEchoReply)option).Info;
case TcpOptionType.TimeStamp:
TcpOptionTimeStamp timeStampOption = (TcpOptionTimeStamp)option;
return "Timestamps: TSval " + timeStampOption.TimeStampValue + ", TSecr " + timeStampOption.TimeStampEchoReply;
case TcpOptionType.Timestamp:
TcpOptionTimestamp timestampOption = (TcpOptionTimestamp)option;
return "Timestamps: TSval " + timestampOption.TimestampValue + ", TSecr " + timestampOption.TimestampEchoReply;
case TcpOptionType.PartialOrderServiceProfile:
return "Unknown (0x0a) (3 bytes)";
......@@ -100,7 +100,7 @@ namespace PcapDotNet.Core.Test
case TcpOptionType.SelectiveAcknowledgmentPermitted:
case TcpOptionType.Echo:
case TcpOptionType.EchoReply:
case TcpOptionType.TimeStamp:
case TcpOptionType.Timestamp:
case TcpOptionType.PartialOrderServiceProfile:
case TcpOptionType.PartialOrderConnectionPermitted:
case TcpOptionType.ConnectionCount:
......
......@@ -77,7 +77,7 @@ namespace PcapDotNet.Core.Test
[TestMethod]
public void ComparePacketsToWiresharkTest()
{
for (int i = 0; i != 500; ++i)
for (int i = 0; i != 50; ++i)
{
// Create packets
List<Packet> packets = new List<Packet>(CreateRandomPackets(200));
......@@ -531,19 +531,19 @@ namespace PcapDotNet.Core.Test
switch (flagField.Name())
{
case "tcp.flags.cwr":
flagField.AssertShowDecimal(tcpDatagram.IsCwr);
flagField.AssertShowDecimal(tcpDatagram.IsCongestionWindowReduced);
break;
case "tcp.flags.ecn":
flagField.AssertShowDecimal(tcpDatagram.IsEce);
flagField.AssertShowDecimal(tcpDatagram.IsExplicitCongestionNotificationEcho);
break;
case "tcp.flags.urg":
flagField.AssertShowDecimal(tcpDatagram.IsUrg);
flagField.AssertShowDecimal(tcpDatagram.IsUrgent);
break;
case "tcp.flags.ack":
flagField.AssertShowDecimal(tcpDatagram.IsAck);
flagField.AssertShowDecimal(tcpDatagram.IsAcknowledgment);
break;
case "tcp.flags.push":
......@@ -555,7 +555,7 @@ namespace PcapDotNet.Core.Test
break;
case "tcp.flags.syn":
flagField.AssertShowDecimal(tcpDatagram.IsSyn);
flagField.AssertShowDecimal(tcpDatagram.IsSynchronize);
break;
case "tcp.flags.fin":
......@@ -643,7 +643,7 @@ namespace PcapDotNet.Core.Test
break;
case "tcp.options.time_stamp":
Assert.IsTrue(option is TcpOptionTimeStamp);
Assert.IsTrue(option is TcpOptionTimestamp);
field.AssertShowDecimal(1);
break;
......
......@@ -25,6 +25,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoWarn>1718</NoWarn>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
......
......@@ -117,14 +117,14 @@ namespace PcapDotNet.Packets.Test
Assert.IsFalse(string.IsNullOrEmpty(option.ToString()));
}
Assert.AreEqual(tcpOptions, packet.Ethernet.IpV4.Tcp.Options, "Options");
Assert.AreEqual((tcpFlags & TcpFlags.Ack) == TcpFlags.Ack, packet.Ethernet.IpV4.Tcp.IsAck, "IsAck");
Assert.AreEqual((tcpFlags & TcpFlags.Cwr) == TcpFlags.Cwr, packet.Ethernet.IpV4.Tcp.IsCwr, "IsCwr");
Assert.AreEqual((tcpFlags & TcpFlags.Ece) == TcpFlags.Ece, packet.Ethernet.IpV4.Tcp.IsEce, "IsEce");
Assert.AreEqual((tcpFlags & TcpFlags.Acknowledgment) == TcpFlags.Acknowledgment, packet.Ethernet.IpV4.Tcp.IsAcknowledgment, "IsAcknowledgment");
Assert.AreEqual((tcpFlags & TcpFlags.CongestionWindowReduced) == TcpFlags.CongestionWindowReduced, packet.Ethernet.IpV4.Tcp.IsCongestionWindowReduced, "IsCongestionWindowReduced");
Assert.AreEqual((tcpFlags & TcpFlags.ExplicitCongestionNotificationEcho) == TcpFlags.ExplicitCongestionNotificationEcho, packet.Ethernet.IpV4.Tcp.IsExplicitCongestionNotificationEcho, "IsExplicitCongestionNotificationEcho");
Assert.AreEqual((tcpFlags & TcpFlags.Fin) == TcpFlags.Fin, packet.Ethernet.IpV4.Tcp.IsFin, "IsFin");
Assert.AreEqual((tcpFlags & TcpFlags.Psh) == TcpFlags.Psh, packet.Ethernet.IpV4.Tcp.IsPush, "IsPush");
Assert.AreEqual((tcpFlags & TcpFlags.Rst) == TcpFlags.Rst, packet.Ethernet.IpV4.Tcp.IsReset, "IsReset");
Assert.AreEqual((tcpFlags & TcpFlags.Syn) == TcpFlags.Syn, packet.Ethernet.IpV4.Tcp.IsSyn, "IsSyn");
Assert.AreEqual((tcpFlags & TcpFlags.Urg) == TcpFlags.Urg, packet.Ethernet.IpV4.Tcp.IsUrg, "IsUrg");
Assert.AreEqual((tcpFlags & TcpFlags.Push) == TcpFlags.Push, packet.Ethernet.IpV4.Tcp.IsPush, "IsPush");
Assert.AreEqual((tcpFlags & TcpFlags.Reset) == TcpFlags.Reset, packet.Ethernet.IpV4.Tcp.IsReset, "IsReset");
Assert.AreEqual((tcpFlags & TcpFlags.Synchronize) == TcpFlags.Synchronize, packet.Ethernet.IpV4.Tcp.IsSynchronize, "IsSynchronize");
Assert.AreEqual((tcpFlags & TcpFlags.Urgent) == TcpFlags.Urgent, packet.Ethernet.IpV4.Tcp.IsUrgent, "IsUrgent");
Assert.IsFalse(packet.Ethernet.IpV4.Tcp.IsChecksumOptional, "IsChecksumOptional");
Assert.AreEqual(TcpDatagram.HeaderMinimumLength + tcpOptions.BytesLength + tcpPayload.Length, packet.Ethernet.IpV4.Tcp.Length, "Total Length");
Assert.IsTrue(packet.Ethernet.IpV4.IsTransportChecksumCorrect, "IsTransportChecksumCorrect");
......
......@@ -287,8 +287,8 @@ namespace PcapDotNet.Packets.TestUtils
impossibleOptionTypes.Add(TcpOptionType.Echo);
if (maximumOptionLength < TcpOptionEchoReply.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.EchoReply);
if (maximumOptionLength < TcpOptionTimeStamp.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.TimeStamp);
if (maximumOptionLength < TcpOptionTimestamp.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Timestamp);
if (maximumOptionLength < TcpOptionPartialOrderServiceProfile.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.PartialOrderServiceProfile);
if (maximumOptionLength < TcpOptionPartialOrderConnectionPermitted.OptionLength)
......@@ -340,8 +340,8 @@ namespace PcapDotNet.Packets.TestUtils
case TcpOptionType.EchoReply:
return new TcpOptionEchoReply(random.NextUInt());
case TcpOptionType.TimeStamp:
return new TcpOptionTimeStamp(random.NextUInt(), random.NextUInt());
case TcpOptionType.Timestamp:
return new TcpOptionTimestamp(random.NextUInt(), random.NextUInt());
case TcpOptionType.PartialOrderServiceProfile:
return new TcpOptionPartialOrderServiceProfile(random.NextBool(), random.NextBool());
......
......@@ -37,6 +37,7 @@
<Word>unicast</Word>
<Word>genser</Word>
<Word>nsa</Word>
<Word>md</Word>
</Recognized>
<Deprecated>
<!--Term PreferredAlternate="EnterpriseServices">complus</Term-->
......
namespace PcapDotNet.Packets
{
/// <summary>
/// A factory interface for an unknown option.
/// </summary>
/// <typeparam name="TOptionType">The option type enum type.</typeparam>
public interface IOptionUnknownFactory<TOptionType>
{
/// <summary>
/// Creates an unknown option from its type and by reading a buffer for its value.
/// </summary>
/// <param name="optionType">The type of the unknown option.</param>
/// <param name="buffer">The buffer of bytes to read the value of the unknown option.</param>
/// <param name="offset">The offset in the buffer to start reading the bytes.</param>
/// <param name="valueLength">The number of bytes to read from the buffer.</param>
/// <returns>An option created from the given type and buffer.</returns>
Option CreateInstance(TOptionType optionType, byte[] buffer, ref int offset, byte valueLength);
}
}
\ No newline at end of file
namespace PcapDotNet.Packets
{
public interface IOptionUnkownFactory<TOptionType>
{
Option CreateInstance(TOptionType optionType, byte[] buffer, ref int offset, byte valueLength);
}
}
\ No newline at end of file
......@@ -183,6 +183,11 @@ namespace PcapDotNet.Packets.IpV4
}
}
/// <summary>
/// Returns whether the TCP or UDP checksum is correct.
/// The protocol must be TCP or UDP.
/// For UDP, the checksum is optional, so 0 checksum is still correct.
/// </summary>
public bool IsTransportChecksumCorrect
{
get
......
......@@ -39,9 +39,9 @@ namespace PcapDotNet.Packets.IpV4
/// Checks whether two options have equivalent type.
/// Useful to check if an option that must appear at most once appears in the list.
/// </summary>
public override bool Equivalent(Option option)
public override bool Equivalent(Option other)
{
return OptionType == ((IpV4Option)option).OptionType;
return OptionType == ((IpV4Option)other).OptionType;
}
/// <summary>
......
......@@ -6,7 +6,10 @@ using PcapDotNet.Base;
namespace PcapDotNet.Packets.IpV4
{
public class IpV4OptionUnknown : IpV4OptionComplex, IOptionUnkownFactory<IpV4OptionType>, IEquatable<IpV4OptionUnknown>
/// <summary>
/// An unknown IPv4 option.
/// </summary>
public class IpV4OptionUnknown : IpV4OptionComplex, IOptionUnknownFactory<IpV4OptionType>, IEquatable<IpV4OptionUnknown>
{
/// <summary>
/// The minimum number of bytes this option take.
......@@ -18,12 +21,18 @@ namespace PcapDotNet.Packets.IpV4
/// </summary>
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
/// <summary>
/// Creates an unknown IPv4 option by the given type and data.
/// </summary>
public IpV4OptionUnknown(IpV4OptionType optionType, IList<byte> data)
: base(optionType)
{
Data = new ReadOnlyCollection<byte>(data);
}
/// <summary>
/// The default unknown option is with type 255 and no data.
/// </summary>
public IpV4OptionUnknown()
: this((IpV4OptionType)255, new byte[] {})
{
......@@ -47,6 +56,9 @@ namespace PcapDotNet.Packets.IpV4
get { return false; }
}
/// <summary>
/// Two unknown options are equal iff they are of equal type and equal data.
/// </summary>
public bool Equals(IpV4OptionUnknown other)
{
if (other == null)
......@@ -56,16 +68,30 @@ namespace PcapDotNet.Packets.IpV4
Data.SequenceEqual(other.Data);
}
/// <summary>
/// Two unknown options are equal iff they are of equal type and equal data.
/// </summary>
public override bool Equals(IpV4Option other)
{
return Equals(other as IpV4OptionUnknown);
}
/// <summary>
/// The hash code for an unknown option is the hash code for the option type xored with the hash code of the data.
/// </summary>
public override int GetHashCode()
{
return base.GetHashCode() ^ Data.BytesSequenceGetHashCode();
}
/// <summary>
/// Creates an unknown option from its type and by reading a buffer for its value.
/// </summary>
/// <param name="optionType">The type of the unknown option.</param>
/// <param name="buffer">The buffer of bytes to read the value of the unknown option.</param>
/// <param name="offset">The offset in the buffer to start reading the bytes.</param>
/// <param name="valueLength">The number of bytes to read from the buffer.</param>
/// <returns>An option created from the given type and buffer.</returns>
public Option CreateInstance(IpV4OptionType optionType, byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
......
namespace PcapDotNet.Packets
{
/// <summary>
/// A generic option (for IPv4 and TCP).
/// The option is read from buffer and can be of different length.
/// </summary>
public abstract class Option
{
/// <summary>
......
......@@ -6,13 +6,20 @@ using PcapDotNet.Base;
namespace PcapDotNet.Packets
{
public class OptionComplexFactory<TOptionType>
public class OptionComplexFactoryBase
{
/// <summary>
/// The header length in bytes for the option (type and size).
/// </summary>
public const int OptionHeaderLength = 2;
protected OptionComplexFactoryBase()
{
}
}
public sealed class OptionComplexFactory<TOptionType> : OptionComplexFactoryBase
{
internal static Option Read(TOptionType optionType, byte[] buffer, ref int offset, int length)
{
if (length < 1)
......@@ -24,22 +31,22 @@ namespace PcapDotNet.Packets
IOptionComplexFactory prototype;
if (!_complexOptions.TryGetValue(optionType, out prototype))
return _unkownFactoryOptionPrototype.CreateInstance(optionType, buffer, ref offset, optionValueLength);
return UnknownFactoryOptionPrototype.CreateInstance(optionType, buffer, ref offset, optionValueLength);
return prototype.CreateInstance(buffer, ref offset, optionValueLength);
}
private static IOptionUnkownFactory<TOptionType> InitializeUnkownOptionPrototype()
private static IOptionUnknownFactory<TOptionType> InitializeUnknownOptionPrototype()
{
var unkownOptions =
var unknownOptions =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IOptionUnkownFactory<TOptionType>).IsAssignableFrom(type)
select (IOptionUnkownFactory<TOptionType>)Activator.CreateInstance(type);
where typeof(IOptionUnknownFactory<TOptionType>).IsAssignableFrom(type)
select (IOptionUnknownFactory<TOptionType>)Activator.CreateInstance(type);
if (unkownOptions.Count() != 1)
throw new InvalidOperationException("Must be only one unkown option for option type " + typeof(TOptionType));
if (unknownOptions.Count() != 1)
throw new InvalidOperationException("Must be only one unknown option for option type " + typeof(TOptionType));
return unkownOptions.First();
return unknownOptions.First();
}
private static Dictionary<TOptionType, IOptionComplexFactory> InitializeComplexOptions()
......@@ -70,7 +77,11 @@ namespace PcapDotNet.Packets
return registraionAttributes.First();
}
private OptionComplexFactory()
{
}
private static readonly Dictionary<TOptionType, IOptionComplexFactory> _complexOptions = InitializeComplexOptions();
private static readonly IOptionUnkownFactory<TOptionType> _unkownFactoryOptionPrototype = InitializeUnkownOptionPrototype();
private static readonly IOptionUnknownFactory<TOptionType> UnknownFactoryOptionPrototype = InitializeUnknownOptionPrototype();
}
}
\ No newline at end of file
......@@ -132,6 +132,7 @@ namespace PcapDotNet.Packets
/// <param name="tcpDestinationPort">The destination udp port.</param>
/// <param name="tcpPayload">The payload of UDP datagram.</param>
/// <returns>A packet with a UDP over IPv4 over Ethernet datagram.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "pointer")]
public static Packet EthernetIpV4Tcp(DateTime timestamp,
MacAddress ethernetSource, MacAddress ethernetDestination,
byte ipV4TypeOfService, ushort ipV4Identification, IpV4Fragmentation ipV4Fragmentation,
......
......@@ -68,7 +68,7 @@
<Compile Include="Ethernet\EthernetType.cs" />
<Compile Include="Ethernet\MacAddress.cs" />
<Compile Include="IDataLink.cs" />
<Compile Include="IOptionUnkownFactory.cs" />
<Compile Include="IOptionUnknownFactory.cs" />
<Compile Include="IpV4\IpV4OptionUnknown.cs" />
<Compile Include="Option.cs" />
<Compile Include="IOptionComplexFactory.cs" />
......@@ -130,7 +130,7 @@
<Compile Include="Transport\TcpOptionSelectiveAcknowledgmentBlock.cs" />
<Compile Include="Transport\TcpOptionSelectiveAcknowledgmentPermitted.cs" />
<Compile Include="Transport\TcpOptionSimple.cs" />
<Compile Include="Transport\TcpOptionTimeStamp.cs" />
<Compile Include="Transport\TcpOptionTimestamp.cs" />
<Compile Include="Transport\TcpOptionType.cs" />
<Compile Include="Transport\TcpOptionUnknown.cs" />
<Compile Include="Transport\TcpOptionWindowScale.cs" />
......
......@@ -75,6 +75,7 @@ namespace PcapDotNet.Packets.Transport
get { return Math.Min(HeaderLength, Length); }
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags")]
public TcpFlags Flags
{
get { return (TcpFlags)(ReadUShort(Offset.HeaderLengthAndFlags, Endianity.Big) & 0x01FF); }
......@@ -90,11 +91,6 @@ namespace PcapDotNet.Packets.Transport
get { return ReadUShort(Offset.Checksum, Endianity.Big); }
}
public override int ChecksumOffset
{
get { return Offset.Checksum; }
}
public override bool IsChecksumOptional
{
get { return false; }
......@@ -123,39 +119,39 @@ namespace PcapDotNet.Packets.Transport
get { return new Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); }
}
public bool IsCwr
public bool IsCongestionWindowReduced
{
get { return (Flags & TcpFlags.Cwr) == TcpFlags.Cwr; }
get { return (Flags & TcpFlags.CongestionWindowReduced) == TcpFlags.CongestionWindowReduced; }
}
public bool IsEce
public bool IsExplicitCongestionNotificationEcho
{
get { return (Flags & TcpFlags.Ece) == TcpFlags.Ece; }
get { return (Flags & TcpFlags.ExplicitCongestionNotificationEcho) == TcpFlags.ExplicitCongestionNotificationEcho; }
}
public bool IsUrg
public bool IsUrgent
{
get { return (Flags & TcpFlags.Urg) == TcpFlags.Urg; }
get { return (Flags & TcpFlags.Urgent) == TcpFlags.Urgent; }
}
public bool IsAck
public bool IsAcknowledgment
{
get { return (Flags & TcpFlags.Ack) == TcpFlags.Ack; }
get { return (Flags & TcpFlags.Acknowledgment) == TcpFlags.Acknowledgment; }
}
public bool IsPush
{
get { return (Flags & TcpFlags.Psh) == TcpFlags.Psh; }
get { return (Flags & TcpFlags.Push) == TcpFlags.Push; }
}
public bool IsReset
{
get { return (Flags & TcpFlags.Rst) == TcpFlags.Rst; }
get { return (Flags & TcpFlags.Reset) == TcpFlags.Reset; }
}
public bool IsSyn
public bool IsSynchronize
{
get { return (Flags & TcpFlags.Syn) == TcpFlags.Syn; }
get { return (Flags & TcpFlags.Synchronize) == TcpFlags.Synchronize; }
}
public bool IsFin
......@@ -163,6 +159,11 @@ namespace PcapDotNet.Packets.Transport
get { return (Flags & TcpFlags.Fin) == TcpFlags.Fin; }
}
internal override int ChecksumOffset
{
get { return Offset.Checksum; }
}
internal static void WriteHeader(byte[] buffer, int offset,
ushort sourcePort, ushort destinationPort,
uint sequenceNumber, uint acknowledgmentNumber,
......
......@@ -10,18 +10,18 @@ namespace PcapDotNet.Packets.Transport
/// | 0 | | NS | CWR | ECE | URG | ACK | PSH | RST | SYN | FIN |
/// +-----+-----+----+-----+-----+-----+-----+-----+-----+-----+-----+
/// </summary>
[Flags]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags"), Flags]
public enum TcpFlags : ushort
{
None = 0x0000,
Fin = 0x0001,
Syn = 0x0002,
Rst = 0x0004,
Psh = 0x0008,
Ack = 0x0010,
Urg = 0x0020,
Ece = 0x0040,
Cwr = 0x0080,
Synchronize = 0x0002,
Reset = 0x0004,
Push = 0x0008,
Acknowledgment = 0x0010,
Urgent = 0x0020,
ExplicitCongestionNotificationEcho = 0x0040,
CongestionWindowReduced = 0x0080,
Ns = 0x0100,
}
}
\ No newline at end of file
......@@ -2,25 +2,42 @@ using System;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// Represents a TCP option according to rfc 793.
/// </summary>
public abstract class TcpOption : Option, IEquatable<TcpOption>
{
/// <summary>
/// This option code indicates the end of the option list.
/// This might not coincide with the end of the TCP header according to the Data Offset field.
/// This is used at the end of all options, not the end of each option,
/// and need only be used if the end of the options would not otherwise coincide with the end of the TCP header.
/// </summary>
public static TcpOption End
{
get { return _end; }
}
/// <summary>
/// This option code may be used between options,
/// for example, to align the beginning of a subsequent option on a word boundary.
/// There is no guarantee that senders will use this option,
/// so receivers must be prepared to process options even if they do not begin on a word boundary.
/// </summary>
public static TcpOption Nop
{
get { return _nop; }
}
public TcpOption(TcpOptionType optionType)
{
OptionType = optionType;
}
/// <summary>
/// The type of the TCP option.
/// </summary>
public TcpOptionType OptionType { get; private set; }
/// <summary>
/// Checks whether two options have equivalent type.
/// Useful to check if an option that must appear at most once appears in the list.
/// </summary>
public override bool Equivalent(Option other)
{
return OptionType == ((TcpOption)other).OptionType;
......@@ -44,11 +61,18 @@ namespace PcapDotNet.Packets.Transport
return Equals(obj as TcpOption);
}
/// <summary>
/// The hash code for a tcp option is the hash code for the option type.
/// This should be overridden by tcp options with data.
/// </summary>
public override int GetHashCode()
{
return OptionType.GetHashCode();
}
/// <summary>
/// The string that represents the option type.
/// </summary>
public override string ToString()
{
return OptionType.ToString();
......@@ -78,6 +102,14 @@ namespace PcapDotNet.Packets.Transport
buffer[offset++] = (byte)OptionType;
}
/// <summary>
/// Initializes the option type.
/// </summary>
protected TcpOption(TcpOptionType optionType)
{
OptionType = optionType;
}
private static readonly TcpOption _end = new TcpOptionSimple(TcpOptionType.EndOfOptionList);
private static readonly TcpOption _nop = new TcpOptionSimple(TcpOptionType.NoOperation);
}
......
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// Represents a complex TCP option.
/// Complex option means that it contains data and not just the type.
/// </summary>
public abstract class TcpOptionComplex : TcpOption
{
public const int OptionHeaderLength = 2;
......
......@@ -53,6 +53,9 @@ namespace PcapDotNet.Packets.Transport
/// </summary>
public const int OptionMinimumLength = 2;
/// <summary>
/// The minimum number of bytes this option's value take.
/// </summary>
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
public TcpOptionSelectiveAcknowledgment(IList<TcpOptionSelectiveAcknowledgmentBlock> blocks)
......
......@@ -5,19 +5,22 @@ namespace PcapDotNet.Packets.Transport
public const int SizeOf = 8;
public TcpOptionSelectiveAcknowledgmentBlock(uint leftEdge, uint rightEdge)
: this()
{
_leftEdge = leftEdge;
_rightEdge = rightEdge;
LeftEdge = leftEdge;
RightEdge = rightEdge;
}
public uint LeftEdge
{
get { return _leftEdge; }
get;
private set;
}
public uint RightEdge
{
get { return _rightEdge; }
get;
private set;
}
public override string ToString()
......@@ -25,7 +28,46 @@ namespace PcapDotNet.Packets.Transport
return LeftEdge + "-" + RightEdge;
}
private readonly uint _leftEdge;
private readonly uint _rightEdge;
/// <summary>
/// Two blocks are equal if the have the same left and right edges.
/// </summary>
public bool Equals(TcpOptionSelectiveAcknowledgmentBlock other)
{
return LeftEdge == other.LeftEdge &&
RightEdge == other.RightEdge;
}
/// <summary>
/// Two blocks are equal if the have the same left and right edges.
/// </summary>
public override bool Equals(object obj)
{
return (obj is TcpOptionSelectiveAcknowledgmentBlock &&
Equals((TcpOptionSelectiveAcknowledgmentBlock)obj));
}
/// <summary>
/// Two blocks are equal if the have the same left and right edges.
/// </summary>
public static bool operator ==(TcpOptionSelectiveAcknowledgmentBlock value1, TcpOptionSelectiveAcknowledgmentBlock value2)
{
return value1.Equals(value2);
}
/// <summary>
/// Two blocks are different if the have the different left or right edge.
/// </summary>
public static bool operator !=(TcpOptionSelectiveAcknowledgmentBlock value1, TcpOptionSelectiveAcknowledgmentBlock value2)
{
return !(value1 == value2);
}
/// <summary>
/// The hash code of a block is the xor between the hash code of left and right edges.
/// </summary>
public override int GetHashCode()
{
return LeftEdge.GetHashCode() ^ RightEdge.GetHashCode();
}
}
}
\ No newline at end of file
using System;
namespace PcapDotNet.Packets.Transport
{
/// <summary>
/// TCP Timestamps Option (TSopt):
/// +-------+-------+---------------------+---------------------+
/// |Kind=8 | 10 | TS Value (TSval) |TS Echo Reply (TSecr)|
/// +-------+-------+---------------------+---------------------+
/// 1 1 4 4
///
/// The Timestamps option carries two four-byte timestamp fields.
/// The Timestamp Value field (TSval) contains the current value of the timestamp clock of the TCP sending the option.
///
/// The Timestamp Echo Reply field (TSecr) is only valid if the ACK bit is set in the TCP header;
/// if it is valid, it echos a timestamp value that was sent by the remote TCP in the TSval field of a Timestamps option.
/// When TSecr is not valid, its value must be zero.
/// The TSecr value will generally be from the most recent Timestamp option that was received; however, there are exceptions that are explained below.
///
/// A TCP may send the Timestamps option (TSopt) in an initial <SYN> segment (i.e., segment containing a SYN bit and no ACK bit),
/// and may send a TSopt in other segments only if it received a TSopt in the initial <SYN> segment for the connection.
/// </summary>
[OptionTypeRegistration(typeof(TcpOptionType), TcpOptionType.Timestamp)]
public class TcpOptionTimestamp : TcpOptionComplex, IOptionComplexFactory, IEquatable<TcpOptionTimestamp>
{
/// <summary>
/// The number of bytes this option take.
/// </summary>
public const int OptionLength = 10;
public const int OptionValueLength = OptionLength - OptionHeaderLength;
public TcpOptionTimestamp(uint timestampValue, uint timestampEchoReply)
: base(TcpOptionType.Timestamp)
{
TimestampValue = timestampValue;
TimestampEchoReply = timestampEchoReply;
}
public TcpOptionTimestamp()
: this(0, 0)
{
}
public uint TimestampValue { get; private set; }
public uint TimestampEchoReply { get; private set; }
/// <summary>
/// The number of bytes this option will take.
/// </summary>
public override int Length
{
get { return OptionLength; }
}
/// <summary>
/// True iff this option may appear at most once in a datagram.
/// </summary>
public override bool IsAppearsAtMostOnce
{
get { return true; }
}
public bool Equals(TcpOptionTimestamp other)
{
if (other == null)
return false;
return TimestampValue == other.TimestampValue &&
TimestampEchoReply == other.TimestampEchoReply;
}
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionTimestamp);
}
/// <summary>
/// Tries to read the option from a buffer starting from the option value (after the type and length).
/// </summary>
/// <param name="buffer">The buffer to read the option from.</param>
/// <param name="offset">The offset to the first byte to read the buffer. Will be incremented by the number of bytes read.</param>
/// <param name="valueLength">The number of bytes the option value should take according to the length field that was already read.</param>
/// <returns>On success - the complex option read. On failure - null.</returns>
public Option CreateInstance(byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength != OptionValueLength)
return null;
uint timeStampValue = buffer.ReadUInt(ref offset, Endianity.Big);
uint timeStampEchoReply = buffer.ReadUInt(ref offset, Endianity.Big);
return new TcpOptionTimestamp(timeStampValue, timeStampEchoReply);
}
internal override void Write(byte[] buffer, ref int offset)
{
base.Write(buffer, ref offset);
buffer.Write(ref offset, TimestampValue, Endianity.Big);
buffer.Write(ref offset, TimestampEchoReply, Endianity.Big);
}
}
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ namespace PcapDotNet.Packets.Transport
SelectiveAcknowledgment = 5,
Echo = 6,
EchoReply = 7,
TimeStamp = 8,
Timestamp = 8,
PartialOrderConnectionPermitted = 9,
PartialOrderServiceProfile = 10,
ConnectionCount = 11,
......
......@@ -6,7 +6,10 @@ using PcapDotNet.Base;
namespace PcapDotNet.Packets.Transport
{
public class TcpOptionUnknown : TcpOptionComplex, IOptionUnkownFactory<TcpOptionType>, IEquatable<TcpOptionUnknown>
/// <summary>
/// An unknown TCP option.
/// </summary>
public class TcpOptionUnknown : TcpOptionComplex, IOptionUnknownFactory<TcpOptionType>, IEquatable<TcpOptionUnknown>
{
/// <summary>
/// The minimum number of bytes this option take.
......@@ -18,17 +21,26 @@ namespace PcapDotNet.Packets.Transport
/// </summary>
public const int OptionValueMinimumLength = OptionMinimumLength - OptionHeaderLength;
/// <summary>
/// Creates an unknown TCP option by the given type and data.
/// </summary>
public TcpOptionUnknown(TcpOptionType optionType, IList<byte> data)
: base(optionType)
{
Data = new ReadOnlyCollection<byte>(data);
}
/// <summary>
/// The default unknown option is with type 255 and no data.
/// </summary>
public TcpOptionUnknown()
: this((TcpOptionType)255, new byte[] { })
{
}
/// <summary>
/// The data of the unknown option.
/// </summary>
public ReadOnlyCollection<byte> Data { get; private set; }
/// <summary>
......@@ -47,6 +59,9 @@ namespace PcapDotNet.Packets.Transport
get { return false; }
}
/// <summary>
/// Two unknown options are equal iff they are of equal type and equal data.
/// </summary>
public bool Equals(TcpOptionUnknown other)
{
if (other == null)
......@@ -56,16 +71,30 @@ namespace PcapDotNet.Packets.Transport
Data.SequenceEqual(other.Data);
}
/// <summary>
/// Two unknown options are equal iff they are of equal type and equal data.
/// </summary>
public override bool Equals(TcpOption other)
{
return Equals(other as TcpOptionUnknown);
}
/// <summary>
/// The hash code for an unknown option is the hash code for the option type xored with the hash code of the data.
/// </summary>
public override int GetHashCode()
{
return base.GetHashCode() ^ Data.BytesSequenceGetHashCode();
}
/// <summary>
/// Creates an unknown option from its type and by reading a buffer for its value.
/// </summary>
/// <param name="optionType">The type of the unknown option.</param>
/// <param name="buffer">The buffer of bytes to read the value of the unknown option.</param>
/// <param name="offset">The offset in the buffer to start reading the bytes.</param>
/// <param name="valueLength">The number of bytes to read from the buffer.</param>
/// <returns>An option created from the given type and buffer.</returns>
public Option CreateInstance(TcpOptionType optionType, byte[] buffer, ref int offset, byte valueLength)
{
if (valueLength < OptionValueMinimumLength)
......
......@@ -41,13 +41,20 @@ namespace PcapDotNet.Packets.Transport
get { return ReadUShort(Offset.DestinationPort, Endianity.Big); }
}
/// <summary>
/// Checksum is the 16-bit one's complement of the one's complement sum of a pseudo header of information from the IP header,
/// the Transport header, and the data, padded with zero octets at the end (if necessary) to make a multiple of two octets.
/// </summary>
public abstract ushort Checksum { get; }
public abstract int ChecksumOffset { get; }
/// <summary>
/// True iff the checksum for the transport type is optional.
/// </summary>
public abstract bool IsChecksumOptional { get; }
protected static void WriteHeader(byte[] buffer, int offset, ushort sourcePort, ushort destinationPort)
internal abstract int ChecksumOffset { get; }
internal static void WriteHeader(byte[] buffer, int offset, ushort sourcePort, ushort destinationPort)
{
buffer.Write(offset + Offset.SourcePort, sourcePort, Endianity.Big);
buffer.Write(offset + Offset.DestinationPort, destinationPort, Endianity.Big);
......
......@@ -24,7 +24,6 @@ namespace PcapDotNet.Packets.Transport
/// |
/// | data octets ...
/// +---------------- ...
/// </summary>
public class UdpDatagram : TransportDatagram
{
......@@ -59,11 +58,6 @@ namespace PcapDotNet.Packets.Transport
get { return ReadUShort(Offset.Checksum, Endianity.Big); }
}
public override int ChecksumOffset
{
get { return Offset.Checksum; }
}
public override bool IsChecksumOptional
{
get { return true; }
......@@ -77,6 +71,11 @@ namespace PcapDotNet.Packets.Transport
get { return new Datagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength); }
}
internal override int ChecksumOffset
{
get { return Offset.Checksum; }
}
internal UdpDatagram(byte[] buffer, int offset, int length)
: base(buffer, offset, length)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment