Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / runtime / remoting / crossappdomainchannel.cs
bloba6c628de3ddc34071354416f75894f3af3e02f85
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 //
7 // Remoting Infrastructure Sink for making calls across context
8 // boundaries.
9 //
10 namespace System.Runtime.Remoting.Channels {
11 using System;
12 using System.Collections;
13 using System.IO;
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;
24 using System.Text;
25 using System.Threading;
26 using System.Runtime.ConstrainedExecution;
30 [Serializable]
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
47 get
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*/);
74 // IChannel Methods
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
90 get{ return 100;}
93 [System.Security.SecurityCritical] // auto-generated
94 public String Parse(String url, out String objectURI)
96 objectURI = url;
97 return null;
100 public virtual Object ChannelData
102 [System.Security.SecurityCritical] // auto-generated
103 get
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
118 objectURI = null;
119 IMessageSink sink = null;
121 // <
124 if ((null != url) && (data == null))
126 if(url.StartsWith(_channelName, StringComparison.Ordinal))
128 throw new RemotingException(
129 Environment.GetResourceString(
130 "Remoting_AppDomains_NYI"));
133 else
135 Message.DebugOut("XAPPDOMAIN::Creating sink for data \n");
136 CrossAppDomainData xadData = data as CrossAppDomainData;
137 if (null != xadData)
139 if (xadData.ProcessGuid.Equals(Identity.ProcessGuid))
141 sink = CrossAppDomainSink.FindOrCreateSink(xadData);
145 return sink;
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)
172 [Serializable]
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 {
180 get {
181 #if WIN32
182 return new IntPtr((int)_ContextID);
183 #else
184 return new IntPtr((long)_ContextID);
185 #endif
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;
199 #if WIN32
200 _ContextID = ctxId.ToInt32();
201 #else
202 _ContextID = ctxId.ToInt64(); // This would have never worked anyway
203 #endif
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.
258 _xadData = xadData;
261 // Note: this should be called from within a synch-block
262 internal static void GrowArrays(int oldSize)
264 if (_sinks == null)
266 _sinks = new CrossAppDomainSink[GROW_BY];
267 _sinkKeys = new int[GROW_BY];
269 else
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);
275 _sinks = tmpSinks;
276 _sinkKeys = tmpKeys;
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;
289 if (_sinks == null)
291 GrowArrays(0);
293 int i=0;
294 while (_sinks[i] != null)
296 if (_sinkKeys[i] == key)
298 return _sinks[i];
300 i++;
301 if (i == _sinks.Length)
303 // could not find a sink, also need to Grow the array.
304 GrowArrays(i);
305 break;
308 // At this point we need to create a new sink and cache
309 // it at location "i"
310 _sinks[i] = new CrossAppDomainSink(xadData);
311 _sinkKeys[i] = key;
312 return _sinks[i];
316 internal static void DomainUnloaded(Int32 domainID)
318 int key = domainID;
319 lock(staticSyncObject) {
320 if (_sinks == null)
322 return;
324 // Note: keep this in sync with FindOrCreateSink
325 int i = 0;
326 int remove = -1;
327 while (_sinks[i] != null)
329 if (_sinkKeys[i] == key)
331 BCLDebug.Assert(remove == -1, "multiple sinks?");
332 remove = i;
334 i++;
335 if (i == _sinks.Length)
337 break;
341 if (remove ==-1) //hasn't been initialized yet
342 return;
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];
350 _sinkKeys[i-1] = 0;
351 _sinks[i-1] = null;
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);
371 else
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)
387 return null;
389 else
391 if (retMsg != 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
395 // messages.
396 LogicalCallContext callCtx = (LogicalCallContext)
397 retMsg.Properties[Message.CallContextKey];
398 if (callCtx != null)
400 if (callCtx.Principal != null)
401 callCtx.Principal = null;
404 return CrossAppDomainSerializer.SerializeMessage(retMsg).GetBuffer();
407 //*********************** SERIALIZE RET-MSG ********************
408 return null;
410 } // DoDispatch
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;
422 #if !FEATURE_CORECLR
423 Message.DebugOut("#### : changed to Server Domain :: "+ (Thread.CurrentContext.InternalContextID).ToString("X") );
424 #endif
425 retBuff = DoDispatch(reqStmBuff, smuggledMcm, out smuggledMrm);
427 catch (Exception e)
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
433 // that case.
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.
438 IMessage retMsg =
439 new ReturnMessage(e, new ErrorMessage());
440 //*********************** SERIALIZE RET-MSG ******************
441 retBuff = CrossAppDomainSerializer.SerializeMessage(retMsg).GetBuffer();
442 retMsg = null;
445 args[2] = smuggledMrm;
447 return retBuff;
450 [System.Security.SecurityCritical] // auto-generated
451 internal byte[] DoTransitionDispatch(
452 byte[] reqStmBuff,
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,
461 _xadData.ContextID,
462 _xadData.DomainID,
463 s_xctxDel,
464 args);
466 #if !FEATURE_CORECLR
467 Message.DebugOut("#### : changed back to Client Domain " + (Thread.CurrentContext.InternalContextID).ToString("X"));
468 #endif
470 smuggledMrm = (SmuggledMethodReturnMessage) args[2];
472 // System.Diagnostics.Debugger.Break();
473 return retBuff;
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);
481 if (errMsg != null)
483 return errMsg;
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;
500 if (lcc != null)
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);
543 else
544 responseBytes = DoTransitionDispatch(reqStm.GetBuffer(), null, out smuggledMrm);
546 finally
548 CallContext.SetLogicalCallContext(oldCallCtx);
551 if (smuggledMrm != null)
553 ArrayList deserializedArgs = smuggledMrm.FixupForNewAppDomain();
554 desRetMsg = new MethodResponse((IMethodCallMessage)reqMsg,
555 smuggledMrm,
556 deserializedArgs);
558 else
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);
569 catch(Exception e)
571 Message.DebugOut("Arrgh.. XAppDomainSink::throwing exception " + e + "\n");
574 desRetMsg = new ReturnMessage(e, (reqMsg as IMethodCallMessage));
576 catch(Exception )
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;
593 return desRetMsg;
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 */
605 replySink);
607 WaitCallback threadFunc = new WaitCallback(workItem.FinishAsyncWork);
608 ThreadPool.QueueUserWorkItem(threadFunc);
610 return null;
613 public IMessageSink NextSink
615 [System.Security.SecurityCritical] // auto-generated
618 // We are a terminating sink for this chain
619 return null;
625 /* package */
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)
643 _reqMsg = reqMsg;
644 _nextSink = nextSink;
645 _replySink = replySink;
646 _callCtx = Thread.CurrentThread.GetMutableExecutionContext().LogicalCallContext;
649 /* package */
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
683 stm.Position = 0;
685 return stm;
688 #if false
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;
701 stm.Position = 0;
702 return stm;
703 } // SerializeMessageParts
704 #endif
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 */);
717 stm.Position = 0;
718 return stm;
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 );
740 stm.Position = 0;
741 return 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)
755 if (stm == null)
756 throw new ArgumentNullException("stm");
758 stm.Position = 0;
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);
766 #if false
767 // called from MessageSmuggler classes
768 internal static ArrayList DeserializeMessageParts(MemoryStream stm, Object[] args)
770 stm.Position = 0;
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
777 #endif
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)
790 stm.Position = 0;
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