Beispiel #1
0
        /// <summary>
        /// Handles ClientRequestServer messages.
        /// It will try to find a matching service (spawn it if not started yet), and ask it to establish a new "server" connection back to us.
        /// </summary>
        /// <param name="clientSocket">The client socket context.</param>
        /// <returns></returns>
        private async Task HandleMessageClientRequestServer(SimpleSocket clientSocket)
        {
            // Check for an existing server
            // TODO: Proper Url parsing (query string)
            var url = await clientSocket.ReadStream.ReadStringAsync();

            string[] urlSegments;
            string   urlParameters;

            RouterHelper.ParseUrl(url, out urlSegments, out urlParameters);
            if (urlSegments.Length == 0)
            {
                throw new InvalidOperationException("No URL Segments");
            }

            SimpleSocket          serverSocket = null;
            ExceptionDispatchInfo serverSocketCapturedException = null;

            try
            {
                // For now, we handle only "service" URL
                switch (urlSegments[0])
                {
                case "service":
                {
                    // From the URL, start service (if not started yet) and ask it to provide a server
                    serverSocket = await SpawnServerFromService(url, false);

                    break;
                }

                case "task":
                    // From the URL, start service (if not started yet) and ask it to provide a server
                    serverSocket = await SpawnServerFromService(url, true);

                    break;

                default:
                    throw new InvalidOperationException("This type of URL is not supported");
                }
            }
            catch (Exception e)
            {
                serverSocketCapturedException = ExceptionDispatchInfo.Capture(e);
            }


            if (serverSocketCapturedException != null)
            {
                try
                {
                    // Notify client that there was an error
                    await clientSocket.WriteStream.WriteInt16Async((short)RouterMessage.ClientServerStarted);

                    await clientSocket.WriteStream.WriteInt32Async(1); // error code Failure

                    await clientSocket.WriteStream.WriteStringAsync(serverSocketCapturedException.SourceException.Message);

                    await clientSocket.WriteStream.FlushAsync();
                }
                finally
                {
                    serverSocketCapturedException.Throw();
                }
            }

            try
            {
                // Notify client that we've found a server for it
                await clientSocket.WriteStream.WriteInt16Async((short)RouterMessage.ClientServerStarted);

                await clientSocket.WriteStream.WriteInt32Async(0); // error code OK

                await clientSocket.WriteStream.FlushAsync();

                // Let's forward clientSocketContext and serverSocketContext
                await await Task.WhenAny(
                    ForwardSocket(clientSocket, serverSocket),
                    ForwardSocket(serverSocket, clientSocket));
            }
            catch
            {
                serverSocket.Dispose();
                throw;
            }
        }
Beispiel #2
0
        private async Task <SimpleSocket> SpawnServerFromService(string url, bool task)
        {
            // Ideally we would like to reuse Uri (or some other similar code), but it doesn't work without a Host
            var parameterIndex       = url.IndexOf('?');
            var urlWithoutParameters = parameterIndex != -1 ? url.Substring(0, parameterIndex) : url;

            string[] urlSegments;
            string   urlParameters;

            RouterHelper.ParseUrl(url, out urlSegments, out urlParameters);

            // Find a matching server
            TaskCompletionSource <Service> serviceTcs;

            lock (registeredServices)
            {
                if (!registeredServices.TryGetValue(urlWithoutParameters, out serviceTcs))
                {
                    if (task)
                    {
                        throw new Exception("ConnectionRouter task not found, a task won't spawn a new service on demand instead must be started explicitly.");
                    }

                    serviceTcs = new TaskCompletionSource <Service>();
                    registeredServices.Add(urlWithoutParameters, serviceTcs);
                }

                if (!serviceTcs.Task.IsCompleted)
                {
                    if (urlSegments.Length < 3)
                    {
                        Log.Error("{0} action URL {1} is invalid", RouterMessage.ClientRequestServer, url);
                        throw new InvalidOperationException();
                    }

                    var xenkoVersion = urlSegments[1];
                    var serviceExe   = urlSegments[2];

                    var xenkoSdkDir = RouterHelper.FindXenkoSdkDir(xenkoVersion);
                    if (xenkoSdkDir == null)
                    {
                        Log.Error("{0} action URL {1} references a Xenko version which is not installed", RouterMessage.ClientRequestServer, url);
                        throw new InvalidOperationException();
                    }

                    var servicePath = Path.Combine(xenkoSdkDir, @"Bin\Windows-Direct3D11", serviceExe);
                    RunServiceProcessAndLog(servicePath);
                }
            }

            var service = await serviceTcs.Task;

            // Generate connection Guid
            var guid            = Guid.NewGuid();
            var serverSocketTcs = new TaskCompletionSource <SimpleSocket>();

            lock (pendingServers)
            {
                pendingServers.Add(guid, serverSocketTcs);
            }

            await service.SendLock.WaitAsync();

            try
            {
                // Notify service that we want it to establish back a new connection to us for this client
                await service.Socket.WriteStream.WriteInt16Async((short)RouterMessage.ServiceRequestServer);

                await service.Socket.WriteStream.WriteStringAsync(url);

                await service.Socket.WriteStream.WriteGuidAsync(guid);

                await service.Socket.WriteStream.FlushAsync();
            }
            finally
            {
                service.SendLock.Release();
            }

            // Should answer within 2 sec
            var ct = new CancellationTokenSource(2000);

            ct.Token.Register(() => serverSocketTcs.TrySetException(new TimeoutException("Server could not connect back in time")));

            // Wait for such a server to be available
            return(await serverSocketTcs.Task);
        }
Beispiel #3
0
        /// <summary>
        /// Handles ClientRequestServer messages.
        /// It will try to find a matching service (spawn it if not started yet), and ask it to establish a new "server" connection back to us.
        /// </summary>
        /// <param name="clientSocket">The client socket context.</param>
        /// <returns></returns>
        private async Task HandleMessageClientRequestServer(SimpleSocket clientSocket)
        {
            // Check for an existing server
            // TODO: Proper Url parsing (query string)
            var url = await clientSocket.ReadStream.ReadStringAsync();

            Log.Info("Client {0}:{1} sent message ClientRequestServer with URL {2}", clientSocket.RemoteAddress, clientSocket.RemotePort, url);

            string[] urlSegments;
            string   urlParameters;

            RouterHelper.ParseUrl(url, out urlSegments, out urlParameters);
            if (urlSegments.Length == 0)
            {
                throw new InvalidOperationException("No URL Segments");
            }

            SimpleSocket          serverSocket = null;
            ExceptionDispatchInfo serverSocketCapturedException = null;

            try
            {
                // For now, we handle only "service" URL
                switch (urlSegments[0])
                {
                case "service":
                {
                    // From the URL, start service (if not started yet) and ask it to provide a server
                    serverSocket = await SpawnServerFromService(url, false);

                    break;
                }

                case "task":
                {
                    // From the URL, start service (if not started yet) and ask it to provide a server
                    serverSocket = await SpawnServerFromService(url, true);
                }
                break;

                case "redirect":
                {
                    // Redirect to a IP/port
                    serverSocket = new SimpleSocket();
                    var host = urlSegments[1];
                    var port = int.Parse(urlSegments[2]);

                    // Note: for security reasons, we currently use a whitelist
                    if (host == "XenkoBuild.siliconstudio.co.jp" && port == 1832)
                    {
                        await serverSocket.StartClient(host, port, false);
                    }
                    else
                    {
                        throw new InvalidOperationException("Trying to redirect to a non-whitelisted host/port");
                    }
                    break;
                }

                default:
                    throw new InvalidOperationException("This type of URL is not supported");
                }
            }
            catch (Exception e)
            {
                serverSocketCapturedException = ExceptionDispatchInfo.Capture(e);
            }


            if (serverSocketCapturedException != null)
            {
                try
                {
                    // Notify client that there was an error
                    await clientSocket.WriteStream.WriteInt16Async((short)RouterMessage.ClientServerStarted);

                    await clientSocket.WriteStream.WriteInt32Async(1); // error code Failure

                    await clientSocket.WriteStream.WriteStringAsync(serverSocketCapturedException.SourceException.Message);

                    await clientSocket.WriteStream.FlushAsync();
                }
                finally
                {
                    serverSocketCapturedException.Throw();
                }
            }

            try
            {
                // Notify client that we've found a server for it
                await clientSocket.WriteStream.WriteInt16Async((short)RouterMessage.ClientServerStarted);

                await clientSocket.WriteStream.WriteInt32Async(0); // error code OK

                await clientSocket.WriteStream.FlushAsync();

                // Let's forward clientSocketContext and serverSocketContext
                await await Task.WhenAny(
                    ForwardSocket(clientSocket, serverSocket),
                    ForwardSocket(serverSocket, clientSocket));
            }
            catch
            {
                serverSocket.Dispose();
                throw;
            }
        }