/// <summary> /// Parses an message received through the messaging client /// </summary> /// <param name="message"></param> private void parseMessage(string message) { //check if the message's format is valid if (!verifyMessageFormat(message)) { logger.Error("Received invalid message, aborting message processing"); sendresult(Result.InvalidFormat); return; } //get the messages metadata and payload IEnumerable <string> parts = message.Split(';').Where(x => !x.IsNullOrEmpty()); string payload_str = message.EndsWith(";") ? null : parts.Last(); parts = (payload_str == null) ? parts : parts.Take(parts.Count() - 1); //parse metadata keys var metadata = parts.Select(x => new Tuple <Key, string>((Key)Enum.Parse(typeof(Key), x.Split(':').First(), true), x.Split(':').Last())); //check for message id var messageIdQuery = metadata.Where(x => x.Item1 == Key.Message_id); int messageId = -1; if (!messageIdQuery.Any() || !int.TryParse(messageIdQuery.First().Item2, out messageId)) { logger.Warn("Invalid message. MessageId not found or invalid"); sendresult(Result.InvalidFormat); return; } //check if message is a delivery notification var resultQuery = metadata.Where(x => x.Item1 == Key.Result); if (metadata.Count() == 2 && messageId > 0 && resultQuery.Any()) { //handle delivery confirmation Result deliveryResult; if (!Enum.TryParse(resultQuery.First().Item2, true, out deliveryResult)) { deliveryResult = Result.UnknownError; } logger.Info("Received delivery confirmation for message {0} from {1}, Result: {2}", messageId, this.Recipient, deliveryResult); lock (this) { //store result in result cache and unblock waiting threads if (waitingThreads.ContainsKey(messageId)) { if (!messageResults.ContainsKey(messageId)) { messageResults.Add(messageId, deliveryResult); } else { messageResults[messageId] = deliveryResult; } //relese threads waiting for the result waitingThreads[messageId].Release(); } } return; } //check for splitted messages var fragmentIndexQuery = metadata.Where(x => x.Item1 == Key.Fragment_Index); var fragmentCountQuery = metadata.Where(x => x.Item1 == Key.Fragment_Count); if (fragmentCountQuery.Any() || fragmentIndexQuery.Any()) { logger.Info("Received splitted message"); if (!(fragmentIndexQuery.Any() && fragmentIndexQuery.Any())) { logger.Error("Missing metadata information for splitted message"); return; } int fragmentIndex = int.Parse(fragmentIndexQuery.First().Item2); int fragmentCount = int.Parse(fragmentCountQuery.First().Item2); if (fragmentCount <= 0 || fragmentIndex < 0) { logger.Warn("Fragment Index or Count out of range"); sendresult(Result.SplittingError, messageId); return; } if (!messageFragments.ContainsKey(messageId)) { messageFragments.Add(messageId, new string[fragmentCount]); } //check if fragment index is valid if (fragmentIndex >= messageFragments[messageId].Length) { logger.Warn("Fragment index out of range"); sendresult(Result.SplittingError, messageId); return; } //check if fragment count is consistent with previous messages if (fragmentCount != messageFragments[messageId].Length) { logger.Error("Inconsistent fragment count"); sendresult(Result.SplittingError, messageId); } messageFragments[messageId][fragmentIndex] = payload_str; //check if all fragments have been received if (messageFragments[messageId].Any(x => x == null)) { logger.Info("Missing fragments of message {0}, waiting for next piece", messageId); return; } else { logger.Info("Received all fragments of message {0}", messageId); payload_str = messageFragments[messageId].Aggregate((str1, str2) => str1 + str2); messageFragments.Remove(messageId); } } ParsingResult result = new ParsingResult(); byte[] payload = payload_str.GetBytesBase64(); //check if message is encrypted var encryptedMetadate = metadata.Any(x => x.Item1 == Key.Encryption) ? metadata.First(x => x.Item1 == Key.Encryption) : null; if (encryptedMetadate != null) { //check if encryption algorith is supported if (encryptedMetadate.Item2.ToLower() != "aes") { logger.Warn("Encryption algorithm not supported"); sendresult(Result.EncryptionError); return; } payload = payload.DecryptAES(this.EncryptionKey, this.EncryptionIV); result.WasEncrypted = true; } //check if message is compressed var compressedMetadate = metadata.Any(x => x.Item1 == Key.Gzip) ? metadata.First(x => x.Item1 == Key.Gzip) : null; if (compressedMetadate != null) { int length; if (!int.TryParse(compressedMetadate.Item2, out length)) { logger.Error("Could not parse length from GZip metadate"); sendresult(Result.InvalidFormat, messageId); } result.WasCompressed = true; payload = payload.Take(length).ToArray <byte>().Decompress(); } result.Payload = payload; //everything went okay => send delivery notifiaction sendresult(Result.Success, messageId); onMessageReceived(result); }
/// <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> /// Parses an message received through the messaging client /// </summary> /// <param name="message"></param> private void parseMessage(string message) { //check if the message's format is valid if (!verifyMessageFormat(message)) { logger.Error("Received invalid message, aborting message processing"); sendresult(Result.InvalidFormat); return; } //get the messages metadata and payload IEnumerable<string> parts = message.Split(';').Where(x => !x.IsNullOrEmpty()); string payload_str = message.EndsWith(";") ? null : parts.Last(); parts = (payload_str == null) ? parts : parts.Take(parts.Count() - 1); //parse metadata keys var metadata = parts.Select(x => new Tuple<Key, string>((Key)Enum.Parse(typeof(Key), x.Split(':').First(), true), x.Split(':').Last())); //check for message id var messageIdQuery = metadata.Where(x => x.Item1 == Key.Message_id); int messageId = -1; if (!messageIdQuery.Any() || !int.TryParse(messageIdQuery.First().Item2, out messageId)) { logger.Warn("Invalid message. MessageId not found or invalid"); sendresult(Result.InvalidFormat); return; } //check if message is a delivery notification var resultQuery = metadata.Where(x => x.Item1 == Key.Result); if (metadata.Count() == 2 && messageId > 0 && resultQuery.Any()) { //handle delivery confirmation Result deliveryResult; if (!Enum.TryParse(resultQuery.First().Item2, true, out deliveryResult)) deliveryResult = Result.UnknownError; logger.Info("Received delivery confirmation for message {0} from {1}, Result: {2}", messageId, this.Recipient, deliveryResult); lock (this) { //store result in result cache and unblock waiting threads if (waitingThreads.ContainsKey(messageId)) { if (!messageResults.ContainsKey(messageId)) messageResults.Add(messageId, deliveryResult); else messageResults[messageId] = deliveryResult; //relese threads waiting for the result waitingThreads[messageId].Release(); } } return; } //check for splitted messages var fragmentIndexQuery = metadata.Where(x => x.Item1 == Key.Fragment_Index); var fragmentCountQuery = metadata.Where(x => x.Item1 == Key.Fragment_Count); if (fragmentCountQuery.Any() || fragmentIndexQuery.Any()) { logger.Info("Received splitted message"); if (!(fragmentIndexQuery.Any() && fragmentIndexQuery.Any())) { logger.Error("Missing metadata information for splitted message"); return; } int fragmentIndex = int.Parse(fragmentIndexQuery.First().Item2); int fragmentCount = int.Parse(fragmentCountQuery.First().Item2); if (fragmentCount <= 0 || fragmentIndex < 0) { logger.Warn("Fragment Index or Count out of range"); sendresult(Result.SplittingError, messageId); return; } if (!messageFragments.ContainsKey(messageId)) messageFragments.Add(messageId, new string[fragmentCount]); //check if fragment index is valid if (fragmentIndex >= messageFragments[messageId].Length) { logger.Warn("Fragment index out of range"); sendresult(Result.SplittingError, messageId); return; } //check if fragment count is consistent with previous messages if (fragmentCount != messageFragments[messageId].Length) { logger.Error("Inconsistent fragment count"); sendresult(Result.SplittingError, messageId); } messageFragments[messageId][fragmentIndex] = payload_str; //check if all fragments have been received if (messageFragments[messageId].Any(x => x == null)) { logger.Info("Missing fragments of message {0}, waiting for next piece", messageId); return; } else { logger.Info("Received all fragments of message {0}", messageId); payload_str = messageFragments[messageId].Aggregate((str1, str2) => str1 + str2); messageFragments.Remove(messageId); } } ParsingResult result = new ParsingResult(); byte[] payload = payload_str.GetBytesBase64(); //check if message is encrypted var encryptedMetadate = metadata.Any(x => x.Item1 == Key.Encryption) ? metadata.First(x => x.Item1 == Key.Encryption) : null; if (encryptedMetadate != null) { //check if encryption algorith is supported if (encryptedMetadate.Item2.ToLower() != "aes") { logger.Warn("Encryption algorithm not supported"); sendresult(Result.EncryptionError); return; } payload = payload.DecryptAES(this.EncryptionKey, this.EncryptionIV); result.WasEncrypted = true; } //check if message is compressed var compressedMetadate = metadata.Any(x => x.Item1 == Key.Gzip) ? metadata.First(x => x.Item1 == Key.Gzip) : null; if (compressedMetadate != null) { int length; if (!int.TryParse(compressedMetadate.Item2, out length)) { logger.Error("Could not parse length from GZip metadate"); sendresult(Result.InvalidFormat, messageId); } result.WasCompressed = true; payload = payload.Take(length).ToArray<byte>().Decompress(); } result.Payload = payload; //everything went okay => send delivery notifiaction sendresult(Result.Success, messageId); onMessageReceived(result); }
/// <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> /// Raises the MessageReceived event /// </summary> /// <param name="message">The message that has been received</param> private void onMessageReceived(ParsingResult message) { if (this.MessageReceived != null) this.MessageReceived(this, message); }