/// <summary> /// Processes an incoming RemoteMethodResponse /// </summary> /// <param name="response">The RemoteMethodResponse that is to be processed</param> protected virtual void processRemoteMethodResponse(RemoteMethodResponse response) { //get the RemoteMethodCall that triggered the response from the cache RemoteMethodCall call = unrepliedCalls.ContainsKey(response.CallId) ? unrepliedCalls[response.CallId] : null; //response is only processed, when the associated method call could be found if (call != null) { //stop the connection from timing out as we just received a message timeoutTimer.Stop(); //if call was synchronous => put the response value in the value cache and release wait handle if (synchronousCalls_WaitHandles.ContainsKey(call.CallId)) { synchonousCalls_ValueCache.Add(call.CallId, response.ResponseValue); synchronousCalls_WaitHandles[call.CallId].Set(); } //remove call from unreplied calls unrepliedCalls.Remove(response.CallId); //decrease the number of repsonses expected from the target client (connection will not time out when no responses are expected if (call.ResponseExpected) { this.expectedResponseCount--; } //if there are still call taht are unreplied, restart the timeout-timer if (unrepliedCalls.Any()) { timeoutTimer.Start(); } } }
public void TestRemoteMethodResponseSerialization_MissingResponseValueElement() { var response = new RemoteMethodResponse(); response.ComponentName = "component"; response.CallId = Guid.NewGuid(); response.ResponseValue = null; var xml = response.Serialize(); xml.Elements(XName.Get("ResponseValue", xml.Name.NamespaceName)).Remove(); var roundtrip = new RemoteMethodResponse(); Assert.IsFalse(roundtrip.Validate(xml)); }
public void TestRemoteMethodResponseSerialization() { var response = new RemoteMethodResponse(); response.ComponentName = "component"; response.CallId = Guid.NewGuid(); response.ResponseValue = 5; var xml = response.Serialize(); var roundtrip = new RemoteMethodResponse(); Assert.IsTrue(roundtrip.Validate(xml)); roundtrip.Deserialize(xml); Assert.IsNotNull(roundtrip); Assert.AreEqual<Guid>(response.CallId, roundtrip.CallId); Assert.AreEqual<string>(response.ComponentName, roundtrip.ComponentName); Assert.AreEqual<int>((int)response.ResponseValue, (int)roundtrip.ResponseValue); }
/// <summary> /// Processes an incoming RemoteMethodCall /// </summary> /// <param name="call">The RemoteMethodCall that is to be processed</param> /// <param name="component">The component that will handle the call</param> protected virtual void processRemoteMethodCall(RemoteMethodCall call, IComponent component) { //get the call's result CallResult callResult = getCallResult(call, component); if (callResult is ErrorResult) { //result was error => send RemoteError sendMessage( new RemoteError((callResult as ErrorResult).ErrorCode) { CallId = call.CallId, ComponentName = call.ComponentName } ); } else if (callResult is ResponseResult) { //result was a response => send RemoteMethodResponse RemoteMethodResponse response = new RemoteMethodResponse(); response.CallId = call.CallId; response.ComponentName = call.ComponentName; response.ResponseValue = (callResult as ResponseResult).ResponseValue; sendMessage(response); } else if (callResult is VoidResult) { //result was VoidResult => do nothing } else { //should not happen, ResponseResult, ErrorResult and VoidResult are the only known subclasses of CallResult the logger.Error("ProcessMessage() encountered an unknown type of CallResult"); } //If a post-processing action has been specified in the call, invoke it now if (callResult.PostProcessingAction != null) { callResult.PostProcessingAction.Invoke(); } }
/// <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> /// 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> /// Processes an incoming RemoteMethodResponse /// </summary> /// <param name="response">The RemoteMethodResponse that is to be processed</param> protected virtual void processRemoteMethodResponse(RemoteMethodResponse response) { //get the RemoteMethodCall that triggered the response from the cache RemoteMethodCall call = unrepliedCalls.ContainsKey(response.CallId) ? unrepliedCalls[response.CallId] : null; //response is only processed, when the associated method call could be found if (call != null) { //stop the connection from timing out as we just received a message timeoutTimer.Stop(); //if call was synchronous => put the response value in the value cache and release wait handle if (synchronousCalls_WaitHandles.ContainsKey(call.CallId)) { synchonousCalls_ValueCache.Add(call.CallId, response.ResponseValue); synchronousCalls_WaitHandles[call.CallId].Set(); } //remove call from unreplied calls unrepliedCalls.Remove(response.CallId); //decrease the number of repsonses expected from the target client (connection will not time out when no responses are expected if (call.ResponseExpected) this.expectedResponseCount--; //if there are still call taht are unreplied, restart the timeout-timer if (unrepliedCalls.Any()) { timeoutTimer.Start(); } } }