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