Skip to content

Commit

Permalink
fix: max packet size, fixes #1
Browse files Browse the repository at this point in the history
  • Loading branch information
richardschneider committed Mar 2, 2018
1 parent 2fee19e commit 3326c93
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 6 deletions.
44 changes: 38 additions & 6 deletions src/MulticastService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class MulticastService
Timer nicTimer;
bool ip6;
IPEndPoint mdnsEndpoint;
// IP header (20 bytes for IPv4; 40 bytes for IPv6) and the UDP header(8 bytes).
const int packetOverhead = 48;
int maxPacketSize;

/// <summary>
/// Set the default TTLs.
Expand Down Expand Up @@ -111,6 +114,7 @@ public MulticastService()
/// </summary>
public void Start()
{
maxPacketSize = 9000 - packetOverhead;
listenerCancellation = new CancellationTokenSource();
knownNics.Clear();
socket = new Socket(
Expand Down Expand Up @@ -154,6 +158,7 @@ void FindNetworkInterfaces(object state)
SocketOptionLevel.IPv6,
SocketOptionName.AddMembership,
mopt);
maxPacketSize = Math.Min(maxPacketSize, properties.GetIPv6Properties().Mtu - packetOverhead);
}
else
{
Expand All @@ -163,6 +168,7 @@ void FindNetworkInterfaces(object state)
SocketOptionLevel.IP,
SocketOptionName.AddMembership,
mopt);
maxPacketSize = Math.Min(maxPacketSize, properties.GetIPv4Properties().Mtu - packetOverhead);
}
knownNics.Add(nic);
}
Expand Down Expand Up @@ -218,11 +224,11 @@ public void Stop()
/// Answers to any query are obtained on the <see cref="AnswerReceived"/>
/// event.
/// </remarks>
/// <exception cref="InvalidOperationException">
/// When the service has not started.
/// </exception>
public void SendQuery(string name, Class klass = Class.IN)
{
if (socket == null)
throw new InvalidOperationException("MDNS is not started");

var msg = new Message
{
Id = 1,
Expand All @@ -248,10 +254,15 @@ public void SendQuery(string name, Class klass = Class.IN)
/// Answers to any query are obtained on the <see cref="AnswerReceived"/>
/// event.
/// </remarks>
/// <exception cref="InvalidOperationException">
/// When the service has not started.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// When the serialised <paramref name="msg"/> is too large.
/// </exception>
public void SendQuery(Message msg)
{
var packet = msg.ToByteArray();
socket.SendTo(packet, 0, packet.Length, SocketFlags.None, mdnsEndpoint);
Send(msg);
}

/// <summary>
Expand All @@ -260,14 +271,35 @@ public void SendQuery(Message msg)
/// <param name="answer">
/// The answer message.
/// </param>
/// <exception cref="InvalidOperationException">
/// When the service has not started.
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">
/// When the serialised <paramref name="msg"/> is too large.
/// </exception>
/// <remarks>
/// The <see cref="Message.AA"/> flag is always set to true.
/// </remarks>
/// <see cref="QueryReceived"/>
/// <seealso cref="Message.CreateResponse"/>
public void SendAnswer(Message answer)
{
// All MDNS answers are authoritative.
answer.AA = true;

var packet = answer.ToByteArray();
Send(answer);
}

private void Send(Message msg)
{
if (socket == null)
throw new InvalidOperationException("MDNS is not started");

var packet = msg.ToByteArray();
if (packet.Length > maxPacketSize)
{
throw new ArgumentOutOfRangeException($"Exceeds max packet size of {maxPacketSize}.");
}
socket.SendTo(packet, 0, packet.Length, SocketFlags.None, mdnsEndpoint);
}

Expand Down
46 changes: 46 additions & 0 deletions test/MulticastServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,51 @@ public void Nics()
mdns.Stop();
}
}

[TestMethod]
public void SendQuery_TooBig()
{
var done = new ManualResetEvent(false);
var mdns = new MulticastService();
mdns.NetworkInterfaceDiscovered += (s, e) => done.Set();
mdns.Start();
try
{
Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "no nic");
var query = new Message();
query.Questions.Add(new Question { Name = "foo.bar.org" });
query.AdditionalRecords.Add(new NULLRecord { Name = "foo.bar.org", Data = new byte[9000] });
ExceptionAssert.Throws<ArgumentOutOfRangeException>(() => {
mdns.SendQuery(query);
});
}
finally
{
mdns.Stop();
}
}

[TestMethod]
public void SendAnswer_TooBig()
{
var done = new ManualResetEvent(false);
var mdns = new MulticastService();
mdns.NetworkInterfaceDiscovered += (s, e) => done.Set();
mdns.Start();
try
{
Assert.IsTrue(done.WaitOne(TimeSpan.FromSeconds(1)), "no nic");
var answer = new Message();
answer.Answers.Add(new ARecord { Name = "foo.bar.org", Address = IPAddress.Loopback });
answer.AdditionalRecords.Add(new NULLRecord { Name = "foo.bar.org", Data = new byte[9000] });
ExceptionAssert.Throws<ArgumentOutOfRangeException>(() => {
mdns.SendAnswer(answer);
});
}
finally
{
mdns.Stop();
}
}
}
}

0 comments on commit 3326c93

Please sign in to comment.