Skip to content

Commit

Permalink
feat: Added broadcasting
Browse files Browse the repository at this point in the history
  • Loading branch information
TwoTenPvP committed Jan 13, 2020
1 parent 5d1cad8 commit d8b9b37
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 46 deletions.
5 changes: 4 additions & 1 deletion Ruffles/Configuration/Constants.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Ruffles.Configuration
using System.Net;

namespace Ruffles.Configuration
{
internal static class Constants
{
Expand All @@ -9,5 +11,6 @@ internal static class Constants
internal static readonly int SOCKET_PACKET_TTL = 64;
internal static readonly int MAX_CHANNELS = byte.MaxValue;
internal static readonly int MAX_FRAGMENTS = 32768;
internal static readonly IPAddress IPv6AllDevicesMulticastAddress = IPAddress.Parse("FF02:0:0:0:0:0:0:1");
}
}
6 changes: 5 additions & 1 deletion Ruffles/Configuration/SocketConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ public class SocketConfig
/// <summary>
/// Whether or not unconnected messages should be allowed.
/// </summary>
public bool AllowUnconnectedMessages = false;
public bool AllowUnconnectedMessages = false;
/// <summary>
/// Whether or not broadcast messages should be allowed.
/// </summary>
public bool AllowBroadcasts = true;

// Performance
/// <summary>
Expand Down
6 changes: 5 additions & 1 deletion Ruffles/Core/NetworkEventType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public enum NetworkEventType
/// <summary>
/// An endpoint sent unconnected data.
/// </summary>
UnconnectedData
UnconnectedData,
/// <summary>
/// An endpoint sent broadcast data.
/// </summary>
BroadcastData
}
}
176 changes: 134 additions & 42 deletions Ruffles/Core/RuffleSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -322,18 +322,28 @@ private bool Bind(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool i

private bool SetupAndBind(Socket socket, IPEndPoint endpoint)
{
// Dont fragment is only supported on IPv4
// Dont fragment and broadcasting is only supported on IPv4
if (socket.AddressFamily == AddressFamily.InterNetwork)
{
try
{
socket.DontFragment = true;
}
catch (SocketException)
catch (SocketException e)
{
// TODO: Handle
// This shouldnt happen when the OS supports it.
// This is used for path MTU to do application level fragmentation
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable DontFragment: " + e);
// TODO: Handle
// This shouldnt happen when the OS supports it.
// This is used for path MTU to do application level fragmentation
}

try
{
socket.EnableBroadcast = true;
}
catch (SocketException e)
{
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Failed to enable broadcasting: " + e);
}
}

Expand Down Expand Up @@ -423,12 +433,12 @@ private bool SetupAndBind(Socket socket, IPEndPoint endpoint)
/// </summary>
/// <param name="payload">Payload.</param>
/// <param name="endpoint">Endpoint.</param>
public void SendUnconnected(ArraySegment<byte> payload, IPEndPoint endpoint)
public bool SendUnconnected(ArraySegment<byte> payload, IPEndPoint endpoint)
{
if (payload.Count > Config.MinimumMTU)
{
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Tried to send unconnected message that was too large. [Size=" + payload.Count + "] [MaxMessageSize=" + Config.MaxFragments + "]");
return;
return false;
}

// Allocate the memory
Expand All @@ -441,10 +451,60 @@ public void SendUnconnected(ArraySegment<byte> payload, IPEndPoint endpoint)
Buffer.BlockCopy(payload.Array, payload.Offset, memory.Buffer, 1, payload.Count);

// Send the packet
SendRaw(endpoint, new ArraySegment<byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount));
bool success = SendRaw(endpoint, new ArraySegment<byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount));

// Release memory
MemoryManager.DeAlloc(memory);
MemoryManager.DeAlloc(memory);

return success;
}

/// <summary>
/// Sends a broadcast packet to all local devices.
/// </summary>
/// <returns><c>true</c>, if broadcast was sent, <c>false</c> otherwise.</returns>
/// <param name="payload">The payload to send.</param>
/// <param name="port">The port to send the broadcast to.</param>
public bool SendBroadcast(ArraySegment<byte> payload, int port)
{
if (payload.Count > Config.MinimumMTU)
{
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Tried to send broadcast message that was too large. [Size=" + payload.Count + "] [MaxMessageSize=" + Config.MaxFragments + "]");
return false;
}

bool broadcastSuccess = false;
bool multicastSuccess = false;

// TODO: If payload has extra space. No need to realloc

// Alloc memory with space for header
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)(payload.Count + 1));

// Write header
memory.Buffer[0] = HeaderPacker.Pack(MessageType.Broadcast);

// Copy payload
Buffer.BlockCopy(payload.Array, payload.Offset, memory.Buffer, 1, payload.Count);

try
{
if (ipv4Socket != null)
{
broadcastSuccess = ipv4Socket.SendTo(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port)) > 0;
}

if (ipv6Socket != null)
{
multicastSuccess = ipv6Socket.SendTo(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount, SocketFlags.None, new IPEndPoint(Constants.IPv6AllDevicesMulticastAddress, port)) > 0;
}
}
catch (Exception e)
{
if (Logging.CurrentLogLevel <= LogLevel.Debug) Logging.LogInfo("Error when sending broadcast: " + e);
}

return broadcastSuccess || multicastSuccess;
}

/// <summary>
Expand Down Expand Up @@ -679,17 +739,17 @@ public NetworkEvent Poll()
};
}

internal void SendRaw(EndPoint endpoint, ArraySegment<byte> payload)
internal bool SendRaw(EndPoint endpoint, ArraySegment<byte> payload)
{
try
{
if (endpoint.AddressFamily == AddressFamily.InterNetwork)
{
int sent = ipv4Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint);
return ipv4Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
}
else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6)
{
int sent = ipv6Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint);
return ipv6Socket.SendTo(payload.Array, payload.Offset, payload.Count, SocketFlags.None, endpoint) > 0;
}
}
catch (SocketException e)
Expand All @@ -704,7 +764,9 @@ internal void SendRaw(EndPoint endpoint, ArraySegment<byte> payload)
catch (Exception e)
{
if (Logging.CurrentLogLevel <= LogLevel.Error) Logging.LogError("Error when sending through socket: " + e);
}
}

return false;
}

private readonly List<ArraySegment<byte>> _mergeSegmentResults = new List<ArraySegment<byte>>();
Expand Down Expand Up @@ -1030,35 +1092,6 @@ internal void HandlePacket(ArraySegment<byte> payload, EndPoint endpoint, bool a
}
}
break;
case MessageType.UnconnectedData:
{
if (!Config.AllowUnconnectedMessages)
{
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got unconnected message but SocketConfig.AllowUnconnectedMessages is disabled.");
return;
}

// Alloc memory that can be borrowed to userspace
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)payload.Count - 1);

// Copy payload to borrowed memory
Buffer.BlockCopy(payload.Array, payload.Offset + 1, memory.Buffer, 0, payload.Count - 1);

// Send to userspace
PublishEvent(new NetworkEvent()
{
Connection = null,
Socket = this,
Type = NetworkEventType.UnconnectedData,
AllowUserRecycle = true,
Data = new ArraySegment<byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount),
InternalMemory = memory,
SocketReceiveTime = NetTime.Now,
ChannelId = 0,
MemoryManager = MemoryManager
});
}
break;
case MessageType.MTURequest:
{
if (!Config.EnablePathMTU)
Expand Down Expand Up @@ -1091,6 +1124,65 @@ internal void HandlePacket(ArraySegment<byte> payload, EndPoint endpoint, bool a
}
}
break;
case MessageType.UnconnectedData:
{
if (!Config.AllowUnconnectedMessages)
{
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got unconnected message but SocketConfig.AllowUnconnectedMessages is false.");
return;
}

// Alloc memory that can be borrowed to userspace
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)payload.Count - 1);

// Copy payload to borrowed memory
Buffer.BlockCopy(payload.Array, payload.Offset + 1, memory.Buffer, 0, payload.Count - 1);

// Send to userspace
PublishEvent(new NetworkEvent()
{
Connection = null,
Socket = this,
Type = NetworkEventType.UnconnectedData,
AllowUserRecycle = true,
Data = new ArraySegment<byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount),
InternalMemory = memory,
SocketReceiveTime = NetTime.Now,
ChannelId = 0,
MemoryManager = MemoryManager
});
}
break;
case MessageType.Broadcast:
{
if (!Config.AllowBroadcasts)
{
if (Logging.CurrentLogLevel <= LogLevel.Warning) Logging.LogWarning("Got broadcast message but SocketConfig.AllowBroadcasts is false.");
return;
}

// Alloc memory that can be borrowed to userspace
HeapMemory memory = MemoryManager.AllocHeapMemory((uint)payload.Count - 1);

// Copy payload to borrowed memory
Buffer.BlockCopy(payload.Array, payload.Offset + 1, memory.Buffer, 0, payload.Count - 1);

// Send to userspace
PublishEvent(new NetworkEvent()
{
Connection = null,
Socket = this,
Type = NetworkEventType.BroadcastData,
AllowUserRecycle = true,
Data = new ArraySegment<byte>(memory.Buffer, (int)memory.VirtualOffset, (int)memory.VirtualCount),
InternalMemory = memory,
SocketReceiveTime = NetTime.Now,
ChannelId = 0,
MemoryManager = MemoryManager
});
}
break;

}
}

Expand Down
1 change: 1 addition & 0 deletions Ruffles/Messaging/MessageType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal enum MessageType : byte
UnconnectedData,
MTURequest,
MTUResponse,
Broadcast,
// Unknown should never be sent down the wire. Keep it at the highest binary
Unknown = 255
}
Expand Down
2 changes: 1 addition & 1 deletion Ruffles/Simulation/NetworkSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal struct OutgoingPacket
public Connection Connection;
}

internal delegate void SendDelegate(EndPoint endpoint, ArraySegment<byte> payload);
internal delegate bool SendDelegate(EndPoint endpoint, ArraySegment<byte> payload);

private readonly System.Random random = new System.Random();
private readonly object _lock = new object();
Expand Down

0 comments on commit d8b9b37

Please sign in to comment.