3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // Remoting Infrastructure Sink for making calls across context
10 namespace System
.Runtime
.Remoting
.Channels
{
12 using System
.Collections
;
14 using System
.Runtime
.InteropServices
;
15 using System
.Runtime
.Remoting
;
16 using System
.Runtime
.Remoting
.Messaging
;
17 using System
.Runtime
.Remoting
.Contexts
;
18 using System
.Runtime
.Serialization
;
19 using System
.Runtime
.Serialization
.Formatters
.Binary
;
20 using System
.Security
;
21 using System
.Security
.Permissions
;
22 using System
.Security
.Policy
;
23 using System
.Security
.Principal
;
25 using System
.Threading
;
26 using System
.Runtime
.ConstrainedExecution
;
31 internal class CrossAppDomainChannel
: IChannel
, IChannelSender
, IChannelReceiver
33 private const String _channelName
= "XAPPDMN";
34 private const String _channelURI
= "XAPPDMN_URI";
37 private static CrossAppDomainChannel gAppDomainChannel
39 get { return Thread.GetDomain().RemotingData.ChannelServicesData.xadmessageSink; }
40 set { Thread.GetDomain().RemotingData.ChannelServicesData.xadmessageSink = value; }
42 private static Object staticSyncObject
= new Object();
43 private static PermissionSet s_fullTrust
= new PermissionSet(PermissionState
.Unrestricted
);
45 internal static CrossAppDomainChannel AppDomainChannel
49 if (gAppDomainChannel
== null)
51 CrossAppDomainChannel tmpChnl
= new CrossAppDomainChannel();
53 lock (staticSyncObject
)
55 if (gAppDomainChannel
== null)
57 gAppDomainChannel
= tmpChnl
;
61 return gAppDomainChannel
;
66 [System
.Security
.SecurityCritical
] // auto-generated
67 internal static void RegisterChannel()
69 CrossAppDomainChannel adc
= CrossAppDomainChannel
.AppDomainChannel
;
70 ChannelServices
.RegisterChannelInternal((IChannel
)adc
, false /*ensureSecurity*/);
76 public virtual String ChannelName
78 [System
.Security
.SecurityCritical
] // auto-generated
79 get{ return _channelName; }
82 public virtual String ChannelURI
84 get{ return _channelURI; }
87 public virtual int ChannelPriority
89 [System
.Security
.SecurityCritical
] // auto-generated
93 [System
.Security
.SecurityCritical
] // auto-generated
94 public String
Parse(String url
, out String objectURI
)
100 public virtual Object ChannelData
102 [System
.Security
.SecurityCritical
] // auto-generated
105 return new CrossAppDomainData(
106 Context
.DefaultContext
.InternalContextID
,
107 Thread
.GetDomain().GetId(),
108 Identity
.ProcessGuid
);
113 [System
.Security
.SecurityCritical
] // auto-generated
114 public virtual IMessageSink
CreateMessageSink(String url
, Object data
,
115 out String objectURI
)
117 // Set the out parameters
119 IMessageSink sink
= null;
124 if ((null != url
) && (data
== null))
126 if(url
.StartsWith(_channelName
, StringComparison
.Ordinal
))
128 throw new RemotingException(
129 Environment
.GetResourceString(
130 "Remoting_AppDomains_NYI"));
135 Message
.DebugOut("XAPPDOMAIN::Creating sink for data \n");
136 CrossAppDomainData xadData
= data
as CrossAppDomainData
;
139 if (xadData
.ProcessGuid
.Equals(Identity
.ProcessGuid
))
141 sink
= CrossAppDomainSink
.FindOrCreateSink(xadData
);
148 [System
.Security
.SecurityCritical
] // auto-generated
149 public virtual String
[] GetUrlsForUri(String objectURI
)
151 throw new NotSupportedException(
152 Environment
.GetResourceString(
153 "NotSupported_Method"));
159 [System
.Security
.SecurityCritical
] // auto-generated
160 public virtual void StartListening(Object data
)
165 [System
.Security
.SecurityCritical
] // auto-generated
166 public virtual void StopListening(Object data
)
173 internal class CrossAppDomainData
175 Object _ContextID
= 0; // This is for backward compatibility
176 int _DomainID
; // server appDomain ID
177 String _processGuid
; // idGuid for the process (shared static)
179 internal virtual IntPtr ContextID
{
182 return new IntPtr((int)_ContextID
);
184 return new IntPtr((long)_ContextID
);
188 internal virtual int DomainID
{
189 [ReliabilityContract(Consistency
.WillNotCorruptState
, Cer
.Success
)]
190 get {return _DomainID;}
193 internal virtual String ProcessGuid { get {return _processGuid;}}
195 internal CrossAppDomainData(IntPtr ctxId
, int domainID
, String processGuid
)
197 _DomainID
= domainID
;
198 _processGuid
= processGuid
;
200 _ContextID
= ctxId
.ToInt32();
202 _ContextID
= ctxId
.ToInt64(); // This would have never worked anyway
206 internal bool IsFromThisProcess()
208 return Identity
.ProcessGuid
.Equals(_processGuid
);
211 [System
.Security
.SecurityCritical
] // auto-generated
212 internal bool IsFromThisAppDomain()
214 return IsFromThisProcess()
216 (Thread
.GetDomain().GetId() == _DomainID
);
219 // Implements the Message Sink provided by the X-AppDomain channel.
220 // We try to use one instance of the sink to make calls to all remote
221 // objects in another AppDomain from one AppDomain.
223 internal class CrossAppDomainSink
224 : InternalSink
, IMessageSink
226 internal const int GROW_BY
= 0x8;
227 internal static volatile int[] _sinkKeys
;
228 internal static volatile CrossAppDomainSink
[] _sinks
;
230 internal const string LCC_DATA_KEY
= "__xADCall";
232 private static Object staticSyncObject
= new Object();
233 private static InternalCrossContextDelegate s_xctxDel
= new InternalCrossContextDelegate(DoTransitionDispatchCallback
);
235 // each sink stores the default ContextID of the server side domain
236 // and the domain ID for the domain
237 internal CrossAppDomainData _xadData
;
239 [System
.Security
.SecuritySafeCritical
] // auto-generated
240 static CrossAppDomainSink()
244 internal CrossAppDomainSink(CrossAppDomainData xadData
)
247 // WARNING: xadData.ContextID may not be valid at this point. Because
248 // CrossAppDomainData._ContextID is an IntPtr and IntPtrs are
249 // value types, the deserializer has to wait until the very
250 // end of deserialization to fixup value types. However, when
251 // we unmarshal objects, we need to setup the x-AD sink and
252 // initialize it with this data. Fortunately, that data won't
253 // be consumed until deserialization is complete, so we just
254 // need to take care not to read _ContextID in the constructor.
255 // The xadData object ref will be finalized by the time we need
256 // to consume its contents and everything should work properly.
261 // Note: this should be called from within a synch-block
262 internal static void GrowArrays(int oldSize
)
266 _sinks
= new CrossAppDomainSink
[GROW_BY
];
267 _sinkKeys
= new int[GROW_BY
];
271 CrossAppDomainSink
[] tmpSinks
= new CrossAppDomainSink
[_sinks
.Length
+ GROW_BY
];
272 int[] tmpKeys
= new int[_sinkKeys
.Length
+ GROW_BY
];
273 Array
.Copy(_sinks
, tmpSinks
, _sinks
.Length
);
274 Array
.Copy(_sinkKeys
, tmpKeys
, _sinkKeys
.Length
);
279 internal static CrossAppDomainSink
FindOrCreateSink(CrossAppDomainData xadData
)
282 // WARNING: Do not read any value type member of xadData in this method!!
283 // xadData is not completely deserialized at this point. See
284 // warning in CrossAppDomainSink::.ctor above
286 lock(staticSyncObject
) {
287 // Note: keep this in sync with DomainUnloaded below
288 int key
= xadData
.DomainID
;
294 while (_sinks
[i
] != null)
296 if (_sinkKeys
[i
] == key
)
301 if (i
== _sinks
.Length
)
303 // could not find a sink, also need to Grow the array.
308 // At this point we need to create a new sink and cache
309 // it at location "i"
310 _sinks
[i
] = new CrossAppDomainSink(xadData
);
316 internal static void DomainUnloaded(Int32 domainID
)
319 lock(staticSyncObject
) {
324 // Note: keep this in sync with FindOrCreateSink
327 while (_sinks
[i
] != null)
329 if (_sinkKeys
[i
] == key
)
331 BCLDebug
.Assert(remove == -1, "multiple sinks?");
335 if (i
== _sinks
.Length
)
341 if (remove ==-1) //hasn't been initialized yet
344 // The sink to remove is at index 'remove'
345 // We will move the last non-null entry to this location
347 BCLDebug
.Assert(remove != -1, "Bad domainId for unload?");
348 _sinkKeys
[remove] = _sinkKeys
[i
-1];
349 _sinks
[remove] = _sinks
[i
-1];
357 [System
.Security
.SecurityCritical
] // auto-generated
358 internal static byte[] DoDispatch(byte[] reqStmBuff
,
359 SmuggledMethodCallMessage smuggledMcm
,
360 out SmuggledMethodReturnMessage smuggledMrm
)
362 //*********************** DE-SERIALIZE REQ-MSG ********************
364 IMessage desReqMsg
= null;
366 if (smuggledMcm
!= null)
368 ArrayList deserializedArgs
= smuggledMcm
.FixupForNewAppDomain();
369 desReqMsg
= new MethodCall(smuggledMcm
, deserializedArgs
);
373 MemoryStream reqStm
= new MemoryStream(reqStmBuff
);
374 desReqMsg
= CrossAppDomainSerializer
.DeserializeMessage(reqStm
);
377 LogicalCallContext lcc
= Thread
.CurrentThread
.GetMutableExecutionContext().LogicalCallContext
;
378 lcc
.SetData(LCC_DATA_KEY
, true);
379 // now we can delegate to the DispatchMessage to do the rest
381 IMessage retMsg
= ChannelServices
.SyncDispatchMessage(desReqMsg
);
382 lcc
.FreeNamedDataSlot(LCC_DATA_KEY
);
384 smuggledMrm
= SmuggledMethodReturnMessage
.SmuggleIfPossible(retMsg
);
385 if (smuggledMrm
!= null)
393 // Null out the principal since we won't use it on the other side.
394 // This is handled inside of SmuggleIfPossible for method call
396 LogicalCallContext callCtx
= (LogicalCallContext
)
397 retMsg
.Properties
[Message
.CallContextKey
];
400 if (callCtx
.Principal
!= null)
401 callCtx
.Principal
= null;
404 return CrossAppDomainSerializer
.SerializeMessage(retMsg
).GetBuffer();
407 //*********************** SERIALIZE RET-MSG ********************
412 [System
.Security
.SecurityCritical
] // auto-generated
413 internal static Object
DoTransitionDispatchCallback(Object
[] args
)
415 byte[] reqStmBuff
= (byte[])args
[0];
416 SmuggledMethodCallMessage smuggledMcm
= (SmuggledMethodCallMessage
)args
[1];
417 SmuggledMethodReturnMessage smuggledMrm
= null;
418 byte[] retBuff
= null;
423 Message
.DebugOut("#### : changed to Server Domain :: "+ (Thread
.CurrentContext
.InternalContextID
).ToString("X") );
425 retBuff
= DoDispatch(reqStmBuff
, smuggledMcm
, out smuggledMrm
);
429 // This will catch exceptions thrown by the infrastructure,
430 // Serialization/Deserialization etc
431 // Those thrown by the server are already taken care of
432 // and encoded in the retMsg .. so we don't come here for
435 // We are in another appDomain, so we can't simply throw
436 // the exception object across. The following marshals it
437 // into a serialized return message.
439 new ReturnMessage(e
, new ErrorMessage());
440 //*********************** SERIALIZE RET-MSG ******************
441 retBuff
= CrossAppDomainSerializer
.SerializeMessage(retMsg
).GetBuffer();
445 args
[2] = smuggledMrm
;
450 [System
.Security
.SecurityCritical
] // auto-generated
451 internal byte[] DoTransitionDispatch(
453 SmuggledMethodCallMessage smuggledMcm
,
454 out SmuggledMethodReturnMessage smuggledMrm
)
456 byte[] retBuff
= null;
458 Object
[] args
= new Object
[] { reqStmBuff, smuggledMcm, null }
;
460 retBuff
= (byte[]) Thread
.CurrentThread
.InternalCrossContextCallback(null,
467 Message
.DebugOut("#### : changed back to Client Domain " + (Thread
.CurrentContext
.InternalContextID
).ToString("X"));
470 smuggledMrm
= (SmuggledMethodReturnMessage
) args
[2];
472 // System.Diagnostics.Debugger.Break();
474 } // DoTransitionDispatch
476 [System
.Security
.SecurityCritical
] // auto-generated
477 public virtual IMessage
SyncProcessMessage(IMessage reqMsg
)
479 Message
.DebugOut("\n::::::::::::::::::::::::: CrossAppDomain Channel: Sync call starting");
480 IMessage errMsg
= InternalSink
.ValidateMessage(reqMsg
);
487 // currentPrincipal is used to save the current principal. It should be
488 // restored on the reply message.
489 IPrincipal currentPrincipal
= null;
492 IMessage desRetMsg
= null;
496 IMethodCallMessage mcmReqMsg
= reqMsg
as IMethodCallMessage
;
497 if (mcmReqMsg
!= null)
499 LogicalCallContext lcc
= mcmReqMsg
.LogicalCallContext
;
502 // Special case Principal since if might not be serializable
503 currentPrincipal
= lcc
.RemovePrincipalIfNotSerializable();
507 MemoryStream reqStm
= null;
508 SmuggledMethodCallMessage smuggledMcm
= SmuggledMethodCallMessage
.SmuggleIfPossible(reqMsg
);
510 if (smuggledMcm
== null)
513 //*********************** SERIALIZE REQ-MSG ****************
514 // Deserialization of objects requires permissions that users
515 // of remoting are not guaranteed to possess. Since remoting
516 // can guarantee that it's users can't abuse deserialization
517 // (since it won't allow them to pass in raw blobs of
518 // serialized data), it should assert the permissions
519 // necessary before calling the deserialization code. This
520 // will terminate the security stackwalk caused when
521 // serialization checks for the correct permissions at the
522 // remoting stack frame so the check won't continue on to
523 // the user and fail. <EMAIL>[from Microsoft]</EMAIL>
524 // We will hold off from doing this for x-process channels
525 // until the big picture of distributed security is finalized.
527 reqStm
= CrossAppDomainSerializer
.SerializeMessage(reqMsg
);
530 // Retrieve calling caller context here, where it is safe from the view
531 // of app domain checking code
532 LogicalCallContext oldCallCtx
= CallContext
.SetLogicalCallContext(null);
534 // Call helper method here, to avoid confusion with stack frames & app domains
535 MemoryStream retStm
= null;
536 byte[] responseBytes
= null;
537 SmuggledMethodReturnMessage smuggledMrm
;
541 if (smuggledMcm
!= null)
542 responseBytes
= DoTransitionDispatch(null, smuggledMcm
, out smuggledMrm
);
544 responseBytes
= DoTransitionDispatch(reqStm
.GetBuffer(), null, out smuggledMrm
);
548 CallContext
.SetLogicalCallContext(oldCallCtx
);
551 if (smuggledMrm
!= null)
553 ArrayList deserializedArgs
= smuggledMrm
.FixupForNewAppDomain();
554 desRetMsg
= new MethodResponse((IMethodCallMessage
)reqMsg
,
560 if (responseBytes
!= null) {
561 retStm
= new MemoryStream(responseBytes
);
563 Message
.DebugOut("::::::::::::::::::::::::::: CrossAppDomain Channel: Sync call returning!!\n");
564 //*********************** DESERIALIZE RET-MSG **************
565 desRetMsg
= CrossAppDomainSerializer
.DeserializeMessage(retStm
, reqMsg
as IMethodCallMessage
);
571 Message
.DebugOut("Arrgh.. XAppDomainSink::throwing exception " + e
+ "\n");
574 desRetMsg
= new ReturnMessage(e
, (reqMsg
as IMethodCallMessage
));
578 // Fatal Error .. can't do much here
582 // restore the principal if necessary.
583 if (currentPrincipal
!= null)
585 IMethodReturnMessage mrmRetMsg
= desRetMsg
as IMethodReturnMessage
;
586 if (mrmRetMsg
!= null)
588 LogicalCallContext lcc
= mrmRetMsg
.LogicalCallContext
;
589 lcc
.Principal
= currentPrincipal
;
596 [System
.Security
.SecurityCritical
] // auto-generated
597 public virtual IMessageCtrl
AsyncProcessMessage(IMessage reqMsg
, IMessageSink replySink
)
599 // This is the case where we take care of returning the calling
600 // thread asap by using the ThreadPool for completing the call.
602 // we use a more elaborate WorkItem and delegate the work to the thread pool
603 ADAsyncWorkItem workItem
= new ADAsyncWorkItem(reqMsg
,
604 (IMessageSink
)this, /* nextSink */
607 WaitCallback threadFunc
= new WaitCallback(workItem
.FinishAsyncWork
);
608 ThreadPool
.QueueUserWorkItem(threadFunc
);
613 public IMessageSink NextSink
615 [System
.Security
.SecurityCritical
] // auto-generated
618 // We are a terminating sink for this chain
626 internal class ADAsyncWorkItem
628 // the replySink passed in to us in AsyncProcessMsg
629 private IMessageSink _replySink
;
631 // the nextSink we have to call
632 private IMessageSink _nextSink
;
634 [System
.Security
.SecurityCritical
] // auto-generated
635 private LogicalCallContext _callCtx
;
637 // the request msg passed in
638 private IMessage _reqMsg
;
640 [System
.Security
.SecurityCritical
] // auto-generated
641 internal ADAsyncWorkItem(IMessage reqMsg
, IMessageSink nextSink
, IMessageSink replySink
)
644 _nextSink
= nextSink
;
645 _replySink
= replySink
;
646 _callCtx
= Thread
.CurrentThread
.GetMutableExecutionContext().LogicalCallContext
;
650 [System
.Security
.SecurityCritical
] // auto-generated
651 internal virtual void FinishAsyncWork(Object stateIgnored
)
653 // install the call context that the calling thread actually had onto
654 // the threadPool thread.
655 LogicalCallContext threadPoolCallCtx
= CallContext
.SetLogicalCallContext(_callCtx
);
657 IMessage retMsg
= _nextSink
.SyncProcessMessage(_reqMsg
);
659 // send the reply back to the replySink we were provided with
660 // note: replySink may be null for one-way calls.
661 if (_replySink
!= null)
663 _replySink
.SyncProcessMessage(retMsg
);
665 CallContext
.SetLogicalCallContext(threadPoolCallCtx
);
670 internal static class CrossAppDomainSerializer
672 [System
.Security
.SecurityCritical
] // auto-generated
673 internal static MemoryStream
SerializeMessage(IMessage msg
)
675 MemoryStream stm
= new MemoryStream();
676 RemotingSurrogateSelector ss
= new RemotingSurrogateSelector();
677 BinaryFormatter fmt
= new BinaryFormatter();
678 fmt
.SurrogateSelector
= ss
;
679 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
680 fmt
.Serialize(stm
, msg
, null, false /* No Security check */);
682 // Reset the stream so that Deserialize happens correctly
689 // called from MessageSmuggler classes
690 internal static MemoryStream
SerializeMessageParts(ArrayList argsToSerialize
, out Object
[] smuggledArgs
)
692 MemoryStream stm
= new MemoryStream();
694 BinaryFormatter fmt
= new BinaryFormatter();
695 RemotingSurrogateSelector ss
= new RemotingSurrogateSelector();
696 fmt
.SurrogateSelector
= ss
;
697 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
698 fmt
.Serialize(stm
, argsToSerialize
, null, false ); // No Security check
700 smuggledArgs
= fmt
.CrossAppDomainArray
;
703 } // SerializeMessageParts
706 [System
.Security
.SecurityCritical
] // auto-generated
707 internal static MemoryStream
SerializeMessageParts(ArrayList argsToSerialize
)
709 MemoryStream stm
= new MemoryStream();
711 BinaryFormatter fmt
= new BinaryFormatter();
712 RemotingSurrogateSelector ss
= new RemotingSurrogateSelector();
713 fmt
.SurrogateSelector
= ss
;
714 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
715 fmt
.Serialize(stm
, argsToSerialize
, null, false /* No Security check */);
719 } // SerializeMessageParts
721 // called from MessageSmuggler classes
722 [System
.Security
.SecurityCritical
] // auto-generated
723 internal static void SerializeObject(Object obj
, MemoryStream stm
)
725 BinaryFormatter fmt
= new BinaryFormatter();
726 RemotingSurrogateSelector ss
= new RemotingSurrogateSelector();
727 fmt
.SurrogateSelector
= ss
;
728 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
729 fmt
.Serialize(stm
, obj
, null, false /* No Security check */);
730 } // SerializeMessageParts
732 // called from MessageSmuggler classes
733 [System
.Security
.SecurityCritical
] // auto-generated
734 internal static MemoryStream
SerializeObject(Object obj
)
736 MemoryStream stm
= new MemoryStream();
738 SerializeObject( obj
, stm
);
742 } // SerializeMessageParts
745 [System
.Security
.SecurityCritical
] // auto-generated
746 internal static IMessage
DeserializeMessage(MemoryStream stm
)
748 return DeserializeMessage(stm
, null);
751 [System
.Security
.SecurityCritical
] // auto-generated
752 internal static IMessage
DeserializeMessage(
753 MemoryStream stm
, IMethodCallMessage reqMsg
)
756 throw new ArgumentNullException("stm");
759 BinaryFormatter fmt
= new BinaryFormatter();
760 fmt
.SurrogateSelector
= null;
761 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
763 return (IMessage
) fmt
.Deserialize(stm
, null, false /* No Security check */, true/*isCrossAppDomain*/, reqMsg
);
767 // called from MessageSmuggler classes
768 internal static ArrayList
DeserializeMessageParts(MemoryStream stm
, Object
[] args
)
772 BinaryFormatter fmt
= new BinaryFormatter();
773 fmt
.CrossAppDomainArray
= args
;
774 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
775 return (ArrayList
) fmt
.Deserialize(stm
, null, false/*checkSEcurity*/, true/*isCrossAppDomain*/, null);
776 } // DeserializeMessageParts
779 [System
.Security
.SecurityCritical
] // auto-generated
780 internal static ArrayList
DeserializeMessageParts(MemoryStream stm
)
782 return (ArrayList
) DeserializeObject(stm
);
784 } // DeserializeMessageParts
787 [System
.Security
.SecurityCritical
] // auto-generated
788 internal static Object
DeserializeObject(MemoryStream stm
)
792 BinaryFormatter fmt
= new BinaryFormatter();
793 fmt
.Context
= new StreamingContext(StreamingContextStates
.CrossAppDomain
);
794 return fmt
.Deserialize(stm
, null, false /* No Security check */, true/*isCrossAppDomain*/, null);
795 } // DeserializeMessageParts