/// <summary> /// Buffer processed data and send to the receive callback. /// </summary> private void ProcessReceivedData() { // get a buffer to dequeue into var buffer = BufferCache.Get(); try { // dequeue a buffer from the pending received data int count = _receivedBuffer.TakeItem().Dequeue(buffer, 0, Global.BufferSizeLocal); _receivedBuffer.Release(); if (count == 0) { // allocate the buffer cache once more BufferCache.Set(buffer); } else { // remove //Log.Debug(new string(System.Text.Encoding.UTF8.GetChars(buffer, 0, count))); // run the callback action _onReceive.AddRun(ActionSet.New(OnReceive, buffer, count)); if (count == Global.BufferSizeLocal) { ManagerUpdate.Control.AddSingle(ProcessReceivedData); return; } } // no bytes to receive CompleteReceive(); } catch (SocketException ex) { _readLock.Release(); BufferCache.Set(buffer); if (ex.SocketErrorCode == SocketError.ConnectionReset) { return; } ProcessError(ex); } catch (Exception ex) { _readLock.Release(); BufferCache.Set(buffer); ProcessError(ex); } }
/// <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> /// Internal addition of a metadata task when the task is ready to run. /// </summary> internal void Add(IAction metaTask) { _sequencer.AddRun(metaTask); }