/// <summary> /// Reads entire <see cref="Stream"/> contents, and returns <see cref="byte"/> array of data. /// </summary> /// <param name="source">The <see cref="Stream"/> to be converted to <see cref="byte"/> array.</param> /// <returns>An array of <see cref="byte"/>.</returns> public static byte[] ReadStream(this Stream source) { using (BlockAllocatedMemoryStream outStream = new BlockAllocatedMemoryStream()) { source.CopyTo(outStream); return outStream.ToArray(); } }
/// <summary> /// Reads entire <see cref="Stream"/> contents, and returns <see cref="byte"/> array of data. /// </summary> /// <param name="source">The <see cref="Stream"/> to be converted to <see cref="byte"/> array.</param> /// <returns>An array of <see cref="byte"/>.</returns> public static byte[] ReadStream(this Stream source) { using (BlockAllocatedMemoryStream outStream = new BlockAllocatedMemoryStream()) { source.CopyTo(outStream); return(outStream.ToArray()); } }
/// <summary> /// Returns a binary array of encrypted data for the given parameters. /// </summary> /// <param name="algorithm"><see cref="SymmetricAlgorithm"/> to use for encryption.</param> /// <param name="data">Source buffer containing data to encrypt.</param> /// <param name="startIndex">Offset into <paramref name="data"/> buffer.</param> /// <param name="length">Number of bytes in <paramref name="data"/> buffer to encrypt starting from <paramref name="startIndex"/> offset.</param> /// <param name="key">The secret key to use for the symmetric algorithm.</param> /// <param name="iv">The initialization vector to use for the symmetric algorithm.</param> /// <returns>Encrypted version of <paramref name="data"/> buffer.</returns> public static byte[] Encrypt(this SymmetricAlgorithm algorithm, byte[] data, int startIndex, int length, byte[] key, byte[] iv) { // Fastest to use existing buffer in non-expandable memory stream for source and large block allocated memory stream for destination using (MemoryStream source = new MemoryStream(data, startIndex, length)) using (BlockAllocatedMemoryStream destination = new BlockAllocatedMemoryStream()) { algorithm.Encrypt(source, destination, key, iv); return destination.ToArray(); } }
public void Test() { MemoryStream ms = new MemoryStream(); BlockAllocatedMemoryStream ms2 = new BlockAllocatedMemoryStream(); for (int x = 0; x < 10000; x++) { int value = Random.Int32; ms.Write(value); ms.Write((byte)value); ms2.Write(value); ms2.Write((byte)value); } Compare(ms, ms2); }
public void Test3() { MemoryStream ms = new MemoryStream(); BlockAllocatedMemoryStream ms2 = new BlockAllocatedMemoryStream(); for (int x = 0; x < 10000; x++) { long position = Random.Int64Between(0, 100000); ms.Position = position; ms2.Position = position; int value = Random.Int32; ms.Write(value); ms2.Write(value); long length = Random.Int64Between(100000 >> 1, 100000); ms.SetLength(length); ms2.SetLength(length); } Compare(ms, ms2); }
public void Test2() { MemoryStream ms = new MemoryStream(); BlockAllocatedMemoryStream ms2 = new BlockAllocatedMemoryStream(); for (int x = 0; x < 10000; x++) { int value = Random.Int32; ms.Write(value); ms2.Write(value); int seek = Random.Int16Between(-10, 20); if (ms.Position + seek < 0) { seek = -seek; } ms.Position += seek; ms2.Position += seek; } Compare(ms, ms2); }
private static byte[] SerializeCache(Dictionary<string, UserData> cache) { using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream()) using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Default)) { writer.Write(CacheHeaderBytes); writer.Write(cache.Count); foreach (KeyValuePair<string, UserData> data in cache) { UserData userData = data.Value; writer.Write(data.Key); writer.Write(userData.Username); writer.Write(userData.FirstName); writer.Write(userData.LastName); writer.Write(userData.CompanyName); writer.Write(userData.PhoneNumber); writer.Write(userData.EmailAddress); writer.Write(userData.IsLockedOut); writer.Write(userData.IsDisabled); writer.Write(userData.PasswordChangeDateTime.Ticks); writer.Write(userData.AccountCreatedDateTime.Ticks); writer.Write(userData.Roles.Count); foreach (string role in userData.Roles) writer.Write(role); writer.Write(userData.Groups.Count); foreach (string group in userData.Groups) writer.Write(group); } return stream.ToArray(); } }
/// <summary> /// Sends a server command to the publisher connection. /// </summary> /// <param name="commandCode"><see cref="ServerCommand"/> to send.</param> /// <param name="data">Optional command data to send.</param> /// <returns><c>true</c> if <paramref name="commandCode"/> transmission was successful; otherwise <c>false</c>.</returns> public virtual bool SendServerCommand(ServerCommand commandCode, byte[] data = null) { if ((object)m_commandChannel != null && m_commandChannel.CurrentState == ClientState.Connected) { try { using (BlockAllocatedMemoryStream commandPacket = new BlockAllocatedMemoryStream()) { // Write command code into command packet commandPacket.WriteByte((byte)commandCode); // Write command buffer into command packet if ((object)data != null && data.Length > 0) commandPacket.Write(data, 0, data.Length); // Send command packet to publisher m_commandChannel.SendAsync(commandPacket.ToArray(), 0, (int)commandPacket.Length); m_metadataRefreshPending = (commandCode == ServerCommand.MetaDataRefresh); } // Track server command in pending request queue lock (m_requests) { // Make sure a pending request does not already exist int index = m_requests.BinarySearch(commandCode); if (index < 0) { // Add the new server command to the request list m_requests.Add(commandCode); // Make sure requests are sorted to allow for binary searching m_requests.Sort(); } } return true; } catch (Exception ex) { OnProcessException(new InvalidOperationException($"Exception occurred while trying to send server command \"{commandCode}\" to publisher: {ex.Message}", ex)); } } else OnProcessException(new InvalidOperationException($"Subscriber is currently unconnected. Cannot send server command \"{commandCode}\" to publisher.")); return false; }
/// <summary> /// Sends a server command to the publisher connection with associated <paramref name="message"/> data. /// </summary> /// <param name="commandCode"><see cref="ServerCommand"/> to send.</param> /// <param name="message">String based command data to send to server.</param> /// <returns><c>true</c> if <paramref name="commandCode"/> transmission was successful; otherwise <c>false</c>.</returns> public virtual bool SendServerCommand(ServerCommand commandCode, string message) { if (!string.IsNullOrWhiteSpace(message)) { using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream()) { byte[] bytes = m_encoding.GetBytes(message); buffer.Write(BigEndian.GetBytes(bytes.Length), 0, 4); buffer.Write(bytes, 0, bytes.Length); return SendServerCommand(commandCode, buffer.ToArray()); } } return SendServerCommand(commandCode); }
/// <summary> /// Subscribes (or re-subscribes) to a data publisher for a set of data points. /// </summary> /// <param name="remotelySynchronized">Boolean value that determines if subscription should be remotely synchronized - note that data publisher may not allow remote synchronization.</param> /// <param name="compactFormat">Boolean value that determines if the compact measurement format should be used. Set to <c>false</c> for full fidelity measurement serialization; otherwise set to <c>true</c> for bandwidth conservation.</param> /// <param name="connectionString">Connection string that defines required and optional parameters for the subscription.</param> /// <returns><c>true</c> if subscribe transmission was successful; otherwise <c>false</c>.</returns> public virtual bool Subscribe(bool remotelySynchronized, bool compactFormat, string connectionString) { bool success = false; if (!string.IsNullOrWhiteSpace(connectionString)) { try { // Parse connection string to see if it contains a data channel definition Dictionary<string, string> settings = connectionString.ParseKeyValuePairs(); UdpClient dataChannel = null; string setting; // Track specified time inclusion for later deserialization if (settings.TryGetValue("includeTime", out setting)) m_includeTime = setting.ParseBoolean(); else m_includeTime = true; settings.TryGetValue("dataChannel", out setting); if (!string.IsNullOrWhiteSpace(setting)) { dataChannel = new UdpClient(setting); dataChannel.ReceiveBufferSize = ushort.MaxValue; dataChannel.MaxConnectionAttempts = -1; dataChannel.ConnectAsync(); } // Assign data channel client reference and attach to needed events DataChannel = dataChannel; // Setup subscription packet using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream()) { DataPacketFlags flags = DataPacketFlags.NoFlags; byte[] bytes; if (remotelySynchronized) flags |= DataPacketFlags.Synchronized; if (compactFormat) flags |= DataPacketFlags.Compact; // Write data packet flags into buffer buffer.WriteByte((byte)flags); // Get encoded bytes of connection string bytes = m_encoding.GetBytes(connectionString); // Write encoded connection string length into buffer buffer.Write(BigEndian.GetBytes(bytes.Length), 0, 4); // Encode connection string into buffer buffer.Write(bytes, 0, bytes.Length); // Cache subscribed synchronization state m_synchronizedSubscription = remotelySynchronized; // Send subscribe server command with associated command buffer success = SendServerCommand(ServerCommand.Subscribe, buffer.ToArray()); } } catch (Exception ex) { OnProcessException(new InvalidOperationException("Exception occurred while trying to make publisher subscription: " + ex.Message, ex)); } } else OnProcessException(new InvalidOperationException("Cannot make publisher subscription without a connection string.")); // Reset decompressor on successful resubscription if (success && (object)m_decompressionBlock != null) m_decompressionBlock.Reset(); return success; }
private void ProcessBinaryMeasurements(IEnumerable<IBinaryMeasurement> measurements, bool useCompactMeasurementFormat, bool usePayloadCompression) { // Create working buffer using (BlockAllocatedMemoryStream workingBuffer = new BlockAllocatedMemoryStream()) { // Serialize data packet flags into response DataPacketFlags flags = DataPacketFlags.NoFlags; // No flags means bit is cleared, i.e., unsynchronized if (useCompactMeasurementFormat) flags |= DataPacketFlags.Compact; workingBuffer.WriteByte((byte)flags); // No frame level timestamp is serialized into the data packet since all data is unsynchronized and essentially // published upon receipt, however timestamps are optionally included in the serialized measurements. // Serialize total number of measurement values to follow workingBuffer.Write(BigEndian.GetBytes(measurements.Count()), 0, 4); // Attempt compression when requested - encoding of compressed buffer only happens if size would be smaller than normal serialization if (!usePayloadCompression || !measurements.Cast<CompactMeasurement>().CompressPayload(workingBuffer, m_compressionStrength, m_includeTime, ref flags)) { // Serialize measurements to data buffer foreach (IBinaryMeasurement measurement in measurements) measurement.CopyBinaryImageToStream(workingBuffer); } // Update data packet flags if it has updated compression flags if ((flags & DataPacketFlags.Compressed) > 0) { workingBuffer.Seek(0, SeekOrigin.Begin); workingBuffer.WriteByte((byte)flags); } // Publish data packet to client if ((object)m_parent != null) m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, workingBuffer.ToArray()); // Track last publication time m_lastPublishTime = DateTime.UtcNow.Ticks; } }
private TransportProvider<EndPoint> AddUdpClient(EndPoint udpClientEndPoint) { TransportProvider<EndPoint> udpClient = new TransportProvider<EndPoint>(); IPEndPoint udpClientIPEndPoint = udpClientEndPoint as IPEndPoint; UdpClientInfo udpClientInfo; // Set up client udpClient.SetReceiveBuffer(ReceiveBufferSize); udpClient.SetSendBuffer(SendBufferSize); udpClient.Provider = udpClientIPEndPoint; // If the IP specified for the client is a multicast IP, subscribe to the specified multicast group. if ((object)udpClientIPEndPoint != null && Transport.IsMulticastIP(udpClientIPEndPoint.Address)) { SocketOptionLevel level = udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? SocketOptionLevel.IPv6 : SocketOptionLevel.IP; string multicastSource; if (m_configData.TryGetValue("multicastSource", out multicastSource)) { IPAddress sourceAddress = IPAddress.Parse(multicastSource); IPAddress localAddress = (udpClientIPEndPoint.AddressFamily == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any); if (sourceAddress.AddressFamily != udpClientIPEndPoint.AddressFamily) throw new InvalidOperationException($"Source address \"{sourceAddress}\" is not in the same IP format as server address \"{udpClientIPEndPoint.Address}\""); if (localAddress.AddressFamily != udpClientIPEndPoint.AddressFamily) throw new InvalidOperationException($"Local address \"{localAddress}\" is not in the same IP format as server address \"{udpClientIPEndPoint.Address}\""); using (BlockAllocatedMemoryStream membershipAddresses = new BlockAllocatedMemoryStream()) { byte[] serverAddressBytes = udpClientIPEndPoint.Address.GetAddressBytes(); byte[] sourceAddressBytes = sourceAddress.GetAddressBytes(); byte[] localAddressBytes = localAddress.GetAddressBytes(); membershipAddresses.Write(serverAddressBytes, 0, serverAddressBytes.Length); membershipAddresses.Write(sourceAddressBytes, 0, sourceAddressBytes.Length); membershipAddresses.Write(localAddressBytes, 0, localAddressBytes.Length); udpClient.MulticastMembershipAddresses = membershipAddresses.ToArray(); } // Execute multicast subscribe for specific source m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddSourceMembership, udpClient.MulticastMembershipAddresses); m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"])); } else { // Execute multicast subscribe for any source m_udpServer.Provider.SetSocketOption(level, SocketOptionName.AddMembership, new MulticastOption(udpClientIPEndPoint.Address)); m_udpServer.Provider.SetSocketOption(level, SocketOptionName.MulticastTimeToLive, int.Parse(m_configData["multicastTimeToLive"])); } } // Create client info object udpClientInfo = new UdpClientInfo { Client = udpClient, SendArgs = FastObjectFactory<SocketAsyncEventArgs>.CreateObjectFunction(), SendLock = new object(), SendQueue = new ConcurrentQueue<UdpServerPayload>() }; udpClientInfo.DumpPayloadsOperation = new ShortSynchronizedOperation(() => { UdpServerPayload payload; // Check to see if the client has reached the maximum send queue size. if (m_maxSendQueueSize > 0 && udpClientInfo.SendQueue.Count >= m_maxSendQueueSize) { for (int i = 0; i < m_maxSendQueueSize; i++) { if (udpClientInfo.SendQueue.TryDequeue(out payload)) { payload.WaitHandle.Set(); payload.WaitHandle.Dispose(); payload.WaitHandle = null; } } throw new InvalidOperationException($"Client {udpClientInfo.Client.ID} connected to UDP server reached maximum send queue size. {m_maxSendQueueSize} payloads dumped from the queue."); } }, ex => OnSendClientDataException(udpClientInfo.Client.ID, ex)); // Set up SocketAsyncEventArgs udpClientInfo.SendArgs.RemoteEndPoint = udpClient.Provider; udpClientInfo.SendArgs.SetBuffer(udpClient.SendBuffer, 0, udpClient.SendBufferSize); udpClientInfo.SendArgs.Completed += m_sendHandler; // Add new client to the lookup m_clientInfoLookup.TryAdd(udpClient.ID, udpClientInfo); OnClientConnected(udpClient.ID); return udpClient; }
/// <summary> /// Attempts to compress payload of <see cref="CompactMeasurement"/> values onto the <paramref name="destination"/> stream. /// </summary> /// <param name="compactMeasurements">Payload of <see cref="CompactMeasurement"/> values.</param> /// <param name="destination">Memory based <paramref name="destination"/> stream to hold compressed payload.</param> /// <param name="compressionStrength">Compression strength to use.</param> /// <param name="includeTime">Flag that determines if time should be included in the compressed payload.</param> /// <param name="flags">Current <see cref="DataPacketFlags"/>.</param> /// <returns><c>true</c> if payload was compressed and encoded onto <paramref name="destination"/> stream; otherwise <c>false</c>.</returns> /// <remarks> /// <para> /// Compressed payload will only be encoded onto <paramref name="destination"/> stream if compressed size would be smaller /// than normal serialized size. /// </para> /// <para> /// As an optimization this function uses a compression method that uses pointers to native structures, as such the /// endian order encoding of the compressed data will always be in the native-endian order of the operating system. /// This will be an important consideration when writing a endian order neutral payload decompressor. To help with /// this the actual endian order used during compression is marked in the data flags. However, measurements values /// are consistently encoded in big-endian order prior to buffer compression. /// </para> /// </remarks> public static bool CompressPayload(this IEnumerable<CompactMeasurement> compactMeasurements, BlockAllocatedMemoryStream destination, byte compressionStrength, bool includeTime, ref DataPacketFlags flags) { // Instantiate a buffer that is larger than we'll need byte[] buffer = new byte[ushort.MaxValue]; // Go ahead an enumerate all the measurements - this will cast all values to compact measurements CompactMeasurement[] measurements = compactMeasurements.ToArray(); int measurementCount = measurements.Length; int sizeToBeat = measurementCount * measurements[0].BinaryLength; int index = 0; // Encode compact state flags and runtime IDs together -- // Together these are three bytes, so we pad with a zero byte. // The zero byte and state flags are considered to be more compressible // than the runtime ID, so these are stored in the higher order bytes. for (int i = 0; i < measurementCount; i++) { uint value = ((uint)measurements[i].CompactStateFlags << 16) | measurements[i].RuntimeID; index += NativeEndianOrder.Default.CopyBytes(value, buffer, index); } // Encode values for (int i = 0; i < measurementCount; i++) { // Encode using adjusted value (accounts for adder and multiplier) index += NativeEndianOrder.Default.CopyBytes((float)measurements[i].AdjustedValue, buffer, index); } if (includeTime) { // Encode timestamps for (int i = 0; i < measurementCount; i++) { // Since large majority of 8-byte tick values will be repeated, they should compress well index += NativeEndianOrder.Default.CopyBytes((long)measurements[i].Timestamp, buffer, index); } } // Attempt to compress buffer int compressedSize = PatternCompressor.CompressBuffer(buffer, 0, index, ushort.MaxValue, compressionStrength); // Only encode compressed buffer if compression actually helped payload size if (compressedSize <= sizeToBeat) { // Set payload compression flag flags |= DataPacketFlags.Compressed; // Make sure decompressor knows original endian encoding order if (BitConverter.IsLittleEndian) flags |= DataPacketFlags.LittleEndianCompression; else flags &= ~DataPacketFlags.LittleEndianCompression; // Copy compressed payload onto destination stream destination.Write(buffer, 0, compressedSize); return true; } // Clear payload compression flag flags &= ~DataPacketFlags.Compressed; return false; }
/// <summary> /// Initiates inter-process synchronized save of <see cref="DataSet"/>. /// </summary> public override void Save() { byte[] serializedDataSet; // Wait for thread level lock on data set lock (m_dataSetLock) { using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream()) { m_dataSet.SerializeToStream(stream); serializedDataSet = stream.ToArray(); } } // File data is the serialized data set, assignment will initiate auto-save if needed FileData = serializedDataSet; }
/// <summary> /// Plays the wave file using <see cref="SoundPlayer"/>. /// </summary> public void Play() { using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream()) { SoundPlayer player = new SoundPlayer(stream); Save(stream); stream.Position = 0; player.Play(); } }
/// <summary> /// Creates an XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object as a single section to write to a file. /// </summary> /// <returns> /// An XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object. /// </returns> /// <param name="parentElement">The <see cref="ConfigurationElement"/> instance to use as the parent when performing the un-merge.</param> /// <param name="name">The name of the section to create.</param> /// <param name="saveMode">The <see cref="ConfigurationSaveMode"/> instance to use when writing to a string.</param> protected override string SerializeSection(ConfigurationElement parentElement, string name, ConfigurationSaveMode saveMode) { if ((object)m_sections != null) { const string tempRoot = "__tempRoot__"; using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream()) { XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8); writer.Indentation = 2; writer.Formatting = Formatting.Indented; // Add a temporary root so that indentation is at the desired level writer.WriteStartElement(tempRoot); writer.WriteStartElement(name); foreach (string section in m_sections.Keys) { CategorizedSettingsElementCollection categorySettings = this[section]; // Add category section writer.WriteStartElement(section); // Write each category value foreach (CategorizedSettingsElement categorySetting in categorySettings) { // <add name="TestConfigParam" value="-1.0" description="Parameter description." encrypted="false" scope="User"/> writer.WriteStartElement("add"); writer.WriteAttributeString("name", categorySetting.Name); writer.WriteAttributeString("value", categorySetting.SerializedValue); writer.WriteAttributeString("description", categorySetting.Description ?? ""); writer.WriteAttributeString("encrypted", categorySetting.Encrypted.ToString()); if (categorySetting.Scope == SettingScope.User) writer.WriteAttributeString("scope", categorySetting.Scope.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.Flush(); string settings = Encoding.UTF8.GetString(stream.ToArray()); // Remove temporary root return settings.Replace(string.Format("<{0}>", tempRoot), "").Replace(string.Format("</{0}>", tempRoot), ""); } } return base.SerializeSection(parentElement, name, saveMode); }
/// <summary> /// Reads XML from the configuration file. /// </summary> /// <param name="reader">The <see cref="System.Xml.XmlReader"/> object, which reads from the configuration file.</param> protected override void DeserializeSection(XmlReader reader) { using (BlockAllocatedMemoryStream configSectionStream = new BlockAllocatedMemoryStream()) { XmlDocument configSection = new XmlDocument(); configSection.Load(reader); configSection.Save(configSectionStream); // Adds all the categories that are under the categorizedSettings section of the configuration file // to the property collection. Again, this is essentially doing what marking a property with the // <ConfigurationProperty()> attribute does. If this is not done, then an exception will be raised // when the category elements are being deserialized. if ((object)configSection.DocumentElement != null) { XmlNodeList categories = configSection.DocumentElement.SelectNodes("*"); if ((object)categories != null) { foreach (XmlNode category in categories) { ConfigurationProperty configProperty = new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection)); base.Properties.Add(configProperty); if ((object)m_sections != null) { CategorizedSettingsElementCollection settingsCategory = new CategorizedSettingsElementCollection { Name = category.Name, Section = this, }; settingsCategory.SetCryptoKey(m_cryptoKey); m_sections.Add(category.Name, settingsCategory); // Read all elements within this category section XmlNodeList elements = category.SelectNodes("*"); SettingScope scope; if ((object)elements != null) { foreach (XmlNode element in elements) { CategorizedSettingsElement categorySetting = new CategorizedSettingsElement(settingsCategory); categorySetting.Name = element.GetAttributeValue("name"); categorySetting.Value = element.GetAttributeValue("value"); categorySetting.Description = element.GetAttributeValue("description") ?? ""; categorySetting.Encrypted = element.GetAttributeValue("encrypted").ToNonNullNorWhiteSpace("false").ParseBoolean(); if (Enum.TryParse(element.GetAttributeValue("scope").ToNonNullNorWhiteSpace("Application"), out scope)) categorySetting.Scope = scope; else categorySetting.Scope = SettingScope.Application; settingsCategory.Add(categorySetting); } } } } } } m_sectionLoaded = true; if ((object)m_sections == null) { configSectionStream.Seek(0, SeekOrigin.Begin); base.DeserializeSection(XmlReader.Create(configSectionStream)); } } }
// Rotates base time offsets private void RotateBaseTimes() { if ((object)m_parent != null && (object)m_baseTimeRotationTimer != null) { if ((object)m_baseTimeOffsets == null) { m_baseTimeOffsets = new long[2]; m_baseTimeOffsets[0] = RealTime; m_baseTimeOffsets[1] = RealTime + (long)m_baseTimeRotationTimer.Interval * Ticks.PerMillisecond; m_timeIndex = 0; } else { int oldIndex = m_timeIndex; // Switch to newer timestamp m_timeIndex ^= 1; // Now make older timestamp the newer timestamp m_baseTimeOffsets[oldIndex] = RealTime + (long)m_baseTimeRotationTimer.Interval * Ticks.PerMillisecond; } // Since this function will only be called periodically, there is no real benefit // to maintaining this memory stream at a member level using (BlockAllocatedMemoryStream responsePacket = new BlockAllocatedMemoryStream()) { responsePacket.Write(BigEndian.GetBytes(m_timeIndex), 0, 4); responsePacket.Write(BigEndian.GetBytes(m_baseTimeOffsets[0]), 0, 8); responsePacket.Write(BigEndian.GetBytes(m_baseTimeOffsets[1]), 0, 8); m_parent.SendClientResponse(m_clientID, ServerResponse.UpdateBaseTimes, ServerCommand.Subscribe, responsePacket.ToArray()); } } }
public void Test4() { MemoryStream ms = new MemoryStream(); BlockAllocatedMemoryStream ms2 = new BlockAllocatedMemoryStream(); for (int x = 0; x < 10000; x++) { int value = Random.Int32; ms.Write(value); ms.Write((byte)value); ms2.Write(value); ms2.Write((byte)value); } for (int x = 0; x < 10000; x++) { long position = Random.Int64Between(0, ms.Length - 5); ms.Position = position; ms2.Position = position; if (ms.ReadInt32() != ms2.ReadInt32()) throw new Exception(); if (ms.ReadNextByte() != ms2.ReadNextByte()) throw new Exception(); } for (int x = 0; x < 10000; x++) { byte[] buffer1 = new byte[100]; byte[] buffer2 = new byte[100]; long position = Random.Int64Between(0, (long)(ms.Length * 1.1)); int readLength = Random.Int32Between(0, 100); ms.Position = position; ms2.Position = position; if (ms.Read(buffer1, 99 - readLength, readLength) != ms2.Read(buffer2, 99 - readLength, readLength)) { CompareBytes(buffer1, buffer2); } } Compare(ms, ms2); }
private static void Compare(MemoryStream ms, BlockAllocatedMemoryStream ms2) { if (ms.Position != ms2.Position) throw new Exception(); if (ms.Length != ms2.Length) throw new Exception(); byte[] data1 = ms.ToArray(); byte[] data2 = ms2.ToArray(); CompareBytes(data1, data2); }
private void ProcessBinaryMeasurements(IEnumerable<IBinaryMeasurement> measurements, long frameLevelTimestamp, bool useCompactMeasurementFormat, bool usePayloadCompression) { // Create working buffer using (BlockAllocatedMemoryStream workingBuffer = new BlockAllocatedMemoryStream()) { // Serialize data packet flags into response DataPacketFlags flags = DataPacketFlags.Synchronized; if (m_compressionModes.HasFlag(CompressionModes.TSSC)) { flags |= DataPacketFlags.Compressed; } else { if (useCompactMeasurementFormat) flags |= DataPacketFlags.Compact; } workingBuffer.WriteByte((byte)flags); // Serialize frame timestamp into data packet - this only occurs in synchronized data packets, // unsynchronized subscriptions always include timestamps in the serialized measurements workingBuffer.Write(BigEndian.GetBytes(frameLevelTimestamp), 0, 8); // Serialize total number of measurement values to follow workingBuffer.Write(BigEndian.GetBytes(measurements.Count()), 0, 4); if (usePayloadCompression && m_compressionModes.HasFlag(CompressionModes.TSSC)) { if ((object)m_compressionBlock == null) m_compressionBlock = new MeasurementCompressionBlock(); else m_compressionBlock.Clear(); foreach (CompactMeasurement measurement in measurements.Cast<CompactMeasurement>()) { if (m_compressionBlock.CanAddMeasurements) { m_compressionBlock.AddMeasurement(measurement.RuntimeID, measurement.Timestamp.Value, (uint)measurement.StateFlags, (float)measurement.AdjustedValue); } else { m_compressionBlock.CopyTo(workingBuffer); m_compressionBlock.Clear(); m_compressionBlock.AddMeasurement(measurement.RuntimeID, measurement.Timestamp.Value, (uint)measurement.StateFlags, (float)measurement.AdjustedValue); } } m_compressionBlock.CopyTo(workingBuffer); } else { // Attempt compression when requested - encoding of compressed buffer only happens if size would be smaller than normal serialization if (!usePayloadCompression || !measurements.Cast<CompactMeasurement>().CompressPayload(workingBuffer, m_compressionStrength, false, ref flags)) { // Serialize measurements to data buffer foreach (IBinaryMeasurement measurement in measurements) { measurement.CopyBinaryImageToStream(workingBuffer); } } // Update data packet flags if it has updated compression flags if ((flags & DataPacketFlags.Compressed) > 0) { workingBuffer.Seek(0, SeekOrigin.Begin); workingBuffer.WriteByte((byte)flags); } } // Publish data packet to client if ((object)m_parent != null) m_parent.SendClientResponse(m_clientID, ServerResponse.DataPacket, ServerCommand.Subscribe, workingBuffer.ToArray()); } }
/// <summary> /// Converts a <see cref="Bitmap"/> image to the specified <see cref="ImageFormat"/>. /// </summary> /// <param name="originalImage">The <see cref="Bitmap"/> image to be converted.</param> /// <param name="newFormat">The new <see cref="ImageFormat"/> of the image.</param> /// <param name="disposeOriginal">true if the original image is to be disposed after converting it; otherwise false.</param> /// <returns>A <see cref="Bitmap"/> instance.</returns> /// <example> /// This example shows how to convert the format of an image and dispose the original image that was converted: /// <code> /// using System; /// using System.Drawing; /// using System.Drawing.Imaging; /// using GSF.Drawing; /// /// class Program /// { /// static void Main(string[] args) /// { /// // Load original, convert it, and dispose original. /// using (Bitmap converted = ((Bitmap)Bitmap.FromFile("Original.jpg")).ConvertTo(ImageFormat.Gif)) /// { /// // Save the converted image to file. /// converted.Save("OriginalGif.gif"); /// } /// /// Console.ReadLine(); /// } /// } /// </code> /// </example> public static Bitmap ConvertTo(this Image originalImage, ImageFormat newFormat, bool disposeOriginal) { Bitmap newImage; using (BlockAllocatedMemoryStream newImageStream = new BlockAllocatedMemoryStream()) { // Save image to memory stream in the specified format. originalImage.Save(newImageStream, newFormat); // Create new bitmap from the memory stream. newImage = new Bitmap(newImageStream); // Dispose original if indicated. if (disposeOriginal) originalImage.Dispose(); return newImage; } }
/// <summary> /// Authenticates subscriber to a data publisher. /// </summary> /// <param name="sharedSecret">Shared secret used to look up private crypto key and initialization vector.</param> /// <param name="authenticationID">Authentication ID that publisher will use to validate subscriber identity.</param> /// <returns><c>true</c> if authentication transmission was successful; otherwise <c>false</c>.</returns> public virtual bool Authenticate(string sharedSecret, string authenticationID) { if (!string.IsNullOrWhiteSpace(authenticationID)) { try { using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream()) { byte[] salt = new byte[DataPublisher.CipherSaltLength]; byte[] bytes; // Generate some random prefix data to make sure auth key transmission is always unique Random.GetBytes(salt); // Get encoded bytes of authentication key bytes = salt.Combine(m_encoding.GetBytes(authenticationID)); // Encrypt authentication key bytes = bytes.Encrypt(sharedSecret, CipherStrength.Aes256); // Write encoded authentication key length into buffer buffer.Write(BigEndian.GetBytes(bytes.Length), 0, 4); // Encode encrypted authentication key into buffer buffer.Write(bytes, 0, bytes.Length); // Send authentication command to server with associated command buffer return SendServerCommand(ServerCommand.Authenticate, buffer.ToArray()); } } catch (Exception ex) { OnProcessException(new InvalidOperationException("Exception occurred while trying to authenticate publisher subscription: " + ex.Message, ex)); } } else OnProcessException(new InvalidOperationException("Cannot authenticate subscription without a connection string.")); return false; }
/// <summary> /// Rotates or initializes the crypto keys for this <see cref="ClientConnection"/>. /// </summary> public bool RotateCipherKeys() { // Make sure at least a second has passed before next key rotation if ((DateTime.UtcNow.Ticks - m_lastCipherKeyUpdateTime).ToMilliseconds() >= 1000.0D) { try { // Since this function cannot be not called more than once per second there // is no real benefit to maintaining these memory streams at a member level using (BlockAllocatedMemoryStream response = new BlockAllocatedMemoryStream()) { byte[] bytes, bufferLen; // Create or update cipher keys and initialization vectors UpdateKeyIVs(); // Add current cipher index to response response.WriteByte((byte)m_cipherIndex); // Serialize new keys using (BlockAllocatedMemoryStream buffer = new BlockAllocatedMemoryStream()) { // Write even key bufferLen = BigEndian.GetBytes(m_keyIVs[EvenKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][KeyIndex], 0, m_keyIVs[EvenKey][KeyIndex].Length); // Write even initialization vector bufferLen = BigEndian.GetBytes(m_keyIVs[EvenKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[EvenKey][IVIndex], 0, m_keyIVs[EvenKey][IVIndex].Length); // Write odd key bufferLen = BigEndian.GetBytes(m_keyIVs[OddKey][KeyIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][KeyIndex], 0, m_keyIVs[OddKey][KeyIndex].Length); // Write odd initialization vector bufferLen = BigEndian.GetBytes(m_keyIVs[OddKey][IVIndex].Length); buffer.Write(bufferLen, 0, bufferLen.Length); buffer.Write(m_keyIVs[OddKey][IVIndex], 0, m_keyIVs[OddKey][IVIndex].Length); // Get bytes from serialized buffer bytes = buffer.ToArray(); } // Encrypt keys using private keys known only to current client and server if (m_authenticated && !string.IsNullOrWhiteSpace(m_sharedSecret)) bytes = bytes.Encrypt(m_sharedSecret, CipherStrength.Aes256); // Add serialized key response response.Write(bytes, 0, bytes.Length); // Send cipher key updates m_parent.SendClientResponse(m_clientID, ServerResponse.UpdateCipherKeys, ServerCommand.Subscribe, response.ToArray()); } // Send success message m_parent.SendClientResponse(m_clientID, ServerResponse.Succeeded, ServerCommand.RotateCipherKeys, "New cipher keys established."); m_parent.OnStatusMessage(ConnectionID + " cipher keys rotated."); return true; } catch (Exception ex) { // Send failure message m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Failed to establish new cipher keys: " + ex.Message); m_parent.OnStatusMessage("Failed to establish new cipher keys for {0}: {1}", ConnectionID, ex.Message); return false; } } m_parent.SendClientResponse(m_clientID, ServerResponse.Failed, ServerCommand.RotateCipherKeys, "Cipher key rotation skipped, keys were already rotated within last second."); m_parent.OnStatusMessage("WARNING: Cipher key rotation skipped for {0}, keys were already rotated within last second.", ConnectionID); return false; }
// Open wave reader - either from memory loaded WAV or directly from disk private WaveDataReader OpenWaveDataReader() { if (MemoryCache) { if ((object)m_dataCache == null) { m_dataCache = new BlockAllocatedMemoryStream(); using (FileStream stream = File.OpenRead(WavFileName)) stream.CopyTo(m_dataCache); } m_dataCache.Position = 0; return WaveDataReader.FromStream(m_dataCache); } return WaveDataReader.FromFile(WavFileName); }
/// <summary> /// Writes the given record to the PQDIF file. /// </summary> /// <param name="record">The record to be written to the file.</param> /// <param name="lastRecord">Indicates whether this record is the last record in the file.</param> public void WriteRecord(Record record, bool lastRecord = false) { byte[] bodyImage; if (m_disposed) throw new ObjectDisposedException(GetType().Name); using (BlockAllocatedMemoryStream bodyStream = new BlockAllocatedMemoryStream()) using (BinaryWriter bodyWriter = new BinaryWriter(bodyStream)) { // Write the record body to the memory stream WriteCollection(bodyWriter, record.Body.Collection); // Read and compress the body to a byte array bodyImage = bodyStream.ToArray(); if (m_compressionAlgorithm == CompressionAlgorithm.Zlib && m_compressionStyle == CompressionStyle.RecordLevel) bodyImage = ZlibStream.CompressBuffer(bodyImage); } // Fix the pointer to the next // record before writing this record if (m_stream.CanSeek && m_stream.Length > 0) { m_writer.Write((int)m_stream.Length); m_stream.Seek(0L, SeekOrigin.End); } // Make sure the header points to the correct location based on the size of the body record.Header.HeaderSize = 64; record.Header.BodySize = bodyImage.Length; record.Header.NextRecordPosition = (int)m_stream.Length + record.Header.HeaderSize + record.Header.BodySize; // Write up to the next record position m_writer.Write(record.Header.RecordSignature.ToByteArray()); m_writer.Write(record.Header.RecordTypeTag.ToByteArray()); m_writer.Write(record.Header.HeaderSize); m_writer.Write(record.Header.BodySize); // The PQDIF standard defines the NextRecordPosition to be 0 for the last record in the file // We treat seekable streams differently because we can go back and fix the pointers later if (m_stream.CanSeek || lastRecord) m_writer.Write(0); else m_writer.Write(record.Header.NextRecordPosition); // Write the rest of the header as well as the body m_writer.Write(record.Header.Checksum); m_writer.Write(record.Header.Reserved); m_writer.Write(bodyImage); // If the stream is seekable, seek to the next record // position so we can fix the pointer if we end up // writing another record to the file if (m_stream.CanSeek) m_stream.Seek(-(24 + record.Header.BodySize), SeekOrigin.Current); // Dispose of the writer if this is the last record if (!m_stream.CanSeek && lastRecord) Dispose(); }
/// <summary> /// Sends a server command to the publisher connection. /// </summary> /// <param name="commandCode"><see cref="ServerCommand"/> to send.</param> /// <param name="data">Optional command data to send.</param> /// <returns><c>true</c> if <paramref name="commandCode"/> transmission was successful; otherwise <c>false</c>.</returns> public virtual bool SendServerCommand(ServerCommand commandCode, byte[] data = null) { if ((object)m_commandChannel != null && m_commandChannel.CurrentState == ClientState.Connected) { try { using (BlockAllocatedMemoryStream commandPacket = new BlockAllocatedMemoryStream()) { // Write command code into command packet commandPacket.WriteByte((byte)commandCode); // Write command buffer into command packet if ((object)data != null && data.Length > 0) commandPacket.Write(data, 0, data.Length); // Send command packet to publisher m_commandChannel.SendAsync(commandPacket.ToArray(), 0, (int)commandPacket.Length); m_metadataRefreshPending = commandCode == ServerCommand.MetaDataRefresh; } return true; } catch (Exception ex) { OnProcessException(MessageLevel.Error, new InvalidOperationException($"Exception occurred while trying to send server command \"{commandCode}\" to publisher: {ex.Message}", ex)); } } else OnProcessException(MessageLevel.Error, new InvalidOperationException($"Subscriber is currently unconnected. Cannot send server command \"{commandCode}\" to publisher.")); return false; }