Ejemplo n.º 1
0
        private SimpleSocket CreateSocketContext()
        {
            var socketContext = new SimpleSocket();
            socketContext.Connected = (clientSocketContext) =>
            {
                Task.Run(async () =>
                {
                    try
                    {

                        // Register service server
                        await socketContext.WriteStream.WriteInt16Async((short)RouterMessage.ServiceProvideServer);
                        await socketContext.WriteStream.WriteStringAsync(serverUrl);
                        await socketContext.WriteStream.FlushAsync();

                        while (true)
                        {
                            var routerMessage = (RouterMessage)await socketContext.ReadStream.ReadInt16Async();

                            switch (routerMessage)
                            {
                                case RouterMessage.ServiceRequestServer:
                                {
                                    var requestedUrl = await clientSocketContext.ReadStream.ReadStringAsync();
                                    var guid = await clientSocketContext.ReadStream.ReadGuidAsync();

                                    // Spawn actual server
                                    var realServerSocketContext = new SimpleSocket();
                                    realServerSocketContext.Connected = async (clientSocketContext2) =>
                                    {
                                        // Write connection string
                                        await clientSocketContext2.WriteStream.WriteInt16Async((short)RouterMessage.ServerStarted);
                                        await clientSocketContext2.WriteStream.WriteGuidAsync(guid);

                                        // Delegate next steps to actual server
                                        HandleClient(clientSocketContext2, requestedUrl);
                                    };

                                    // Start connection
                                    await realServerSocketContext.StartClient(address, port);
                                    break;
                                }
                                default:
                                    Console.WriteLine("Router: Unknown message: {0}", routerMessage);
                                    throw new ArgumentOutOfRangeException();
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // TODO: Ideally, separate socket-related error messages (disconnection) from real errors
                        // Unfortunately, it seems WinRT returns Exception, so it seems we can't filter with SocketException/IOException only?
                        Log.Info("Client {0}:{1} disconnected with exception: {2}", clientSocketContext.RemoteAddress, clientSocketContext.RemotePort, e.Message);
                        clientSocketContext.Dispose();
                    }
                });
            };

            return socketContext;
        }
Ejemplo n.º 2
0
        public async Task StartServer(int port, bool singleConnection)
        {
            // Create TCP listener
            var listener = new TcpSocketListener(2048);

            listener.ConnectionReceived = async (sender, args) =>
            {
                var clientSocketContext = new SimpleSocket();

                try
                {
                    // Stop listening if we accept only a single connection
                    if (singleConnection)
                        await listener.StopListeningAsync();

                    clientSocketContext.SetSocket((TcpSocketClient)args.SocketClient);

                    // Do an ack with magic packet (necessary so that we know it's not a dead connection,
                    // it sometimes happen when doing port forwarding because service don't refuse connection right away but only fails when sending data)
                    await SendAndReceiveAck(clientSocketContext.socket, MagicAck, MagicAck);

                    if (Connected != null)
                        Connected(clientSocketContext);

                    clientSocketContext.isConnected = true;
                }
                catch (Exception)
                {
                    clientSocketContext.DisposeSocket();
                }
            };

            // Start listening
            await listener.StartListeningAsync(port);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Initiates a connection to the router.
        /// </summary>
        /// <returns></returns>
        private static Task<SimpleSocket> InitiateConnectionToRouter()
        {
            var socketContextTCS = new TaskCompletionSource<SimpleSocket>();
            var socketContext = new SimpleSocket();
            socketContext.Connected = async context =>
            {
                socketContextTCS.TrySetResult(context);
            };

            Task.Run(async () =>
            {
                try
                {
                    // If connecting as a client, try once, otherwise try to listen multiple time (in case port is shared)
                    switch (ConnectionMode)
                    {
                        case RouterConnectionMode.Connect:
                            await socketContext.StartClient("127.0.0.1", DefaultPort);
                            break;
                        case RouterConnectionMode.Listen:
                            await socketContext.StartServer(DefaultListenPort, true, 10);
                            break;
                        case RouterConnectionMode.ConnectThenListen:
                            bool clientException = false;
                            try
                            {
                                await socketContext.StartClient("127.0.0.1", DefaultPort);
                            }
                            catch (Exception) // Ideally we should filter SocketException, but not available on some platforms (maybe it should be wrapped in a type available on all paltforms?)
                            {
                                clientException = true;
                            }
                            if (clientException)
                            {
                                await socketContext.StartServer(DefaultListenPort, true, 10);
                            }
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
                catch (Exception e)
                {
                    Log.Error("Could not connect to connection router using mode {0}: {1}", ConnectionMode, e.Message);
                    throw;
                }
            });

            // Wait for server to connect to us (as a Task)
            return socketContextTCS.Task;
        }
Ejemplo n.º 4
0
        private SimpleSocket CreateSocketContext()
        {
            var socketContext = new SimpleSocket();
            socketContext.Connected = (clientSocketContext) =>
            {
                Task.Run(async () =>
                {
                    try
                    {
                        // Routing
                        var routerMessage = (RouterMessage)await clientSocketContext.ReadStream.ReadInt16Async();

                        Log.Info("Client {0}:{1} connected, with message {2}", clientSocketContext.RemoteAddress, clientSocketContext.RemotePort, routerMessage);

                        switch (routerMessage)
                        {
                            case RouterMessage.ServiceProvideServer:
                            {
                                await HandleMessageServiceProvideServer(clientSocketContext);
                                break;
                            }
                            case RouterMessage.ServerStarted:
                            {
                                await HandleMessageServerStarted(clientSocketContext);
                                break;
                            }
                            case RouterMessage.ClientRequestServer:
                            {
                                await HandleMessageClientRequestServer(clientSocketContext);
                                break;
                            }
                            default:
                                throw new ArgumentOutOfRangeException(string.Format("Router: Unknown message: {0}", routerMessage));
                        }
                    }
                    catch (Exception e)
                    {
                        // TODO: Ideally, separate socket-related error messages (disconnection) from real errors
                        // Unfortunately, it seems WinRT returns Exception, so it seems we can't filter with SocketException/IOException only?
                        Log.Info("Client {0}:{1} disconnected with exception: {2}", clientSocketContext.RemoteAddress, clientSocketContext.RemotePort, e.Message);
                        clientSocketContext.Dispose();
                    }
                });
            };

            return socketContext;
        }
Ejemplo n.º 5
0
        private SimpleSocket CreateSocketContext()
        {
            var socketContext = new SimpleSocket();
            socketContext.Connected = async (clientSocketContext) =>
            {
                // Register service server
                await socketContext.WriteStream.WriteInt16Async((short)RouterMessage.ServiceProvideServer);
                await socketContext.WriteStream.WriteStringAsync(serverUrl);
                await socketContext.WriteStream.FlushAsync();

                while (true)
                {
                    var routerMessage = (RouterMessage)await socketContext.ReadStream.ReadInt16Async();

                    switch (routerMessage)
                    {
                        case RouterMessage.ServiceRequestServer:
                        {
                            var requestedUrl = await clientSocketContext.ReadStream.ReadStringAsync();
                            var guid = await clientSocketContext.ReadStream.ReadGuidAsync();

                            // Spawn actual server
                            var realServerSocketContext = new SimpleSocket();
                            realServerSocketContext.Connected = async (clientSocketContext2) =>
                            {
                                // Write connection string
                                await clientSocketContext2.WriteStream.WriteInt16Async((short)RouterMessage.ServerStarted);
                                await clientSocketContext2.WriteStream.WriteGuidAsync(guid);

                                // Delegate next steps to actual server
                                HandleClient(clientSocketContext2, requestedUrl);
                            };

                            // Start connection
                            await realServerSocketContext.StartClient(address, port);
                            break;
                        }
                        default:
                            Console.WriteLine("Router: Unknown message: {0}", routerMessage);
                            throw new ArgumentOutOfRangeException();
                    }
                }
            };

            return socketContext;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Initiates a connection to the router.
        /// </summary>
        /// <returns></returns>
        private static Task<SimpleSocket> InitiateConnectionToRouter()
        {
            var socketContextTCS = new TaskCompletionSource<SimpleSocket>();
            var socketContext = new SimpleSocket();
            socketContext.Connected = async context =>
            {
                socketContextTCS.TrySetResult(context);
            };

            Task.Run(async () =>
            {
                // Keep trying to establish connections until no errors
                bool hasErrors;
                do
                {
                    try
                    {
                        hasErrors = false;
                        if (PlatformIsPortForward)
                            await socketContext.StartServer(DefaultListenPort, true);
                        else
                            await socketContext.StartClient("127.0.0.1", DefaultPort);
                    }
                    catch (Exception)
                    {
                        hasErrors = true;
                    }
                    if (hasErrors)
                    {
                        // Wait a little bit before next try
                        await Task.Delay(100);
                    }
                } while (hasErrors);
            });

            // Wait for server to connect to us (as a Task)
            return socketContextTCS.Task;
        }
Ejemplo n.º 7
0
        /// <inheritdoc/>
        protected override async void HandleClient(SimpleSocket clientSocket, string url)
        {
            string[] urlSegments;
            string urlParameters;
            RouterHelper.ParseUrl(url, out urlSegments, out urlParameters);
            var parameters = RouterHelper.ParseQueryString(urlParameters);
            var mode = parameters["mode"];

            // We accept everything
            await AcceptConnection(clientSocket);

            var socketMessageLayer = new SocketMessageLayer(clientSocket, true);

            Guid? packageId = null;
            {
                Guid packageIdParsed;
                if (Guid.TryParse(parameters["packageid"], out packageIdParsed))
                    packageId = packageIdParsed;
            }

            if (mode == "gamestudio")
            {
                Console.WriteLine("GameStudio mode started!");

                if (!packageId.HasValue)
                    return;

                lock (gameStudioPerPackageId)
                {
                    gameStudioPerPackageId[packageId.Value] = socketMessageLayer;
                }
            }
            else
            {
                // Create an effect compiler per connection
                var effectCompiler = new EffectCompiler();

                Console.WriteLine("Client connected");

                // TODO: Properly close the file, and choose where to copy/move it?
                var recordedEffectCompile = new EffectLogStore(new MemoryStream());

                // TODO: This should come from an "init" packet
                effectCompiler.SourceDirectories.Add(EffectCompilerBase.DefaultSourceShaderFolder);

                // Make a VFS that will access remotely the DatabaseFileProvider
                // TODO: Is that how we really want to do that in the future?
                var networkVFS = new NetworkVirtualFileProvider(socketMessageLayer, "/asset");
                VirtualFileSystem.RegisterProvider(networkVFS);
                effectCompiler.FileProvider = networkVFS;

                socketMessageLayer.AddPacketHandler<RemoteEffectCompilerEffectRequest>((packet) => ShaderCompilerRequestHandler(socketMessageLayer, recordedEffectCompile, effectCompiler, packet));

                socketMessageLayer.AddPacketHandler<RemoteEffectCompilerEffectRequested>((packet) =>
                {
                    if (!packageId.HasValue)
                        return;

                    SocketMessageLayer gameStudio;
                    lock (gameStudioPerPackageId)
                    {
                        if (!gameStudioPerPackageId.TryGetValue(packageId.Value, out gameStudio))
                            return;
                    }

                    // Forward to game studio
                    gameStudio.Send(packet);
                });
            }

            Task.Run(() => socketMessageLayer.MessageLoop());
        }
Ejemplo n.º 8
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);
                        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;
            }
        }
Ejemplo n.º 9
0
 public Service(SimpleSocket socket)
 {
     Socket = socket;
 }
Ejemplo n.º 10
0
 private async Task ForwardSocket(SimpleSocket source, SimpleSocket target)
 {
     var buffer = new byte[1024];
     while (true)
     {
         var bufferLength = await source.ReadStream.ReadAsync(buffer, 0, buffer.Length);
         if (bufferLength == 0)
             throw new IOException("Socket closed");
         await target.WriteStream.WriteAsync(buffer, 0, bufferLength);
         await target.WriteStream.FlushAsync();
     }
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Handles ServiceProvideServer messages. It allows service to publicize what "server" they can instantiate.
        /// </summary>
        /// <param name="clientSocket">The client socket context.</param>
        /// <returns></returns>
        private async Task HandleMessageServiceProvideServer(SimpleSocket clientSocket)
        {
            var url = await clientSocket.ReadStream.ReadStringAsync();
            TaskCompletionSource<Service> service;

            lock (registeredServices)
            {
                if (!registeredServices.TryGetValue(url, out service))
                {
                    service = new TaskCompletionSource<Service>();
                    registeredServices.Add(url, service);
                }

                service.TrySetResult(new Service(clientSocket));
            }

            // TODO: Handle server disconnections
            //clientSocketContext.Disconnected += 
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Handles ServerStarted messages. It happens when service opened a new "server" connection back to us.
        /// </summary>
        /// <param name="clientSocket">The client socket context.</param>
        /// <returns></returns>
        private async Task HandleMessageServerStarted(SimpleSocket clientSocket)
        {
            var guid = await clientSocket.ReadStream.ReadGuidAsync();
            var errorCode = await clientSocket.ReadStream.ReadInt32Async();
            var errorMessage = (errorCode != 0) ? await clientSocket.ReadStream.ReadStringAsync() : null;

            // Notify any waiter that a server with given GUID is available
            TaskCompletionSource<SimpleSocket> serverSocketTCS;
            lock (pendingServers)
            {
                if (!pendingServers.TryGetValue(guid, out serverSocketTCS))
                {
                    Log.Error("Could not find a matching server Guid");
                    clientSocket.Dispose();
                    return;
                }

                pendingServers.Remove(guid);
            }

            if (errorCode != 0)
                serverSocketTCS.TrySetException(new Exception(errorMessage));
            else
                serverSocketTCS.TrySetResult(clientSocket);
        }
Ejemplo n.º 13
0
 /// <summary>
 /// Let router knows that we want to continue with that connection.
 /// </summary>
 /// <param name="clientSocket">The client socket.</param>
 /// <returns></returns>
 protected async Task AcceptConnection(SimpleSocket clientSocket)
 {
     await clientSocket.WriteStream.WriteInt32Async(0); // error code OK
     await clientSocket.WriteStream.FlushAsync();
 }
Ejemplo n.º 14
0
 /// <summary>
 /// Called when a new client connection has been established.
 /// Before writing anything to the stream, HandleClient is responsible for either calling <see cref="AcceptConnection"/> or <see cref="RefuseConnection"/>.
 /// </summary>
 /// <param name="clientSocket">The client socket.</param>
 /// <param name="url">The requested URL.</param>
 protected abstract void HandleClient(SimpleSocket clientSocket, string url);
Ejemplo n.º 15
0
 /// <summary>
 /// Let router knows we refuse the connection, and why.
 /// </summary>
 /// <param name="clientSocket">The client socket.</param>
 /// <param name="errorCode">The error code.</param>
 /// <param name="errorMessage">The error message.</param>
 /// <returns></returns>
 protected async Task RefuseConnection(SimpleSocket clientSocket, int errorCode, string errorMessage)
 {
     await clientSocket.WriteStream.WriteInt32Async(errorCode);
     await clientSocket.WriteStream.WriteStringAsync(errorMessage);
     await clientSocket.WriteStream.FlushAsync();
 }