/// <summary> /// Write the specified byte buffer. /// </summary> public override void Write(byte[] buffer, int offset, int count) { if (_initialize) { Initialize(false); } _updated |= count > 0; // iterate while there are more bytes to write while (count > 0) { if (_section == null) { SetSection(_sectionIndex); } // will the section be filled by the section? if (count > _sectionSize - _sectionPosition) { // yes, fill the current section var bytes = _sectionSize - _sectionPosition; Micron.CopyMemory(buffer, offset, _section.Bytes, _sectionPosition, bytes); offset += bytes; count -= bytes; _section.Updated = true; _section.Length += bytes; // increment the section NextSection(); // add the bytes count AddByteCount(bytes); } else { // no, copy the buffer bytes Micron.CopyMemory(buffer, offset, _section.Bytes, _sectionPosition, count); // increment the section position _sectionPosition += count; _section.Length += count; _section.Updated = true; AddByteCount(count); count = 0; } } if (_position + _sectionPosition > _length) { _length = _position + _sectionPosition; } }
/// <summary> /// Save the section. /// </summary> protected void SaveSection(BlobSection section, int sectionIndex) { section.Updated = false; if (section.Length != _sectionSize) { byte[] bytes = new byte[section.Length]; Micron.CopyMemory(section.Bytes, bytes, section.Length); _blobs.BlobData.Set(Id, sectionIndex, bytes); } else { _blobs.BlobData.Set(Id, sectionIndex, section.Bytes); } }
/// <summary> /// Append the specified bytes to the next read. /// </summary> protected void Buffer(byte[] bytes, int offset, int length) { _buffer = true; // does the buffer have room for the specified bytes? if (length > _bufferTarget - _bufferIndex) { // no, resize the prepared byte array _bufferBytes = BufferCache.Get(_bufferTarget + length); } // copy the byte buffer into the prepared collection Micron.CopyMemory(bytes, offset, _bufferBytes, _bufferIndex, length); // increment the index _bufferIndex += length; }
/// <summary> /// On socket data being received. /// </summary> private unsafe void OnReceiveSocketData(IAsyncResult ar) { int count = 0; try { // end the receive count = Socket.EndReceiveFrom(ar, ref _receiveEndPoint); } catch (Exception ex) { // release the read lock _syncLock.ReleaseRead(); ProcessError(ex); return; } if (count > 0) { // is the received buffer chunked? byte flag = _receiveBuffer[0]; if (flag < 60 || flag >= 188) { count -= ChunkHeaderSize; int chunkId; int chunkIndex; int chunkCount; // sanity check for correct number of bytes received if (count < 0) { _syncLock.ReleaseRead(); ProcessError("Socket didn't receive enough data for chunked information."); return; } // yes, read the chunk details fixed(byte *intP = &_receiveBuffer[1]) { chunkId = *(int *)intP; } fixed(byte *intP = &_receiveBuffer[5]) { chunkIndex = *(int *)intP; } fixed(byte *intP = &_receiveBuffer[9]) { chunkCount = *(int *)intP; } // sanity check for the chunk data being valid if (chunkIndex >= chunkCount) { _syncLock.ReleaseRead(); ProcessError("Socket received invalid chunk index and count information."); return; } // write ChunkedGram chunkedGram; if (_receivedChunks.TryGetValue(chunkId, out chunkedGram)) { chunkedGram.Length += count; chunkedGram.Chunks.Insert(Teple.New(count, _receiveBuffer), chunkIndex); // have all chunks been added? if (chunkedGram.Chunks.Count == chunkCount) { // yes, remove from the collection _receivedChunks.Remove(chunkId); // create a byte buffer for the entire message byte[] result = new byte[chunkedGram.Length]; int index = 0; foreach (var chunk in chunkedGram.Chunks) { int length = chunk.ArgA; Micron.CopyMemory(chunk.ArgB, ChunkHeaderSize, result, index, length); index += length; } // reference the endpoint from which the data was received IPEndPoint endpoint = (IPEndPoint)_receiveEndPoint; // run the callback _onReceive.AddRun(ActionSet.New(OnReceive, endpoint, result, chunkedGram.Length)); } else { // no, create a new receive buffer _receiveBuffer = BufferCache.Get(); } } else { chunkedGram = new ChunkedGram { Chunks = new ArrayRig <Teple <int, byte[]> >(chunkCount), Timestamp = Time.Timestamp }; _receivedChunks.Add(chunkId, chunkedGram); chunkedGram.Chunks.Add(Teple.New(count, _receiveBuffer)); chunkedGram.Length += count; // create a new receive buffer _receiveBuffer = BufferCache.Get(); } } else { // no, copy the received buffer --count; byte[] buffer = BufferCache.Get(count); Micron.CopyMemory(_receiveBuffer, 1, buffer, 0, count); // reference the endpoint from which the data was received IPEndPoint endpoint = (IPEndPoint)_receiveEndPoint; // run the callback _onReceive.AddRun(ActionSet.New(OnReceive, endpoint, buffer, count)); } } if (_receivedChunks.Count > 0) { // check for any chunked data timeouts ArrayRig <int> toRemove = null; foreach (var chunkedGram in _receivedChunks) { if (Time.Timestamp - chunkedGram.Value.Timestamp > ChunkedGramTimeout) { if (toRemove == null) { toRemove = new ArrayRig <int>(); } toRemove.Add(chunkedGram.Key); } } if (toRemove != null) { foreach (var chunkId in toRemove) { ChunkedGram chunked; if (_receivedChunks.TryGetValue(chunkId, out chunked)) { _receivedChunks.Remove(chunkId); chunked.Chunks.Dispose(); } } } } // release the read lock _syncLock.ReleaseRead(); // create the endpoint for receiving data _receiveEndPoint = new IPEndPoint(RemoteEndPoint.Address, RemoteEndPoint.Port); try { // start receiving again Socket.BeginReceiveFrom(_receiveBuffer, 0, Global.BufferSizeLocal, SocketFlags.None, ref _receiveEndPoint, OnReceiveSocketData, null); } catch (Exception ex) { ProcessError(ex); return; } }
/// <summary> /// Read and fill the byte buffer from the stream. /// </summary> public override int Read(byte[] buffer, int offset, int count) { if (_initialize) { Initialize(true); } int start = offset; // get the required sections while (count > 0) { if (_section == null) { if (_sectionIndex == _sectionCount) { Log.Error(Position + "- Read Last " + (offset - start) + " bytes. Was hoping for " + count); return(offset - start); } // load the required section SetSection(_sectionIndex); if (count >= _section.Length - _sectionPosition) { var copySize = _section.Length - _sectionPosition; Micron.CopyMemory(_section.Bytes, _sectionPosition, buffer, offset, copySize); count -= copySize; offset += copySize; NextSection(); } else { Micron.CopyMemory(_section.Bytes, _sectionPosition, buffer, offset, count); offset += count; _sectionPosition += count; count = 0; } } else { // will the buffer be filled with the current section? if (count >= _section.Length - _sectionPosition) { // no, copy bytes from the current section int bufferSize = _section.Length - _sectionPosition; Micron.CopyMemory(_section.Bytes, _sectionPosition, buffer, offset, bufferSize); offset += bufferSize; count -= bufferSize; // increment the section NextSection(); } else { // yes, copy bytes from the current section Micron.CopyMemory(_section.Bytes, _sectionPosition, buffer, offset, count); // increment the section position _sectionPosition += count; offset += count; count = 0; if (_sectionPosition > _length) { _length = _sectionPosition; } } } } // all required bytes were read return(offset - start); }
/// <summary> /// Read a single block of data, interpreting the bytes as a meaningful type. /// </summary> public virtual bool Read(byte[] bytes, int offset, int length) { // reset local buffers Reset(); // are some required bytes being prepared? if (_buffer) { bool result = false; // iterate while the buffer requirement is filled by the new bytes while (_bufferIndex + length - offset >= _bufferTarget) { // iterate while the prepared buffer contains enough bytes while (_bufferCount - _bufferIndex > _bufferTarget) { // send the prepared bytes int target = _bufferTarget; result |= Next(_bufferBytes, _bufferIndex, target); _bufferIndex += target; } // any prepared bytes remaining? if (_bufferCount > _bufferIndex) { // yes, copy the bytes to the start of the prepared array Micron.CopyMemory(_bufferBytes, _bufferIndex, _bufferBytes, 0, _bufferCount - _bufferIndex); // update the prepared count _bufferCount -= _bufferIndex; _bufferIndex = 0; } else { // no, copy any new bytes to the start of the buffer Micron.CopyMemory(bytes, offset, _bufferBytes, 0, length - offset); // reset the buffer parameters _bufferIndex = _bufferCount = 0; break; } // append new bytes to the buffer Micron.CopyMemory(bytes, offset, _bufferBytes, _bufferIndex, _bufferCapacity - _bufferIndex); offset += _bufferCount - _bufferIndex; } // iterate new buffer while (length - offset > _bufferTarget) { result |= Next(bytes, offset, _bufferTarget); offset += _bufferTarget; } // copy the remaining new bytes to the buffer Micron.CopyMemory(bytes, offset, _bufferBytes, _bufferIndex, length); return(result); } // any bytes in the buffer? if (_bufferIndex < _bufferCount) { // yes, will the new bytes fit in the buffer? if (length > _bufferCapacity - _bufferCount) { // no, resize the buffer Array.Resize(ref _bufferBytes, _bufferCapacity + length); } // copy the new bytes into the buffer Micron.CopyMemory(bytes, offset, _bufferBytes, _bufferIndex, length); int index = _bufferIndex; _bufferIndex += _bufferCount; // read the buffer bytes return(Next(_bufferBytes, index, _bufferCount)); } // read all bytes passed return(Next(bytes, offset, length)); }