/// <summary> /// Processes an incoming message (using the MessageProcessor for deserialization) /// </summary> /// <param name="message">The message to be processed</param> private void processMessage(ParsingResult message) { //parse the message XElement xmlMessage; RpcMessage msg = null; var body = message.Payload.ToStringUTF8(); try { //try to parse it as XML xmlMessage = XElement.Parse(body); switch (xmlMessage.Name.LocalName.ToLower()) { case "remotemethodcall": msg = new RemoteMethodCall(); break; case "remotemethodresponse": msg = new RemoteMethodResponse(); break; case "remoteerror": msg = new RemoteError(); break; } if (!msg.Validate(xmlMessage)) { logger.Error("Message from {0} could not be validated", this.Target); var error = new RemoteError(RemoteErrorCode.InvalidXmlError); sendMessage(error); return; } msg.Deserialize(xmlMessage); } //Catch XmlException and wrap it into a format exception (makes catching errors in the caller easier) catch (XmlException) { logger.Error("Could not parse message received from {0}", this.Target); RemoteError error = new RemoteError(RemoteErrorCode.InvalidXmlError); sendMessage(error); return; } //encryption is mandatory if TrustLevel is 2 or higher //if message was not encrypted it will result in a RemoteError and the connection will be reset if (this.TrustLevel >= 2 && !message.WasEncrypted && !(msg is RemoteMethodCall && (msg as RemoteMethodCall).MethodName == CoreMethods.SendResetNotice)) { RemoteError error = new RemoteError(RemoteErrorCode.EncryptionError); if (msg.CallId != Guid.Empty) { error.CallId = msg.CallId; } error.ComponentName = "Authentication"; //The RemoteError will not be encrypted WtlpClient.EncryptMessages = false; sendMessage(error); ResetConnection(); return; } if (msg is RemoteMethodCall) { //get the component responsible for handling the message string componentName = (msg as RpcMessage).ComponentName; var component = GetServerComponent(componentName); if (component == null) { //no component to handle the request was found => send a RemoteError as response and return RemoteError error = new RemoteError(RemoteErrorCode.ComponentNotFoundError); error.CallId = (msg as RemoteMethodCall).CallId; sendMessage(error); return; } var processingTask = new Task(delegate { processRemoteMethodCall(msg as RemoteMethodCall, component); }); processingTask.Start(); var heartBeatTask = new Task(delegate { var coreComponent = new CoreClientComponent(); coreComponent.ClientConnection = this; while (!processingTask.IsCompleted) { Thread.Sleep(25000); if (!processingTask.IsCompleted) { coreComponent.HeartbeatAsync(); } } }); heartBeatTask.Start(); } else if (msg is RemoteMethodResponse) { processRemoteMethodResponse(msg as RemoteMethodResponse); } else if (msg is RemoteError) { processRemoteError(msg as RemoteError); } else { logger.Error("ProcessMessage() encoutered an unknown type of Message"); sendMessage(new RemoteError(RemoteErrorCode.UnknownMessage)); } }
/// <summary> /// Send a message to the target client /// </summary> /// <param name="msg">The message to process and send</param> protected virtual void sendMessage(RpcMessage msg) { //if message is a RemoteMethodCall, it will be cached to be able to process response messages if (msg is RemoteMethodCall) { RemoteMethodCall call = msg as RemoteMethodCall; if (call.ResponseExpected) { unrepliedCalls.Add(call.CallId, call); expectedResponseCount++; timeoutTimer.Start(); } } //process the message using the MessageProcessor and pass the result to the ConnectionManager to send try { this.WtlpClient.Send(msg.Serialize().ToString().GetBytesUTF8()); } catch (WtlpException ex) { if (ex.Error == Result.Timeout) throw new TimeoutException(); else throw new RemoteErrorException(); } }