1
0
mirror of https://github.com/Ylianst/MeshCentralRouter synced 2025-12-14 15:23:35 +00:00

Windows native websocket fixes.

This commit is contained in:
Ylian Saint-Hilaire
2021-10-28 16:47:05 -07:00
parent eb1f0a8cdb
commit 0bcb7a0164
2 changed files with 65 additions and 36 deletions

View File

@@ -50,32 +50,6 @@ namespace MeshCentralRouter
public delegate void onStateMsgChangedHandler(string statemsg); public delegate void onStateMsgChangedHandler(string statemsg);
public event onStateMsgChangedHandler onStateMsgChanged; public event onStateMsgChangedHandler onStateMsgChanged;
public static string GetProxyForUrlUsingPac(string DestinationUrl, string PacUri)
{
IntPtr WinHttpSession = Win32Api.WinHttpOpen("User", Win32Api.WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, IntPtr.Zero, IntPtr.Zero, 0);
Win32Api.WINHTTP_AUTOPROXY_OPTIONS ProxyOptions = new Win32Api.WINHTTP_AUTOPROXY_OPTIONS();
Win32Api.WINHTTP_PROXY_INFO ProxyInfo = new Win32Api.WINHTTP_PROXY_INFO();
ProxyOptions.dwFlags = Win32Api.WINHTTP_AUTOPROXY_CONFIG_URL;
ProxyOptions.dwAutoDetectFlags = (Win32Api.WINHTTP_AUTO_DETECT_TYPE_DHCP | Win32Api.WINHTTP_AUTO_DETECT_TYPE_DNS_A);
ProxyOptions.lpszAutoConfigUrl = PacUri;
// Get Proxy
bool IsSuccess = Win32Api.WinHttpGetProxyForUrl(WinHttpSession, DestinationUrl, ref ProxyOptions, ref ProxyInfo);
Win32Api.WinHttpCloseHandle(WinHttpSession);
if (IsSuccess)
{
return ProxyInfo.lpszProxy;
}
else
{
Console.WriteLine("Error: {0}", Win32Api.GetLastError());
return null;
}
}
// Starts the routing server, called when the start button is pressed // Starts the routing server, called when the start button is pressed
public void start(MeshCentralServer parent, int protocol, int localPort, string url, int remotePort, string remoteIP) public void start(MeshCentralServer parent, int protocol, int localPort, string url, int remotePort, string remoteIP)
{ {

View File

@@ -74,7 +74,7 @@ namespace MeshCentralRouter
public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify;
public X509Certificate2 failedTlsCert = null; public X509Certificate2 failedTlsCert = null;
static public bool nativeWebSocketFirst = true; static public bool nativeWebSocketFirst = true;
private SemaphoreSlim receiveLock = new SemaphoreSlim(1, 1);
// Outside variables // Outside variables
public object tag = null; public object tag = null;
@@ -704,7 +704,17 @@ namespace MeshCentralRouter
return SendFragment(null, 0, 0, 138); return SendFragment(null, 0, 0, 138);
} }
Task pendingSend = null; // This controls the flow of fragments being sent, queuing send operations if needed
private Task pendingSend = null;
private List<pendingSendClass> pendingSends = new List<pendingSendClass>();
private class pendingSendClass
{
public pendingSendClass(byte[] data, int offset, int len, byte op) { this.data = data; this.offset = offset; this.len = len; this.op = op; }
public byte[] data;
public int offset;
public int len;
public byte op;
}
// Fragment op code (129 = text, 130 = binary) // Fragment op code (129 = text, 130 = binary)
public int SendFragment(byte[] data, int offset, int len, byte op) public int SendFragment(byte[] data, int offset, int len, byte op)
@@ -713,12 +723,21 @@ namespace MeshCentralRouter
if (ws != null) if (ws != null)
{ {
// Using native websocket // Using native websocket
lock (this) lock (pendingSends)
{ {
if ((pendingSend != null) && (pendingSend.IsCompleted == false)) { pendingSend.Wait(); } if (pendingSend != null)
{
// A send operating is already being processes, queue this send.
pendingSends.Add(new pendingSendClass(data, offset, len, op));
}
else
{
// No send operations being performed now, send this fragment now.
ArraySegment<byte> arr = new ArraySegment<byte>(data, offset, len); ArraySegment<byte> arr = new ArraySegment<byte>(data, offset, len);
WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary);
pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token);
pendingSend.ContinueWith(antecedent => SendFragmentDone());
}
} }
return len; return len;
} }
@@ -804,6 +823,29 @@ namespace MeshCentralRouter
} }
} }
// Called when a fragment is done sending. We look to send the next one or signal that we can accept more data
private void SendFragmentDone()
{
bool q = false;
lock (pendingSends)
{
pendingSend = null;
if (pendingSends.Count > 0)
{
// There is more send operation pending, send the next one now.
pendingSendClass p = pendingSends[0];
pendingSends.RemoveAt(0);
ArraySegment<byte> arr = new ArraySegment<byte>(p.data, p.offset, p.len);
WebSocketMessageType msgType = ((p.op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary);
pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token);
pendingSend.ContinueWith(antecedent => SendFragmentDone());
}
else { q = true; } // No pending send operations, signal ok to send more.
}
if ((q == true) && (onSendOk != null)) { onSendOk(this); }
}
private void SendData(byte[] buf) { SendData(buf, 0, buf.Length); } private void SendData(byte[] buf) { SendData(buf, 0, buf.Length); }
private void SendData(byte[] buf, int off, int len) private void SendData(byte[] buf, int off, int len)
@@ -847,7 +889,9 @@ namespace MeshCentralRouter
{ {
lock (mainLock) lock (mainLock)
{ {
if (readPaused == true) return;
readPaused = true; readPaused = true;
if (ws != null) { receiveLock.Wait(); }
} }
} }
@@ -857,6 +901,12 @@ namespace MeshCentralRouter
{ {
if (readPaused == false) return; if (readPaused == false) return;
readPaused = false; readPaused = false;
if (ws != null)
{
receiveLock.Release();
}
else
{
if (shouldRead == true) if (shouldRead == true)
{ {
shouldRead = false; shouldRead = false;
@@ -864,6 +914,7 @@ namespace MeshCentralRouter
} }
} }
} }
}
private async Task ReceiveLoop() private async Task ReceiveLoop()
{ {
@@ -887,6 +938,10 @@ namespace MeshCentralRouter
while (!receiveResult.EndOfMessage); while (!receiveResult.EndOfMessage);
if (receiveResult.MessageType == WebSocketMessageType.Close) break; if (receiveResult.MessageType == WebSocketMessageType.Close) break;
outputStream.Position = 0; outputStream.Position = 0;
receiveLock.Wait(); // Pause reading if needed
receiveLock.Release();
if (receiveResult.MessageType == WebSocketMessageType.Text) if (receiveResult.MessageType == WebSocketMessageType.Text)
{ {
Log("Websocket got string data, len = " + (int)outputStream.Length); Log("Websocket got string data, len = " + (int)outputStream.Length);