217 lines
8.6 KiB
C#
Raw Normal View History

2022-09-06 21:46:35 +08:00
using GTA.UI;
using Lidgren.Network;
2022-05-22 15:55:26 +08:00
using RageCoop.Core;
2022-07-20 17:50:01 +08:00
using System;
2022-07-29 21:15:23 +08:00
using System.Collections.Generic;
2022-09-06 21:46:35 +08:00
using System.Net;
2022-07-19 17:15:53 +08:00
using System.Security.Cryptography;
2022-07-20 17:50:01 +08:00
using System.Threading;
using System.Threading.Tasks;
2022-08-18 17:45:08 +08:00
2022-05-22 15:55:26 +08:00
namespace RageCoop.Client
{
internal static partial class Networking
2022-05-22 15:55:26 +08:00
{
2022-08-11 16:25:38 +08:00
public static CoopPeer Peer;
2022-09-06 21:46:35 +08:00
public static float Latency => ServerConnection.AverageRoundtripTime / 2;
public static bool ShowNetworkInfo = false;
2022-08-06 12:32:04 +08:00
public static Security Security;
public static NetConnection ServerConnection;
private static readonly Dictionary<int, Action<PacketType, NetIncomingMessage>> PendingResponses = new Dictionary<int, Action<PacketType, NetIncomingMessage>>();
internal static readonly Dictionary<PacketType, Func<NetIncomingMessage, Packet>> RequestHandlers = new Dictionary<PacketType, Func<NetIncomingMessage, Packet>>();
2022-09-06 21:46:35 +08:00
internal static float SimulatedLatency = 0;
2022-07-31 20:47:04 +08:00
public static bool IsConnecting { get; private set; }
2022-08-18 18:59:38 +08:00
public static IPEndPoint _targetServerEP;
static Networking()
{
2022-09-06 21:46:35 +08:00
Security = new Security(Main.Logger);
Packets.CustomEvent.ResolveHandle = _resolveHandle;
}
2022-09-06 21:46:35 +08:00
public static void ToggleConnection(string address, string username = null, string password = null, PublicKey publicKey = null)
2022-05-22 15:55:26 +08:00
{
2022-09-06 21:46:35 +08:00
Menus.CoopMenu.Menu.Visible = false;
2022-08-11 18:25:01 +08:00
Peer?.Shutdown("Bye");
if (IsOnServer)
2022-05-22 15:55:26 +08:00
{
2022-08-11 14:59:09 +02:00
// ?
2022-05-22 15:55:26 +08:00
}
2022-09-06 21:46:35 +08:00
else if (IsConnecting)
{
2022-07-31 20:47:04 +08:00
_publicKeyReceived.Set();
IsConnecting = false;
2022-08-12 20:40:50 +08:00
Notification.Show("Connection has been canceled");
2022-07-31 20:47:04 +08:00
}
2022-05-22 15:55:26 +08:00
else
{
2022-08-11 18:25:01 +08:00
Peer?.Dispose();
2022-07-31 20:47:04 +08:00
IsConnecting = true;
2022-06-24 10:33:36 +08:00
password = password ?? Main.Settings.Password;
2022-09-06 21:46:35 +08:00
username = username ?? Main.Settings.Username;
2022-08-04 17:14:07 +08:00
2022-05-22 15:55:26 +08:00
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
{
2022-08-02 17:43:18 +08:00
AutoFlushSendQueue = false,
2022-09-06 21:46:35 +08:00
SimulatedMinimumLatency = SimulatedLatency,
SimulatedRandomLatency = 0,
2022-08-08 17:03:41 +08:00
AcceptIncomingConnections = true,
MaximumConnections = 32,
PingInterval = 5
2022-05-22 15:55:26 +08:00
};
2022-06-24 10:33:36 +08:00
config.EnableMessageType(NetIncomingMessageType.UnconnectedData);
2022-08-06 12:32:04 +08:00
config.EnableMessageType(NetIncomingMessageType.NatIntroductionSuccess);
2022-05-22 15:55:26 +08:00
string[] ip = new string[2];
int idx = address.LastIndexOf(':');
if (idx != -1)
{
ip[0] = address.Substring(0, idx);
ip[1] = address.Substring(idx + 1);
}
if (ip.Length != 2)
{
throw new Exception("Malformed URL");
}
PlayerList.Cleanup();
2022-05-22 15:55:26 +08:00
EntityPool.AddPlayer();
2022-09-06 21:46:35 +08:00
if (publicKey == null && !string.IsNullOrEmpty(password) && !Menus.CoopMenu.ShowPopUp("", "WARNING", "Server's IP can be spoofed when using direct connection, do you wish to continue?", "", true))
2022-08-18 17:45:08 +08:00
{
2022-09-06 21:46:35 +08:00
IsConnecting = false;
2022-08-18 17:45:08 +08:00
return;
}
2022-06-24 10:33:36 +08:00
Task.Run(() =>
2022-05-22 15:55:26 +08:00
{
2022-07-02 17:14:56 +08:00
try
{
2022-09-06 21:46:35 +08:00
_targetServerEP = CoreUtils.StringToEndPoint(address);
// Ensure static constructor invocation
2022-07-02 17:14:56 +08:00
DownloadManager.Cleanup();
2022-08-11 16:25:38 +08:00
Peer = new CoopPeer(config);
2022-09-06 21:46:35 +08:00
Peer.OnMessageReceived += (s, m) =>
2022-08-11 16:25:38 +08:00
{
try { ProcessMessage(m); }
catch (Exception ex) { Main.Logger.Error(ex); }
};
2022-08-12 20:40:50 +08:00
Main.QueueAction(() => { Notification.Show($"~y~Trying to connect..."); });
2022-09-06 21:46:35 +08:00
Menus.CoopMenu._serverConnectItem.Enabled = false;
2022-07-02 17:14:56 +08:00
Security.Regen();
2022-09-06 21:46:35 +08:00
if (publicKey == null)
{
if (!GetServerPublicKey(ip[0], int.Parse(ip[1])))
2022-08-18 17:45:08 +08:00
{
2022-09-06 21:46:35 +08:00
Menus.CoopMenu._serverConnectItem.Enabled = true;
2022-08-18 17:45:08 +08:00
throw new TimeoutException("Failed to retrive server's public key");
}
}
2022-09-06 21:46:35 +08:00
else
{
Security.SetServerPublicKey(publicKey.Modulus, publicKey.Exponent);
2022-07-11 11:06:31 +08:00
}
2022-07-20 17:50:01 +08:00
2022-08-18 17:45:08 +08:00
// Send handshake packet
2022-08-06 12:32:04 +08:00
NetOutgoingMessage outgoingMessage = Peer.CreateMessage();
2022-07-02 17:14:56 +08:00
var handshake = new Packets.Handshake()
{
2022-09-06 21:46:35 +08:00
PedID = Main.LocalPlayerID,
Username = username,
2022-08-16 23:17:04 +08:00
ModVersion = Main.Version.ToString(),
2022-09-06 21:46:35 +08:00
PasswordEncrypted = Security.Encrypt(password.GetBytes()),
2022-08-11 16:25:38 +08:00
InternalEndPoint = new System.Net.IPEndPoint(CoreUtils.GetLocalAddress(ip[0]), Peer.Port)
2022-07-02 17:14:56 +08:00
};
Security.GetSymmetricKeysCrypted(out handshake.AesKeyCrypted, out handshake.AesIVCrypted);
handshake.Pack(outgoingMessage);
2022-08-06 12:32:04 +08:00
ServerConnection = Peer.Connect(ip[0], short.Parse(ip[1]), outgoingMessage);
2022-06-24 10:33:36 +08:00
2022-07-02 17:14:56 +08:00
}
2022-07-20 17:50:01 +08:00
catch (Exception ex)
2022-06-24 10:33:36 +08:00
{
2022-07-11 11:06:31 +08:00
Main.Logger.Error("Cannot connect to server: ", ex);
2022-09-06 21:46:35 +08:00
Main.QueueAction(() => Notification.Show("Cannot connect to server: " + ex.Message));
2022-07-02 17:14:56 +08:00
}
2022-09-06 21:46:35 +08:00
IsConnecting = false;
2022-06-24 10:33:36 +08:00
});
2022-05-22 15:55:26 +08:00
}
}
2022-08-11 14:59:09 +02:00
public static bool IsOnServer { get => ServerConnection?.Status == NetConnectionStatus.Connected; }
2022-07-20 17:50:01 +08:00
2022-05-22 15:55:26 +08:00
#region -- PLAYER --
private static void PlayerConnect(Packets.PlayerConnect packet)
2022-05-22 15:55:26 +08:00
{
2022-08-08 17:03:41 +08:00
var p = new Player
2022-05-22 15:55:26 +08:00
{
2022-08-27 14:17:10 +08:00
ID = packet.PedID,
2022-09-06 21:46:35 +08:00
Username = packet.Username,
2022-05-22 15:55:26 +08:00
};
PlayerList.SetPlayer(packet.PedID, packet.Username);
2022-05-22 15:55:26 +08:00
Main.Logger.Debug($"player connected:{p.Username}");
2022-08-10 20:42:47 +08:00
Main.QueueAction(() =>
GTA.UI.Notification.Show($"~h~{p.Username}~h~ connected."));
2022-05-22 15:55:26 +08:00
}
private static void PlayerDisconnect(Packets.PlayerDisconnect packet)
2022-05-22 15:55:26 +08:00
{
2022-08-11 15:38:19 +08:00
var player = PlayerList.GetPlayer(packet.PedID);
2022-09-06 21:46:35 +08:00
if (player == null) { return; }
PlayerList.RemovePlayer(packet.PedID);
2022-09-06 21:46:35 +08:00
Main.QueueAction(() =>
{
2022-08-11 15:38:19 +08:00
EntityPool.RemoveAllFromPlayer(packet.PedID);
GTA.UI.Notification.Show($"~h~{player.Username}~h~ left.");
});
2022-05-22 15:55:26 +08:00
}
#endregion // -- PLAYER --
#region -- GET --
2022-09-06 21:46:35 +08:00
private static bool GetServerPublicKey(string host, int port, int timeout = 10000)
2022-06-24 10:33:36 +08:00
{
2022-09-06 21:46:35 +08:00
Security.ServerRSA = null;
2022-08-06 12:32:04 +08:00
var msg = Peer.CreateMessage();
2022-07-20 17:50:01 +08:00
new Packets.PublicKeyRequest().Pack(msg);
2022-08-12 20:40:50 +08:00
Peer.SendUnconnectedMessage(msg, host, port);
2022-09-06 21:46:35 +08:00
return _publicKeyReceived.WaitOne(timeout) && Security.ServerRSA != null;
2022-06-24 10:33:36 +08:00
}
public static void GetResponse<T>(Packet request, Action<T> callback, ConnectionChannel channel = ConnectionChannel.RequestResponse) where T : Packet, new()
2022-07-19 17:15:53 +08:00
{
var received = new AutoResetEvent(false);
var id = NewRequestID();
PendingResponses.Add(id, (type, p) =>
{
var result = new T();
2022-08-06 10:43:24 +08:00
result.Deserialize(p);
2022-07-19 17:15:53 +08:00
callback(result);
});
2022-08-06 12:32:04 +08:00
var msg = Peer.CreateMessage();
2022-07-19 17:15:53 +08:00
msg.Write((byte)PacketType.Request);
msg.Write(id);
request.Pack(msg);
2022-09-06 21:46:35 +08:00
Peer.SendMessage(msg, ServerConnection, NetDeliveryMethod.ReliableOrdered, (int)channel);
2022-07-19 17:15:53 +08:00
}
#endregion
2022-07-19 17:15:53 +08:00
private static int NewRequestID()
{
int ID = 0;
2022-09-06 21:46:35 +08:00
while ((ID == 0) || PendingResponses.ContainsKey(ID))
2022-07-19 17:15:53 +08:00
{
byte[] rngBytes = new byte[4];
RandomNumberGenerator.Create().GetBytes(rngBytes);
// Convert the bytes into an integer
ID = BitConverter.ToInt32(rngBytes, 0);
}
return ID;
}
2022-05-22 15:55:26 +08:00
}
}