diff --git a/MeshMapper.cs b/MeshMapper.cs index a4bf003..398cf9f 100644 --- a/MeshMapper.cs +++ b/MeshMapper.cs @@ -50,32 +50,6 @@ namespace MeshCentralRouter public delegate void onStateMsgChangedHandler(string statemsg); 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 public void start(MeshCentralServer parent, int protocol, int localPort, string url, int remotePort, string remoteIP) { diff --git a/WebSocketClient.cs b/WebSocketClient.cs index c3d8534..3bf39db 100644 --- a/WebSocketClient.cs +++ b/WebSocketClient.cs @@ -74,7 +74,7 @@ namespace MeshCentralRouter public TLSCertificateCheck TLSCertCheck = TLSCertificateCheck.Verify; public X509Certificate2 failedTlsCert = null; static public bool nativeWebSocketFirst = true; - + private SemaphoreSlim receiveLock = new SemaphoreSlim(1, 1); // Outside variables public object tag = null; @@ -704,7 +704,17 @@ namespace MeshCentralRouter 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 pendingSends = new List(); + 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) public int SendFragment(byte[] data, int offset, int len, byte op) @@ -713,12 +723,21 @@ namespace MeshCentralRouter if (ws != null) { // Using native websocket - lock (this) + lock (pendingSends) { - if ((pendingSend != null) && (pendingSend.IsCompleted == false)) { pendingSend.Wait(); } - ArraySegment arr = new ArraySegment(data, offset, len); - WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); - pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + 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 arr = new ArraySegment(data, offset, len); + WebSocketMessageType msgType = ((op == 129) ? WebSocketMessageType.Text : WebSocketMessageType.Binary); + pendingSend = ws.SendAsync(arr, msgType, true, CTS.Token); + pendingSend.ContinueWith(antecedent => SendFragmentDone()); + } } 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 arr = new ArraySegment(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, int off, int len) @@ -847,7 +889,9 @@ namespace MeshCentralRouter { lock (mainLock) { + if (readPaused == true) return; readPaused = true; + if (ws != null) { receiveLock.Wait(); } } } @@ -857,10 +901,17 @@ namespace MeshCentralRouter { if (readPaused == false) return; readPaused = false; - if (shouldRead == true) + if (ws != null) { - shouldRead = false; - try { wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); } catch (Exception) { } + receiveLock.Release(); + } + else + { + if (shouldRead == true) + { + shouldRead = false; + try { wsstream.BeginRead(readBuffer, readBufferLen, readBuffer.Length - readBufferLen, new AsyncCallback(OnTlsDataSink), this); } catch (Exception) { } + } } } } @@ -887,6 +938,10 @@ namespace MeshCentralRouter while (!receiveResult.EndOfMessage); if (receiveResult.MessageType == WebSocketMessageType.Close) break; outputStream.Position = 0; + + receiveLock.Wait(); // Pause reading if needed + receiveLock.Release(); + if (receiveResult.MessageType == WebSocketMessageType.Text) { Log("Websocket got string data, len = " + (int)outputStream.Length);