The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Channels \ IServerChannelSinkStack

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** File:    ChannelSinkStacks.cs
  18. **
  19. ** Purpose: Defines the stack interfaces.
  20. **
  21. **
  22. ===========================================================*/
  23. using System;
  24. using System.Collections;
  25. using System.IO;
  26. using System.Reflection;
  27. using System.Runtime.Remoting;
  28. using System.Runtime.Remoting.Messaging;
  29. using System.Runtime.Remoting.Metadata;
  30. using System.Security.Permissions;
  31. namespace System.Runtime.Remoting.Channels
  32. {
  33.    
  34.    
  35.     // interface for maintaining the sink stack
  36.     // The formatter sink MUST provide this object.
  37.     // No other sinks should have to check to see if this is null.
  38.     [System.Runtime.InteropServices.ComVisible(true)]
  39.     public interface IClientChannelSinkStack : IClientResponseChannelSinkStack
  40.     {
  41.         // Push a sink to the stack (it will be called on the way back to get
  42.         // the response stream).
  43.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  44.         void Push(IClientChannelSink sink, object state);
  45.        
  46.         // Retrieve state previously pushed by sink.
  47.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  48.         object Pop(IClientChannelSink sink);
  49.        
  50.     }
  51.     // IChannelSinkStack
  52.     [System.Runtime.InteropServices.ComVisible(true)]
  53.     public interface IClientResponseChannelSinkStack
  54.     {
  55.         // Call AsyncProcessResponse (on previous channel sink)
  56.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  57.         void AsyncProcessResponse(ITransportHeaders headers, Stream stream);
  58.        
  59.         // Called by client formatter sink in AsyncProcessResponse once it has
  60.         // deserialized the response message.
  61.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  62.         void DispatchReplyMessage(IMessage msg);
  63.        
  64.         // If an exception happens on the async channel sink path, the
  65.         // sink should call this method with the exception.
  66.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  67.         void DispatchException(Exception e);
  68.        
  69.     }
  70.     // interface IClientResponseChannelSinkStack
  71.    
  72.     [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  73.     [System.Runtime.InteropServices.ComVisible(true)]
  74.     public class ClientChannelSinkStack : IClientChannelSinkStack
  75.     {
  76.         private class SinkStack
  77.         {
  78.             public SinkStack PrevStack;
  79.            
  80.             public IClientChannelSink Sink;
  81.             public object State;
  82.         }
  83.        
  84.         private SinkStack _stack = null;
  85.        
  86.         private IMessageSink _replySink = null;
  87.        
  88.        
  89.         public ClientChannelSinkStack()
  90.         {
  91.         }
  92.        
  93.         // use this constructor when initiating an async call
  94.         public ClientChannelSinkStack(IMessageSink replySink)
  95.         {
  96.             _replySink = replySink;
  97.         }
  98.        
  99.        
  100.        
  101.         public void Push(IClientChannelSink sink, object state)
  102.         {
  103.             SinkStack newStack = new SinkStack();
  104.             newStack.PrevStack = _stack;
  105.             newStack.Sink = sink;
  106.             newStack.State = state;
  107.             _stack = newStack;
  108.         }
  109.         // Push
  110.        
  111.         // retrieve state previously pushed by sink
  112.         public object Pop(IClientChannelSink sink)
  113.         {
  114.             if (_stack == null) {
  115.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
  116.             }
  117.            
  118.             // find this sink on the stack
  119.             do {
  120.                 if (_stack.Sink == sink)
  121.                     break;
  122.                
  123.                 _stack = _stack.PrevStack;
  124.             }
  125.             while (_stack != null);
  126.            
  127.             if (_stack.Sink == null) {
  128.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
  129.             }
  130.            
  131.             object state = _stack.State;
  132.             _stack = _stack.PrevStack;
  133.            
  134.             return state;
  135.         }
  136.         // Pop
  137.        
  138.         public void AsyncProcessResponse(ITransportHeaders headers, Stream stream)
  139.         {
  140.             // If the reply sink is null, this is a one way message, so we're not
  141.             // going to process the reply path.
  142.             if (_replySink != null) {
  143.                 if (_stack == null) {
  144.                     throw new RemotingException(Environment.GetResourceString("Remoting_Channel_CantCallAPRWhenStackEmpty"));
  145.                 }
  146.                
  147.                 IClientChannelSink sink = _stack.Sink;
  148.                 object state = _stack.State;
  149.                 _stack = _stack.PrevStack;
  150.                
  151.                 sink.AsyncProcessResponse(this, state, headers, stream);
  152.             }
  153.         }
  154.         // AsyncProcessResponse
  155.        
  156.         // Client formatter sink should call this in AysncProcessResponse once
  157.         // it has deserialized a message.
  158.         public void DispatchReplyMessage(IMessage msg)
  159.         {
  160.             if (_replySink != null)
  161.                 _replySink.SyncProcessMessage(msg);
  162.         }
  163.         // DispatchReplyMessage
  164.        
  165.         public void DispatchException(Exception e)
  166.         {
  167.             DispatchReplyMessage(new ReturnMessage(e, null));
  168.         }
  169.         // DispatchException
  170.     }
  171.     // ClientChannelSinkStack
  172.    
  173.    
  174.    
  175.    
  176.     // interface for maintaining the sink stack
  177.     // The transport sink MUST provide this object.
  178.     // No other sinks should have to check to see if this is null.
  179.     [System.Runtime.InteropServices.ComVisible(true)]
  180.     public interface IServerChannelSinkStack : IServerResponseChannelSinkStack
  181.     {
  182.         // Push a sink to the stack (it will be called on the way back to get
  183.         // the response stream).
  184.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  185.         void Push(IServerChannelSink sink, object state);
  186.        
  187.         // Retrieve state previously pushed by sink.
  188.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  189.         object Pop(IServerChannelSink sink);
  190.        
  191.         /// <internalonly/>
  192.        
  193.         // IMPORTANT: If a sink did a Push(), it must do a Pop()
  194.         // before calling GetResponseStream inside of ProcessMessage.
  195.        
  196.         // On the way back, if it is determined that a asynchronous processing is
  197.         // needed, a sink should call Store() instead of Pop()
  198.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  199.         void Store(IServerChannelSink sink, object state);
  200.        
  201.         /// <internalonly/>
  202.        
  203.         // Called by the server transport sink to complete the dispatch, if async
  204.         // processing is being used.
  205.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  206.         void StoreAndDispatch(IServerChannelSink sink, object state);
  207.        
  208.         /// <internalonly/>
  209.        
  210.         // handles callback after message has been dispatched asynchronously
  211.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  212.         void ServerCallback(IAsyncResult ar);
  213.        
  214.     }
  215.     // IServerChannelSinkStack
  216.     [System.Runtime.InteropServices.ComVisible(true)]
  217.     public interface IServerResponseChannelSinkStack
  218.     {
  219.         /// <internalonly/>
  220.         // Call AsyncProcessResponse (on previous channel sink)
  221.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  222.         void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream);
  223.        
  224.         // Call GetResponseStream (on previous channel sink)
  225.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  226.         Stream GetResponseStream(IMessage msg, ITransportHeaders headers);
  227.     }
  228.     // interface IServerResponseChannelSinkStack
  229.    
  230.     [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  231.     [System.Runtime.InteropServices.ComVisible(true)]
  232.     public class ServerChannelSinkStack : IServerChannelSinkStack
  233.     {
  234.         private class SinkStack
  235.         {
  236.             public SinkStack PrevStack;
  237.            
  238.             public IServerChannelSink Sink;
  239.             public object State;
  240.         }
  241.        
  242.         private SinkStack _stack = null;
  243.         private SinkStack _rememberedStack = null;
  244.        
  245.         // async callback support
  246.         private IMessage _asyncMsg = null;
  247.         private MethodInfo _asyncEnd = null;
  248.         private object _serverObject = null;
  249.         private IMethodCallMessage _msg = null;
  250.        
  251.        
  252.         public void Push(IServerChannelSink sink, object state)
  253.         {
  254.             SinkStack newStack = new SinkStack();
  255.             newStack.PrevStack = _stack;
  256.             newStack.Sink = sink;
  257.             newStack.State = state;
  258.             _stack = newStack;
  259.         }
  260.         // Push
  261.        
  262.         public object Pop(IServerChannelSink sink)
  263.         {
  264.             if (_stack == null) {
  265.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
  266.             }
  267.            
  268.             // find this sink on the stack
  269.             do {
  270.                 if (_stack.Sink == sink)
  271.                     break;
  272.                
  273.                 _stack = _stack.PrevStack;
  274.             }
  275.             while (_stack != null);
  276.            
  277.             if (_stack.Sink == null) {
  278.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
  279.             }
  280.            
  281.             object state = _stack.State;
  282.             _stack = _stack.PrevStack;
  283.            
  284.             return state;
  285.         }
  286.         // Pop
  287.        
  288.         public void Store(IServerChannelSink sink, object state)
  289.         {
  290.             if (_stack == null) {
  291.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_StoreOnEmptySinkStack"));
  292.             }
  293.            
  294.             // find this sink on the stack
  295.             do {
  296.                 if (_stack.Sink == sink)
  297.                     break;
  298.                
  299.                 _stack = _stack.PrevStack;
  300.             }
  301.             while (_stack != null);
  302.            
  303.             if (_stack.Sink == null) {
  304.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_StoreOnSinkStackWithoutPush"));
  305.             }
  306.            
  307.             SinkStack remStack = new SinkStack();
  308.             remStack.PrevStack = _rememberedStack;
  309.             remStack.Sink = sink;
  310.             remStack.State = state;
  311.             _rememberedStack = remStack;
  312.            
  313.             Pop(sink);
  314.         }
  315.         // Store
  316.         public void StoreAndDispatch(IServerChannelSink sink, object state)
  317.         {
  318.             Store(sink, state);
  319.             FlipRememberedStack();
  320.            
  321.             CrossContextChannel.DoAsyncDispatch(_asyncMsg, null);
  322.         }
  323.         // Store
  324.         // Reverses remebered stack so that return message may be dispatched.
  325.         private void FlipRememberedStack()
  326.         {
  327.             if (_stack != null)
  328.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_CantCallFRSWhenStackEmtpy"));
  329.            
  330.             while (_rememberedStack != null) {
  331.                 SinkStack newStack = new SinkStack();
  332.                 newStack.PrevStack = _stack;
  333.                 newStack.Sink = _rememberedStack.Sink;
  334.                 newStack.State = _rememberedStack.State;
  335.                 _stack = newStack;
  336.                 _rememberedStack = _rememberedStack.PrevStack;
  337.             }
  338.         }
  339.         // FlipRememberedStack
  340.        
  341.         public void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream)
  342.         {
  343.             if (_stack == null) {
  344.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_CantCallAPRWhenStackEmpty"));
  345.             }
  346.            
  347.             IServerChannelSink sink = _stack.Sink;
  348.             object state = _stack.State;
  349.             _stack = _stack.PrevStack;
  350.            
  351.             sink.AsyncProcessResponse(this, state, msg, headers, stream);
  352.         }
  353.         // AsyncProcessResponse
  354.        
  355.         public Stream GetResponseStream(IMessage msg, ITransportHeaders headers)
  356.         {
  357.             if (_stack == null) {
  358.                 throw new RemotingException(Environment.GetResourceString("Remoting_Channel_CantCallGetResponseStreamWhenStackEmpty"));
  359.             }
  360.            
  361.             // save state
  362.             IServerChannelSink savedSink = _stack.Sink;
  363.             object savedState = _stack.State;
  364.            
  365.             _stack = _stack.PrevStack;
  366.             Stream stream = savedSink.GetResponseStream(this, savedState, msg, headers);
  367.            
  368.             // restore state
  369.             Push(savedSink, savedState);
  370.            
  371.             return stream;
  372.         }
  373.         // GetResponseStream
  374.         // Store server that is going to be called back
  375.         internal object ServerObject {
  376.             set { _serverObject = value; }
  377.         }
  378.        
  379.         public void ServerCallback(IAsyncResult ar)
  380.         {
  381.             if (_asyncEnd != null) {
  382.                 RemotingMethodCachedData asyncEndCache = (RemotingMethodCachedData)InternalRemotingServices.GetReflectionCachedData(_asyncEnd);
  383.                
  384.                 MethodInfo syncMI = (MethodInfo)_msg.MethodBase;
  385.                 RemotingMethodCachedData syncCache = (RemotingMethodCachedData)InternalRemotingServices.GetReflectionCachedData(syncMI);
  386.                
  387.                 ParameterInfo[] paramList = asyncEndCache.Parameters;
  388.                
  389.                 // construct list to pass into End
  390.                 object[] parameters = new object[paramList.Length];
  391.                 parameters[paramList.Length - 1] = ar;
  392.                 // last parameter is the async result
  393.                 object[] syncMsgArgs = _msg.Args;
  394.                
  395.                 // copy out and ref parameters to the parameters list
  396.                 AsyncMessageHelper.GetOutArgs(syncCache.Parameters, syncMsgArgs, parameters);
  397.                
  398.                 object[] outArgs;
  399.                
  400.                 StackBuilderSink s = new StackBuilderSink(_serverObject);
  401.                 object returnValue = s.PrivateProcessMessage(_asyncEnd.MethodHandle, System.Runtime.Remoting.Messaging.Message.CoerceArgs(_asyncEnd, parameters, paramList), _serverObject, 0, false, out outArgs);
  402.                
  403.                 // The outArgs list is associated with the EndXXX method. We need to make sure
  404.                 // it is sized properly for the out args of the XXX method.
  405.                 if (outArgs != null)
  406.                     outArgs = ArgMapper.ExpandAsyncEndArgsToSyncArgs(syncCache, outArgs);
  407.                
  408.                 s.CopyNonByrefOutArgsFromOriginalArgs(syncCache, syncMsgArgs, ref outArgs);
  409.                
  410.                 IMessage retMessage = new ReturnMessage(returnValue, outArgs, _msg.ArgCount, CallContext.GetLogicalCallContext(), _msg);
  411.                
  412.                 AsyncProcessResponse(retMessage, null, null);
  413.             }
  414.         }
  415.         // ServerCallback
  416.     }
  417.     // ServerChannelSinkStack
  418.     // helper class for transforming sync message parameter lists into its
  419.     // async counterparts
  420.     static internal class AsyncMessageHelper
  421.     {
  422.         static internal void GetOutArgs(ParameterInfo[] syncParams, object[] syncArgs, object[] endArgs)
  423.         {
  424.             int outCount = 0;
  425.            
  426.             for (int co = 0; co < syncParams.Length; co++) {
  427.                 if (syncParams[co].IsOut || syncParams[co].ParameterType.IsByRef) {
  428.                     endArgs[outCount++] = syncArgs[co];
  429.                 }
  430.             }
  431.            
  432.         }
  433.         // GetOutArgs
  434.     }
  435.     // AsyncMessageHelper
  436. }
  437. // namespace System.Runtime.Remoting.Channels

Developer Fusion