/// <summary> /// push image(s) updates(s) (region(s) or fullscreen(s)) from the rdp session to the browser /// this is done through a long-polling request (also known as reverse ajax or ajax comet) issued by a zero sized iframe /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Page_Load( object sender, EventArgs e) { // if cookies are enabled, the http session id is added to the http request headers; otherwise, it's added to the http request url // in both cases, the given http session is automatically bound to the current http context RemoteSessionManager remoteSessionManager = null; try { // retrieve the remote session manager for the current http session remoteSessionManager = (RemoteSessionManager)HttpContext.Current.Session[HttpSessionStateVariables.RemoteSessionManager.ToString()]; } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve the remote session manager for the http session {0}, ({1})", HttpContext.Current.Session.SessionID, exc); return; } try { // retrieve params var longPollingDuration = int.Parse(HttpContext.Current.Request.QueryString["longPollingDuration"]); var imgIdx = int.Parse(HttpContext.Current.Request.QueryString["imgIdx"]); // if a websocket is set at this step, the client had probably changed the rendering mode (html5 -> html4) or configuration while the remote session is active, then reloaded the page (F5) // close the websocket (a new one will be set if the client change back to html5 again...) if (remoteSessionManager.WebSocket != null) { System.Diagnostics.Trace.TraceInformation("Removing no longer used websocket (the client had probably changed the rendering mode from HTML5 to HTML4 then reloaded the page (F5)), remote session {0}", remoteSessionManager.RemoteSession.Id); remoteSessionManager.WebSocket.Close(); remoteSessionManager.WebSocket = null; } // stream image(s) data within the response for the given duration // the connection will be automatically reseted by the client when the request ends var startTime = DateTime.Now; var remainingTime = longPollingDuration; var currentImgIdx = imgIdx; while (remainingTime > 0) { // ensure the remote session is still connected if (remoteSessionManager.RemoteSession.State == RemoteSessionState.Disconnected) { // the remote session is disconnected, back to home page HttpContext.Current.Response.Write("<script>parent.location.href = parent.getConfig().getHttpServerUrl();</script>"); HttpContext.Current.Response.Flush(); break; } // the remote clipboard content was requested else if (remoteSessionManager.ClipboardRequested) { HttpContext.Current.Response.Write(string.Format("<script>parent.showDialogPopup('showDialogPopup', 'ShowDialog.aspx', 'Ctrl+C to copy to local clipboard (Cmd-C on Mac)', '{0}', true);</script>", remoteSessionManager.ClipboardText)); HttpContext.Current.Response.Flush(); remoteSessionManager.ClipboardRequested = false; } // retrieve the next update, if available; otherwise, wait it for the remaining time var image = remoteSessionManager.GetNextUpdate(currentImgIdx, remainingTime); if (image != null) { System.Diagnostics.Trace.TraceInformation("Pushing image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), remoteSessionManager.RemoteSession.Id); var imgData = image.Idx + "," + image.PosX + "," + image.PosY + "," + image.Width + "," + image.Height + "," + "'" + image.Format.ToString().ToLower() + "'," + image.Quality + "," + "'" + image.Base64Data + "'," + image.Fullscreen.ToString().ToLower(); imgData = "<script>parent.pushImage(" + imgData + ");</script>"; // write the output HttpContext.Current.Response.Write(imgData); HttpContext.Current.Response.Flush(); currentImgIdx = image.Idx; } remainingTime = longPollingDuration - Convert.ToInt32((DateTime.Now - startTime).TotalMilliseconds); } } catch (HttpException) { // this occurs if the user reloads the page while the long-polling request is going on... } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to push display update(s), remote session {0} ({1})", remoteSessionManager.RemoteSession.Id, exc); } }
/// <summary> /// send user input(s) (mouse, keyboard) to the rdp session /// if long-polling is disabled (xhr only), also returns image data within the response /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Page_Load( object sender, EventArgs e) { // if cookies are enabled, the http session id is added to the http request headers; otherwise, it's added to the http request url // in both cases, the given http session is automatically bound to the current http context RemoteSessionManager remoteSessionManager = null; try { // retrieve the remote session manager for the current http session remoteSessionManager = (RemoteSessionManager)HttpContext.Current.Session[HttpSessionStateVariables.RemoteSessionManager.ToString()]; } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to retrieve the remote session manager for the http session {0}, ({1})", HttpContext.Current.Session.SessionID, exc); return; } try { // retrieve params var data = HttpContext.Current.Request.QueryString["data"]; var fsu = int.Parse(HttpContext.Current.Request.QueryString["fsu"]) == 1; var imgIdx = int.Parse(HttpContext.Current.Request.QueryString["imgIdx"]); var imgEncoding = HttpContext.Current.Request.QueryString["imgEncoding"]; var imgQuality = int.Parse(HttpContext.Current.Request.QueryString["imgQuality"]); var imgReturn = int.Parse(HttpContext.Current.Request.QueryString["imgReturn"]) == 1; var bandwidthRatio = int.Parse(HttpContext.Current.Request.QueryString["bandwidthRatio"]); // image encoding var encoding = ImageEncoding.JPEG; Enum.TryParse(imgEncoding, true, out encoding); remoteSessionManager.ImageEncoding = encoding; // throttle the image quality depending on the bandwidth usage ratio if (bandwidthRatio >= (int)ImageQualityTweakBandwidthRatio.HigherBound) { remoteSessionManager.ImageQuality = imgQuality / 4; } else if (bandwidthRatio >= (int)ImageQualityTweakBandwidthRatio.LowerBound && bandwidthRatio < (int)ImageQualityTweakBandwidthRatio.HigherBound) { remoteSessionManager.ImageQuality = imgQuality / 2; } else { remoteSessionManager.ImageQuality = imgQuality; } // if defined, send the user input(s) through the rdp session // also, a websocket triggers periodical dummy xhr calls, without data, in order to keep the http session alive; such calls musn't close the websocket! if (!string.IsNullOrEmpty(data)) { remoteSessionManager.SendUserEvent(data); // if a websocket is set at this step, the client had probably changed the rendering mode (html5 -> html4) or configuration while the remote session is active, then reloaded the page (F5) // close the websocket (a new one will be set if the client change back to html5 again...) if (remoteSessionManager.WebSocket != null) { System.Diagnostics.Trace.TraceInformation("Removing no longer used websocket (the client had probably changed the rendering mode from HTML5 to HTML4 then reloaded the page (F5)), remote session {0}", remoteSessionManager.RemoteSession.Id); remoteSessionManager.WebSocket.Close(); remoteSessionManager.WebSocket = null; } } // if requested, ask for a fullscreen update if (fsu) { System.Diagnostics.Trace.TraceInformation("Requesting fullscreen update, remote session {0}", remoteSessionManager.RemoteSession.Id); remoteSessionManager.SendCommand(RemoteSessionCommand.SendFullscreenUpdate); } // xhr only if (imgReturn) { var image = remoteSessionManager.GetNextUpdate(imgIdx); if (image != null) { System.Diagnostics.Trace.TraceInformation("Returning image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), remoteSessionManager.RemoteSession.Id); var imgData = image.Idx + "," + image.PosX + "," + image.PosY + "," + image.Width + "," + image.Height + "," + image.Format.ToString().ToLower() + "," + image.Quality + "," + image.Base64Data + "," + image.Fullscreen.ToString().ToLower(); // write the output HttpContext.Current.Response.Write(imgData); } // ensure the remote session is still connected else if (remoteSessionManager.RemoteSession.State == RemoteSessionState.Disconnected) { HttpContext.Current.Response.Write("disconnected"); } // the remote clipboard content was requested else if (remoteSessionManager.ClipboardRequested) { HttpContext.Current.Response.Write(string.Format("clipboard|{0}", remoteSessionManager.ClipboardText)); remoteSessionManager.ClipboardRequested = false; } } } catch (Exception exc) { System.Diagnostics.Trace.TraceError("Failed to send user input(s), remote session {0} ({1})", remoteSessionManager.RemoteSession.Id, exc); } }