// This file is provided under The MIT License as part of RiptideNetworking.
// Copyright (c) Tom Weiland
// For additional information please see the included LICENSE.md file or view it on GitHub:
// https://github.com/RiptideNetworking/Riptide/blob/main/LICENSE.md
using System;
using System.Collections.Generic;
using System.Net;
namespace Riptide.Transports.Udp
{
/// A server which can accept connections from s.
public class UdpServer : UdpPeer, IServer
{
///
public event EventHandler Connected;
///
public event EventHandler DataReceived;
///
public ushort Port { get; private set; }
/// The currently open connections, accessible by their endpoints.
private Dictionary connections;
/// The IP address to bind the socket to, if any.
private readonly IPAddress listenAddress;
///
public UdpServer(SocketMode mode = SocketMode.Both, int socketBufferSize = DefaultSocketBufferSize) : base(mode, socketBufferSize) { }
/// Initializes the transport, binding the socket to a specific IP address.
/// The IP address to bind the socket to.
/// How big the socket's send and receive buffers should be.
public UdpServer(IPAddress listenAddress, int socketBufferSize = DefaultSocketBufferSize) : base(SocketMode.Both, socketBufferSize)
{
this.listenAddress = listenAddress;
}
///
public void Start(ushort port)
{
Port = port;
connections = new Dictionary();
OpenSocket(listenAddress, port);
}
/// Decides what to do with a connection attempt.
/// The endpoint the connection attempt is coming from.
/// Whether or not the connection attempt was from a new connection.
private bool HandleConnectionAttempt(IPEndPoint fromEndPoint)
{
if (connections.ContainsKey(fromEndPoint))
return false;
UdpConnection connection = new UdpConnection(fromEndPoint, this);
connections.Add(fromEndPoint, connection);
OnConnected(connection);
return true;
}
///
public void Close(Connection connection)
{
if (connection is UdpConnection udpConnection)
connections.Remove(udpConnection.RemoteEndPoint);
}
///
public void Shutdown()
{
CloseSocket();
connections.Clear();
}
/// Invokes the event.
/// The successfully established connection.
protected virtual void OnConnected(Connection connection)
{
Connected?.Invoke(this, new ConnectedEventArgs(connection));
}
///
protected override void OnDataReceived(byte[] dataBuffer, int amount, IPEndPoint fromEndPoint)
{
if ((MessageHeader)(dataBuffer[0] & Message.HeaderBitmask) == MessageHeader.Connect && !HandleConnectionAttempt(fromEndPoint))
return;
if (connections.TryGetValue(fromEndPoint, out Connection connection) && !connection.IsNotConnected)
DataReceived?.Invoke(this, new DataReceivedEventArgs(dataBuffer, amount, connection));
}
}
}