public async Task MessageLoop() { try { while (true) { // Get next packet size var bufferSize = await context.ReadStream.ReadInt32Async(); // Get next packet data (until complete) var buffer = new byte[bufferSize]; await context.ReadStream.ReadAllAsync(buffer, 0, bufferSize); // Deserialize as an object var binaryReader = new BinarySerializationReader(new MemoryStream(buffer)); object obj = null; binaryReader.Context.SerializerSelector = SerializerSelector.AssetWithReuse; binaryReader.SerializeExtended <object>(ref obj, ArchiveMode.Deserialize, null); // If it's a message, process it separately (StreamId) if (obj is SocketMessage) { var socketMessage = (SocketMessage)obj; ProcessMessage(socketMessage); } // Check if there is a specific handler for this packet type bool handlerFound; Tuple <Action <object>, bool> handler; lock (packetHandlers) { handlerFound = packetHandlers.TryGetValue(obj.GetType(), out handler); // one-time handler if (handlerFound && handler.Item2) { packetHandlers.Remove(obj.GetType()); } } if (handlerFound) { handler.Item1(obj); } } } catch (Exception) { context.Dispose(); throw; } }
/// <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); }
public async Task MessageLoop() { try { while (true) { // Get next packet size var bufferSize = await context.ReadStream.ReadInt32Async(); // Get next packet data (until complete) var buffer = new byte[bufferSize]; await context.ReadStream.ReadAllAsync(buffer, 0, bufferSize); // Deserialize as an object var binaryReader = new BinarySerializationReader(new MemoryStream(buffer)); object obj = null; binaryReader.Context.SerializerSelector = SerializerSelector.AssetWithReuse; binaryReader.SerializeExtended <object>(ref obj, ArchiveMode.Deserialize, null); // If it's a message, process it separately (StreamId) var message = obj as SocketMessage; if (message != null) { var socketMessage = message; ProcessMessage(socketMessage); } // Check if there is a specific handler for this packet type bool handlerFound; Tuple <Action <object>, bool> handler; lock (packetHandlers) { handlerFound = packetHandlers.TryGetValue(obj.GetType(), out handler); // one-time handler if (handlerFound && handler.Item2) { packetHandlers.Remove(obj.GetType()); } } if (handlerFound) { try { handler.Item1(obj); } catch (Exception ex) { if (message != null && message.StreamId != 0) { var exceptionMessage = new ExceptionMessage { ExceptionInfo = new ExceptionInfo(ex), StreamId = message.StreamId }; await Send(exceptionMessage); } } } } } catch (Exception e) { context.Dispose(); lock (packetCompletionTasks) { // Cancel all pending packets foreach (var packetCompletionTask in packetCompletionTasks) { packetCompletionTask.Value.TrySetException(e); } packetCompletionTasks.Clear(); } throw; } }
/// <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; } }