diff options
Diffstat (limited to 'crypto/src/tls/DtlsReassembler.cs')
-rw-r--r-- | crypto/src/tls/DtlsReassembler.cs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/crypto/src/tls/DtlsReassembler.cs b/crypto/src/tls/DtlsReassembler.cs new file mode 100644 index 000000000..964c8eb84 --- /dev/null +++ b/crypto/src/tls/DtlsReassembler.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; + +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Tls +{ + internal sealed class DtlsReassembler + { + private readonly short m_msg_type; + private readonly byte[] m_body; + + private readonly IList m_missing = Platform.CreateArrayList(); + + internal DtlsReassembler(short msg_type, int length) + { + this.m_msg_type = msg_type; + this.m_body = new byte[length]; + this.m_missing.Add(new Range(0, length)); + } + + internal short MsgType + { + get { return m_msg_type; } + } + + internal byte[] GetBodyIfComplete() + { + return m_missing.Count > 0 ? null : m_body; + } + + internal void ContributeFragment(short msg_type, int length, byte[] buf, int off, int fragment_offset, + int fragment_length) + { + int fragment_end = fragment_offset + fragment_length; + + if (m_msg_type != msg_type || m_body.Length != length || fragment_end > length) + return; + + if (fragment_length == 0) + { + // NOTE: Empty messages still require an empty fragment to complete it + if (fragment_offset == 0 && m_missing.Count > 0) + { + Range firstRange = (Range)m_missing[0]; + if (firstRange.End == 0) + { + m_missing.RemoveAt(0); + } + } + return; + } + + for (int i = 0; i < m_missing.Count; ++i) + { + Range range = (Range)m_missing[i]; + if (range.Start >= fragment_end) + break; + + if (range.End > fragment_offset) + { + int copyStart = System.Math.Max(range.Start, fragment_offset); + int copyEnd = System.Math.Min(range.End, fragment_end); + int copyLength = copyEnd - copyStart; + + Array.Copy(buf, off + copyStart - fragment_offset, m_body, copyStart, copyLength); + + if (copyStart == range.Start) + { + if (copyEnd == range.End) + { + m_missing.RemoveAt(i--); + } + else + { + range.Start = copyEnd; + } + } + else + { + if (copyEnd != range.End) + { + m_missing.Insert(++i, new Range(copyEnd, range.End)); + } + range.End = copyStart; + } + } + } + } + + internal void Reset() + { + m_missing.Clear(); + m_missing.Add(new Range(0, m_body.Length)); + } + + private sealed class Range + { + private int m_start, m_end; + + internal Range(int start, int end) + { + this.m_start = start; + this.m_end = end; + } + + public int Start + { + get { return m_start; } + set { this.m_start = value; } + } + + public int End + { + get { return m_end; } + set { this.m_end = value; } + } + } + } +} |