Example #1
0
        /// <summary>Creates a new <see cref="OutgoingResponseFrame"/> for an operation that returns void.</summary>
        /// <param name="current">The Current object for the corresponding incoming request.</param>
        /// <returns>A new OutgoingResponseFrame.</returns>
        public static OutgoingResponseFrame WithVoidReturnValue(Current current)
        {
            var response = new OutgoingResponseFrame(current.Protocol, current.Encoding);

            response.Payload.Add(current.Protocol.GetVoidReturnPayload(current.Encoding));
            return(response);
        }
Example #2
0
 internal static void TraceFrame(Communicator communicator, ReadOnlySpan <byte> header,
                                 OutgoingResponseFrame frame) =>
 TraceResponse(
     "sending response",
     communicator,
     header[8],                                // Message Type
     header[9],                                // Compression Status
     InputStream.ReadInt(header.Slice(10, 4)), // Request size
     InputStream.ReadInt(header.Slice(14, 4)), // Request-Id,
     frame.ReplyStatus,
     frame.Encoding);
Example #3
0
        public static OutgoingResponseFrame WithReturnValue <T>(
            Current current,
            bool compress,
            FormatType format,
            T returnValue,
            Action <SocketStream, T, System.Threading.CancellationToken> writer)
        {
            OutgoingResponseFrame response = WithVoidReturnValue(current);

            // TODO: deal with compress, format and cancellation token
            response.StreamDataWriter = socketStream => writer(socketStream, returnValue, default);
            return(response);
        }
Example #4
0
 internal static void TraceFrame(
     Communicator communicator,
     ReadOnlySpan <byte> header,
     OutgoingResponseFrame frame) =>
 TraceResponse(
     "sending response",
     communicator,
     frame.Protocol,
     header[8],                                                                          // Frame type
     header[9],                                                                          // Compression Status
     InputStream.ReadFixedLengthSize(frame.Protocol.GetEncoding(), header.Slice(10, 4)), // Request size
     InputStream.ReadInt(header.Slice(14, 4)),                                           // Request-Id,
     frame.ReplyStatus,
     frame.Encoding);
Example #5
0
        internal static List <ArraySegment <byte> > GetResponseData(OutgoingResponseFrame frame, int requestId)
        {
            byte[] headerData = new byte[HeaderSize + 4];
            ReplyHeader.CopyTo(headerData.AsSpan());

            OutputStream.WriteInt(frame.Size + HeaderSize + 4, headerData.AsSpan(10, 4));
            OutputStream.WriteInt(requestId, headerData.AsSpan(HeaderSize, 4));

            var data = new List <ArraySegment <byte> >()
            {
                headerData
            };

            data.AddRange(frame.Data);
            return(data);
        }
Example #6
0
        internal static List <ArraySegment <byte> > GetResponseData(OutgoingResponseFrame frame, long streamId)
        {
            byte[] headerData = new byte[HeaderSize + 4];
            ReplyHeader.CopyTo(headerData.AsSpan());

            OutputStream.WriteSize20(frame.Size + HeaderSize + 4, headerData.AsSpan(10, 4));
            // TODO: Fix to support long streamId
            OutputStream.WriteInt((int)streamId, headerData.AsSpan(HeaderSize, 4));

            var data = new List <ArraySegment <byte> >()
            {
                headerData
            };

            data.AddRange(frame.Data);
            return(data);
        }
Example #7
0
        /// <summary>Creates a new outgoing response frame with an OK reply status and a return value.</summary>
        /// <param name="current">The Current object for the corresponding incoming request.</param>
        /// <param name="format">The format type used to marshal classes and exceptions, when this parameter is null
        /// the communicator's default format is used.</param>
        /// <param name="value">The return value to marshal.</param>
        /// <param name="writer">A delegate that must write the value to the frame.</param>
        /// <returns>A new OutgoingResponseFrame.</returns>
        public static OutgoingResponseFrame WithReturnValue <T>(Current current,
                                                                FormatType?format,
                                                                T value,
                                                                OutputStreamWriter <T> writer)
        {
            var response = new OutgoingResponseFrame(current.Encoding);

            byte[] buffer = new byte[256];
            buffer[0] = (byte)ReplyStatus.OK;
            response.Data.Add(buffer);
            var ostr = new OutputStream(Ice1Definitions.Encoding, response.Data, new OutputStream.Position(0, 1),
                                        response.Encoding, format ?? current.Adapter.Communicator.DefaultFormat);

            writer(ostr, value);
            ostr.Save();
            response.Finish();
            return(response);
        }
Example #8
0
 // TODO avoid copy payload (ToArray) creates a copy, that should be possible when
 // the frame has a single segment.
 public IncomingResponseFrame(Communicator communicator, OutgoingResponseFrame frame)
     : this(communicator, frame.Protocol, frame.Payload.ToArray())
 {
 }
Example #9
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();
            }
        }
Example #10
0
        private async Task <OutgoingResponseFrame> DispatchAsync(
            OutgoingRequestFrame outgoingRequest,
            int requestId,
            CancellationToken cancel)
        {
            // Increase the direct count to prevent the object adapter from being destroyed while the dispatch is in
            // progress. This will also throw if the object adapter has been deactivated.
            _adapter.IncDirectCount();

            IDispatchObserver?dispatchObserver = null;

            try
            {
                var incomingRequest = new IncomingRequestFrame(outgoingRequest, _adapter.IncomingFrameSizeMax);
                var current         = new Current(_adapter, incomingRequest, oneway: requestId == 0, cancel);

                // Then notify and set dispatch observer, if any.
                ICommunicatorObserver?communicatorObserver = _adapter.Communicator.Observer;
                if (communicatorObserver != null)
                {
                    dispatchObserver = communicatorObserver.GetDispatchObserver(current,
                                                                                requestId,
                                                                                incomingRequest.Size);
                    dispatchObserver?.Attach();
                }

                OutgoingResponseFrame?outgoingResponseFrame = null;
                try
                {
                    IObject?servant = current.Adapter.Find(current.Identity, current.Facet);

                    if (servant == null)
                    {
                        throw new ObjectNotExistException(current.Identity, current.Facet, current.Operation);
                    }

                    ValueTask <OutgoingResponseFrame> vt = servant.DispatchAsync(incomingRequest, current);
                    if (requestId != 0)
                    {
                        // We don't use the cancelable WaitAsync for the await here. The asynchronous dispatch is
                        // not completed yet and we want to make sure the observer is detached only when the dispatch
                        // completes, not when the caller cancels the request.
                        outgoingResponseFrame = await vt.ConfigureAwait(false);

                        outgoingResponseFrame.Finish();
                        dispatchObserver?.Reply(outgoingResponseFrame.Size);
                    }
                }
                catch (Exception ex)
                {
                    RemoteException actualEx;
                    if (ex is RemoteException remoteEx && !remoteEx.ConvertToUnhandled)
                    {
                        actualEx = remoteEx;
                    }
                    else
                    {
                        actualEx = new UnhandledException(current.Identity, current.Facet, current.Operation, ex);
                    }

                    Incoming.ReportException(actualEx, dispatchObserver, current);

                    if (requestId != 0)
                    {
                        outgoingResponseFrame = new OutgoingResponseFrame(incomingRequest, actualEx);
                        outgoingResponseFrame.Finish();
                        dispatchObserver?.Reply(outgoingResponseFrame.Size);
                    }
                }