/// <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); }
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);
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); }
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);
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); }
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); }
/// <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); }
// 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()) { }
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(); } }
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); } }