diff --git a/MCGalaxy/Network/Sockets.cs b/MCGalaxy/Network/Sockets.cs
index 7dcead7c8..e37a428c3 100644
--- a/MCGalaxy/Network/Sockets.cs
+++ b/MCGalaxy/Network/Sockets.cs
@@ -18,6 +18,10 @@ using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
+using System.IO;
+using System.Net.Security;
+using System.Threading;
+using System.Security.Cryptography.X509Certificates;
namespace MCGalaxy.Network {
@@ -53,7 +57,14 @@ namespace MCGalaxy.Network {
} else if (opcode == 'G' && Server.Config.WebClient) {
pending.Remove(this);
return new WebSocket(this);
- } else {
+ }
+#if SECURE_WEBSOCKETS
+ else if (opcode == 0x16 && Server.Config.WebClient) {
+ pending.Remove(this);
+ return new SecureSocket(this);
+ }
+#endif
+ else {
Logger.Log(LogType.UserActivity, "Disconnected {0} (unknown opcode {1})", IP, opcode);
Close();
return null;
@@ -251,7 +262,7 @@ namespace MCGalaxy.Network {
}
}
- /// Abstracts a WebSocket on top of a TCP socket.
+ /// Abstracts a WebSocket on top of a socket.
public sealed class WebSocket : INetSocket, INetProtocol {
readonly INetSocket s;
@@ -481,4 +492,100 @@ namespace MCGalaxy.Network {
public void Disconnect() { Disconnect(1000); }
public override void Close() { s.Close(); }
}
+#if SECURE_WEBSOCKETS
+ public sealed class SecureSocket : INetSocket, INetProtocol {
+ readonly INetSocket raw;
+ WrapperStream wrapper;
+ SslStream ssl;
+
+ public SecureSocket(INetSocket socket) {
+ IP = socket.IP;
+ raw = socket;
+
+ wrapper = new WrapperStream();
+ wrapper.s = this;
+
+ ssl = new SslStream(wrapper);
+ new Thread(IOThread).Start();
+ }
+
+ // Init taken care by underlying socket
+ public override void Init() { }
+ public override bool LowLatency { set { raw.LowLatency = value; } }
+ public override void Close() { raw.Close(); }
+ public void Disconnect() { Close(); }
+
+ public override void Send(byte[] buffer, bool sync) { ssl.Write(buffer); }
+ public override void SendLowPriority(byte[] buffer) { ssl.Write(buffer); }
+
+ public int ProcessReceived(byte[] data, int count) {
+ lock (wrapper.locker) {
+ for (int i = 0; i < count; i++) {
+ wrapper.input.Add(data[i]);
+ }
+ }
+ return count;
+ }
+
+ void IOThread() {
+ try {
+ // UGLY HACK I don't know what this file should even contain??? seems you need public and private key
+ X509Certificate2 cert = new X509Certificate2(Server.Config.SslCertPath, Server.Config.SslCertPass);
+ ssl.AuthenticateAsServer(cert);
+
+ Server.s.Log(".. reading player packets ..");
+ byte[] buffer = new byte[4096];
+ for (;;) {
+ int read = ssl.Read(buffer, 0, 4096);
+ if (read == 0) break;
+ this.HandleReceived(buffer, read);
+ }
+ } catch (Exception ex) {
+ Logger.LogError("Error reading from secure stream", ex);
+ }
+ }
+
+ // UGLY HACK because can't derive from two base classes
+ sealed class WrapperStream : Stream {
+ public SecureSocket s;
+ public readonly object locker = new object();
+ public readonly List input = new List();
+
+ public override bool CanRead { get { return true; } }
+ public override bool CanSeek { get { return false; } }
+ public override bool CanWrite { get { return true; } }
+
+ static Exception ex = new NotSupportedException();
+ public override void Flush() { }
+ public override long Length { get { throw ex; } }
+ public override long Position { get { throw ex; } set { throw ex; } }
+ public override long Seek(long offset, SeekOrigin origin) { throw ex; }
+ public override void SetLength(long length) { throw ex; }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ // UGLY HACK wait until got some data
+ for (;;) {
+ lock (locker) { if (input.Count > 0) break; }
+ Thread.Sleep(1);
+ }
+
+ // now actually output the data
+ lock (locker) {
+ count = Math.Min(count, input.Count);
+ for (int i = 0; i < count; i++) {
+ buffer[offset++] = input[i];
+ }
+ input.RemoveRange(0, count);
+ }
+ return count;
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ byte[] data = new byte[count];
+ Buffer.BlockCopy(buffer, offset, data, 0, count);
+ s.raw.Send(data, false);
+ }
+ }
+ }
+#endif
}
diff --git a/MCGalaxy/Server/ServerConfig.cs b/MCGalaxy/Server/ServerConfig.cs
index d1c1250b8..d561e819a 100644
--- a/MCGalaxy/Server/ServerConfig.cs
+++ b/MCGalaxy/Server/ServerConfig.cs
@@ -41,8 +41,13 @@ namespace MCGalaxy {
public bool Public = false;
[ConfigBool("verify-names", "Server", true)]
public bool VerifyNames = true;
+
[ConfigBool("support-web-client", "Server", true)]
public bool WebClient = true;
+ [ConfigString("ssl-certificate-path", "Other", "", true)]
+ public string SslCertPath = "";
+ [ConfigString("ssl-certificate-password", "Other", "", true)]
+ public string SslCertPass = "";
[ConfigBool("autoload", "Server", true)]
public bool AutoLoadMaps = true;