/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IRemoteSender.Send(System.String)"]/*'/> public void Send(string message) { metricsUtilities.Begin(new MessageSendTime()); try { CheckNotDisposed(); CheckConnectionOpen(); // Send a message ITextMessage textMessage = session.CreateTextMessage(message); textMessage.Properties.SetString(filterIdentifier, messageFilter); try { producer.Send(textMessage); } catch (Exception e) { throw new Exception("Error sending message.", e); } } catch (Exception e) { metricsUtilities.CancelBegin(new MessageSendTime()); throw; } metricsUtilities.End(new MessageSendTime()); metricsUtilities.Increment(new MessageSent()); loggingUtilities.Log(this, LogLevel.Information, "Message sent."); }
/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IRemoteReceiver.Receive"]/*'/> public string Receive() { CheckNotDisposed(); string returnMessage = ""; cancelRequest = false; try { while (cancelRequest == false) { if (fileSystem.CheckFileExists(messageFilePath) == true) { if (fileSystem.CheckFileExists(lockFilePath) == false) { metricsUtilities.Begin(new MessageReceiveTime()); try { returnMessage = messageFile.ReadAll(); fileSystem.DeleteFile(messageFilePath); } catch (Exception e) { metricsUtilities.CancelBegin(new MessageReceiveTime()); throw; } metricsUtilities.End(new MessageReceiveTime()); metricsUtilities.Increment(new MessageReceived()); metricsUtilities.Add(new ReceivedMessageSize(returnMessage.Length)); loggingUtilities.LogMessageReceived(this, returnMessage); break; } } else { waitingForTimeout = true; if (readLoopTimeout > 0) { System.Threading.Thread.Sleep(readLoopTimeout); } waitingForTimeout = false; } } } catch (Exception e) { throw new Exception("Error receiving message.", e); } return(returnMessage); }
/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IMethodInvocationRemoteReceiver.Receive"]/*'/> public void Receive() { cancelRequest = false; receiveLoopThread = new Thread(delegate() { while (cancelRequest == false) { try { string serializedMethodInvocation = receiver.Receive(); if (serializedMethodInvocation != "") { metricsUtilities.Begin(new RemoteMethodReceiveTime()); IMethodInvocation receivedMethodInvocation; try { receivedMethodInvocation = serializer.Deserialize(serializedMethodInvocation); OnMethodInvocationReceived(new MethodInvocationReceivedEventArgs(receivedMethodInvocation)); } catch (Exception e) { metricsUtilities.CancelBegin(new RemoteMethodReceiveTime()); throw; } loggingUtilities.Log(this, LogLevel.Information, "Received method invocation '" + receivedMethodInvocation.Name + "'."); } } catch (Exception e) { throw new Exception("Failed to invoke method.", e); } } }); receiveLoopThread.Name = "MethodInvocationRemoting.MethodInvocationRemoteReceiver message receive worker thread."; receiveLoopThread.Start(); }
/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IMethodInvocationSerializer.Serialize(MethodInvocationRemoting.IMethodInvocation)"]/*'/> public string Serialize(IMethodInvocation inputMethodInvocation) { metricsUtilities.Begin(new MethodInvocationSerializeTime()); string returnString = ""; try { returnString = SerializeObject(inputMethodInvocation); } catch (Exception e) { metricsUtilities.CancelBegin(new MethodInvocationSerializeTime()); throw new SerializationException("Failed to serialize method invocation '" + inputMethodInvocation.Name + "'.", inputMethodInvocation, e); } metricsUtilities.End(new MethodInvocationSerializeTime()); metricsUtilities.Increment(new MethodInvocationSerialized()); metricsUtilities.Add(new SerializedMethodInvocationSize(returnString.Length)); loggingUtilities.LogSerializedItem(this, returnString, "method invocation"); return(returnString); }
/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IMethodInvocationRemoteSender.InvokeMethod(MethodInvocationRemoting.IMethodInvocation)"]/*'/> public object InvokeMethod(IMethodInvocation inputMethodInvocation) { metricsUtilities.Begin(new RemoteMethodSendTime()); object returnValue; try { // Check that inputted method invocation does not have a void return type. if (inputMethodInvocation.ReturnType == null) { throw new ArgumentException("Method invocation cannot have a void return type.", "inputMethodInvocation"); } string serializedReturnValue = SerializeAndSend(inputMethodInvocation); try { returnValue = serializer.DeserializeReturnValue(serializedReturnValue); } catch (Exception e) { throw new Exception("Failed to deserialize return value.", e); } } catch (Exception e) { metricsUtilities.CancelBegin(new RemoteMethodSendTime()); throw; } metricsUtilities.End(new RemoteMethodSendTime()); metricsUtilities.Increment(new RemoteMethodSent()); loggingUtilities.Log(this, LogLevel.Information, "Invoked method '" + inputMethodInvocation.Name + "'."); return(returnValue); }
/// <include file='InterfaceDocumentationComments.xml' path='doc/members/member[@name="M:MethodInvocationRemoting.IRemoteSender.Send(System.String)"]/*'/> public void Send(string message) { metricsUtilities.Begin(new MessageSendTime()); CheckNotDisposed(); try { // Lock file is created before data is written to the message file // The FileRemoteReceiver class checks for the absence of the lock file to prevent attempting to open the message file when it is partially written and causing an exception lockFile.WriteAll(""); messageFile.WriteAll(message); fileSystem.DeleteFile(lockFilePath); } catch (Exception e) { metricsUtilities.CancelBegin(new MessageSendTime()); throw new Exception("Error sending message.", e); } metricsUtilities.End(new MessageSendTime()); metricsUtilities.Increment(new MessageSent()); loggingUtilities.Log(this, LogLevel.Information, "Message sent."); }
//------------------------------------------------------------------------------ // // Method: HandleExceptionAndResend // //------------------------------------------------------------------------------ /// <summary> /// Handles an exception that occurred when attempting to send a message, before reconnecting and re-sending. /// </summary> /// <param name="sendException">The exception that occurred when attempting to send the message.</param> /// <param name="message">The message to send.</param> private void HandleExceptionAndResend(Exception sendException, string message) { /* * In testing of this class, the only exhibited exception for probable real-world network issues (i.e. disconnecting network cable), was the System.IO.IOException. * However, the documentation states that numerous exceptions can potentially be thrown by the NetworkStream and TcpClient classes. Hence the below code block handles all theoretically potential exceptions. * These exceptions, and the classes which can cause them are listed below... * TcpClient.Available * ObjectDisposedException * SocketException * TcpClient.GetStream() * InvalidOperationException * ObjectDisposedException * NetworkStream.ReadByte() * IOException * ObjectDisposedException * NetworkStream.Write(byte[] buffer, int offset, int size) * IOException * ObjectDisposedException */ try { if (sendException is System.IO.IOException) { logger.Log(this, LogLevel.Error, sendException.GetType().Name + " occurred whilst attempting to send message.", sendException); // If the TCP client is still connected, the situation cannot be handled so re-throw the exception if (client.Connected == true) { throw new Exception("Error sending message. IOException occurred when sending message, but client is reporting that it is still connected.", sendException); } logger.Log(this, LogLevel.Warning, "Disconnected from TCP socket."); } else if ((sendException is MessageAcknowledgementTimeoutException) || (sendException is System.Net.Sockets.SocketException) || (sendException is ObjectDisposedException) || (sendException is InvalidOperationException)) { logger.Log(this, LogLevel.Error, sendException.GetType().Name + " occurred whilst attempting to send message.", sendException); } else { throw new Exception("Error sending message. Unhandled exception while sending message.", sendException); } logger.Log(this, LogLevel.Warning, "Attempting to reconnect to TCP socket."); client.Close(); AttemptConnect(); metricsUtilities.Increment(new TcpRemoteSenderReconnected()); try { EncodeAndSend(message); } catch (Exception e) { throw new Exception("Error sending message. Failed to send message after reconnecting.", e); } } catch (Exception e) { metricsUtilities.CancelBegin(new MessageSendTime()); throw; } }
//------------------------------------------------------------------------------ // // Method: HandleExceptionAndRereadMessage // //------------------------------------------------------------------------------ /// <summary> /// Handles an exception that occurred when attempting to read a message, before re-establishing the connection and repeating the read operation. /// </summary> /// <param name="readException">The exception that occurred when attempting to read the message.</param> /// <param name="parseState">The current state of parsing the message.</param> /// <param name="messageSequenceNumber">Populated with the seqence number of the received message.</param> /// <returns>The bytes of the message that were read.</returns> private Queue <byte> HandleExceptionAndRereadMessage(Exception readException, ref MessageParseState parseState, ref int messageSequenceNumber) { /* * In testing of this class, the only exhibited exception for probable real-world network issues (i.e. disconnecting network cable), was the System.IO.IOException. * However, the documentation states that numerous exceptions can potentially be thrown by the NetworkStream and TcpClient classes. Hence the below code block handles all theoretically potential exceptions. * These exceptions, and the methods which can cause them are listed below... * TcpClient.Available * ObjectDisposedException * SocketException * TcpClient.GetStream() * InvalidOperationException * ObjectDisposedException * NetworkStream.Read(byte[] buffer, int offset, int size) * IOException * ObjectDisposedException * NetworkStream.WriteByte() * IOException * NotSupportedException * ObjectDisposedException */ Queue <byte> messageBytes = new Queue <byte>(); try { if (readException is System.IO.IOException) { logger.Log(this, LogLevel.Error, "IOException occurred whilst attempting to receive and acknowledge message.", readException); } else if ((readException is System.Net.Sockets.SocketException) || (readException is ObjectDisposedException) || (readException is InvalidOperationException) || (readException is NotSupportedException)) { logger.Log(this, LogLevel.Error, readException.GetType().Name + " occurred whilst attempting to receive and acknowledge message.", readException); } else { throw new Exception("Error receiving message. Unhandled exception while attempting to receive and acknowledge message.", readException); } logger.Log(this, LogLevel.Warning, "Attempting to reconnect to and re-receive."); AttemptConnect(); metricsUtilities.Increment(new TcpRemoteReceiverReconnected()); parseState = MessageParseState.StartOfMessage; try { messageBytes = SetupAndReadMessage(ref parseState, ref messageSequenceNumber); } catch (Exception e) { throw new Exception("Error receiving message. Failed to read message after reconnecting.", e); } } catch (Exception e) { metricsUtilities.CancelBegin(new MessageReceiveTime()); throw; } return(messageBytes); }
//------------------------------------------------------------------------------ // // Method: DecompressString // //------------------------------------------------------------------------------ /// <summary> /// Decompresses a string. /// </summary> /// <param name="inputString">The string to decompress.</param> /// <returns>The decompressed string.</returns> private string DecompressString(string inputString) { metricsUtilities.Begin(new StringDecompressTime()); decompressing = true; List <byte[]> readBuffers = new List <byte[]>(); int currentReadBufferPosition = 0; string returnString = ""; try { // Decode from base 64 byte[] encodedBytes = Convert.FromBase64String(inputString); using (MemoryStream decompressedStringStream = new MemoryStream(encodedBytes)) using (GZipStream decompressor = new GZipStream(decompressedStringStream, CompressionMode.Decompress)) { int bytesRead = -1; while (bytesRead != 0) { // If the list of buffers is empty, or the read position in the current (last) buffer is at the end of the buffer, then create a new read buffer if ((readBuffers.Count == 0) || (currentReadBufferPosition == decompressionBufferSize)) { readBuffers.Add(new byte[decompressionBufferSize]); currentReadBufferPosition = 0; metricsUtilities.Increment(new RemoteReceiverDecompressorReadBufferCreated()); } bytesRead = decompressor.Read(readBuffers[readBuffers.Count - 1], currentReadBufferPosition, decompressionBufferSize - currentReadBufferPosition); currentReadBufferPosition = currentReadBufferPosition + bytesRead; } decompressor.Close(); decompressedStringStream.Close(); } // Create decompressed byte array with size as buffer size times the number of buffers (except the last buffer), plus the position within the last buffer byte[] decompressedBytes = new byte[((readBuffers.Count - 1) * decompressionBufferSize) + currentReadBufferPosition]; // Copy the contents of the read buffers into the decompressed byte array int decompressedBytesPosition = 0; foreach (byte[] currentReadBuffer in readBuffers) { if (currentReadBuffer != readBuffers[readBuffers.Count - 1]) { Array.Copy(currentReadBuffer, 0, decompressedBytes, decompressedBytesPosition, decompressionBufferSize); decompressedBytesPosition = decompressedBytesPosition + decompressionBufferSize; } else { Array.Copy(currentReadBuffer, 0, decompressedBytes, decompressedBytesPosition, currentReadBufferPosition); } } returnString = stringEncoding.GetString(decompressedBytes); } catch (Exception e) { metricsUtilities.CancelBegin(new StringDecompressTime()); throw new Exception("Error decompressing message.", e); } metricsUtilities.End(new StringDecompressTime()); metricsUtilities.Increment(new StringDecompressed()); loggingUtilities.LogDecompressedString(this, returnString); decompressing = false; return(returnString); }