/// <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));
        }
Пример #2
0
 /// <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&lt;TransportEvent&gt; 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));
                }
            }
        }
Пример #4
0
        /// <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);
        }
Пример #6
0
        /// <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;
                    }
                }
            }
        }