/// <summary> /// Construct a new packet from the supplied data. /// </summary> /// <param name="contentsContainsGarbageByte"> /// True if the "contents" array contains a garbage (padding) byte that should NOT /// be factored into the Length field of the PUP. This is necessary so we can properly /// support the Echo protocol; since some PUP tests that check validation require that the /// PUP be echoed in its entirety (including the supposedly-ignorable "garbage" byte on /// odd-length PUPs) we need to be able to craft a PUP with one extra byte of content that's /// otherwise ignored... /// /// TODO: Update to use Serialization code rather than packing bytes by hand. /// </param> /// public PUP(PupType type, byte transportControl, UInt32 id, PUPPort destination, PUPPort source, byte[] contents, bool contentsContainsGarbageByte) { _rawData = null; // Ensure content length is <= 532 bytes. (Technically larger PUPs are allowed, // but conventionally they are not used and I want to keep things safe.) if (contents.Length > MAX_PUP_SIZE) { throw new InvalidOperationException("PUP size must not exceed 532 bytes."); } // // Sanity check: // "contentsContainGarbageByte" can ONLY be true if "contents" is of even length // if (contentsContainsGarbageByte && (contents.Length % 2) != 0) { throw new InvalidOperationException("Odd content length with garbage byte specified."); } TransportControl = transportControl; Type = type; ID = id; DestinationPort = destination; SourcePort = source; // Ensure contents are an even number of bytes. int contentLength = (contents.Length % 2) == 0 ? contents.Length : contents.Length + 1; Contents = new byte[contents.Length]; contents.CopyTo(Contents, 0); // Length is always the real length of the data (not padded to an even number) Length = (ushort)(PUP_HEADER_SIZE + PUP_CHECKSUM_SIZE + contents.Length); // Stuff data into raw array _rawData = new byte[PUP_HEADER_SIZE + PUP_CHECKSUM_SIZE + contentLength]; // // Subtract off one byte from the Length value if the contents contain a garbage byte. // (See header comments for function) if (contentsContainsGarbageByte) { Length--; } Helpers.WriteUShort(ref _rawData, Length, 0); _rawData[2] = TransportControl; _rawData[3] = (byte)Type; Helpers.WriteUInt(ref _rawData, ID, 4); DestinationPort.WriteToArray(ref _rawData, 8); SourcePort.WriteToArray(ref _rawData, 14); Array.Copy(Contents, 0, _rawData, 20, Contents.Length); // Calculate the checksum and stow it Checksum = CalculateChecksum(); Helpers.WriteUShort(ref _rawData, Checksum, _rawData.Length - 2); }
/// <summary> /// Same as above, but with no content (i.e. a zero-byte payload) /// </summary> /// <param name="type"></param> /// <param name="id"></param> /// <param name="destination"></param> /// <param name="source"></param> public PUP(PupType type, UInt32 id, PUPPort destination, PUPPort source) : this(type, id, destination, source, new byte[0]) { }
/// <summary> /// Same as above, no garbage byte. /// </summary> /// <param name="type"></param> /// <param name="id"></param> /// <param name="destination"></param> /// <param name="source"></param> /// <param name="contents"></param> public PUP(PupType type, UInt32 id, PUPPort destination, PUPPort source, byte[] contents) : this(type, id, destination, source, contents, false) { }
/// <summary> /// Constructor that assumes a transport control of 0 /// </summary> /// <param name="type"></param> /// <param name="id"></param> /// <param name="destination"></param> /// <param name="source"></param> /// <param name="contents"></param> /// <param name="contentsContainsGarbageByte"></param> public PUP(PupType type, UInt32 id, PUPPort destination, PUPPort source, byte[] contents, bool contentsContainsGarbageByte) : this(type, 0, id, destination, source, contents, contentsContainsGarbageByte) { }