예제 #1
0
        // retrieve the next image
        public RemoteSessionImage GetNextUpdate(int imageIdx, int?waitDuration = null)
        {
            RemoteSessionImage image = null;

            lock (_imageEventLock)
            {
                try
                {
                    // retrieve the next available image from cache, up to the latest received
                    if (imageIdx < _lastReceivedImageIdx)
                    {
                        for (var idx = imageIdx + 1; idx <= _lastReceivedImageIdx; idx++)
                        {
                            image = GetCachedUpdate(idx);
                            if (image != null)
                            {
                                break;
                            }
                        }
                    }

                    // if no image is available and a wait duration is specified, wait for a new image
                    if (image == null && waitDuration.HasValue)
                    {
                        Trace.TraceInformation("Waiting for new image, remote session {0}", RemoteSession.Id);
                        _imageEventPending = true;
                        if (waitDuration.Value > 0)
                        {
                            // wait for the specified time
                            if (Monitor.Wait(_imageEventLock, waitDuration.Value))
                            {
                                image = GetCachedUpdate(_lastReceivedImageIdx);
                            }
                        }
                        else
                        {
                            // wait indefinitely
                            if (Monitor.Wait(_imageEventLock))
                            {
                                image = GetCachedUpdate(_lastReceivedImageIdx);
                            }
                        }
                        _imageEventPending = false;
                        Monitor.Pulse(_imageEventLock);
                    }
                }
                catch (Exception exc)
                {
                    Trace.TraceError("Failed to retrieve next update from index {0}, remote session {1} ({2})", imageIdx, RemoteSession.Id, exc);
                }
            }

            return(image);
        }
 public void SendImage(RemoteSessionImage image)
 {
     if (!BinaryMode)
     {
         Send(GetImageText(image) + ";");
     }
     else
     {
         Send(GetImageBytes(image));
     }
 }
 private string GetImageText(RemoteSessionImage image)
 {
     return
         (image.Idx + "," +
          image.PosX + "," +
          image.PosY + "," +
          image.Width + "," +
          image.Height + "," +
          image.Format.ToString().ToLower() + "," +
          image.Quality + "," +
          image.Fullscreen.ToString().ToLower() + "," +
          Convert.ToBase64String(image.Data));
 }
예제 #4
0
        public byte[] TakeScreenshot(Guid connectionId)
        {
            try
            {
                HttpContext.Current.Application.Lock();

                var remoteSessions = (IDictionary <Guid, RemoteSession>)HttpContext.Current.Application[HttpApplicationStateVariables.RemoteSessions.ToString()];
                if (!remoteSessions.ContainsKey(connectionId))
                {
                    throw new Exception(string.Format("connection {0} not found", connectionId));
                }
                else
                {
                    var remoteSession = remoteSessions[connectionId];

                    RemoteSessionImage screenshot = null;

                    // one screenshot at a time
                    if (remoteSession.Manager.ScreenshotEventLock == null)
                    {
                        remoteSession.Manager.ScreenshotEventLock = new object();

                        // request a screenshot (async) and wait it (up to 10 seconds)
                        lock (remoteSession.Manager.ScreenshotEventLock)
                        {
                            remoteSession.Manager.SendCommand(RemoteSessionCommand.TakeScreenshot);
                            remoteSession.Manager.ScreenshotEventPending = true;
                            if (Monitor.Wait(remoteSession.Manager.ScreenshotEventLock, 10000))
                            {
                                screenshot = remoteSession.Manager.GetCachedUpdate(remoteSession.Manager.ScreenshotImageIdx);
                            }
                            remoteSession.Manager.ScreenshotEventPending = false;
                            Monitor.Pulse(remoteSession.Manager.ScreenshotEventLock);
                        }

                        remoteSession.Manager.ScreenshotEventLock = null;
                    }

                    return(screenshot?.Data);
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to take screenshot for connection {0} ({1})", connectionId, exc);
                throw;
            }
            finally
            {
                HttpContext.Current.Application.UnLock();
            }
        }
예제 #5
0
 public void ProcessImage(RemoteSessionImage image)
 {
     if (!BinaryMode)
     {
         Send(GetImageText(image) + ";");
     }
     else
     {
         using (var memoryStream = new MemoryStream())
         {
             var bytes = GetImageBytes(image);
             memoryStream.Write(BitConverter.GetBytes(bytes.Length), 0, 4);
             memoryStream.Write(bytes, 0, bytes.Length);
             Send(memoryStream.ToArray());
         }
     }
 }
예제 #6
0
        // retrieve a cached image
        public RemoteSessionImage GetCachedUpdate(int imageIdx)
        {
            RemoteSessionImage image = null;

            try
            {
                var imageObj = _cache["remoteSessionImage_" + RemoteSession.Id + "_" + imageIdx];
                if (imageObj != null)
                {
                    image = (RemoteSessionImage)imageObj;
                    Trace.TraceInformation("Retrieved image {0} ({1}) from cache, remote session {2}", imageIdx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to retrieve image {0} from cache, remote session {1} ({2})", imageIdx, RemoteSession.Id, exc);
            }

            return(image);
        }
        private byte[] GetImageBytes(RemoteSessionImage image)
        {
            using (var memoryStream = new MemoryStream())
            {
                // tag (4 bytes)
                memoryStream.Write(BitConverter.GetBytes(0), 0, 4);

                // info (32 bytes)
                memoryStream.Write(BitConverter.GetBytes(image.Idx), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.PosX), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.PosY), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.Width), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.Height), 0, 4);
                memoryStream.Write(BitConverter.GetBytes((int)image.Format), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.Quality), 0, 4);
                memoryStream.Write(BitConverter.GetBytes(image.Fullscreen ? 1 : 0), 0, 4);

                // data
                memoryStream.Write(image.Data, 0, image.Data.Length);

                return(memoryStream.ToArray());
            }
        }
예제 #8
0
        // new image
        private void ProcessUpdate(byte[] data)
        {
            try
            {
                if (data.Length <= 36)
                {
                    throw new Exception("invalid image data");
                }

                // image info (8 items, 32 bits each => 8 * 4 = 32 bytes)
                var imgInfo = new byte[32];
                Array.Copy(data, 4, imgInfo, 0, 32);

                // CAUTION! if the remote session is reconnected (i.e.: browser resize), a new instance of wfreerdp is spawned
                // the image index can no longer be handled by wfreerdp, this must be done by the remote session manager
                // the image index provided by wfreerdp is relative to its own instance, if needed

                var image = new RemoteSessionImage
                {
                    //Idx = BitConverter.ToInt32(imgInfo, 0),
                    Idx        = ++_imageIdx,
                    PosX       = BitConverter.ToInt32(imgInfo, 4),
                    PosY       = BitConverter.ToInt32(imgInfo, 8),
                    Width      = BitConverter.ToInt32(imgInfo, 12),
                    Height     = BitConverter.ToInt32(imgInfo, 16),
                    Format     = (ImageFormat)BitConverter.ToInt32(imgInfo, 20),
                    Quality    = BitConverter.ToInt32(imgInfo, 24),
                    Fullscreen = BitConverter.ToInt32(imgInfo, 28) == 1,
                    Data       = new byte[data.Length - 36]
                };

                Array.Copy(data, 36, image.Data, 0, data.Length - 36);

                // cache the image, even if using websocket (used to retrieve the mouse cursor on IE)
                _cache.Insert(
                    "remoteSessionImage_" + RemoteSession.Id + "_" + image.Idx,
                    image,
                    null,
                    DateTime.Now.AddMilliseconds(_imageCacheDuration),
                    Cache.NoSlidingExpiration);

                Trace.TraceInformation("Received image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                // while a fullscreen update is pending, discard all updates; the fullscreen will replace all of them
                if (FullscreenEventPending)
                {
                    if (!image.Fullscreen)
                    {
                        Trace.TraceInformation("Discarding image {0} (region) as a fullscreen update is pending, remote session {1}", image.Idx, RemoteSession.Id);
                        return;
                    }
                    else
                    {
                        Trace.TraceInformation("Fullscreen update received, resuming image(s) processing, remote session {0}", RemoteSession.Id);
                        FullscreenEventPending = false;

                        // screenshot request
                        if (ScreenshotEventLock != null)
                        {
                            lock (ScreenshotEventLock)
                            {
                                // screenshot image index
                                ScreenshotImageIdx = image.Idx;

                                // if waiting for a screenshot, signal the reception
                                if (ScreenshotEventPending)
                                {
                                    ScreenshotEventPending = false;
                                    Monitor.Pulse(ScreenshotEventLock);
                                }
                            }
                        }
                    }
                }

                // HTML5 client(s)
                if (WebSockets.Count > 0)
                {
                    Trace.TraceInformation("Sending image {0} ({1}) on websocket(s), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                    foreach (var webSocket in WebSockets)
                    {
                        webSocket.SendImage(image);
                    }
                }

                // HTML4 client(s)
                lock (_imageEventLock)
                {
                    // last received image index
                    _lastReceivedImageIdx = image.Idx;

                    // if waiting for a new image, signal the reception
                    if (_imageEventPending)
                    {
                        _imageEventPending = false;
                        Monitor.Pulse(_imageEventLock);
                    }
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to process update, remote session {0} ({1})", RemoteSession.Id, exc);
            }
        }
예제 #9
0
        // new image
        private void ProcessUpdate(byte[] data)
        {
            try
            {
                if (data.Length <= 36)
                {
                    throw new Exception("invalid image data");
                }

                // image info (8 items, 32 bits each => 8 * 4 = 32 bytes)
                var imgInfo = new byte[32];
                Array.Copy(data, 4, imgInfo, 0, 32);

                var image = new RemoteSessionImage
                {
                    Idx        = BitConverter.ToInt32(imgInfo, 0),
                    PosX       = BitConverter.ToInt32(imgInfo, 4),
                    PosY       = BitConverter.ToInt32(imgInfo, 8),
                    Width      = BitConverter.ToInt32(imgInfo, 12),
                    Height     = BitConverter.ToInt32(imgInfo, 16),
                    Format     = (ImageFormat)BitConverter.ToInt32(imgInfo, 20),
                    Quality    = BitConverter.ToInt32(imgInfo, 24),
                    Fullscreen = BitConverter.ToInt32(imgInfo, 28) == 1,
                    Data       = new byte[data.Length - 36]
                };

                Array.Copy(data, 36, image.Data, 0, data.Length - 36);

                // cache the image, even if using websocket (used to retrieve the mouse cursor on IE)
                _imageCache.Insert(
                    "remoteSessionImage_" + RemoteSession.Id + "_" + image.Idx,
                    image,
                    null,
                    DateTime.Now.AddMilliseconds(_imageCacheDuration),
                    Cache.NoSlidingExpiration);

                Trace.TraceInformation("Received image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                // while a fullscreen update is pending, discard all updates; the fullscreen will replace all of them
                if (FullscreenEventPending)
                {
                    if (!image.Fullscreen)
                    {
                        Trace.TraceInformation("Discarding image {0} (region) as a fullscreen update is pending, remote session {1}", image.Idx, RemoteSession.Id);
                        return;
                    }
                    else
                    {
                        Trace.TraceInformation("Fullscreen update received, resuming image(s) processing, remote session {0}", RemoteSession.Id);
                        FullscreenEventPending = false;
                    }
                }

                // if using websocket(s), send the image
                if (WebSockets.Count > 0)
                {
                    Trace.TraceInformation("Sending image {0} ({1}) on websocket(s), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                    foreach (var webSocket in WebSockets)
                    {
                        if (!webSocket.BinaryMode)
                        {
                            webSocket.Send(
                                image.Idx + "," +
                                image.PosX + "," +
                                image.PosY + "," +
                                image.Width + "," +
                                image.Height + "," +
                                image.Format.ToString().ToLower() + "," +
                                image.Quality + "," +
                                image.Fullscreen.ToString().ToLower() + "," +
                                Convert.ToBase64String(image.Data));
                        }
                        else
                        {
                            webSocket.Send(data);
                        }
                    }
                }
                // otherwise, it will be retrieved later
                else
                {
                    lock (_imageEventLock)
                    {
                        // last received image index
                        _lastReceivedImageIdx = image.Idx;

                        // if waiting for a new image, signal the reception
                        if (_imageEventPending)
                        {
                            _imageEventPending = false;
                            Monitor.Pulse(_imageEventLock);
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to process update, remote session {0} ({1})", RemoteSession.Id, exc);
            }
        }
예제 #10
0
        // new image
        public void ProcessUpdate(string data)
        {
            try
            {
                var imgParts = data.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);

                if (imgParts.Length != 9)
                {
                    throw new Exception("image can't be deserialized");
                }

                var image = new RemoteSessionImage
                {
                    Idx        = int.Parse(imgParts[0]),
                    PosX       = int.Parse(imgParts[1]),
                    PosY       = int.Parse(imgParts[2]),
                    Width      = int.Parse(imgParts[3]),
                    Height     = int.Parse(imgParts[4]),
                    Format     = (ImageFormat)Enum.Parse(typeof(ImageFormat), imgParts[5]),
                    Quality    = int.Parse(imgParts[6]),
                    Base64Data = imgParts[7].Replace("\n", ""),
                    Fullscreen = imgParts[8] == "1"
                };

                Trace.TraceInformation("Received image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                // while a fullscreen update is pending, discard all updates; the fullscreen will replace all of them
                if (_fullscreenPending)
                {
                    if (!image.Fullscreen)
                    {
                        Trace.TraceInformation("Discarding image {0} (region) as a fullscreen update is pending, remote session {1}", image.Idx, RemoteSession.Id);
                        return;
                    }
                    else
                    {
                        Trace.TraceInformation("Fullscreen update received, resuming image(s) processing, remote session {0}", RemoteSession.Id);
                        _fullscreenPending = false;
                    }
                }

                // if using a websocket, send the image
                if (WebSocket != null)
                {
                    if (WebSocket.IsAvailable)
                    {
                        Trace.TraceInformation("Sending image {0} ({1}) on websocket, remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                        WebSocket.Send(
                            image.Idx + "," +
                            image.PosX + "," +
                            image.PosY + "," +
                            image.Width + "," +
                            image.Height + "," +
                            image.Format.ToString().ToLower() + "," +
                            image.Quality + "," +
                            image.Base64Data + "," +
                            image.Fullscreen.ToString().ToLower());
                    }
                    else
                    {
                        Trace.TraceInformation("Websocket is unavailable (connection closed by client?), remote session {0}, status: {1}", RemoteSession.Id, RemoteSession.State);
                    }
                }
                // otherwise cache it (will be retrieved later)
                else
                {
                    lock (ImageEventLock)
                    {
                        _imageCache.Insert(
                            "remoteSessionImage_" + RemoteSession.Id + "_" + image.Idx,
                            image,
                            null,
                            DateTime.Now.AddMilliseconds(_imageCacheDuration),
                            Cache.NoSlidingExpiration);

                        // last received image index
                        _lastReceivedImageIdx = image.Idx;

                        // if waiting for a new image, signal the reception
                        if (ImageEventPending)
                        {
                            ImageEventPending = false;
                            Monitor.Pulse(ImageEventLock);
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to process update {0}, remote session {1} ({2})", data, RemoteSession.Id, exc);
            }
        }
예제 #11
0
        // new image
        private void ProcessUpdate(byte[] data)
        {
            try
            {
                if (data.Length <= 36)
                {
                    throw new Exception("invalid image data");
                }

                // image info (8 items, 32 bits each => 8 * 4 = 32 bytes)
                var imgInfo = new byte[32];
                Array.Copy(data, 4, imgInfo, 0, 32);

                // CAUTION! if the remote session is reconnected (i.e.: browser resize), a new instance of wfreerdp is spawned
                // the image index can no longer be handled by wfreerdp, this must be done by the remote session manager
                // the image index provided by wfreerdp is relative to its own instance, if needed

                var image = new RemoteSessionImage
                {
                    //Idx = BitConverter.ToInt32(imgInfo, 0),
                    Idx        = _imageIdx == int.MaxValue ? 1 : ++_imageIdx,
                    PosX       = BitConverter.ToInt32(imgInfo, 4),
                    PosY       = BitConverter.ToInt32(imgInfo, 8),
                    Width      = BitConverter.ToInt32(imgInfo, 12),
                    Height     = BitConverter.ToInt32(imgInfo, 16),
                    Format     = (ImageFormat)BitConverter.ToInt32(imgInfo, 20),
                    Quality    = BitConverter.ToInt32(imgInfo, 24),
                    Fullscreen = BitConverter.ToInt32(imgInfo, 28) == 1,
                    Data       = new byte[data.Length - 36]
                };

                Array.Copy(data, 36, image.Data, 0, data.Length - 36);

                // cache the image, even if using websocket (used to retrieve the mouse cursor on IE)
                _cache.Insert(
                    "remoteSessionImage_" + RemoteSession.Id + "_" + image.Idx,
                    image,
                    null,
                    DateTime.Now.AddMilliseconds(_imageCacheDuration),
                    Cache.NoSlidingExpiration);

                Trace.TraceInformation("Received image {0} ({1}), remote session {2}", image.Idx, (image.Fullscreen ? "screen" : "region"), RemoteSession.Id);

                // a fullscreen update was requested
                if (FullscreenEventPending && image.Fullscreen)
                {
                    Trace.TraceInformation("Fullscreen update received, remote session {0}", RemoteSession.Id);
                    FullscreenEventPending = false;

                    // screenshot request
                    if (ScreenshotEventLock != null)
                    {
                        lock (ScreenshotEventLock)
                        {
                            // screenshot image index
                            ScreenshotImageIdx = image.Idx;

                            // if waiting for a screenshot, signal the reception
                            if (ScreenshotEventPending)
                            {
                                ScreenshotEventPending = false;
                                Monitor.Pulse(ScreenshotEventLock);
                            }
                        }
                    }
                }

                // send update to client(s)
                foreach (var client in Clients.Values)
                {
                    // send the update if the client latency is normal or if it's a fullscreen update
                    if (client.Latency <= _imageCacheDuration || image.Fullscreen)
                    {
                        // websocket(s)
                        if (client.WebSockets != null && client.WebSockets.Count > 0)
                        {
                            // round robin on the client websockets down pool
                            if (client.WebSocketsRoundRobinIdx >= client.WebSockets.Count)
                            {
                                client.WebSocketsRoundRobinIdx = 0;
                            }

                            Trace.TraceInformation("Sending image {0} ({1}) on websocket, client {2}, remote session {3}", image.Idx, (image.Fullscreen ? "screen" : "region"), client.Id, RemoteSession.Id);
                            client.WebSockets[client.WebSocketsRoundRobinIdx++].SendImage(image);
                        }
                        // event source
                        else if (client.EventSource != null)
                        {
                            Trace.TraceInformation("Sending image {0} ({1}) on event source, client {2}, remote session {3}", image.Idx, (image.Fullscreen ? "screen" : "region"), client.Id, RemoteSession.Id);
                            client.EventSource.SendImage(image);
                        }
                        // long polling
                        else if (client.LongPolling != null)
                        {
                            Trace.TraceInformation("Sending image {0} ({1}) on long polling, client {2}, remote session {3}", image.Idx, (image.Fullscreen ? "screen" : "region"), client.Id, RemoteSession.Id);
                            client.LongPolling.SendImage(image);
                        }
                        // xhr: updates are polled against the cache by the client
                    }
                }

                // image event
                lock (_imageEventLock)
                {
                    // last received image index
                    _lastReceivedImageIdx = image.Idx;

                    // if waiting for a new image, signal the reception
                    if (_imageEventPending)
                    {
                        _imageEventPending = false;
                        Monitor.Pulse(_imageEventLock);
                    }
                }
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to process update, remote session {0} ({1})", RemoteSession.Id, exc);
            }
        }
 public void SendImage(RemoteSessionImage image)
 {
     Send(GetImageText(image));
 }
 public void SendImage(RemoteSessionImage image)
 {
     Send("<script>parent.lpProcessImage(" + GetImageText(image) + ");</script>");
 }
예제 #14
0
 public void SendImage(RemoteSessionImage image)
 {
     Send(string.Format("<script>parent.lpProcessImage({0});</script>", GetImageText(image)));
 }