/// <summary> /// Creates a byte array useful for transmission, without packaging the data. /// </summary> /// <returns>Byte array.</returns> internal byte[] ToHeaderBytes(long contentLength) { SetHeaderFieldBitmap(); byte[] headerFieldsBytes = new byte[8]; headerFieldsBytes = BitArrayToBytes(HeaderFields); headerFieldsBytes = ReverseByteArray(headerFieldsBytes); byte[] ret = new byte[headerFieldsBytes.Length]; Buffer.BlockCopy(headerFieldsBytes, 0, ret, 0, headerFieldsBytes.Length); #region Header-Fields for (int i = 0; i < HeaderFields.Length; i++) { if (HeaderFields[i]) { if (_Debug) { Console.WriteLine("Header field " + i + " is set"); } MessageField field = GetMessageField(i); switch (i) { case 0: // preshared key if (_Debug) { Console.WriteLine("PresharedKey: " + Encoding.UTF8.GetString(PresharedKey)); } ret = AppendBytes(ret, PresharedKey); break; case 1: // status if (_Debug) { Console.WriteLine("Status: " + Status.ToString() + " " + (int)Status); } ret = AppendBytes(ret, IntegerToBytes((int)Status)); break; default: throw new ArgumentException("Unknown bit number."); } } } #endregion #region Prepend-Message-Length long finalLen = ret.Length + contentLength; if (_Debug) { Console.WriteLine("Content length: " + finalLen + " (" + ret.Length + " + " + contentLength + ")"); } byte[] lengthHeader = Encoding.UTF8.GetBytes(finalLen.ToString() + ":"); byte[] final = new byte[(lengthHeader.Length + ret.Length)]; Buffer.BlockCopy(lengthHeader, 0, final, 0, lengthHeader.Length); Buffer.BlockCopy(ret, 0, final, lengthHeader.Length, ret.Length); #endregion if (_Debug) { Console.WriteLine("ToHeaderBytes returning: " + Encoding.UTF8.GetString(final)); } return(final); }
/// <summary> /// Awaitable async method to build the Message object from data that awaits in a NetworkStream or SslStream, returning the stream itself. /// </summary> /// <returns>Always returns true (void cannot be a return parameter).</returns> internal async Task <bool> BuildStream() { try { #region Read-Message-Length using (MemoryStream msgLengthMs = new MemoryStream()) { while (true) { byte[] data = await ReadFromNetwork(1, "MessageLength"); await msgLengthMs.WriteAsync(data, 0, 1); if (data[0] == 58) { break; } } byte[] msgLengthBytes = msgLengthMs.ToArray(); if (msgLengthBytes == null || msgLengthBytes.Length < 1) { return(false); } string msgLengthString = Encoding.UTF8.GetString(msgLengthBytes).Replace(":", ""); long length; Int64.TryParse(msgLengthString, out length); Length = length; Log("Message payload length: " + Length + " bytes"); } #endregion Read-Message-Length #region Process-Header-Fields byte[] headerFields = await ReadFromNetwork(8, "HeaderFields"); headerFields = ReverseByteArray(headerFields); HeaderFields = new BitArray(headerFields); long payloadLength = Length - 8; for (int i = 0; i < HeaderFields.Length; i++) { if (HeaderFields[i]) { MessageField field = GetMessageField(i); Log("Reading header field " + i + " " + field.Name + " " + field.Type.ToString() + " " + field.Length + " bytes"); object val = await ReadField(field.Type, field.Length, field.Name); SetMessageValue(field, val); payloadLength -= field.Length; } } if (MetadataLength > 0) { MetadataBytes = await ReadFromNetwork(MetadataLength, "MetadataBytes"); // payloadLength -= MetadataLength; Metadata = SerializationHelper.DeserializeJson <Dictionary <object, object> >(Encoding.UTF8.GetString(MetadataBytes)); } ContentLength = payloadLength; Data = null; #endregion Process-Header-Fields return(true); } catch (Exception e) { Log(Environment.NewLine + "Message build from stream exception:" + Environment.NewLine + e.ToString() + Environment.NewLine); return(false); } }
/// <summary> /// Awaitable async method to build the Message object from data that awaits in a NetworkStream or SslStream, returning the stream itself. /// </summary> /// <returns>Always returns true (void cannot be a return parameter).</returns> internal async Task <bool> BuildStream() { try { #region Read-Message-Length using (MemoryStream msgLengthMs = new MemoryStream()) { while (true) { byte[] data = await ReadFromNetwork(1, "MessageLength"); await msgLengthMs.WriteAsync(data, 0, 1); if (data[0] == 58) { break; } } byte[] msgLengthBytes = msgLengthMs.ToArray(); if (msgLengthBytes == null || msgLengthBytes.Length < 1) { return(false); } string msgLengthString = Encoding.UTF8.GetString(msgLengthBytes).Replace(":", ""); long length; Int64.TryParse(msgLengthString, out length); Length = length; if (_Debug) { Console.WriteLine("Message payload length: " + Length + " bytes"); } } #endregion #region Process-Header-Fields byte[] headerFields = await ReadFromNetwork(8, "HeaderFields"); headerFields = ReverseByteArray(headerFields); HeaderFields = new BitArray(headerFields); long payloadLength = Length - 8; for (int i = 0; i < HeaderFields.Length; i++) { if (HeaderFields[i]) { MessageField field = GetMessageField(i); if (_Debug) { Console.WriteLine("Reading header field " + i + " " + field.Name + " " + field.Type.ToString() + " " + field.Length + " bytes"); } object val = await ReadField(field.Type, field.Length, field.Name); SetMessageValue(field, val); payloadLength -= field.Length; } } ContentLength = payloadLength; Data = null; if (_NetworkStream != null) { DataStream = _NetworkStream; } else if (_SslStream != null) { DataStream = _SslStream; } else { throw new IOException("No suitable input stream found."); } #endregion return(true); } catch (Exception e) { if (_Debug) { Console.WriteLine(Common.SerializeJson(e)); } throw e; } finally { if (_Debug) { Console.WriteLine("Message build completed:"); Console.WriteLine(this.ToString()); } } }
/// <summary> /// Awaitable async method to build the Message object from data that awaits in a NetworkStream or SslStream. /// </summary> /// <returns>Always returns true (void cannot be a return parameter).</returns> public async Task <bool> Build() { try { int read = 0; int totalBytesRead = 0; #region Read-Message-Length using (MemoryStream msgLengthMs = new MemoryStream()) { byte[] msgLengthBuffer = new byte[1]; if (_NetworkStream != null) { while ((read = await _NetworkStream.ReadAsync(msgLengthBuffer, 0, msgLengthBuffer.Length)) > 0) { await msgLengthMs.WriteAsync(msgLengthBuffer, 0, read); // check if end of headers reached if (msgLengthBuffer[0] == 58) { break; } } } else if (_SslStream != null) { while ((read = await _SslStream.ReadAsync(msgLengthBuffer, 0, msgLengthBuffer.Length)) > 0) { await msgLengthMs.WriteAsync(msgLengthBuffer, 0, read); totalBytesRead += read; // check if end of headers reached if (msgLengthBuffer[0] == 58) { break; } } } else { throw new ArgumentException("Unknown stream type."); } byte[] msgLengthBytes = msgLengthMs.ToArray(); if (msgLengthBytes == null || msgLengthBytes.Length < 1) { return(false); } string msgLengthString = Encoding.UTF8.GetString(msgLengthBytes).Replace(":", ""); long length; Int64.TryParse(msgLengthString, out length); Length = length; if (_Debug) { Console.WriteLine("Message payload length: " + Length + " bytes"); } } #endregion #region Process-Header-Fields byte[] headerFields = await ReadFromNetwork(8, "HeaderFields"); headerFields = ReverseByteArray(headerFields); HeaderFields = new BitArray(headerFields); long payloadBytes = Length - 8; for (int i = 0; i < HeaderFields.Length; i++) { if (HeaderFields[i]) { MessageField field = GetMessageField(i); if (_Debug) { Console.WriteLine("Reading header field " + i + " " + field.Name + " " + field.Type.ToString() + " " + field.Length + " bytes"); } object val = await ReadField(field.Type, field.Length, field.Name); SetMessageValue(field, val); payloadBytes -= field.Length; } } Data = await ReadFromNetwork(payloadBytes, "Payload"); #endregion return(true); } catch (Exception e) { if (_Debug) { Console.WriteLine("Message build exception: " + e.Message); } throw; } finally { if (_Debug) { Console.WriteLine("Message build completed"); } } }