/// <summary> /// Creates a new instance of the MessageException class. /// </summary> /// <param name="msg">Error message</param> /// <param name="innerException">Inner exception (can be null)</param> /// <param name="connection">Affected Duplex Channel Connection</param> public MessageException(string msg, Exception innerException, Connection connection) : base(msg, innerException) { Connection = connection; }
/// <summary> /// Begins receiving message data asynchronously. /// </summary> /// <param name="connection">Duplex Channel Connection</param> /// <param name="callback">Delegate to invoke, when asynchronous operation is completed</param> /// <param name="asyncState">Pass through state object</param> /// <returns>Result</returns> public static IAsyncResult BeginReceive(Connection connection, AsyncCallback callback, object asyncState) { byte[] buffer = new Byte[SizeOfGuid]; AsyncResult myAr = new AsyncResult(connection, buffer, callback, asyncState); myAr.InternalAsyncResult = connection.Socket.BeginReceive(buffer, 0, SizeOfGuid, SocketFlags.None, new AsyncCallback(myAr.Complete), null); return myAr; }
/// <summary> /// Creates a new instance of the AsyncResult class. /// </summary> /// <param name="connection">Duplex Channel Connection</param> /// <param name="buffer">Buffer</param> /// <param name="callback">Delegate to invoke, when asynchronous operation is completed</param> /// <param name="asyncState">Pass trough state object</param> public AsyncResult(Connection connection, byte[] buffer, AsyncCallback callback, object asyncState) { this.buffer = buffer; this.callback = callback; this.asyncState = asyncState; this.connection = connection; }
/// <summary> /// Sends a specified message over a specified connection. /// </summary> /// <param name="connection">Duplex Channel Connection</param> /// <param name="guid">Unique identifier of the Message</param> /// <param name="headers">Remoting transport headers</param> /// <param name="message">Stream with raw data of the message</param> public static void Send(Connection connection, Guid guid, ITransportHeaders headers, Stream message) { try { connection.LockWrite(); BinaryWriter writer = connection.Writer; if (writer == null) { // Unexpected connection loss. Connection isn´t working anymore, so close it. connection.ReleaseWrite(); connection.Close(); connection = null; } else { writer.Write(guid.ToByteArray()); var headerStream = TransportHeaderWrapper.Serialize(headers); writer.Write((int)headerStream.Length); writer.Write(headerStream.GetBuffer(), 0, (int)headerStream.Length); writer.Write((int)message.Length); MemoryStream ms = message as MemoryStream; if (ms == null) { byte[] msgBuffer = new byte[message.Length]; message.Read(msgBuffer, 0, (int)message.Length); writer.Write(msgBuffer, 0, (int)message.Length); } else writer.Write(ms.GetBuffer(), 0, (int)message.Length); writer.Flush(); } } catch (ObjectDisposedException) { // Socket may be closed meanwhile. Connection isn´t working anymore, so close it. connection.ReleaseWrite(); connection.Close(); connection = null; } catch (IOException) { // Unexpected connection loss. Connection isn´t working anymore, so close it. connection.ReleaseWrite(); connection.Close(); connection = null; } catch (SocketException) { // Unexpected connection loss. Connection isn´t working anymore, so close it. connection.ReleaseWrite(); connection.Close(); connection = null; } finally { if (connection != null) connection.ReleaseWrite(); } }
/// <summary> /// Receives a message over a specified Duplex Channel Connection. /// </summary> /// <param name="connection">Duplex Channel Connection</param> /// <param name="ar">Result (for Async pattern)</param> /// <returns>Received message</returns> public static Message EndReceive(out Connection connection, IAsyncResult ar) { AsyncResult myAr = (AsyncResult)ar; connection = myAr.Connection; try { connection.LockRead(); if (connection.Socket == null) { throw new MessageException("Connection closed.", null, connection); } SocketError socketError; int bytesRead = connection.Socket.EndReceive(myAr.InternalAsyncResult, out socketError); if (bytesRead == 0 || connection.Channel == null) { throw new MessageException("Connection closed.", new SocketException((int)socketError), connection); } // read message identifier var reader = connection.Reader; if (bytesRead < SizeOfGuid) { var rest = reader.Read(myAr.Buffer, bytesRead, SizeOfGuid - bytesRead); if (rest < SizeOfGuid - bytesRead) { throw new MessageException("Insufficient data received. Got " + bytesRead + " bytes.", new SocketException((int)socketError), connection); } } // read message header Message retVal = new Message(); retVal.Guid = new Guid(myAr.Buffer); int headerLength = reader.ReadInt32(); MemoryStream headerStream = new MemoryStream(reader.ReadBytes(headerLength)); if (headerStream.Length != headerLength) throw new Exception("Not enough headers read..."); retVal.Headers = TransportHeaderWrapper.Deserialize(headerStream); int bodyLength = reader.ReadInt32(); if (bodyLength > 0) { retVal.messageBodyBytes = reader.ReadBytes(bodyLength); if (retVal.messageBodyBytes.Length != bodyLength) throw new Exception("Not enough body read..."); System.Diagnostics.Debug.Assert(retVal.MessageBody.CanRead); } Message.BeginReceive(connection, myAr.Callback, myAr.AsyncState); return retVal; } catch (Exception e) { throw new MessageException("Error receiving message", e, connection); } finally { connection.ReleaseRead(); } }
/// <summary> /// Receives a message over a specified Duplex Channel Connection. /// </summary> /// <param name="connection">Duplex Channel Connection</param> /// <param name="ar">Result (for Async pattern)</param> /// <returns>Received message</returns> public static Message EndReceive(out Connection connection, IAsyncResult ar) { AsyncResult myAr = (AsyncResult)ar; connection = myAr.Connection; try { connection.LockRead(); if (connection.Socket == null) { throw new MessageException("Connection closed.", null, connection); } int bytesRead = connection.Socket.EndReceive(myAr.InternalAsyncResult); if (bytesRead == 16) { Message retVal = new Message(); retVal.Guid = new Guid(myAr.Buffer); BinaryReader reader = connection.Reader; int headerLength = reader.ReadInt32(); MemoryStream headerStream = new MemoryStream(reader.ReadBytes(headerLength)); if (headerStream.Length != headerLength) throw new Exception("Not enough headers read..."); retVal.Headers = TransportHeaderWrapper.Deserialize(headerStream); int bodyLength = reader.ReadInt32(); if (bodyLength > 0) { retVal.messageBodyBytes = reader.ReadBytes(bodyLength); if (retVal.messageBodyBytes.Length != bodyLength) throw new Exception("Not enough body read..."); System.Diagnostics.Debug.Assert(retVal.MessageBody.CanRead); } Message.BeginReceive(connection, myAr.Callback, myAr.AsyncState); return retVal; } else if (bytesRead == 0) { throw new MessageException("Connection closed.", null, connection); } else throw new MessageException("Insufficient data received", null, connection); } catch (Exception e) { throw new MessageException("Error receiving message", e, connection); } finally { connection.ReleaseRead(); } }