* Identity.cs: Added envoy message sink.
[mono.git] / mcs / class / corlib / System.Runtime.Remoting / RemotingServices.cs
1 //
2 // System.Runtime.Remoting.RemotingServices.cs
3 //
4 // Authors:
5 //   Dietmar Maurer (dietmar@ximian.com)
6 //   Lluis Sanchez Gual (lluis@ideary.com)
7 //   Patrik Torstensson
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 //
11
12 using System;
13 using System.Reflection;
14 using System.Threading;
15 using System.Collections;
16 using System.Runtime.Remoting.Messaging;
17 using System.Runtime.Remoting.Proxies;
18 using System.Runtime.Remoting.Channels;
19 using System.Runtime.Remoting.Contexts;
20 using System.Runtime.Remoting.Activation;
21 using System.Runtime.Remoting.Lifetime;
22 using System.Runtime.CompilerServices;
23 using System.Runtime.Serialization;
24
25 namespace System.Runtime.Remoting
26 {
27         public sealed class RemotingServices 
28         {
29                 // Holds the identities of the objects, using uri as index
30                 static Hashtable uri_hash = new Hashtable ();           
31
32                 internal static string app_id;
33                 static int next_id = 1;
34                 
35                 static RemotingServices ()
36                 {
37                         app_id = "/" + Guid.NewGuid().ToString().Replace('-', '_') + "/";
38
39                         CreateWellKnownServerIdentity (typeof(RemoteActivator), "RemoteActivationService.rem", WellKnownObjectMode.Singleton);
40                 }
41         
42                 private RemotingServices () {}
43
44                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
45                 internal extern static object InternalExecute (MonoMethod method, Object obj,
46                                                                Object[] parameters, out object [] out_args);
47
48                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
49                 public extern static bool IsTransparentProxy (object proxy);
50                 
51                 internal static IMethodReturnMessage InternalExecuteMessage (
52                         MarshalByRefObject target, IMethodCallMessage reqMsg)
53                 {
54                         ReturnMessage result;
55                         
56                         MonoMethod method = (MonoMethod)reqMsg.MethodBase;
57
58                         try {
59                                 object [] out_args;
60                                 object rval = InternalExecute (method, target, reqMsg.Args, out out_args);
61                                 result = new ReturnMessage (rval, out_args, out_args.Length,
62                                                             reqMsg.LogicalCallContext, reqMsg);
63                         
64                         } catch (Exception e) {
65                                 result = new ReturnMessage (e, reqMsg);
66                         }
67
68                         return result;
69                 }
70
71                 public static IMethodReturnMessage ExecuteMessage (
72                         MarshalByRefObject target, IMethodCallMessage reqMsg)
73                 {
74                         if (IsTransparentProxy(target))
75                         {
76                                 // Message must go through all chain of sinks
77                                 RealProxy rp = GetRealProxy (target);
78                                 return (IMethodReturnMessage) rp.Invoke (reqMsg);
79                         }
80                         else    // Direct call
81                                 return InternalExecuteMessage (target, reqMsg);
82                 }
83
84                 public static object Connect (Type classToProxy, string url)
85                 {
86                         ObjRef objRef = new ObjRef (classToProxy, url, null);
87                         return GetRemoteObject(objRef);
88                 }
89
90                 public static object Connect (Type classToProxy, string url, object data)
91                 {
92                         ObjRef objRef = new ObjRef (classToProxy, url, data);
93                         return GetRemoteObject(objRef);
94                 }
95
96                 public static Type GetServerTypeForUri (string uri)
97                 {
98                         Identity ident = GetIdentityForUri (uri);
99                         if (ident == null) return null;
100                         return ident.ObjectType;
101                 }
102
103                 public static string GetObjectUri (MarshalByRefObject obj)
104                 {
105                         Identity ident = GetObjectIdentity(obj);
106                         if (ident != null) return ident.ObjectUri;
107                         else return null;
108                 }
109
110                 public static object Unmarshal (ObjRef objref)
111                 {
112                         return Unmarshal(objref, false);
113                 }
114
115                 public static object Unmarshal (ObjRef objref, bool fRefine)
116                 {
117                         // FIXME: use type name when fRefine==true
118
119                         if (objref.IsReferenceToWellKnow)
120                                 return GetRemoteObject(objref);
121                         else
122                         {
123                                 ClientActivatedIdentity identity = uri_hash [objref.URI] as ClientActivatedIdentity;
124                                 if (identity != null) return identity.GetServerObject ();
125                                 else return GetRemoteObject (objref);
126                         }
127                 }
128
129                 public static ObjRef Marshal (MarshalByRefObject obj)
130                 {
131                         return Marshal (obj, null, null);
132                 }
133                 
134                 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
135                 {
136                         return Marshal (obj, uri, null);
137                 }
138                 
139                 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
140                 {
141                         if (IsTransparentProxy (obj))
142                         {
143                                 RealProxy proxy = RemotingServices.GetRealProxy(obj);
144                                 Identity identity = proxy.ObjectIdentity;
145
146                                 if (identity != null)
147                                 {
148                                         if (identity.ObjectType.IsContextful && identity.ObjectUri == null)
149                                         {
150                                                 // Unregistered contextbound object. Register now.
151                                                 if (uri == null) uri = NewUri();
152                                                 identity.ObjectUri = uri;
153                                                 RegisterServerIdentity ((ServerIdentity) identity);
154                                                 ((ServerIdentity)identity).StartTrackingLifetime();
155                                         }
156                                         else if (uri != null)
157                                                 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
158
159                                         return proxy.ObjectIdentity.CreateObjRef(requested_type);
160                                 }
161                         }
162
163                         if (requested_type == null) requested_type = obj.GetType();
164
165                         if (uri == null) 
166                         {
167                                 uri = NewUri();
168                                 CreateClientActivatedServerIdentity (obj, requested_type, uri);
169                         }
170                         else
171                         {
172                                 ClientActivatedIdentity identity = uri_hash [uri] as ClientActivatedIdentity;
173                                 if (identity == null || obj != identity.GetServerObject()) 
174                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
175                         }
176
177                         return obj.CreateObjRef(requested_type);
178                 }
179
180                 static string NewUri ()
181                 {
182                         return app_id + Environment.TickCount + "_" + next_id++;
183                 }
184
185                 public static RealProxy GetRealProxy (object proxy)
186                 {
187                         if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
188                         return (RealProxy)((TransparentProxy)proxy)._rp;
189                 }
190
191                 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
192                 {
193                         Type type = Type.GetType (msg.TypeName);
194                         if (type == null)
195                                 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
196
197                         BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
198                         if (msg.MethodSignature == null)
199                                 return type.GetMethod (msg.MethodName, bflags);
200                         else
201                                 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
202                 }
203
204                 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
205                 {
206                         if (obj == null) throw new ArgumentNullException ("obj");
207
208                         ObjRef oref = Marshal ((MarshalByRefObject)obj);
209                         oref.GetObjectData (info, context);
210                 }
211
212                 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
213                 {
214                         Identity ident = GetObjectIdentity(obj);
215                         if (ident == null) return null;
216                         else return ident.CreateObjRef(null);
217                 }
218
219                 [MonoTODO]
220                 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
221                 {
222                         throw new NotImplementedException (); 
223                 }
224
225                 public static bool IsMethodOverloaded(IMethodMessage msg)
226                 {
227                         Type type = msg.MethodBase.DeclaringType;
228                         MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
229                         return members.Length > 1;
230                 }
231
232                 public static bool IsObjectOutOfAppDomain(object tp)
233                 {
234                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
235                         if (ident != null) return !ident.IsFromThisAppDomain;
236                         else return false;
237                 }
238
239                 public static bool IsObjectOutOfContext(object tp)
240                 {
241                         ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
242                         if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
243                         else return false;
244                 }
245
246                 public static bool IsOneWay(MethodBase method)
247                 {
248                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
249                         return atts.Length > 0;
250                 }
251
252                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
253                 {
254                         if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
255                         Marshal (obj, uri);
256                 }
257
258                 #region Internal Methods
259                 
260                 internal static object CreateClientProxy (ActivatedClientTypeEntry entry)
261                 {
262                         string activationUrl = entry.ApplicationUrl + "/RemoteActivationService.rem";
263
264                         string objectUri;
265                         IMessageSink sink = GetClientChannelSinkChain (activationUrl, null, out objectUri);
266
267                         RemotingProxy proxy = new RemotingProxy (entry.ObjectType, activationUrl, sink);
268                         return proxy.GetTransparentProxy();
269                 }
270         
271                 internal static object CreateClientProxy (WellKnownClientTypeEntry entry)
272                 {
273                         return Connect (entry.ObjectType, entry.ObjectUrl);
274                 }
275         
276                 internal static object CreateClientProxyForContextBound (Type type)
277                 {
278                         RemotingProxy proxy = new RemotingProxy (type, ChannelServices.CrossContextUrl, ChannelServices.CrossContextChannel);
279                         return proxy.GetTransparentProxy();
280                 }
281         
282                 internal static Identity GetIdentityForUri (string uri)
283                 {
284                         lock (uri_hash)
285                         {
286                                 return (Identity)uri_hash [uri];
287                         }
288                 }
289
290                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
291                 {
292                         if (IsTransparentProxy(obj))
293                                 return GetRealProxy (obj).ObjectIdentity;
294                         else
295                                 return obj.ObjectIdentity;
296                 }
297
298                 internal static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef, RealProxy proxyToAttach)
299                 {
300                         // This method looks for an identity for the given url. 
301                         // If an identity is not found, it creates the identity and 
302                         // assigns it a proxy to the remote object.
303
304                         // Creates the client sink chain for the given url or channelData.
305                         // It will also get the object uri from the url.
306
307                         object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
308                         string url = (channelData == null) ? objRef.URI : null;
309
310                         string objectUri;
311                         IMessageSink sink = GetClientChannelSinkChain (url, channelData, out objectUri);
312
313                         if (objectUri == null) objectUri = objRef.URI;
314
315                         lock (uri_hash)
316                         {
317                                 ClientIdentity identity = uri_hash [objRef.URI] as ClientIdentity;
318                                 if (identity != null) 
319                                         return identity;        // Object already registered
320
321                                 // Creates an identity and a proxy for the remote object
322
323                                 identity = new ClientIdentity (objectUri, objRef);
324                                 identity.ChannelSink = sink;
325
326                                 if (proxyToAttach == null) proxyToAttach = new RemotingProxy (Type.GetType (objRef.TypeInfo.TypeName), identity);
327                                 identity.ClientProxy = (MarshalByRefObject) proxyToAttach.GetTransparentProxy();
328
329                                 // Registers the identity
330                                 uri_hash [objRef.URI] = identity;
331                                 return identity;
332                         }
333                 }
334
335                 static IMessageSink GetClientChannelSinkChain(string url, object channelData, out string objectUri)
336                 {
337                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
338                         if (sink == null) 
339                         {
340                                 if (url != null) \r
341                                 {
342                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
343                                         throw new RemotingException (msg);
344                                 }
345                                 else \r
346                                 {
347                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
348                                         throw new RemotingException (msg);
349                                 }
350                         }
351                         return sink;
352                 }
353
354                 internal static ClientActivatedIdentity CreateContextBoundObjectIdentity(Type objectType)
355                 {
356                         ClientActivatedIdentity identity = new ClientActivatedIdentity (null, objectType);
357                         identity.ChannelSink = ChannelServices.CrossContextChannel;
358                         return identity;
359                 }
360
361                 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
362                 {
363                         ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, objectType);
364                         identity.AttachServerObject (realObject, Context.DefaultContext);
365                         RegisterServerIdentity (identity);
366                         identity.StartTrackingLifetime();
367                         return identity;
368                 }
369
370                 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
371                 {
372                         ServerIdentity identity;
373
374                         if (mode == WellKnownObjectMode.SingleCall)
375                                 identity = new  SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
376                         else
377                                 identity = new  SingletonIdentity(objectUri, Context.DefaultContext, objectType);
378
379                         RegisterServerIdentity (identity);
380                         return identity;
381                 }
382
383                 private static void RegisterServerIdentity(ServerIdentity identity)
384                 {
385                         lock (uri_hash)
386                         {
387                                 if (uri_hash.ContainsKey (identity.ObjectUri)) 
388                                         throw new RemotingException ("Uri already in use: " + identity.ObjectUri);
389
390                                 uri_hash[identity.ObjectUri] = identity;
391                         }
392                 }
393
394                 internal static object GetRemoteObject(ObjRef objRef)
395                 {
396                         ClientIdentity id = GetOrCreateClientIdentity (objRef, null);
397                         return id.ClientProxy;
398                 }
399
400                 internal static object GetDomainProxy(AppDomain domain) 
401                 {
402                         ObjRef appRef = null;
403
404                         // Make sure that the channels is active in this domain
405                         RegisterInternalChannels();
406
407                         // this should use contexts in the future
408                         AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
409                         try 
410                         {
411                                 // Make sure that our new domain also has the internal channels
412                                 RegisterInternalChannels();
413
414                                 appRef = RemotingServices.Marshal(domain, null, null);
415                         }
416                         finally 
417                         {
418                                 AppDomain.InternalSetDomain (currentDomain);
419                         }
420
421                         return (AppDomain) RemotingServices.Unmarshal(appRef);
422                 }
423
424                 private static void RegisterInternalChannels() 
425                 {
426                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();
427                 }
428                 
429                 internal static void DisposeIdentity (Identity ident)
430                 {
431                         uri_hash.Remove (ident.ObjectUri);
432                 }
433
434                 internal static Identity GetMessageTargetIdentity (IMessage msg)
435                 {
436                         // Returns the identity where the message is sent
437
438                         if (msg is IInternalMessage) 
439                                 return ((IInternalMessage)msg).TargetIdentity;
440
441                         lock (uri_hash)
442                         {
443                                 return uri_hash [((IMethodMessage)msg).Uri] as ServerIdentity;
444                         }
445                 }
446
447                 internal static void SetMessageTargetIdentity (IMessage msg, Identity ident)
448                 {
449                         if (msg is IInternalMessage) 
450                                 ((IInternalMessage)msg).TargetIdentity = ident;
451                 }
452
453                 #endregion
454         }
455 }