internal virtual async void HandleClient()
{
string kickMessage = "Failed to login";
bool success = true;
try
{
ClientRemoteInterface clientRemoteInterface =
ClientRemoteInterface.Create(new NetworkStream(_networkSocket), 60);
_clientEndPoint = new ProxyEndPoint(clientRemoteInterface, clientRemoteInterface.EndPoint.Version);
_clientEndPoint.RemoteEndPoint = (IPEndPoint) _networkSocket.RemoteEndPoint;
Packet packet = await clientRemoteInterface.ReadPacketAsync ();
var listPing = packet as PlayerListPing;
var handshakeRequest = packet as HandshakeRequest;
if (listPing != null) // send motd
{
_isMotDRequest = true;
if (listPing.MagicByte == 1)
{
//Plugin Message begins @ 1.6
AdditionalServerListInformation additionalInformation = null;
try
{
clientRemoteInterface.EndPoint.Stream.ReadTimeout = 1;
}
catch (InvalidOperationException)
{
}
try
{
additionalInformation =
await clientRemoteInterface.ReadAdditionalServerListInformationAsync();
}
catch (TimeoutException timeOut)
{
}
additionalInformation = additionalInformation ?? new AdditionalServerListInformation
{
Host = _server.LocalEndPoint.Address.ToString(),
Port = _server.LocalEndPoint.Port,
ProtocolVersion = (byte) _server.PublicMinecraftVersion
};
additionalInformation.ProtocolVersion = ProtocolInformation.MaxSupportedClientVersion <
additionalInformation.ProtocolVersion
? (byte) ProtocolInformation.MaxSupportedClientVersion
: additionalInformation.ProtocolVersion;
additionalInformation.ProtocolVersion = ProtocolInformation.MinSupportedClientVersion >
additionalInformation.ProtocolVersion
? (byte) ProtocolInformation.MinSupportedClientVersion
: additionalInformation.ProtocolVersion;
string response = ProtocolHelper.BuildMotDString(additionalInformation.ProtocolVersion,
_server.ServerVersionName, _server.MotD,
_server.ConnectedUsers, _server.MaxUsers);
await KickUserAsync(response);
}
else
{
string response = ProtocolHelper.BuildMotDString(_server.MotD, _server.ConnectedUsers,
_server.MaxUsers);
await KickUserAsync(response);
}
return;
}
if (handshakeRequest != null)
{
Username = handshakeRequest.UserName;
Host = handshakeRequest.Host;
ClientEndPoint.ProtocolVersion = handshakeRequest.ProtocolVersion;
if (handshakeRequest.ProtocolVersion < ProtocolInformation.MinSupportedClientVersion)
{
await KickUserAsync("Outdated Client");
return;
}
else if (handshakeRequest.ProtocolVersion > ProtocolInformation.MaxSupportedClientVersion)
{
await KickUserAsync("Outdated Server");
return;
}
var args = new UserEventArgs(this);
_server.PluginManager.TriggerPlugin.OnPlayerConnected(args);
if (args.Canceled)
{
await ClientEndPoint.SendPacketAsync(new DisconnectPacket {Reason = args.CancelMessage});
_networkSocket.Close ();
_server.RemoveConnection(this);
return;
}
bool onlineMode = _server.OnlineModeEnabled(this);
string serverId = onlineMode ? Session.GetSessionHash () : "-";
var randomBuffer = new byte[4];
_random.NextBytes(randomBuffer);
await ClientEndPoint.SendPacketAsync(new EncryptionKeyRequest
{
ServerId = serverId,
PublicKey =
AsnKeyBuilder.PublicKeyToX509(_server.RSAKeyPair).
GetBytes (),
VerifyToken = randomBuffer
});
do
{
packet = await ClientEndPoint.ReceivePacketAsync ();
} while (packet is KeepAlive);
var encryptionKeyResponse = (EncryptionKeyResponse) packet;
byte[] verification = ProtocolSecurity.RsaDecrypt(
encryptionKeyResponse.VerifyToken.ToArray (), _server.RSACryptoServiceProvider, true);
byte[] sharedKey = ProtocolSecurity.RsaDecrypt(
encryptionKeyResponse.SharedKey.ToArray (), _server.RSACryptoServiceProvider, true);
if (verification.Length != randomBuffer.Length
|| !verification.Zip(randomBuffer, (a, b) => a == b).All(a => a))
{
await KickUserAsync("Verify token failure");
_logger.Error("Failed to login a Client, Verify token failure");
return;
}
await ClientEndPoint.SendPacketAsync(new EncryptionKeyResponse {SharedKey = new byte[0]});
ClientEndPoint.ConnectionKey = sharedKey;
ClientEndPoint.EnableAes (); //now everything is encrypted
Packet p = await ClientEndPoint.ReceivePacketAsync ();
if (!(p is RespawnRequestPacket))
{
await KickUserAsync("Protocol failure");
_logger.Error("Failed to login a Client, Protocol failure");
return;
}
string hash = ProtocolSecurity.ComputeHash(
Encoding.ASCII.GetBytes(serverId),
ClientEndPoint.ConnectionKey,
AsnKeyBuilder.PublicKeyToX509(_server.RSAKeyPair).GetBytes ());
if (onlineMode)
{
bool result;
try
{
result = await _server.CheckUserAccountAsync(this, hash);
}
catch (OperationCanceledException ex)
{
Task t = KickUserAsync(ex.Message);
return;
}
if (!result)
{
await KickUserAsync("User not premium");
return;
}
}
_logger.InfoFormat("{0}[{1}] is connected", Username, _networkSocket.RemoteEndPoint);
_server.PromoteConnection(this);
Packet response = await InitializeServerAsync ();
var logonResponse = response as LogOnResponse;
if (logonResponse != null)
{
EntityID = logonResponse.EntityId;
}
await ClientEndPoint.SendPacketAsync(response);
StartClientListening ();
StartServerListening ();
args = new UserEventArgs(this);
_server.PluginManager.TriggerPlugin.OnUserConnectedCompleted(args);
args.EnsureSuccess ();
}
}
catch (TaskCanceledException)
{
return;
}
catch (OperationCanceledException ex)
{
kickMessage = ex.Message;
success = false;
_quitMessagePosted = true;
_logger.Error(string.Format("Client login aborted ({0})", Username), ex);
}
catch (Exception ex)
{
success = false;
_quitMessagePosted = true;
if (!string.IsNullOrEmpty(Username))
_logger.Error(string.Format("Failed to login a client ({0})", Username), ex);
}
if (!success)
await KickUserAsync(kickMessage);
}