2 // System.Runtime.Remoting.RemotingServices.cs
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
9 // (C) 2001 Ximian, Inc. http://www.ximian.com
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System
.Diagnostics
;
38 using System
.Reflection
;
39 using System
.Threading
;
40 using System
.Collections
;
41 using System
.Runtime
.Remoting
.Messaging
;
42 using System
.Runtime
.Remoting
.Proxies
;
43 using System
.Runtime
.Remoting
.Channels
;
44 using System
.Runtime
.Remoting
.Contexts
;
45 using System
.Runtime
.Remoting
.Activation
;
46 using System
.Runtime
.Remoting
.Lifetime
;
47 using System
.Runtime
.CompilerServices
;
48 using System
.Runtime
.Serialization
;
51 namespace System
.Runtime
.Remoting
53 public sealed class RemotingServices
55 // Holds the identities of the objects, using uri as index
56 static Hashtable uri_hash
= new Hashtable ();
58 internal static string app_id
;
59 static int next_id
= 1;
60 static readonly BindingFlags methodBindings
= BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
;
62 static RemotingServices ()
64 RegisterInternalChannels ();
65 app_id
= Guid
.NewGuid().ToString().Replace('-', '_') + "/";
66 CreateWellKnownServerIdentity (typeof(RemoteActivator
), "RemoteActivationService.rem", WellKnownObjectMode
.Singleton
);
69 private RemotingServices () {}
71 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
72 internal extern static object InternalExecute (MonoMethod method
, Object obj
,
73 Object
[] parameters
, out object [] out_args
);
75 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
76 public extern static bool IsTransparentProxy (object proxy
);
78 internal static IMethodReturnMessage
InternalExecuteMessage (
79 MarshalByRefObject target
, IMethodCallMessage reqMsg
)
83 MonoMethod method
= (MonoMethod
) target
.GetType().GetMethod(reqMsg
.MethodName
, BindingFlags
.Public
|BindingFlags
.NonPublic
|BindingFlags
.Instance
, null, (Type
[]) reqMsg
.MethodSignature
, null);
84 object oldContext
= CallContext
.SetCurrentCallContext (reqMsg
.LogicalCallContext
);
89 object rval
= InternalExecute (method
, target
, reqMsg
.Args
, out out_args
);
91 // Collect parameters with Out flag from the request message
92 // FIXME: This can be done in the unmanaged side and will be
95 ParameterInfo
[] parameters
= method
.GetParameters();
96 object[] returnArgs
= new object [parameters
.Length
];
100 foreach (ParameterInfo par
in parameters
)
102 if (par
.IsOut
&& !par
.ParameterType
.IsByRef
)
103 returnArgs
[n
++] = reqMsg
.GetArg (par
.Position
);
104 else if (par
.ParameterType
.IsByRef
)
105 returnArgs
[n
++] = out_args
[noa
++];
107 returnArgs
[n
++] = null;
110 result
= new ReturnMessage (rval
, returnArgs
, n
, CallContext
.CreateLogicalCallContext(), reqMsg
);
114 result
= new ReturnMessage (e
, reqMsg
);
117 CallContext
.RestoreCallContext (oldContext
);
121 public static IMethodReturnMessage
ExecuteMessage (
122 MarshalByRefObject target
, IMethodCallMessage reqMsg
)
124 if (IsTransparentProxy(target
))
126 // Message must go through all chain of sinks
127 RealProxy rp
= GetRealProxy (target
);
128 return (IMethodReturnMessage
) rp
.Invoke (reqMsg
);
131 return InternalExecuteMessage (target
, reqMsg
);
134 public static object Connect (Type classToProxy
, string url
)
136 ObjRef objRef
= new ObjRef (classToProxy
, url
, null);
137 return GetRemoteObject (objRef
, classToProxy
);
140 public static object Connect (Type classToProxy
, string url
, object data
)
142 ObjRef objRef
= new ObjRef (classToProxy
, url
, data
);
143 return GetRemoteObject (objRef
, classToProxy
);
146 public static bool Disconnect (MarshalByRefObject obj
)
148 if (obj
== null) throw new ArgumentNullException ("obj");
150 ServerIdentity identity
;
152 if (IsTransparentProxy (obj
))
154 // CBOs are always accessed through a proxy, even in the server, so
155 // for server CBOs it is ok to disconnect a proxy
157 RealProxy proxy
= GetRealProxy(obj
);
158 if (proxy
.GetProxiedType().IsContextful
&& (proxy
.ObjectIdentity
is ServerIdentity
))
159 identity
= proxy
.ObjectIdentity
as ServerIdentity
;
161 throw new ArgumentException ("The obj parameter is a proxy.");
164 identity
= obj
.ObjectIdentity
;
165 obj
.ObjectIdentity
= null;
168 if (identity
== null || !identity
.IsConnected
)
172 LifetimeServices
.StopTrackingLifetime (identity
);
173 DisposeIdentity (identity
);
178 public static Type
GetServerTypeForUri (string uri
)
180 ServerIdentity ident
= GetIdentityForUri (uri
) as ServerIdentity
;
181 if (ident
== null) return null;
182 return ident
.ObjectType
;
185 public static string GetObjectUri (MarshalByRefObject obj
)
187 Identity ident
= GetObjectIdentity(obj
);
188 if (ident
is ClientIdentity
) return ((ClientIdentity
)ident
).TargetUri
;
189 else if (ident
!= null) return ident
.ObjectUri
;
193 public static object Unmarshal (ObjRef objref
)
195 return Unmarshal(objref
, true);
198 public static object Unmarshal (ObjRef objref
, bool fRefine
)
200 Type classToProxy
= fRefine
? objref
.ServerType
: typeof (MarshalByRefObject
);
201 if (classToProxy
== null) classToProxy
= typeof (MarshalByRefObject
);
203 if (objref
.IsReferenceToWellKnow
)
204 return GetRemoteObject(objref
, classToProxy
);
207 if (classToProxy
.IsContextful
)
209 // Look for a ProxyAttribute
210 ProxyAttribute att
= (ProxyAttribute
) Attribute
.GetCustomAttribute (classToProxy
, typeof(ProxyAttribute
),true);
212 return att
.CreateProxy (objref
, classToProxy
, null, null).GetTransparentProxy();
214 return GetProxyForRemoteObject (objref
, classToProxy
);
218 public static ObjRef
Marshal (MarshalByRefObject obj
)
220 return Marshal (obj
, null, null);
223 public static ObjRef
Marshal (MarshalByRefObject obj
, string uri
)
225 return Marshal (obj
, uri
, null);
228 public static ObjRef
Marshal (MarshalByRefObject obj
, string uri
, Type requested_type
)
230 if (IsTransparentProxy (obj
))
232 RealProxy proxy
= RemotingServices
.GetRealProxy(obj
);
233 Identity identity
= proxy
.ObjectIdentity
;
235 if (identity
!= null)
237 if (proxy
.GetProxiedType().IsContextful
&& !identity
.IsConnected
)
239 // Unregistered local contextbound object. Register now.
240 ClientActivatedIdentity cboundIdentity
= (ClientActivatedIdentity
)identity
;
241 if (uri
== null) uri
= NewUri();
242 cboundIdentity
.ObjectUri
= uri
;
243 RegisterServerIdentity (cboundIdentity
);
244 cboundIdentity
.StartTrackingLifetime ((ILease
)obj
.InitializeLifetimeService());
245 return cboundIdentity
.CreateObjRef(requested_type
);
247 else if (uri
!= null)
248 throw new RemotingException ("It is not possible marshal a proxy of a remote object.");
250 return proxy
.ObjectIdentity
.CreateObjRef(requested_type
);
254 if (requested_type
== null) requested_type
= obj
.GetType();
258 if (obj
.ObjectIdentity
== null)
261 CreateClientActivatedServerIdentity (obj
, requested_type
, uri
);
266 ClientActivatedIdentity identity
= GetIdentityForUri ("/" + uri
) as ClientActivatedIdentity
;
267 if (identity
== null || obj
!= identity
.GetServerObject())
268 CreateClientActivatedServerIdentity (obj
, requested_type
, uri
);
271 if (IsTransparentProxy (obj
))
272 return RemotingServices
.GetRealProxy(obj
).ObjectIdentity
.CreateObjRef (requested_type
);
274 return obj
.CreateObjRef(requested_type
);
277 static string NewUri ()
279 int n
= Interlocked
.Increment (ref next_id
);
280 return app_id
+ Environment
.TickCount
+ "_" + n
+ ".rem";
283 public static RealProxy
GetRealProxy (object proxy
)
285 if (!IsTransparentProxy(proxy
)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy.");
286 return (RealProxy
)((TransparentProxy
)proxy
)._rp
;
289 public static MethodBase
GetMethodBaseFromMethodMessage(IMethodMessage msg
)
291 Type type
= Type
.GetType (msg
.TypeName
);
293 throw new RemotingException ("Type '" + msg
.TypeName
+ "' not found.");
295 return GetMethodBaseFromName (type
, msg
.MethodName
, (Type
[]) msg
.MethodSignature
);
298 internal static MethodBase
GetMethodBaseFromName (Type type
, string methodName
, Type
[] signature
)
300 if (type
.IsInterface
) {
301 return FindInterfaceMethod (type
, methodName
, signature
);
304 MethodBase method
= null;
305 if (signature
== null)
306 method
= type
.GetMethod (methodName
, methodBindings
);
308 method
= type
.GetMethod (methodName
, methodBindings
, null, (Type
[]) signature
, null);
313 if (signature
== null)
314 return type
.GetConstructor (methodBindings
, null, Type
.EmptyTypes
, null);
316 return type
.GetConstructor (methodBindings
, null, signature
, null);
320 static MethodBase
FindInterfaceMethod (Type type
, string methodName
, Type
[] signature
)
322 MethodBase method
= null;
324 if (signature
== null)
325 method
= type
.GetMethod (methodName
, methodBindings
);
327 method
= type
.GetMethod (methodName
, methodBindings
, null, signature
, null);
329 if (method
!= null) return method
;
331 foreach (Type t
in type
.GetInterfaces ()) {
332 method
= FindInterfaceMethod (t
, methodName
, signature
);
333 if (method
!= null) return method
;
339 public static void GetObjectData(object obj
, SerializationInfo info
, StreamingContext context
)
341 if (obj
== null) throw new ArgumentNullException ("obj");
343 ObjRef oref
= Marshal ((MarshalByRefObject
)obj
);
344 oref
.GetObjectData (info
, context
);
347 public static ObjRef
GetObjRefForProxy(MarshalByRefObject obj
)
349 Identity ident
= GetObjectIdentity(obj
);
350 if (ident
== null) return null;
351 else return ident
.CreateObjRef(null);
354 public static object GetLifetimeService (MarshalByRefObject obj
)
356 if (obj
== null) return null;
357 return obj
.GetLifetimeService ();
360 public static IMessageSink
GetEnvoyChainForProxy (MarshalByRefObject obj
)
362 if (IsTransparentProxy(obj
))
363 return ((ClientIdentity
)GetRealProxy (obj
).ObjectIdentity
).EnvoySink
;
365 throw new ArgumentException ("obj must be a proxy.","obj");
369 [Conditional ("REMOTING_PERF")]
370 public static void LogRemotingStage (int stage
)
372 throw new NotImplementedException ();
375 public static string GetSessionIdForMethodMessage(IMethodMessage msg
)
377 // It seems that this it what MS returns.
381 public static bool IsMethodOverloaded(IMethodMessage msg
)
383 // TODO: use internal call for better performance
384 Type type
= msg
.MethodBase
.DeclaringType
;
385 MemberInfo
[] members
= type
.GetMember (msg
.MethodName
, MemberTypes
.Method
, BindingFlags
.NonPublic
| BindingFlags
.Public
| BindingFlags
.Instance
);
386 return members
.Length
> 1;
389 public static bool IsObjectOutOfAppDomain(object tp
)
391 // TODO: use internal call for better performance
392 Identity ident
= GetObjectIdentity((MarshalByRefObject
)tp
);
393 return ident
is ClientIdentity
;
396 public static bool IsObjectOutOfContext(object tp
)
398 // TODO: use internal call for better performance
399 Identity ident
= GetObjectIdentity((MarshalByRefObject
)tp
);
400 if (ident
== null) return false;
402 ServerIdentity sident
= ident
as ServerIdentity
;
403 if (sident
!= null) return sident
.Context
!= System
.Threading
.Thread
.CurrentContext
;
407 public static bool IsOneWay(MethodBase method
)
409 return method
.IsDefined (typeof (OneWayAttribute
), false);
412 internal static bool IsAsyncMessage(IMessage msg
)
414 if (! (msg
is MonoMethodMessage
)) return false;
415 else if (((MonoMethodMessage
)msg
).IsAsync
) return true;
416 else if (IsOneWay (((MonoMethodMessage
)msg
).MethodBase
)) return true;
420 public static void SetObjectUriForMarshal(MarshalByRefObject obj
, string uri
)
422 if (IsTransparentProxy (obj
)) {
423 RealProxy proxy
= RemotingServices
.GetRealProxy(obj
);
424 Identity identity
= proxy
.ObjectIdentity
;
426 if (identity
!= null && !(identity
is ServerIdentity
) && !proxy
.GetProxiedType().IsContextful
)
427 throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
433 #region Internal Methods
435 internal static object CreateClientProxy (ActivatedClientTypeEntry entry
, object[] activationAttributes
)
437 if (entry
.ContextAttributes
!= null || activationAttributes
!= null)
439 ArrayList props
= new ArrayList ();
440 if (entry
.ContextAttributes
!= null) props
.AddRange (entry
.ContextAttributes
);
441 if (activationAttributes
!= null) props
.AddRange (activationAttributes
);
442 return CreateClientProxy (entry
.ObjectType
, entry
.ApplicationUrl
, props
.ToArray ());
445 return CreateClientProxy (entry
.ObjectType
, entry
.ApplicationUrl
, null);
448 internal static object CreateClientProxy (Type objectType
, string url
, object[] activationAttributes
)
450 string activationUrl
= url
+ "/RemoteActivationService.rem";
453 IMessageSink sink
= GetClientChannelSinkChain (activationUrl
, null, out objectUri
);
455 RemotingProxy proxy
= new RemotingProxy (objectType
, activationUrl
, activationAttributes
);
456 return proxy
.GetTransparentProxy();
459 internal static object CreateClientProxy (WellKnownClientTypeEntry entry
)
461 return Connect (entry
.ObjectType
, entry
.ObjectUrl
, null);
464 internal static object CreateClientProxyForContextBound (Type type
, object[] activationAttributes
)
466 if (type
.IsContextful
)
468 // Look for a ProxyAttribute
469 ProxyAttribute att
= (ProxyAttribute
) Attribute
.GetCustomAttribute (type
, typeof(ProxyAttribute
), true);
471 return att
.CreateInstance (type
);
473 RemotingProxy proxy
= new RemotingProxy (type
, ChannelServices
.CrossContextUrl
, activationAttributes
);
474 return proxy
.GetTransparentProxy();
477 internal static Identity
GetIdentityForUri (string uri
)
481 return (Identity
)uri_hash
[GetNormalizedUri(uri
)];
485 internal static Identity
GetObjectIdentity (MarshalByRefObject obj
)
487 if (IsTransparentProxy(obj
))
488 return GetRealProxy (obj
).ObjectIdentity
;
490 return obj
.ObjectIdentity
;
493 internal static ClientIdentity
GetOrCreateClientIdentity(ObjRef objRef
, Type proxyType
, out object clientProxy
)
495 // This method looks for an identity for the given url.
496 // If an identity is not found, it creates the identity and
497 // assigns it a proxy to the remote object.
499 // Creates the client sink chain for the given url or channelData.
500 // It will also get the object uri from the url.
502 object channelData
= objRef
.ChannelInfo
!= null ? objRef
.ChannelInfo
.ChannelData
: null;
503 string url
= (channelData
== null) ? objRef
.URI
: null;
506 IMessageSink sink
= GetClientChannelSinkChain (url
, channelData
, out objectUri
);
508 if (objectUri
== null) objectUri
= objRef
.URI
;
513 string uri
= GetNormalizedUri (objRef
.URI
);
515 ClientIdentity identity
= uri_hash
[uri
] as ClientIdentity
;
516 if (identity
!= null)
518 // Object already registered
519 clientProxy
= identity
.ClientProxy
;
520 if (clientProxy
!= null) return identity
;
522 // The proxy has just been GCed, so its identity cannot
523 // be reused. Just dispose it.
524 DisposeIdentity (identity
);
527 // Creates an identity and a proxy for the remote object
529 identity
= new ClientIdentity (objectUri
, objRef
);
530 identity
.ChannelSink
= sink
;
532 // Registers the identity
533 uri_hash
[uri
] = identity
;
535 if (proxyType
!= null)
537 RemotingProxy proxy
= new RemotingProxy (proxyType
, identity
);
538 clientProxy
= proxy
.GetTransparentProxy();
539 identity
.ClientProxy
= (MarshalByRefObject
) clientProxy
;
546 static IMessageSink
GetClientChannelSinkChain(string url
, object channelData
, out string objectUri
)
548 IMessageSink sink
= ChannelServices
.CreateClientChannelSinkChain (url
, channelData
, out objectUri
);
553 string msg
= String
.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url
);
554 throw new RemotingException (msg
);
558 string msg
= String
.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url
);
559 throw new RemotingException (msg
);
565 internal static ClientActivatedIdentity
CreateContextBoundObjectIdentity(Type objectType
)
567 ClientActivatedIdentity identity
= new ClientActivatedIdentity (null, objectType
);
568 identity
.ChannelSink
= ChannelServices
.CrossContextChannel
;
572 internal static ClientActivatedIdentity
CreateClientActivatedServerIdentity(MarshalByRefObject realObject
, Type objectType
, string objectUri
)
574 ClientActivatedIdentity identity
= new ClientActivatedIdentity (objectUri
, objectType
);
575 identity
.AttachServerObject (realObject
, Context
.DefaultContext
);
576 RegisterServerIdentity (identity
);
577 identity
.StartTrackingLifetime ((ILease
)realObject
.InitializeLifetimeService ());
581 internal static ServerIdentity
CreateWellKnownServerIdentity(Type objectType
, string objectUri
, WellKnownObjectMode mode
)
583 ServerIdentity identity
;
585 if (mode
== WellKnownObjectMode
.SingleCall
)
586 identity
= new SingleCallIdentity(objectUri
, Context
.DefaultContext
, objectType
);
588 identity
= new SingletonIdentity(objectUri
, Context
.DefaultContext
, objectType
);
590 RegisterServerIdentity (identity
);
594 private static void RegisterServerIdentity(ServerIdentity identity
)
598 if (uri_hash
.ContainsKey (identity
.ObjectUri
))
599 throw new RemotingException ("Uri already in use: " + identity
.ObjectUri
+ ".");
601 uri_hash
[identity
.ObjectUri
] = identity
;
605 internal static object GetProxyForRemoteObject (ObjRef objref
, Type classToProxy
)
607 ClientActivatedIdentity identity
= GetIdentityForUri (objref
.URI
) as ClientActivatedIdentity
;
608 if (identity
!= null) return identity
.GetServerObject ();
609 else return GetRemoteObject (objref
, classToProxy
);
612 internal static object GetRemoteObject(ObjRef objRef
, Type proxyType
)
615 GetOrCreateClientIdentity (objRef
, proxyType
, out proxy
);
619 internal static object GetDomainProxy(AppDomain domain
)
623 Context currentContext
= Thread
.CurrentContext
;
627 data
= (byte[])AppDomain
.InvokeInDomain (domain
, typeof (AppDomain
).GetMethod ("GetMarshalledDomainObjRef", BindingFlags
.Instance
|BindingFlags
.NonPublic
), domain
, null);
631 AppDomain
.InternalSetContext (currentContext
);
634 MemoryStream stream
= new MemoryStream (data
);
635 ObjRef appref
= (ObjRef
) CADSerializer
.DeserializeObject (stream
);
636 return (AppDomain
) RemotingServices
.Unmarshal(appref
);
639 private static void RegisterInternalChannels()
641 CrossAppDomainChannel
.RegisterCrossAppDomainChannel();
644 internal static void DisposeIdentity (Identity ident
)
648 if (!ident
.Disposed
) {
649 ClientIdentity clientId
= ident
as ClientIdentity
;
650 if (clientId
!= null)
651 uri_hash
.Remove (GetNormalizedUri (clientId
.TargetUri
));
653 uri_hash
.Remove (ident
.ObjectUri
);
655 ident
.Disposed
= true;
660 internal static Identity
GetMessageTargetIdentity (IMessage msg
)
662 // Returns the identity where the message is sent
664 if (msg
is IInternalMessage
)
665 return ((IInternalMessage
)msg
).TargetIdentity
;
669 string uri
= GetNormalizedUri (((IMethodMessage
)msg
).Uri
);
670 return uri_hash
[uri
] as ServerIdentity
;
674 internal static void SetMessageTargetIdentity (IMessage msg
, Identity ident
)
676 if (msg
is IInternalMessage
)
677 ((IInternalMessage
)msg
).TargetIdentity
= ident
;
680 internal static bool UpdateOutArgObject (ParameterInfo pi
, object local
, object remote
)
682 if (local
is StringBuilder
)
684 StringBuilder sb
= local
as StringBuilder
;
685 sb
.Remove (0, sb
.Length
);
686 sb
.Append (remote
.ToString());
689 else if (pi
.ParameterType
.IsArray
&& ((Array
)local
).Rank
== 1)
691 Array alocal
= (Array
) local
;
692 if (alocal
.Rank
== 1)
694 Array
.Copy ((Array
) remote
, alocal
, alocal
.Length
);
705 static string GetNormalizedUri (string uri
)
707 if (uri
.StartsWith ("/")) return uri
.Substring (1);