95d3b542f766583c0fa97912e8e0ed8492627eb6
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / remoting / channelsinkstacks.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** File:    ChannelSinkStacks.cs
9 **
10 ** Purpose: Defines the stack interfaces.
11 **
12 **
13 ===========================================================*/
14
15 using System;
16 using System.Collections;
17 using System.IO;
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;
24
25
26 namespace System.Runtime.Remoting.Channels {
27         
28
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
34     {
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);
39
40         // Retrieve state previously pushed by sink.
41         [System.Security.SecurityCritical]  // auto-generated_required
42         Object Pop(IClientChannelSink sink);
43         
44     } // IChannelSinkStack
45
46 [System.Runtime.InteropServices.ComVisible(true)]
47     public interface IClientResponseChannelSinkStack
48     {
49         // Call AsyncProcessResponse (on previous channel sink)
50         [System.Security.SecurityCritical]  // auto-generated_required
51         void AsyncProcessResponse(ITransportHeaders headers, Stream stream);
52
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);
57
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);
62      
63     } // interface IClientResponseChannelSinkStack
64
65
66     [System.Security.SecurityCritical]  // auto-generated_required
67     [System.Runtime.InteropServices.ComVisible(true)]
68     public class ClientChannelSinkStack : IClientChannelSinkStack
69     {
70         private class SinkStack
71         {
72             public SinkStack PrevStack;
73             
74             public IClientChannelSink Sink;
75             public Object State;
76         }
77
78         private SinkStack _stack = null;
79         
80         private IMessageSink _replySink = null;
81
82
83         public ClientChannelSinkStack()
84         {
85         }
86
87         // use this constructor when initiating an async call
88         public ClientChannelSinkStack(IMessageSink replySink)
89         {
90             _replySink = replySink;
91         }
92
93
94
95         [System.Security.SecurityCritical]
96         public void Push(IClientChannelSink sink, Object state)
97         {
98             SinkStack newStack = new SinkStack();
99             newStack.PrevStack = _stack;
100             newStack.Sink = sink;
101             newStack.State = state;
102             _stack = newStack;
103         } // Push
104
105
106         // retrieve state previously pushed by sink
107         [System.Security.SecurityCritical]
108         public Object Pop(IClientChannelSink sink)
109         {
110             if (_stack == null)
111             {
112                 throw new RemotingException(
113                     Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
114             }
115
116             // find this sink on the stack
117             do 
118             {
119                 if (_stack.Sink == sink)
120                     break;
121
122                 _stack = _stack.PrevStack;
123             } while (_stack != null);
124
125             if (_stack.Sink == null)
126             {
127                 throw new RemotingException(
128                     Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
129             }
130
131             Object state = _stack.State;
132             _stack = _stack.PrevStack;
133
134             return state;
135         } // Pop
136
137
138         [System.Security.SecurityCritical]  // auto-generated
139         public void AsyncProcessResponse(ITransportHeaders headers, Stream stream)
140         {
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)
144             {
145                 if (_stack == null)
146                 {
147                     throw new RemotingException(
148                         Environment.GetResourceString(
149                             "Remoting_Channel_CantCallAPRWhenStackEmpty"));
150                 }
151
152                 IClientChannelSink sink = _stack.Sink;
153                 Object state = _stack.State;
154                 _stack = _stack.PrevStack;
155     
156                 sink.AsyncProcessResponse(this, state, headers, stream);
157             }
158         } // AsyncProcessResponse
159
160
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)
165         {
166             if (_replySink != null)
167                 _replySink.SyncProcessMessage(msg);
168         } // DispatchReplyMessage
169
170
171         [System.Security.SecurityCritical]  // auto-generated
172         public void DispatchException(Exception e)
173         {
174             DispatchReplyMessage(new ReturnMessage(e, null));
175         } // DispatchException
176         
177     } // ClientChannelSinkStack
178
179
180
181
182
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
188     {
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);
193
194         // Retrieve state previously pushed by sink.
195         [System.Security.SecurityCritical]  // auto-generated_required
196         Object Pop(IServerChannelSink sink);
197         
198         /// <internalonly/>
199
200         // IMPORTANT: If a sink did a Push(), it must do a Pop()
201         //   before calling GetResponseStream inside of ProcessMessage.
202     
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);
207         
208         /// <internalonly/>
209         
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);
214         
215         /// <internalonly/>
216         
217         // handles callback after message has been dispatched asynchronously
218         [System.Security.SecurityCritical]  // auto-generated_required
219         void ServerCallback(IAsyncResult ar);
220         
221     } // IServerChannelSinkStack
222
223 [System.Runtime.InteropServices.ComVisible(true)]
224     public interface IServerResponseChannelSinkStack
225     {
226         /// <internalonly/> 
227         // Call AsyncProcessResponse (on previous channel sink)
228         [System.Security.SecurityCritical]  // auto-generated_required
229         void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream);
230
231         // Call GetResponseStream (on previous channel sink)
232         [System.Security.SecurityCritical]  // auto-generated_required
233         Stream GetResponseStream(IMessage msg, ITransportHeaders headers);
234     } // interface IServerResponseChannelSinkStack
235
236
237     [System.Security.SecurityCritical]  // auto-generated_required
238     [System.Runtime.InteropServices.ComVisible(true)]
239     public class ServerChannelSinkStack : IServerChannelSinkStack
240     {
241         private class SinkStack
242         {
243             public SinkStack PrevStack;
244             
245             public IServerChannelSink Sink;
246             public Object State;
247         }
248
249         private SinkStack _stack = null;
250         private SinkStack _rememberedStack = null;
251
252         // async callback support
253         private IMessage   _asyncMsg = null;
254         private MethodInfo _asyncEnd = null;
255         private Object     _serverObject = null;
256         private IMethodCallMessage   _msg = null;
257
258
259         [System.Security.SecurityCritical]
260         public void Push(IServerChannelSink sink, Object state)
261         {
262             SinkStack newStack = new SinkStack();
263             newStack.PrevStack = _stack;
264             newStack.Sink = sink;
265             newStack.State = state;
266             _stack = newStack;
267         } // Push
268
269
270         [System.Security.SecurityCritical]
271         public Object Pop(IServerChannelSink sink)
272         {
273             if (_stack == null)
274             {
275                 throw new RemotingException(
276                     Environment.GetResourceString("Remoting_Channel_PopOnEmptySinkStack"));
277             }
278             
279             // find this sink on the stack
280             do 
281             {
282                 if (_stack.Sink == sink)
283                     break;
284
285                 _stack = _stack.PrevStack;
286             } while (_stack != null);
287
288             if (_stack.Sink == null)
289             {
290                 throw new RemotingException(
291                     Environment.GetResourceString("Remoting_Channel_PopFromSinkStackWithoutPush"));
292             }
293             
294             Object state = _stack.State;
295             _stack = _stack.PrevStack;
296
297             return state;
298         } // Pop
299
300         
301         [System.Security.SecurityCritical]  // auto-generated
302         public void Store(IServerChannelSink sink, Object state)
303         {
304             if (_stack == null)
305             {
306                 throw new RemotingException(
307                     Environment.GetResourceString(
308                         "Remoting_Channel_StoreOnEmptySinkStack"));
309             }
310
311             // find this sink on the stack
312             do 
313             {
314                 if (_stack.Sink == sink)
315                     break;
316
317                 _stack = _stack.PrevStack;
318             } while (_stack != null);
319
320             if (_stack.Sink == null)
321             {
322                 throw new RemotingException(
323                     Environment.GetResourceString("Remoting_Channel_StoreOnSinkStackWithoutPush"));
324             }                            
325
326             SinkStack remStack = new SinkStack();
327             remStack.PrevStack = _rememberedStack;
328             remStack.Sink = sink;
329             remStack.State = state;
330             _rememberedStack = remStack;
331
332             Pop(sink);
333         } // Store
334
335         [System.Security.SecurityCritical]  // auto-generated
336         public void StoreAndDispatch(IServerChannelSink sink, Object state)
337         {
338             Store(sink, state);
339             FlipRememberedStack();
340             
341             CrossContextChannel.DoAsyncDispatch(_asyncMsg, null);
342         } // Store
343
344         // Reverses remebered stack so that return message may be dispatched.
345         private void FlipRememberedStack()
346         { 
347             if (_stack != null)
348                 throw new RemotingException(
349                     Environment.GetResourceString(
350                         "Remoting_Channel_CantCallFRSWhenStackEmtpy"));
351         
352             while (_rememberedStack != null)
353             {
354                 SinkStack newStack = new SinkStack();
355                 newStack.PrevStack = _stack;
356                 newStack.Sink = _rememberedStack.Sink;
357                 newStack.State = _rememberedStack.State;
358                 _stack = newStack;
359                 _rememberedStack = _rememberedStack.PrevStack;
360             }
361         } // FlipRememberedStack
362
363
364         [System.Security.SecurityCritical]  // auto-generated
365         public void AsyncProcessResponse(IMessage msg, ITransportHeaders headers, Stream stream)
366         {
367             if (_stack == null)
368             {
369                 throw new RemotingException(
370                     Environment.GetResourceString(
371                         "Remoting_Channel_CantCallAPRWhenStackEmpty"));
372             }
373                
374             IServerChannelSink sink = _stack.Sink;
375             Object state = _stack.State;
376             _stack = _stack.PrevStack;
377     
378             sink.AsyncProcessResponse(this, state, msg, headers, stream);
379         } // AsyncProcessResponse
380
381
382         [System.Security.SecurityCritical]  // auto-generated
383         public Stream GetResponseStream(IMessage msg, ITransportHeaders headers)
384         {
385             if (_stack == null)
386             {
387                 throw new RemotingException(
388                     Environment.GetResourceString(
389                         "Remoting_Channel_CantCallGetResponseStreamWhenStackEmpty"));
390             }
391         
392             // save state
393             IServerChannelSink savedSink = _stack.Sink;
394             Object savedState = _stack.State;
395             
396             _stack = _stack.PrevStack;
397             Stream stream = savedSink.GetResponseStream(this, savedState, msg, headers);
398
399             // restore state
400             Push(savedSink, savedState);
401
402             return stream;
403         } // GetResponseStream
404
405         // Store server that is going to be called back
406         internal Object ServerObject { set { _serverObject = value; } }
407         
408         [System.Security.SecurityCritical]  // auto-generated
409         public void ServerCallback(IAsyncResult ar)
410         {
411             if (_asyncEnd != null)
412             {
413                 RemotingMethodCachedData asyncEndCache = (RemotingMethodCachedData)
414                     InternalRemotingServices.GetReflectionCachedData(_asyncEnd);
415
416                 MethodInfo syncMI = (MethodInfo)_msg.MethodBase;
417                 RemotingMethodCachedData syncCache = (RemotingMethodCachedData)
418                     InternalRemotingServices.GetReflectionCachedData(syncMI);
419             
420                 ParameterInfo[] paramList = asyncEndCache.Parameters;
421
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
425
426                 Object[] syncMsgArgs = _msg.Args;
427
428                 // copy out and ref parameters to the parameters list
429                 AsyncMessageHelper.GetOutArgs(syncCache.Parameters, syncMsgArgs, parameters);
430
431                 Object[] outArgs;
432                 
433                 StackBuilderSink s = new StackBuilderSink(_serverObject);
434                 Object returnValue =
435                     s.PrivateProcessMessage(_asyncEnd.MethodHandle,
436                         System.Runtime.Remoting.Messaging.Message.CoerceArgs(_asyncEnd, parameters, paramList),
437                         _serverObject,
438                         out outArgs);   
439
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.
442                 if (outArgs != null)                        
443                     outArgs = ArgMapper.ExpandAsyncEndArgsToSyncArgs(syncCache, outArgs);
444                     
445                 s.CopyNonByrefOutArgsFromOriginalArgs(syncCache, syncMsgArgs, ref outArgs);                
446
447                 IMessage retMessage = new ReturnMessage(
448                     returnValue, outArgs, _msg.ArgCount, Thread.CurrentThread.GetMutableExecutionContext().LogicalCallContext, _msg);
449
450                 AsyncProcessResponse(retMessage, null, null);
451             }
452         } // ServerCallback     
453         
454     } // ServerChannelSinkStack    
455
456     // helper class for transforming sync message parameter lists into its
457     //   async counterparts
458     internal static class AsyncMessageHelper
459     {
460         internal static void GetOutArgs(ParameterInfo[] syncParams, Object[] syncArgs, 
461                                         Object[] endArgs)
462         {
463             int outCount = 0;
464
465             for (int co = 0; co < syncParams.Length; co++)
466             {
467                 if (syncParams[co].IsOut || syncParams[co].ParameterType.IsByRef)
468                 {
469                     endArgs[outCount++] = syncArgs[co];
470                 }
471             }
472             
473         } // GetOutArgs
474     } // AsyncMessageHelper
475
476 } // namespace System.Runtime.Remoting.Channels