3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
8 ** File: ChannelSinkStacks.cs
10 ** Purpose: Defines the stack interfaces.
13 ===========================================================*/
16 using System.Collections;
18 using System.Reflection;
19 using System.Runtime.Remoting;
20 using System.Runtime.Remoting.Messaging;
21 using System.Runtime.Remoting.Metadata;
22 using System.Security.Permissions;
23 using System.Threading;
26 namespace System.Runtime.Remoting.Channels {
29 // interface for maintaining the sink stack
30 // The formatter sink MUST provide this object.
31 // No other sinks should have to check to see if this is null.
32 [System.Runtime.InteropServices.ComVisible(true)]
33 public interface IClientChannelSinkStack : IClientResponseChannelSinkStack
35 // Push a sink to the stack (it will be called on the way back to get
36 // the response stream).
37 [System.Security.SecurityCritical] // auto-generated_required
38 void Push(IClientChannelSink sink, Object state);
40 // Retrieve state previously pushed by sink.
41 [System.Security.SecurityCritical] // auto-generated_required
42 Object Pop(IClientChannelSink sink);
44 } // IChannelSinkStack
46 [System.Runtime.InteropServices.ComVisible(true)]
47 public interface IClientResponseChannelSinkStack
49 // Call AsyncProcessResponse (on previous channel sink)
50 [System.Security.SecurityCritical] // auto-generated_required
51 void AsyncProcessResponse(ITransportHeaders headers, Stream stream);
53 // Called by client formatter sink in AsyncProcessResponse once it has
54 // deserialized the response message.
55 [System.Security.SecurityCritical] // auto-generated_required
56 void DispatchReplyMessage(IMessage msg);
58 // If an exception happens on the async channel sink path, the
59 // sink should call this method with the exception.
60 [System.Security.SecurityCritical] // auto-generated_required
61 void DispatchException(Exception e);
63 } // interface IClientResponseChannelSinkStack
66 [System.Security.SecurityCritical] // auto-generated_required
67 [System.Runtime.InteropServices.ComVisible(true)]
68 public class ClientChannelSinkStack : IClientChannelSinkStack
70 private class SinkStack
72 public SinkStack PrevStack;
74 public IClientChannelSink Sink;
78 private SinkStack _stack = null;
80 private IMessageSink _replySink = null;
83 public ClientChannelSinkStack()
87 // use this constructor when initiating an async call
88 public ClientChannelSinkStack(IMessageSink replySink)
90 _replySink = replySink;
95 [System.Security.SecurityCritical]
96 public void Push(IClientChannelSink sink, Object state)
98 SinkStack newStack = new SinkStack();
99 newStack.PrevStack = _stack;
100 newStack.Sink = sink;
101 newStack.State = state;
106 // retrieve state previously pushed by sink
107 [System.Security.SecurityCritical]
108 public Object Pop(IClientChannelSink sink)
112 throw new RemotingException(
113 Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
116 // find this sink on the stack
119 if (_stack.Sink == sink)
122 _stack = _stack.PrevStack;
123 } while (_stack != null);
125 if (_stack.Sink == null)
127 throw new RemotingException(
128 Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
131 Object state = _stack.State;
132 _stack = _stack.PrevStack;
138 [System.Security.SecurityCritical] // auto-generated
139 public void AsyncProcessResponse(ITransportHeaders headers, Stream stream)
141 // If the reply sink is null, this is a one way message, so we're not
142 // going to process the reply path.
143 if (_replySink != null)
147 throw new RemotingException(
148 Environment.GetResourceString(
149 "Remoting_Channel_CantCallAPRWhenStackEmpty"));
152 IClientChannelSink sink = _stack.Sink;
153 Object state = _stack.State;
154 _stack = _stack.PrevStack;
156 sink.AsyncProcessResponse(this, state, headers, stream);
158 } // AsyncProcessResponse
161 // Client formatter sink should call this in AysncProcessResponse once
162 // it has deserialized a message.
163 [System.Security.SecurityCritical] // auto-generated
164 public void DispatchReplyMessage(IMessage msg)
166 if (_replySink != null)
167 _replySink.SyncProcessMessage(msg);
168 } // DispatchReplyMessage
171 [System.Security.SecurityCritical] // auto-generated
172 public void DispatchException(Exception e)
174 DispatchReplyMessage(new ReturnMessage(e, null));
175 } // DispatchException
177 } // ClientChannelSinkStack
183 // interface for maintaining the sink stack
184 // The transport sink MUST provide this object.
185 // No other sinks should have to check to see if this is null.
186 [System.Runtime.InteropServices.ComVisible(true)]
187 public interface IServerChannelSinkStack : IServerResponseChannelSinkStack
189 // Push a sink to the stack (it will be called on the way back to get
190 // the response stream).
191 [System.Security.SecurityCritical] // auto-generated_required
192 void Push(IServerChannelSink sink, Object state);
194 // Retrieve state previously pushed by sink.
195 [System.Security.SecurityCritical] // auto-generated_required
196 Object Pop(IServerChannelSink sink);
200 // IMPORTANT: If a sink did a Push(), it must do a Pop()
201 // before calling GetResponseStream inside of ProcessMessage.
203 // On the way back, if it is determined that a asynchronous processing is
204 // needed, a sink should call Store() instead of Pop()
205 [System.Security.SecurityCritical] // auto-generated_required
206 void Store(IServerChannelSink sink, Object state);
210 // Called by the server transport sink to complete the dispatch, if async
211 // processing is being used.
212 [System.Security.SecurityCritical] // auto-generated_required
213 void StoreAndDispatch(IServerChannelSink sink, Object state);
217 // handles callback after message has been dispatched asynchronously
218 [System.Security.SecurityCritical] // auto-generated_required
219 void ServerCallback(IAsyncResult ar);
221 } // IServerChannelSinkStack
223 [System.Runtime.InteropServices.ComVisible(true)]
224 public interface IServerResponseChannelSinkStack
227 // Call AsyncProcessResponse (on previous channel sink)
228 [System.Security.SecurityCritical] // auto-generated_required
229 void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream);
231 // Call GetResponseStream (on previous channel sink)
232 [System.Security.SecurityCritical] // auto-generated_required
233 Stream GetResponseStream(IMessage msg, ITransportHeaders headers);
234 } // interface IServerResponseChannelSinkStack
237 [System.Security.SecurityCritical] // auto-generated_required
238 [System.Runtime.InteropServices.ComVisible(true)]
239 public class ServerChannelSinkStack : IServerChannelSinkStack
241 private class SinkStack
243 public SinkStack PrevStack;
245 public IServerChannelSink Sink;
249 private SinkStack _stack = null;
250 private SinkStack _rememberedStack = null;
252 // async callback support
253 private IMessage _asyncMsg = null;
254 private MethodInfo _asyncEnd = null;
255 private Object _serverObject = null;
256 private IMethodCallMessage _msg = null;
259 [System.Security.SecurityCritical]
260 public void Push(IServerChannelSink sink, Object state)
262 SinkStack newStack = new SinkStack();
263 newStack.PrevStack = _stack;
264 newStack.Sink = sink;
265 newStack.State = state;
270 [System.Security.SecurityCritical]
271 public Object Pop(IServerChannelSink sink)
275 throw new RemotingException(
276 Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
279 // find this sink on the stack
282 if (_stack.Sink == sink)
285 _stack = _stack.PrevStack;
286 } while (_stack != null);
288 if (_stack.Sink == null)
290 throw new RemotingException(
291 Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
294 Object state = _stack.State;
295 _stack = _stack.PrevStack;
301 [System.Security.SecurityCritical] // auto-generated
302 public void Store(IServerChannelSink sink, Object state)
306 throw new RemotingException(
307 Environment.GetResourceString(
308 "Remoting_Channel_StoreOnEmptySinkStack"));
311 // find this sink on the stack
314 if (_stack.Sink == sink)
317 _stack = _stack.PrevStack;
318 } while (_stack != null);
320 if (_stack.Sink == null)
322 throw new RemotingException(
323 Environment.GetResourceString("Remoting_Channel_StoreOnSinkStackWithoutPush"));
326 SinkStack remStack = new SinkStack();
327 remStack.PrevStack = _rememberedStack;
328 remStack.Sink = sink;
329 remStack.State = state;
330 _rememberedStack = remStack;
335 [System.Security.SecurityCritical] // auto-generated
336 public void StoreAndDispatch(IServerChannelSink sink, Object state)
339 FlipRememberedStack();
341 CrossContextChannel.DoAsyncDispatch(_asyncMsg, null);
344 // Reverses remebered stack so that return message may be dispatched.
345 private void FlipRememberedStack()
348 throw new RemotingException(
349 Environment.GetResourceString(
350 "Remoting_Channel_CantCallFRSWhenStackEmtpy"));
352 while (_rememberedStack != null)
354 SinkStack newStack = new SinkStack();
355 newStack.PrevStack = _stack;
356 newStack.Sink = _rememberedStack.Sink;
357 newStack.State = _rememberedStack.State;
359 _rememberedStack = _rememberedStack.PrevStack;
361 } // FlipRememberedStack
364 [System.Security.SecurityCritical] // auto-generated
365 public void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream)
369 throw new RemotingException(
370 Environment.GetResourceString(
371 "Remoting_Channel_CantCallAPRWhenStackEmpty"));
374 IServerChannelSink sink = _stack.Sink;
375 Object state = _stack.State;
376 _stack = _stack.PrevStack;
378 sink.AsyncProcessResponse(this, state, msg, headers, stream);
379 } // AsyncProcessResponse
382 [System.Security.SecurityCritical] // auto-generated
383 public Stream GetResponseStream(IMessage msg, ITransportHeaders headers)
387 throw new RemotingException(
388 Environment.GetResourceString(
389 "Remoting_Channel_CantCallGetResponseStreamWhenStackEmpty"));
393 IServerChannelSink savedSink = _stack.Sink;
394 Object savedState = _stack.State;
396 _stack = _stack.PrevStack;
397 Stream stream = savedSink.GetResponseStream(this, savedState, msg, headers);
400 Push(savedSink, savedState);
403 } // GetResponseStream
405 // Store server that is going to be called back
406 internal Object ServerObject { set { _serverObject = value; } }
408 [System.Security.SecurityCritical] // auto-generated
409 public void ServerCallback(IAsyncResult ar)
411 if (_asyncEnd != null)
413 RemotingMethodCachedData asyncEndCache = (RemotingMethodCachedData)
414 InternalRemotingServices.GetReflectionCachedData(_asyncEnd);
416 MethodInfo syncMI = (MethodInfo)_msg.MethodBase;
417 RemotingMethodCachedData syncCache = (RemotingMethodCachedData)
418 InternalRemotingServices.GetReflectionCachedData(syncMI);
420 ParameterInfo[] paramList = asyncEndCache.Parameters;
422 // construct list to pass into End
423 Object[] parameters = new Object[paramList.Length];
424 parameters[paramList.Length - 1] = ar; // last parameter is the async result
426 Object[] syncMsgArgs = _msg.Args;
428 // copy out and ref parameters to the parameters list
429 AsyncMessageHelper.GetOutArgs(syncCache.Parameters, syncMsgArgs, parameters);
433 StackBuilderSink s = new StackBuilderSink(_serverObject);
435 s.PrivateProcessMessage(_asyncEnd.MethodHandle,
436 System.Runtime.Remoting.Messaging.Message.CoerceArgs(_asyncEnd, parameters, paramList),
440 // The outArgs list is associated with the EndXXX method. We need to make sure
441 // it is sized properly for the out args of the XXX method.
443 outArgs = ArgMapper.ExpandAsyncEndArgsToSyncArgs(syncCache, outArgs);
445 s.CopyNonByrefOutArgsFromOriginalArgs(syncCache, syncMsgArgs, ref outArgs);
447 IMessage retMessage = new ReturnMessage(
448 returnValue, outArgs, _msg.ArgCount, Thread.CurrentThread.GetMutableExecutionContext().LogicalCallContext, _msg);
450 AsyncProcessResponse(retMessage, null, null);
454 } // ServerChannelSinkStack
456 // helper class for transforming sync message parameter lists into its
457 // async counterparts
458 internal static class AsyncMessageHelper
460 internal static void GetOutArgs(ParameterInfo[] syncParams, Object[] syncArgs,
465 for (int co = 0; co < syncParams.Length; co++)
467 if (syncParams[co].IsOut || syncParams[co].ParameterType.IsByRef)
469 endArgs[outCount++] = syncArgs[co];
474 } // AsyncMessageHelper
476 } // namespace System.Runtime.Remoting.Channels