Defines a stream whose backing store is memory. Externally this class operates similar to a MemoryStream, internally it uses dynamically allocated buffer blocks instead of one large contiguous array of data.

The BlockAllocatedMemoryStream has two primary benefits over a normal MemoryStream, first, the allocation of a large contiguous array of data in MemoryStream can fail when the requested amount of contiguous memory is unavailable - the BlockAllocatedMemoryStream prevents this; second, a MemoryStream will constantly reallocate the buffer size as the stream grows and shrinks and then copy all the data from the old buffer to the new - the BlockAllocatedMemoryStream maintains its blocks over its life cycle, unless manually cleared, thus eliminating unnecessary allocations and garbage collections when growing and reusing a stream.

Important: Unlike MemoryStream, the BlockAllocatedMemoryStream will not use a user provided buffer as its backing buffer. Any user provided buffers used to instantiate the class will be copied into internally managed reusable memory buffers. Subsequently, the BlockAllocatedMemoryStream does not support the notion of a non-expandable stream. If you are using a MemoryStream with your own buffer, the BlockAllocatedMemoryStream will not provide any immediate benefit.

Note that the BlockAllocatedMemoryStream will maintain all allocated blocks for stream use until the Clear method is called or the class is disposed.

No members in the BlockAllocatedMemoryStream are guaranteed to be thread safe. Make sure any calls are synchronized when simultaneously accessed from different threads.

Inheritance: Stream
Example #1
0
 /// <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();
     }
 }
Example #2
0
 /// <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);
        }
Example #7
0
        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();
            }
        }
Example #8
0
        /// <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;
        }
Example #9
0
        /// <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);
        }
Example #10
0
        /// <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;
            }
        }
Example #12
0
        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;
        }
Example #13
0
        /// <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;
        }
Example #14
0
        /// <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;
        }
Example #15
0
 /// <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());
            }
        }
Example #22
0
        /// <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;
            }
        }
Example #23
0
        /// <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;
        }
Example #24
0
        /// <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);
        }
Example #26
0
        /// <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;
        }