/// <summary> /// Asynchronously initialize the server side of this connection /// </summary> /// <param name="serverEndPoint"> Information of the new server this connection should connect to. </param> /// <returns> A task which returns the LogOnPacket or DisconnectPacket of the established connection. </returns> public async Task<Packet> InitializeServerAsync(RemoteServerInfo serverEndPoint) { ProxyEndPoint server = null; try { UnregisterServer (); _serverEndPoint = null; if (!string.IsNullOrEmpty(serverEndPoint.KickMessage)) { await KickUserAsync(serverEndPoint.KickMessage); throw new OperationCanceledException("User got kicked."); } if (serverEndPoint.MinecraftVersion == 0) _server.GetServerVersion(this, serverEndPoint); if (serverEndPoint.MinecraftVersion == null) { var information =await MinecraftPinger.GetServerInformationAsync(serverEndPoint.EndPoint); if((serverEndPoint.MinecraftVersion = information.ProtocolVersion) == null) throw new InvalidOperationException("Could not auto detect server version"); } var socket = new Socket(serverEndPoint.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { ReceiveBufferSize = 1024*1024 }; await socket.ConnectTaskAsync(serverEndPoint.EndPoint); server = new ProxyEndPoint( ServerRemoteInterface.Create(new NetworkStream(socket), (int)serverEndPoint.MinecraftVersion), (int)serverEndPoint.MinecraftVersion); server.RemoteEndPoint = (IPEndPoint) socket.RemoteEndPoint; var handshakeRequest = new HandshakeRequest { UserName = Username, Host = Host, ProtocolVersion = (byte) serverEndPoint.MinecraftVersion }; await server.SendPacketAsync(handshakeRequest); Packet tp = await server.ReceivePacketAsync (); if (tp is DisconnectPacket) { throw new OperationCanceledException((tp as DisconnectPacket).Reason); } var encryptionKeyRequest = tp as EncryptionKeyRequest; server.ConnectionKey = ProtocolSecurity.GenerateAes128Key (); byte[] key = ProtocolSecurity.RsaEncrypt(server.ConnectionKey, encryptionKeyRequest.PublicKey.ToArray (), false); byte[] verifyToken = ProtocolSecurity.RsaEncrypt(encryptionKeyRequest.VerifyToken.ToArray (), encryptionKeyRequest.PublicKey.ToArray (), false); var encryptionKeyResponse = new EncryptionKeyResponse { SharedKey = key, VerifyToken = verifyToken }; await server.SendPacketAsync(encryptionKeyResponse); Packet p = await server.ReceivePacketAsync (); server.EnableAes (); await server.SendPacketAsync(new RespawnRequestPacket ()); return await server.ReceivePacketAsync (); } catch (Exception ex) { _quitMessagePosted = true; _logger.Error("Could not connect to remote server", ex); throw; } finally { _serverEndPoint = server; } }