* Identity.cs: Added ObjRef attribute, that holds the objref of the object.
[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                                 if (proxy != null && proxy.ObjectIdentity != null)
145                                 {
146                                         if (uri != null)
147                                                 throw new RemotingException ("It is not possible marshal a proxy of a remote object");
148
149                                         return proxy.ObjectIdentity.CreateObjRef(requested_type);
150                                 }
151                         }
152
153                         if (requested_type == null) requested_type = obj.GetType();
154
155                         if (uri == null) 
156                         {
157                                 uri = app_id + Environment.TickCount + "_" + next_id++;
158                                 CreateClientActivatedServerIdentity (obj, requested_type, uri);
159                         }
160                         else
161                         {
162                                 ClientActivatedIdentity identity = uri_hash [uri] as ClientActivatedIdentity;
163                                 if (identity == null || obj != identity.GetServerObject()) 
164                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
165                         }
166
167                         return obj.CreateObjRef(requested_type);
168                 }
169
170                 public static RealProxy GetRealProxy (object proxy)
171                 {
172                         if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy");
173                         return (RealProxy)((TransparentProxy)proxy)._rp;
174                 }
175
176                 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
177                 {
178                         Type type = Type.GetType (msg.TypeName);
179                         if (type == null)
180                                 throw new RemotingException ("Type '" + msg.TypeName + "' not found!");
181
182                         BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
183                         if (msg.MethodSignature == null)
184                                 return type.GetMethod (msg.MethodName, bflags);
185                         else
186                                 return type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
187                 }
188
189                 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
190                 {
191                         if (obj == null) throw new ArgumentNullException ("obj");
192
193                         MarshalByRefObject mbr = (MarshalByRefObject)obj;
194
195                         ObjRef oref;
196                         Identity ident = GetObjectIdentity(mbr);
197
198                         if (ident != null)
199                                 oref = ident.CreateObjRef(null);
200                         else
201                                 oref = Marshal (mbr);
202
203                         oref.GetObjectData (info, context);
204                 }
205
206                 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
207                 {
208                         Identity ident = GetObjectIdentity(obj);
209                         if (ident == null) return null;
210                         else return ident.CreateObjRef(null);
211                 }
212
213                 [MonoTODO]
214                 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
215                 {
216                         throw new NotImplementedException (); 
217                 }
218
219                 public static bool IsMethodOverloaded(IMethodMessage msg)
220                 {
221                         Type type = msg.MethodBase.DeclaringType;
222                         MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
223                         return members.Length > 1;
224                 }
225
226                 public static bool IsObjectOutOfAppDomain(object tp)
227                 {
228                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
229                         if (ident != null) return !ident.IsFromThisAppDomain;
230                         else return false;
231                 }
232
233                 public static bool IsObjectOutOfContext(object tp)
234                 {
235                         ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
236                         if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
237                         else return false;
238                 }
239
240                 public static bool IsOneWay(MethodBase method)
241                 {
242                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
243                         return atts.Length > 0;
244                 }
245
246                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
247                 {
248                         if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
249                         Marshal (obj, uri);
250                 }
251
252                 #region Internal Methods
253                 
254                 internal static Identity GetIdentityForUri (string uri)
255                 {
256                         lock (uri_hash)
257                         {
258                                 return (Identity)uri_hash [uri];
259                         }
260                 }
261
262                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
263                 {
264                         if (IsTransparentProxy(obj))
265                                 return GetRealProxy (obj).ObjectIdentity;
266                         else
267                                 return obj.ObjectIdentity;
268                 }
269
270                 private static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef)
271                 {
272                         // This method looks for an identity for the given url. 
273                         // If an identity is not found, it creates the identity and 
274                         // assigns it a proxy to the remote object.
275
276                         // Creates the client sink chain for the given url or channelData.
277                         // It will also get the object uri from the url.
278
279                         object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
280                         string url = (channelData == null) ? objRef.URI : null;
281
282                         string objectUri;
283                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
284                         if (sink == null) 
285                         {
286                                 if (url != null) {
287                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
288                                         throw new RemotingException (msg);
289                                 }
290                                 else {
291                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
292                                         throw new RemotingException (msg);
293                                 }
294                         }
295
296                         if (objectUri == null) objectUri = objRef.URI;
297
298                         lock (uri_hash)
299                         {
300                                 ClientIdentity identity = uri_hash [objRef.URI] as ClientIdentity;
301                                 if (identity != null) 
302                                         return identity;        // Object already registered
303
304                                 // Creates an identity and a proxy for the remote object
305
306                                 identity = new ClientIdentity (objectUri, objRef);
307                                 identity.ClientSink = sink;
308
309                                 RemotingProxy proxy = new RemotingProxy (Type.GetType (objRef.TypeInfo.TypeName), identity);
310                                 identity.ClientProxy = (MarshalByRefObject) proxy.GetTransparentProxy();
311
312                                 // Registers the identity
313                                 uri_hash [objRef.URI] = identity;
314                                 return identity;
315                         }
316                 }
317
318                 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
319                 {
320                         ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, Context.DefaultContext, objectType);
321                         identity.AttachServerObject (realObject);
322                         RegisterServerIdentity (identity);
323                         return identity;
324                 }
325
326                 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
327                 {
328                         ServerIdentity identity;
329
330                         if (mode == WellKnownObjectMode.SingleCall)
331                                 identity = new  SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
332                         else
333                                 identity = new  SingletonIdentity(objectUri, Context.DefaultContext, objectType);
334
335                         RegisterServerIdentity (identity);
336                         return identity;
337                 }
338
339                 private static void RegisterServerIdentity(Identity identity)
340                 {
341                         lock (uri_hash)
342                         {
343                                 if (uri_hash.ContainsKey (identity.ObjectUri)) 
344                                         throw new RemotingException ("Uri already in use: " + identity.ObjectUri);
345
346                                 uri_hash[identity.ObjectUri] = identity;
347                         }
348                 }
349
350                 internal static object GetRemoteObject(ObjRef objRef)
351                 {
352                         ClientIdentity id = GetOrCreateClientIdentity (objRef);
353                         return id.ClientProxy;
354                 }
355
356                 internal static object GetDomainProxy(AppDomain domain) 
357                 {
358                         ObjRef appRef = null;
359
360                         // Make sure that the channels is active in this domain
361                         RegisterInternalChannels();
362
363                         // this should use contexts in the future
364                         AppDomain currentDomain = AppDomain.InternalSetDomain (domain);
365                         try 
366                         {
367                                 // Make sure that our new domain also has the internal channels
368                                 RegisterInternalChannels();
369
370                                 appRef = RemotingServices.Marshal(domain, null, null);
371                         }
372                         finally 
373                         {
374                                 AppDomain.InternalSetDomain (currentDomain);
375                         }
376
377                         return (AppDomain) RemotingServices.Unmarshal(appRef);
378                 }
379
380                 private static void RegisterInternalChannels() 
381                 {
382                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();
383                 }
384                 
385                 internal static void DisposeIdentity (Identity ident)
386                 {
387                         uri_hash.Remove (ident.ObjectUri);
388                 }
389
390                 internal static ServerIdentity GetMessageTargetIdentity (IMessage msg)
391                 {
392                         // Returns the identity where the message is sent
393                         // TODO: check for identity embedded in MethodCall
394
395                         lock (uri_hash)
396                         {
397                                 return uri_hash [((IMethodMessage)msg).Uri] as ServerIdentity;
398                         }
399                 }
400
401                 #endregion
402         }
403 }