示例#1
0
        public ValueTask <Task <IncomingResponseFrame>?> SendRequestAsync(
            OutgoingRequestFrame outgoingRequestFrame,
            bool oneway,
            bool synchronous,
            IInvocationObserver?observer,
            CancellationToken cancel)
        {
            cancel.ThrowIfCancellationRequested();

            //
            // Increase the direct count to prevent the thread pool from being destroyed before
            // invokeAll is called. This will also throw if the object adapter has been deactivated.
            //
            _adapter.IncDirectCount();

            IChildInvocationObserver?childObserver = null;
            int requestId = 0;

            // The CollocatedRequestHandler is an internal object so it's safe to lock (this) as long as our
            // code doesn't use the collocated request handler as a lock. The lock here is useful to ensure
            // the protocol trace and observer call is output or called in the same order as the request ID
            // is allocated.
            lock (_mutex)
            {
                if (!oneway)
                {
                    requestId = ++_requestId;
                }

                if (observer != null)
                {
                    childObserver = observer.GetCollocatedObserver(_adapter, requestId, outgoingRequestFrame.Size);
                    childObserver?.Attach();
                }

                if (_adapter.Communicator.TraceLevels.Protocol >= 1)
                {
                    ProtocolTrace.TraceCollocatedFrame(_adapter.Communicator,
                                                       (byte)Ice1Definitions.FrameType.Request,
                                                       requestId,
                                                       outgoingRequestFrame);
                }
            }

            Task <IncomingResponseFrame?> task;

            if (_adapter.TaskScheduler != null || !synchronous || oneway || _reference.InvocationTimeout > 0)
            {
                // Don't invoke from the user thread if async or invocation timeout is set. We also don't dispatch
                // oneway from the user thread to match the non-collocated behavior where the oneway synchronous
                // request returns as soon as it's sent over the transport.
                task = Task.Factory.StartNew(() => InvokeAllAsync(outgoingRequestFrame, requestId, cancel),
                                             cancel,
                                             TaskCreationOptions.None,
                                             _adapter.TaskScheduler ?? TaskScheduler.Default).Unwrap();

                if (oneway)
                {
                    childObserver?.Detach();
                    return(default);
示例#2
0
        public async Task <IncomingResponseFrame> SendRequestAsync(
            OutgoingRequestFrame outgoingRequest,
            bool oneway,
            bool synchronous,
            IInvocationObserver?observer,
            IProgress <bool> progress,
            CancellationToken cancel)
        {
            cancel.ThrowIfCancellationRequested();

            IChildInvocationObserver?childObserver = null;
            int requestId = 0;

            // The CollocatedRequestHandler is an internal object so it's safe to lock (this) as long as our
            // code doesn't use the collocated request handler as a lock. The lock here is useful to ensure
            // the protocol trace and observer call is output or called in the same order as the request ID
            // is allocated.
            lock (_mutex)
            {
                if (!oneway)
                {
                    requestId = ++_requestId;
                }

                if (observer != null)
                {
                    childObserver = observer.GetCollocatedObserver(_adapter, requestId, outgoingRequest.Size);
                    childObserver?.Attach();
                }

                if (_adapter.Communicator.TraceLevels.Protocol >= 1)
                {
                    ProtocolTrace.TraceFrame(_adapter.Communicator, requestId, outgoingRequest);
                }
            }

            Task <OutgoingResponseFrame> task;

            if (_adapter.TaskScheduler != null ||
                !synchronous ||
                oneway ||
                cancel != CancellationToken.None)
            {
                // Don't invoke from the user thread if async or cancellation token is set. We also don't dispatch
                // oneway from the user thread to match the non-collocated behavior where the oneway synchronous
                // request returns as soon as it's sent over the transport.
                task = Task.Factory.StartNew(() =>
                {
                    progress.Report(false);
                    return(DispatchAsync(outgoingRequest, requestId, cancel));
                },
                                             cancel,
                                             TaskCreationOptions.None,
                                             _adapter.TaskScheduler ?? TaskScheduler.Default).Unwrap();

                if (oneway)
                {
                    childObserver?.Detach();
                    return(IncomingResponseFrame.WithVoidReturnValue(outgoingRequest.Protocol,
                                                                     outgoingRequest.Encoding));
                }
            }
            else // Optimization: directly call DispatchAsync
            {
                progress.Report(false);
                task = DispatchAsync(outgoingRequest, requestId, cancel);
            }

            Debug.Assert(!oneway);
            try
            {
                OutgoingResponseFrame outgoingResponseFrame = await task.WaitAsync(cancel).ConfigureAwait(false);

                var incomingResponse = new IncomingResponseFrame(
                    outgoingRequest.Protocol,
                    outgoingResponseFrame.Data.AsArraySegment(),
                    _adapter.IncomingFrameSizeMax);

                if (_adapter.Communicator.TraceLevels.Protocol >= 1)
                {
                    ProtocolTrace.TraceFrame(_adapter.Communicator, requestId, incomingResponse);
                }

                childObserver?.Reply(incomingResponse.Size);
                return(incomingResponse);
            }
            catch (Exception ex)
            {
                childObserver?.Failed(ex.GetType().FullName ?? "System.Exception");
                throw;
            }
            finally
            {
                childObserver?.Detach();
            }
        }
示例#3
0
        internal override async ValueTask <(long StreamId, IncomingFrame?Frame, bool Fin)> ReceiveAsync(
            CancellationToken cancel)
        {
            FrameType           type;
            ArraySegment <byte> data;

            while (true)
            {
                // Read Slic frame header
                (type, data) = await ReceiveFrameAsync(CancellationToken.None).ConfigureAwait(false);

                switch (type)
                {
                case FrameType.Ping:
                {
                    ValueTask task = PrepareAndSendFrameAsync(FrameType.Pong, null, CancellationToken.None);
                    HeartbeatCallback !();
                    break;
                }

                case FrameType.Pong:
                {
                    // TODO: setup a timer to expect pong frame response?
                    break;
                }

                case FrameType.Stream:
                case FrameType.StreamLast:
                {
                    (long streamId, int streamIdSize) = data.AsReadOnlySpan().ReadVarLong();
                    data = data.Slice(streamIdSize);
                    IncomingFrame frame = ParseIce2Frame(data);
                    if (Endpoint.Communicator.TraceLevels.Protocol >= 1)
                    {
                        ProtocolTrace.TraceFrame(Endpoint.Communicator, streamId, frame);
                    }
                    return(StreamId : streamId, Frame : frame, Fin : type == FrameType.StreamLast);
                }

                case FrameType.ResetStream:
                {
                    var  istr     = new InputStream(data, Encoding);
                    long streamId = istr.ReadVarLong();
                    long reason   = istr.ReadVarLong();
                    return(StreamId : streamId, Frame : null, Fin : true);
                }

                case FrameType.Close:
                {
                    var    istr   = new InputStream(data, Encoding);
                    long   code   = istr.ReadVarLong(); // TODO: is this really useful?
                    string reason = istr.ReadString();
                    throw new ConnectionClosedByPeerException(reason);
                }

                default:
                {
                    throw new InvalidDataException($"unexpected Slic frame with frame type `{type}'");
                }
                }
            }
        }