private async Task <bool> ReadContent(HorseMessage message, Stream stream) { if (message.Length == 0) { return(true); } if (message.Content == null) { message.Content = new MemoryStream(); } ulong left = message.Length; ulong blen = (ulong)_buffer.Length; do { int rcount = (int)(left > blen ? blen : left); int read = await stream.ReadAsync(_buffer, 0, rcount); if (read == 0) { return(false); } left -= (uint)read; await message.Content.WriteAsync(_buffer, 0, read); }while (left > 0); return(true); }
/// <summary> /// Reads first Hello message from client /// </summary> private async Task <bool> ProcessFirstMessage(HorseMessage message, IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { if (message.Type != MessageType.Server || message.ContentType != KnownContentTypes.Hello) { return(false); } ConnectionData connectionData = new ConnectionData(); message.Content.Position = 0; await connectionData.ReadFromStream(message.Content); HorseServerSocket socket = await _handler.Connected(_server, info, connectionData); if (socket == null) { info.Close(); return(false); } info.State = ConnectionStates.Pipe; handshakeResult.Socket = socket; _server.HeartbeatManager.Add(socket); socket.SetCleanupAction(s => { _server.HeartbeatManager.Remove(socket); _handler.Disconnected(_server, s); }); return(true); }
/// <summary> /// Handles the connection and reads received HMQ messages /// </summary> public async Task HandleConnection(IConnectionInfo info, ProtocolHandshakeResult handshakeResult) { //if user makes a mistake in ready method, we should not interrupt connection handling try { await _handler.Ready(_server, (HorseServerSocket)handshakeResult.Socket); } catch (Exception e) { if (_server.Logger != null) { _server.Logger.LogException("Unhandled Exception", e); } } HmqReader reader = new HmqReader(); while (info.Client != null && info.Client.Connected) { HorseMessage message = await reader.Read(info.GetStream()); if (message == null) { info.Close(); return; } await ProcessMessage(info, message, (HorseServerSocket)handshakeResult.Socket); } }
private Task ProcessMessage(IConnectionInfo info, HorseMessage message, HorseServerSocket socket) { //if user makes a mistake in received method, we should not interrupt connection handling try { if (socket.SmartHealthCheck) { socket.KeepAlive(); } else if (message.Type == MessageType.Pong) { socket.KeepAlive(); } return(_handler.Received(_server, info, socket, message)); } catch (Exception e) { if (_server.Logger != null) { _server.Logger.LogException("Unhandled Exception", e); } return(Task.CompletedTask); } }
private static void WriteContent(MemoryStream ms, HorseMessage message) { if (message.Length > 0 && message.Content != null) { message.Content.WriteTo(ms); } ms.Position = 0; }
/// <summary> /// Sends HMQ message to client /// </summary> public virtual Task <bool> SendAsync(HorseMessage message, IList <KeyValuePair <string, string> > additionalHeaders = null) { if (UseUniqueMessageId && string.IsNullOrEmpty(message.MessageId)) { message.SetMessageId(_uniqueIdGenerator.Create()); } byte[] data = HmqWriter.Create(message, additionalHeaders); return(SendAsync(data)); }
/// <summary> /// Create a response message of the message /// </summary> public HorseMessage CreateResponse(HorseResultCode status) { HorseMessage message = new HorseMessage(); message.HighPriority = Type == MessageType.DirectMessage; message.Type = MessageType.Response; message.ContentType = Convert.ToUInt16(status); message.SetMessageId(MessageId); message.SetTarget(Type == MessageType.QueueMessage ? Target : Source); return(message); }
/// <summary> /// Clones the message /// </summary> public HorseMessage Clone(bool cloneHeaders, bool cloneContent, string cloneId, List <KeyValuePair <string, string> > additionalHeaders = null) { HorseMessage clone = new HorseMessage(Type, Target); if (!string.IsNullOrEmpty(cloneId)) { clone.SetMessageId(cloneId); } clone.SetSource(Source); clone.HighPriority = HighPriority; clone.WaitResponse = WaitResponse; clone.ContentType = ContentType; if (cloneHeaders && HasHeader) { clone.HasHeader = true; clone.HeadersList = new List <KeyValuePair <string, string> >(HeadersList); } if (additionalHeaders != null && additionalHeaders.Count > 0) { if (!clone.HasHeader) { clone.HasHeader = true; clone.HeadersList = new List <KeyValuePair <string, string> >(additionalHeaders); } else { clone.HeadersList.AddRange(additionalHeaders); } } if (cloneContent && Content != null && Content.Length > 0) { Content.Position = 0; clone.Content = new MemoryStream(); Content.WriteTo(clone.Content); clone.Length = Convert.ToUInt64(clone.Content.Length); } return(clone); }
/// <summary> /// Writes a HMQ message to stream /// </summary> public static void Write(HorseMessage value, Stream stream, IList <KeyValuePair <string, string> > additionalHeaders = null) { bool hasAdditionalHeader = additionalHeaders != null && additionalHeaders.Count > 0; using MemoryStream ms = new MemoryStream(); WriteFrame(ms, value, hasAdditionalHeader); if (value.HasHeader || hasAdditionalHeader) { WriteHeader(ms, value, additionalHeaders); } if (value.Length > 0) { WriteContent(ms, value); } ms.WriteTo(stream); }
/// <summary> /// Creates byte array of HMQ message /// </summary> public static byte[] Create(HorseMessage value, IList <KeyValuePair <string, string> > additionalHeaders = null) { bool hasAdditionalHeader = additionalHeaders != null && additionalHeaders.Count > 0; using MemoryStream ms = new MemoryStream(); WriteFrame(ms, value, hasAdditionalHeader); if (value.HasHeader || hasAdditionalHeader) { WriteHeader(ms, value, additionalHeaders); } if (value.Length > 0) { WriteContent(ms, value); } return(ms.ToArray()); }
/// <summary> /// Reads HMQ message from stream /// </summary> public async Task <HorseMessage> Read(Stream stream) { byte[] bytes = new byte[REQUIRED_SIZE]; bool done = await ReadCertainBytes(stream, bytes, 0, REQUIRED_SIZE); if (!done) { return(null); } HorseMessage message = new HorseMessage(); done = await ReadFrame(message, bytes, stream); if (!done) { return(null); } if (message.HasHeader) { done = await ReadHeader(message, stream); } if (!done) { return(null); } bool success = await ReadContent(message, stream); if (!success) { return(null); } if (message.Content != null && message.Content.Position > 0) { message.Content.Position = 0; } return(message); }
/// <summary> /// Create an acknowledge message of the message /// </summary> public HorseMessage CreateAcknowledge(string negativeReason = null) { HorseMessage message = new HorseMessage(); message.SetMessageId(MessageId); message.Type = MessageType.Response; if (Type == MessageType.DirectMessage) { message.HighPriority = true; message.SetSource(Target); message.SetTarget(Source); } else { message.HighPriority = false; //target will be queue name message.SetTarget(Target); } if (!string.IsNullOrEmpty(negativeReason)) { message.ContentType = KnownContentTypes.Failed; if (!message.HasHeader) { message.HasHeader = true; } if (message.HeadersList == null) { message.HeadersList = new List <KeyValuePair <string, string> >(); } message.HeadersList.Add(new KeyValuePair <string, string>(HorseHeaders.NEGATIVE_ACKNOWLEDGE_REASON, negativeReason)); } else { message.ContentType = Convert.ToUInt16(HorseResultCode.Ok); } return(message); }
private static async Task <bool> ReadHeader(HorseMessage message, Stream stream) { byte[] size = new byte[2]; bool read = await ReadCertainBytes(stream, size, 0, size.Length); if (!read) { return(false); } int headerLength = BitConverter.ToUInt16(size); byte[] data = new byte[headerLength]; read = await ReadCertainBytes(stream, data, 0, data.Length); if (!read) { return(false); } string[] headers = Encoding.UTF8.GetString(data).Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string header in headers) { int i = header.IndexOf(':'); if (i < 1) { continue; } string key = header.Substring(0, i); string value = header.Substring(i + 1); message.HeadersList.Add(new KeyValuePair <string, string>(key, value)); } return(true); }
private static void WriteHeader(MemoryStream ms, HorseMessage message, IList <KeyValuePair <string, string> > additionalHeaders) { using MemoryStream headerStream = new MemoryStream(); if (message.HeadersList != null) { foreach (KeyValuePair <string, string> pair in message.HeadersList) { headerStream.Write(Encoding.UTF8.GetBytes(pair.Key + ":" + pair.Value + "\r\n")); } } if (additionalHeaders != null) { foreach (KeyValuePair <string, string> pair in additionalHeaders) { headerStream.Write(Encoding.UTF8.GetBytes(pair.Key + ":" + pair.Value + "\r\n")); } } ms.Write(BitConverter.GetBytes((ushort)headerStream.Length)); headerStream.Position = 0; headerStream.WriteTo(ms); }
/// <summary> /// Checks if received data is a HMQ protocol message /// </summary> public async Task <ProtocolHandshakeResult> Handshake(IConnectionInfo info, byte[] data) { ProtocolHandshakeResult result = new ProtocolHandshakeResult(); if (data.Length < 8) { return(await Task.FromResult(result)); } ProtocolVersion version = CheckProtocol(data); result.Accepted = version != ProtocolVersion.Unknown; if (!result.Accepted) { return(result); } HmqReader reader = new HmqReader(); HorseMessage message = await reader.Read(info.GetStream()); //sends protocol message await info.GetStream().WriteAsync(PredefinedMessages.PROTOCOL_BYTES_V2); bool alive = await ProcessFirstMessage(message, info, result); if (!alive) { return(result); } result.PipeConnection = true; info.State = ConnectionStates.Pipe; info.Protocol = this; return(result); }
private static void WriteFrame(MemoryStream ms, HorseMessage message, bool hasAdditionalHeaders) { byte proto = (byte)message.Type; if (message.WaitResponse) { proto += 128; } if (message.HighPriority) { proto += 64; } if (message.HasHeader || hasAdditionalHeaders) { proto += 32; } ms.WriteByte(proto); byte reserved = 0; ms.WriteByte(reserved); ms.WriteByte((byte)message.MessageIdLength); ms.WriteByte((byte)message.SourceLength); ms.WriteByte((byte)message.TargetLength); ms.Write(BitConverter.GetBytes(message.ContentType)); if (message.Content != null && message.Length == 0) { message.Length = (ulong)message.Content.Length; } if (message.Length < 253) { ms.WriteByte((byte)message.Length); } else if (message.Length <= ushort.MaxValue) { ms.WriteByte(253); ms.Write(BitConverter.GetBytes((ushort)message.Length)); } else if (message.Length <= uint.MaxValue) { ms.WriteByte(254); ms.Write(BitConverter.GetBytes((uint)message.Length)); } else { ms.WriteByte(255); ms.Write(BitConverter.GetBytes(message.Length)); } if (message.MessageIdLength > 0) { byte[] bytes = Encoding.UTF8.GetBytes(message.MessageId); ms.Write(bytes); } if (message.SourceLength > 0) { byte[] bytes = Encoding.UTF8.GetBytes(message.Source); ms.Write(bytes); } if (message.TargetLength > 0) { byte[] bytes = Encoding.UTF8.GetBytes(message.Target); ms.Write(bytes); } }
/// <summary> /// Creates byte array of only HMQ message frame /// </summary> public static byte[] CreateFrame(HorseMessage value) { using MemoryStream ms = new MemoryStream(); WriteFrame(ms, value, false); return(ms.ToArray()); }
/// <summary> /// Creates byte array of only HMQ message content /// </summary> public static byte[] CreateContent(HorseMessage value) { using MemoryStream ms = new MemoryStream(); WriteContent(ms, value); return(ms.ToArray()); }
private async Task <bool> ReadFrame(HorseMessage message, byte[] bytes, Stream stream) { byte proto = bytes[0]; if (proto >= 128) { message.WaitResponse = true; proto -= 128; } if (proto >= 64) { message.HighPriority = true; proto -= 64; } if (proto >= 32) { proto -= 32; message.Type = (MessageType)proto; if (message.Type != MessageType.Ping && message.Type != MessageType.Pong) { message.HasHeader = true; message.HeadersList = new List <KeyValuePair <string, string> >(); } } else { message.Type = (MessageType)proto; } // bytes[1] is reserved message.MessageIdLength = bytes[2]; message.SourceLength = bytes[3]; message.TargetLength = bytes[4]; message.ContentType = BitConverter.ToUInt16(bytes, 5); byte length = bytes[7]; if (length == 253) { bool done = await ReadCertainBytes(stream, bytes, 0, 2); if (!done) { return(false); } message.Length = BitConverter.ToUInt16(bytes, 0); } else if (length == 254) { bool done = await ReadCertainBytes(stream, bytes, 0, 4); if (!done) { return(false); } message.Length = BitConverter.ToUInt32(bytes, 0); } else if (length == 255) { byte[] b = new byte[8]; bool done = await ReadCertainBytes(stream, b, 0, 8); if (!done) { return(false); } message.Length = BitConverter.ToUInt64(b, 0); } else { message.Length = length; } if (message.MessageIdLength > 0) { message.MessageId = await ReadOctetSizeData(stream, message.MessageIdLength); } if (message.SourceLength > 0) { message.Source = await ReadOctetSizeData(stream, message.SourceLength); } if (message.TargetLength > 0) { message.Target = await ReadOctetSizeData(stream, message.TargetLength); } return(true); }