private void SyntaxError(byte cmd, byte[] buf, string extra = "") { string bufText = buf.Length < 20 ? (" [" + string.Join(", ", buf) + "]") : " [buffer length: " + buf.Length + "]"; Logger.Debug("Malformed Command." + (Command)cmd + extra + bufText); Send(new byte[] { (byte)Command.Error_SyntaxError }); }
private void streamLoop_inner(object objArgs) { Stopwatch frameTimer = new Stopwatch(); frameTimer.Start(); long nextFrameStart = 0; StreamThreadArgs args = (StreamThreadArgs)objArgs; while (!args.abortFlag.abort) { try { int sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds); while (sleepTime > 0 || (Interlocked.Read(ref args.numSentFrames) >= Interlocked.Read(ref args.numAcknowledgedFrames) + maxUnacknowledgedFrames)) { if (args.abortFlag.abort) { return; } Thread.Sleep(BPMath.Clamp(sleepTime, 1, 10)); sleepTime = (int)(nextFrameStart - frameTimer.ElapsedMilliseconds); } if (args.abortFlag.abort) { return; } nextFrameStart = frameTimer.ElapsedMilliseconds + (1000 / maxFPS); if (streamerController == null) { return; } FragmentedImage fragmentedImage = streamerController.GetRawDesktopCapture(imgFlags, jpegQuality, args.abortFlag); if (args.abortFlag.abort) { return; } if (fragmentedImage == null) { fragmentedImage = new FragmentedImage(); } fragmentedImage.streamId = (byte)args.myStreamNumber; using (MemoryDataStream mds = new MemoryDataStream(fragmentedImage.GetMaximumRequiredBufferSize())) { byte[] compressionBuffer = null; fragmentedImage.WriteToDataStream(mds, ref compressionBuffer); Interlocked.Increment(ref args.numSentFrames); Send(mds.ToArray()); } } catch (ThreadAbortException) { throw; } catch (Exception ex) { Logger.Debug(ex); } } }
private void onTcpcConnect(IAsyncResult ar) { if (ar.IsCompleted) { dynamic args = (dynamic)ar.AsyncState; TcpClient tcpc = (TcpClient)args.tcpc; string connectionKey = (string)args.connectionKey; byte[] buf = Encoding.UTF8.GetBytes("GET /WebSocketProxy" + connectionKey + " HTTP/1.1\r\n\r\n"); tcpc.GetStream().Write(buf, 0, buf.Length); srv.AcceptTcpClient(tcpc); } else { Logger.Debug("SHRDWebSocketServer.onTcpcConnect with IsCompleted == false"); } }
private void streamLoop(object objArgs) { try { // streamLoop itself isn't in the stack trace from what I've seen! So I've nested the logic into another method to help with debugging. streamLoop_inner(objArgs); } catch (ThreadAbortException) { Logger.Debug("WebSocket Streaming thread had to be aborted. Closing the web socket because it could be in a bad state."); CloseSocket(); } catch (Exception ex) { Logger.Debug(ex); } }
public SHRDWebSocketServer(int port) { srv = new WebSocketServer(port, false); srv.Log.Output = (LogData data, string path) => { if (data.Level >= LogLevel.Error) { Logger.Debug(data.Message); } else { Logger.Info(data.Message); } }; srv.AddWebSocketService <SHRDWebSocketBehavior>("/SHRD"); Logger.Info("WebSocket Service Added on port " + port + ": /SHRD"); }
private void onTcpcConnect(IAsyncResult ar) { if (ar.IsCompleted) { dynamic args = (dynamic)ar.AsyncState; TcpClient tcpc = (TcpClient)args.tcpc; tcpc.NoDelay = true; string connectionKey = (string)args.connectionKey; // Send to the Master Server an HTTP request that will be transforned into a web socket proxy. // After the connection key, append the port number, then append this service's path (e.g. connectionKey + "/80/SHRD") // This could have been hard-coded in the Master Server, but it seems more flexible if we send it here. // For example, at some point in the future, a host service might want to customize or randomize its web socket listening endpoint. Console.WriteLine("GET /WebSocketHostProxy/" + connectionKey + "/" + srv.Port + myPath + " HTTP/1.1"); byte[] buf = Encoding.UTF8.GetBytes("GET /WebSocketHostProxy/" + connectionKey + "/" + srv.Port + myPath + " HTTP/1.1\r\n\r\n"); tcpc.GetStream().Write(buf, 0, buf.Length); Console.WriteLine("srv.AcceptTcpClient"); srv.AcceptTcpClient(tcpc); } else { Logger.Debug("SHRDWebSocketServer.onTcpcConnect with IsCompleted == false"); } }
protected override void OnMessage(MessageEventArgs e) { if (!e.IsBinary) { CloseSocket(); return; } byte[] buf = e.RawData; if (buf.Length == 0) { CloseSocket(); return; } Command cmd = (Command)buf[0]; try { switch (cmd) { case Command.StartStreaming: if (buf.Length < 3) { SyntaxError(buf[0], buf); break; } StopStreaming(); Console.WriteLine(ID + " Command.StartStreaming " + (byte)Interlocked.Read(ref activeStreamNumber)); Send(new byte[] { buf[0], (byte)Interlocked.Read(ref activeStreamNumber) }); StartStreaming(buf); break; case Command.StopStreaming: Console.WriteLine(ID + " Command.StopStreaming"); StopStreaming(); break; case Command.AcknowledgeFrame: if (buf.Length < 2) { SyntaxError(buf[0], buf); break; } AcknowledgeFrame(buf[1]); break; case Command.ReproduceUserInput: if (buf.Length < 2) { SyntaxError(buf[0], buf); break; } InputType inputType = (InputType)buf[1]; if (inputType == InputType.KeyDown || inputType == InputType.KeyUp) { if (buf.Length < 10) { SyntaxError(buf[0], buf, inputType); break; } int keyCode = ByteUtil.ReadInt32(buf, 2); ModifierKeys modifiers = (ModifierKeys)ByteUtil.ReadUInt32(buf, 6); streamerController.DoKeyboardInput(keyCode, modifiers, inputType == InputType.KeyUp); } else if (inputType == InputType.MouseMove) { if (buf.Length < 10) { SyntaxError(buf[0], buf, inputType); break; } float x = ByteUtil.ReadFloat(buf, 2); float y = ByteUtil.ReadFloat(buf, 6); streamerController.DoMouseMove(x, y); } else if (inputType == InputType.MouseButtonDown || inputType == InputType.MouseButtonUp) { if (buf.Length < 3) { SyntaxError(buf[0], buf, inputType); break; } MouseButton button = (MouseButton)buf[2]; streamerController.DoMouseButton(button, inputType == InputType.MouseButtonUp); } else if (inputType == InputType.MouseWheel) { if (buf.Length < 6) { SyntaxError(buf[0], buf, inputType); break; } short deltaX = ByteUtil.ReadInt16(buf, 2); short deltaY = ByteUtil.ReadInt16(buf, 4); streamerController.DoMouseWheel(deltaX, deltaY); } break; case Command.GetDesktopInfo: DesktopInfo desktopInfo = streamerController.GetDesktopInfo(); using (MemoryDataStream mds = new MemoryDataStream()) { desktopInfo.WriteToDataStream(mds); Send(mds.ToArray()); } break; case Command.SetStreamSettings: if (buf.Length < 5) { SyntaxError(buf[0], buf); break; } imgFlags = (ImgFlags)buf[1]; jpegQuality = BPMath.Clamp <byte>(buf[2], 1, 100); maxFPS = BPMath.Clamp <byte>(buf[3], 1, byte.MaxValue); maxUnacknowledgedFrames = BPMath.Clamp <byte>(buf[4], 1, byte.MaxValue); break; case Command.GetStreamSettings: byte[] response = new byte[4]; response[0] = buf[0]; response[1] = (byte)imgFlags; response[2] = jpegQuality; response[3] = maxFPS; Send(response); break; case Command.KeepAlive: break; default: // CloseSocket(); Send(new byte[] { (byte)Command.Error_CommandCodeUnknown }); break; } } catch (ThreadAbortException) { throw; } catch (Exception ex) { Logger.Debug(ex, "WebSocketServer"); } }