/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint must be the endpoint that is returned to the user, /// that is the endpoint return by Connect(). /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="packetCache"> /// a list that contains the stackpackets. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, SyncFilterQueue <StackPacket> packetCache) { // get the packet in packet list. if (packetCache.Count > 0) { return(Utility.GetOne <StackPacket>(packetCache, null)); } // the consumed length of decoder. int consumedLength = 0; // decode packet, return null or at least one packet. StackPacket[] packets = ExpectMultiPacketsVisitor.Visit( buffer, decoder, endpoint, timeout, out consumedLength); // packet is null, buffer is closed, no packet will come. if (packets == null) { return(null); } // if packet arrived, add to packet list, and return the first. foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } return(Utility.GetOne <StackPacket>(packetCache, null)); }
/// <summary> /// enqueue the receivied transport event.<para/> /// add the transport event to the event queue, for user to expect specified event directly.<para/> /// add the transport event to data sequence, for user to expect any event(include received packet).<para/> /// it's thread-safe. /// </summary> /// <param name="eventQueue"> /// a SyncFilterQueue<TransportEvent> that specifies the queue to store event. /// </param> /// <param name="sequence"> /// a DataSequence object that stores the received data or event sequence. /// </param> /// <param name="transportEvent"> /// a TransportEvent object that specifies the received event. /// </param> public static void Enqueue(SyncFilterQueue <TransportEvent> eventQueue, DataSequence sequence, TransportEvent transportEvent) { lock (eventQueue) { sequence.Add(transportEvent, new byte[0], null); eventQueue.Enqueue(transportEvent); } }
/// <summary> /// Notify callback /// </summary> private void NotifyCallback(Object stateInfo) { // notify main thread, NotifyCallback is started. threadStartSemaphore.Release(); LogEvent("NotifyCallback is started..."); while (true) { // Wait for submitting request or disconnection rdmaNotificationSemaphore.WaitOne(); rdmaNotificationSemaphore.Release(); if (requestCount <= 0) { // no request in the list, the semaphore is released from disconnection //threadStopSemaphore.Release(); LogEvent("NotifyCallback has stopped."); return; } NtStatus status = (NtStatus)rdmaCompletionQueue.Notify(); LogEvent(string.Format("NotifyCallback: get notification with status {0}.", status)); if (status != NtStatus.STATUS_SUCCESS) { continue; } while (true) { UInt64 resultId; RdmaNetworkDirectResult ndResult; UInt64 size = rdmaCompletionQueue.GetResult(out resultId, out ndResult); if (size == 0) { break; } // WaitOne for reduce the request count rdmaNotificationSemaphore.WaitOne(); requestCount--; RequestType type = RequestType.None; int segmentIndex = -1; #region Receive and invalid memory window lock (locker) { foreach (SmbdRequest request in receiveRequestList) { if (request.ResultId == resultId) { type = request.Type; segmentIndex = request.EntryIndex; // get the result SmbdRequestResult requestResultItem = new SmbdRequestResult(); requestResultItem.EntryIndex = request.EntryIndex; requestResultItem.ResultInfo = ndResult; requestResultItem.ResultId = request.ResultId; switch (request.Type) { case RequestType.Receive: receiveRequestResult.Enqueue(requestResultItem); ReceivePostedCount--; break; case RequestType.Invalid: for (int i = 0; i < memoryWindowList.Count; ++i) { if (memoryWindowList[i].InvalidResultId == request.ResultId) { memoryWindowList[i].IsValid = false; } } break; } receiveRequestList.Remove(request); break; } } } #endregion if (type == RequestType.None) { otherRequestResult.Enqueue( new SmbdRequestResult() { ResultId = resultId, ResultInfo = ndResult }); } // log this.LogEvent( string.Format( "1 operation {0} has been finished with result {1} and result Id: {2:X};" + " Bytes of data transferred is {3}; Segment Index is {4}; Count of work items is {5}", type, (NtStatus)ndResult.Status, resultId, ndResult.BytesTransferred, segmentIndex, this.receiveRequestList.Count)); } } }
/// <summary> /// the method to receive message from server. /// </summary> private void StreamReceiveLoopImp() { byte[] data = new byte[this.streamConfig.BufferSize]; NetworkStream networkStream = this.stream as NetworkStream; while (!this.stopThread) { // if the underlayer stream is network stream, using the unblock mode. if (networkStream != null) { // wait for the exit event or stream data is available. while (!this.stopThread && !networkStream.DataAvailable) { Thread.Sleep(MilliSecondsToWaitStreamDataAvailable); } // if is exit event, do not read and exit. if (this.stopThread) { break; } } int receivedLength = 0; // read event try { // received data from server. receivedLength = this.stream.Read(data, 0, data.Length); // if the server close the stream, return. if (receivedLength == 0) { this.AddEvent(new TransportEvent( EventType.Disconnected, null, this.localEndPoint, null)); break; } this.buffer.AddRange(ArrayUtility.SubArray <byte>(data, 0, receivedLength)); int expectedLength = 0; int consumedLength = 0; StackPacket[] packets = decoder(localEndPoint, buffer.ToArray(), out consumedLength, out expectedLength); while (packets != null) { foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } if (consumedLength > 0) { buffer.RemoveRange(0, consumedLength); } packets = decoder(localEndPoint, buffer.ToArray(), out consumedLength, out expectedLength); } } catch (Exception ex) { // handle exception event, return. this.AddEvent(new TransportEvent( EventType.Exception, null, this.localEndPoint, ex)); throw; } } }
/// <summary> /// expect packet from transport. /// </summary> /// <param name="buffer"> /// a BytesBuffer object that contains the received data from endpoint. /// </param> /// <param name="decoder"> /// a DecodePacketCallback delegate that is used to decode packet from buffer. /// </param> /// <param name="endpoint"> /// an object that specifies the endpoint for decoder.<para/> /// remember: this endpoint must be the endpoint that is returned to the user, /// that is the endpoint return by Connect(). /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="packetCache"> /// a list that contains the stackpackets. /// </param> /// <returns> /// a StackPacket object that specifies the received packet. /// </returns> public static StackPacket Visit( BytesBuffer buffer, DecodePacketCallback decoder, object endpoint, TimeSpan timeout, SyncFilterQueue<StackPacket> packetCache) { // get the packet in packet list. if (packetCache.Count > 0) { return Utility.GetOne<StackPacket>(packetCache, null); } // the consumed length of decoder. int consumedLength = 0; // decode packet, return null or at least one packet. StackPacket[] packets = ExpectMultiPacketsVisitor.Visit( buffer, decoder, endpoint, timeout, out consumedLength); // packet is null, buffer is closed, no packet will come. if (packets == null) { return null; } // if packet arrived, add to packet list, and return the first. foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } return Utility.GetOne<StackPacket>(packetCache, null); }
/// <summary> /// the method to receive message from server. /// </summary> private void StreamReceiveLoopImp() { byte[] data = new byte[this.streamConfig.BufferSize]; NetworkStream networkStream = this.stream as NetworkStream; while (!this.stopThread) { int receivedLength = 0; // read event try { // received data from server. receivedLength = this.stream.Read(data, 0, data.Length); // if the server close the stream, return. if (receivedLength == 0) { this.AddEvent(new TransportEvent( EventType.Disconnected, null, this.localEndPoint, null)); break; } this.buffer.AddRange(ArrayUtility.SubArray <byte>(data, 0, receivedLength)); int expectedLength = 0; int consumedLength = 0; bool errorPduReceived = false; while (buffer.Count > 0) { StackPacket[] packets = decoder(localEndPoint, buffer.ToArray(), out consumedLength, out expectedLength); if (packets == null) { break; } foreach (StackPacket packet in packets) { packetCache.Enqueue(packet); } if (packets.Any(packet => packet is ErrorPdu)) { errorPduReceived = true; } if (consumedLength > 0) { buffer.RemoveRange(0, consumedLength); } } if (errorPduReceived) { // Exit since ErrorPdu is received from decoder. break; } } catch (Exception ex) { bool handled = false; bool exit = false; if (ex is IOException ioException) { if (ioException.InnerException is SocketException socketException) { if (socketException.SocketErrorCode == SocketError.ConnectionReset) { // Add the disconnected transport event, if connection is reset by SUT. this.AddEvent(new TransportEvent(EventType.Disconnected, null, this.localEndPoint, null)); handled = true; exit = true; } if (socketException.SocketErrorCode == SocketError.WouldBlock) { // No data was received within receive timeout. handled = true; } } } if (!handled) { // Throw to outside handler. throw; } if (exit) { break; } } } }