This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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 //
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
35 using System;
36 using System.Diagnostics;
37 using System.Text;
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;
49 using System.IO;
50
51 namespace System.Runtime.Remoting
52 {
53         public sealed class RemotingServices 
54         {
55                 // Holds the identities of the objects, using uri as index
56                 static Hashtable uri_hash = new Hashtable ();           
57
58                 internal static string app_id;
59                 static int next_id = 1;
60                 
61                 static RemotingServices ()
62                 {
63                         RegisterInternalChannels ();
64                         app_id = Guid.NewGuid().ToString().Replace('-', '_') + "/";
65                         CreateWellKnownServerIdentity (typeof(RemoteActivator), "RemoteActivationService.rem", WellKnownObjectMode.Singleton);
66                 }
67         
68                 private RemotingServices () {}
69
70                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
71                 internal extern static object InternalExecute (MonoMethod method, Object obj,
72                                                                Object[] parameters, out object [] out_args);
73
74                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
75                 public extern static bool IsTransparentProxy (object proxy);
76                 
77                 internal static IMethodReturnMessage InternalExecuteMessage (
78                         MarshalByRefObject target, IMethodCallMessage reqMsg)
79                 {
80                         ReturnMessage result;
81                         
82                         MonoMethod method = (MonoMethod) target.GetType().GetMethod(reqMsg.MethodName, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, (Type[]) reqMsg.MethodSignature, null);
83                         object oldContext = CallContext.SetCurrentCallContext (reqMsg.LogicalCallContext);
84                         
85                         try 
86                         {
87                                 object [] out_args;
88                                 object rval = InternalExecute (method, target, reqMsg.Args, out out_args);
89                         
90                                 // Collect parameters with Out flag from the request message
91                                 // FIXME: This can be done in the unmanaged side and will be
92                                 // more efficient
93                                 
94                                 ParameterInfo[] parameters = method.GetParameters();
95                                 object[] returnArgs = new object [parameters.Length];
96                                 
97                                 int n = 0;
98                                 int noa = 0;
99                                 foreach (ParameterInfo par in parameters)
100                                 {
101                                         if (par.IsOut && !par.ParameterType.IsByRef) 
102                                                 returnArgs [n++] = reqMsg.GetArg (par.Position);
103                                         else if (par.ParameterType.IsByRef)
104                                                 returnArgs [n++] = out_args [noa++]; 
105                                         else
106                                                 returnArgs [n++] = null; 
107                                 }
108                                 
109                                 result = new ReturnMessage (rval, returnArgs, n, CallContext.CreateLogicalCallContext(), reqMsg);
110                         } 
111                         catch (Exception e) 
112                         {
113                                 result = new ReturnMessage (e, reqMsg);
114                         }
115                         
116                         CallContext.RestoreCallContext (oldContext);
117                         return result;
118                 }
119
120                 public static IMethodReturnMessage ExecuteMessage (
121                         MarshalByRefObject target, IMethodCallMessage reqMsg)
122                 {
123                         if (IsTransparentProxy(target))
124                         {
125                                 // Message must go through all chain of sinks
126                                 RealProxy rp = GetRealProxy (target);
127                                 return (IMethodReturnMessage) rp.Invoke (reqMsg);
128                         }
129                         else    // Direct call
130                                 return InternalExecuteMessage (target, reqMsg);
131                 }
132
133                 public static object Connect (Type classToProxy, string url)
134                 {
135                         ObjRef objRef = new ObjRef (classToProxy, url, null);
136                         return GetRemoteObject (objRef, classToProxy);
137                 }
138
139                 public static object Connect (Type classToProxy, string url, object data)
140                 {
141                         ObjRef objRef = new ObjRef (classToProxy, url, data);
142                         return GetRemoteObject (objRef, classToProxy);
143                 }
144
145                 public static bool Disconnect (MarshalByRefObject obj)
146                 {
147                         if (obj == null) throw new ArgumentNullException ("obj");
148
149                         ServerIdentity identity;
150
151                         if (IsTransparentProxy (obj))
152                         {
153                                 // CBOs are always accessed through a proxy, even in the server, so
154                                 // for server CBOs it is ok to disconnect a proxy
155
156                                 RealProxy proxy = GetRealProxy(obj);
157                                 if (proxy.GetProxiedType().IsContextful && (proxy.ObjectIdentity is ServerIdentity))
158                                         identity = proxy.ObjectIdentity as ServerIdentity;
159                                 else
160                                         throw new ArgumentException ("The obj parameter is a proxy.");
161                         }
162                         else {
163                                 identity = obj.ObjectIdentity;
164                                 obj.ObjectIdentity = null;
165                         }
166
167                         if (identity == null || !identity.IsConnected)
168                                 return false;
169                         else
170                         {
171                                 LifetimeServices.StopTrackingLifetime (identity);
172                                 DisposeIdentity (identity);
173                                 return true;
174                         }
175                 }
176
177                 public static Type GetServerTypeForUri (string uri)
178                 {
179                         ServerIdentity ident = GetIdentityForUri (uri) as ServerIdentity;
180                         if (ident == null) return null;
181                         return ident.ObjectType;
182                 }
183
184                 public static string GetObjectUri (MarshalByRefObject obj)
185                 {
186                         Identity ident = GetObjectIdentity(obj);
187                         if (ident is ClientIdentity) return ((ClientIdentity)ident).TargetUri;
188                         else if (ident != null) return ident.ObjectUri;
189                         else return null;
190                 }
191
192                 public static object Unmarshal (ObjRef objref)
193                 {
194                         return Unmarshal(objref, true);
195                 }
196
197                 public static object Unmarshal (ObjRef objref, bool fRefine)
198                 {
199                         Type classToProxy = fRefine ? objref.ServerType : typeof (MarshalByRefObject);
200                         if (classToProxy == null) classToProxy = typeof (MarshalByRefObject);
201
202                         if (objref.IsReferenceToWellKnow)
203                                 return GetRemoteObject(objref, classToProxy);
204                         else
205                         {
206                                 if (classToProxy.IsContextful)
207                                 {
208                                         // Look for a ProxyAttribute
209                                         ProxyAttribute att = (ProxyAttribute) Attribute.GetCustomAttribute (classToProxy, typeof(ProxyAttribute),true);
210                                         if (att != null)
211                                                 return att.CreateProxy (objref, classToProxy, null, null).GetTransparentProxy();
212                                 }
213                                 return GetProxyForRemoteObject (objref, classToProxy);
214                         }
215                 }
216
217                 public static ObjRef Marshal (MarshalByRefObject obj)
218                 {
219                         return Marshal (obj, null, null);
220                 }
221                 
222                 public static ObjRef Marshal (MarshalByRefObject obj, string uri)
223                 {
224                         return Marshal (obj, uri, null);
225                 }
226                 
227                 public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
228                 {
229                         if (IsTransparentProxy (obj))
230                         {
231                                 RealProxy proxy = RemotingServices.GetRealProxy(obj);
232                                 Identity identity = proxy.ObjectIdentity;
233
234                                 if (identity != null)
235                                 {
236                                         if (proxy.GetProxiedType().IsContextful && !identity.IsConnected)
237                                         {
238                                                 // Unregistered local contextbound object. Register now.
239                                                 ClientActivatedIdentity cboundIdentity = (ClientActivatedIdentity)identity;
240                                                 if (uri == null) uri = NewUri();
241                                                 cboundIdentity.ObjectUri = uri;
242                                                 RegisterServerIdentity (cboundIdentity);
243                                                 cboundIdentity.StartTrackingLifetime ((ILease)obj.InitializeLifetimeService());
244                                                 return cboundIdentity.CreateObjRef(requested_type);
245                                         }
246                                         else if (uri != null)
247                                                 throw new RemotingException ("It is not possible marshal a proxy of a remote object.");
248
249                                         return proxy.ObjectIdentity.CreateObjRef(requested_type);
250                                 }
251                         }
252
253                         if (requested_type == null) requested_type = obj.GetType();
254
255                         if (uri == null) 
256                         {
257                                 if (obj.ObjectIdentity == null)
258                                 {
259                                         uri = NewUri();
260                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
261                                 }
262                         }
263                         else
264                         {
265                                 ClientActivatedIdentity identity = GetIdentityForUri ("/" + uri) as ClientActivatedIdentity;
266                                 if (identity == null || obj != identity.GetServerObject()) 
267                                         CreateClientActivatedServerIdentity (obj, requested_type, uri);
268                         }
269
270                         if (IsTransparentProxy (obj))
271                                 return RemotingServices.GetRealProxy(obj).ObjectIdentity.CreateObjRef (requested_type);
272                         else
273                                 return obj.CreateObjRef(requested_type);
274                 }
275
276                 static string NewUri ()
277                 {
278                         int n = Interlocked.Increment (ref next_id);
279                         return app_id + Environment.TickCount + "_" + n + ".rem";
280                 }
281
282                 public static RealProxy GetRealProxy (object proxy)
283                 {
284                         if (!IsTransparentProxy(proxy)) throw new RemotingException("Cannot get the real proxy from an object that is not a transparent proxy.");
285                         return (RealProxy)((TransparentProxy)proxy)._rp;
286                 }
287
288                 public static MethodBase GetMethodBaseFromMethodMessage(IMethodMessage msg)
289                 {
290                         Type type = Type.GetType (msg.TypeName);
291                         if (type == null)
292                                 throw new RemotingException ("Type '" + msg.TypeName + "' not found.");
293
294                         BindingFlags bflags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
295                         
296                         MethodBase method;
297                         if (msg.MethodSignature == null)
298                                 method = type.GetMethod (msg.MethodName, bflags);
299                         else
300                                 method = type.GetMethod (msg.MethodName, bflags, null, (Type[]) msg.MethodSignature, null);
301                         
302                         if (method != null) 
303                                 return method;
304                         
305                         if (msg.MethodSignature == null)
306                                 return type.GetConstructor (bflags, null, Type.EmptyTypes, null);
307                         else
308                                 return type.GetConstructor (bflags, null, (Type[]) msg.MethodSignature, null);
309                 }
310
311                 public static void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
312                 {
313                         if (obj == null) throw new ArgumentNullException ("obj");
314
315                         ObjRef oref = Marshal ((MarshalByRefObject)obj);
316                         oref.GetObjectData (info, context);
317                 }
318
319                 public static ObjRef GetObjRefForProxy(MarshalByRefObject obj)
320                 {
321                         Identity ident = GetObjectIdentity(obj);
322                         if (ident == null) return null;
323                         else return ident.CreateObjRef(null);
324                 }
325
326                 public static object GetLifetimeService (MarshalByRefObject obj)
327                 {
328                         if (obj == null) return null;
329                         return obj.GetLifetimeService ();
330                 }
331
332                 public static IMessageSink GetEnvoyChainForProxy (MarshalByRefObject obj)
333                 {
334                         if (IsTransparentProxy(obj))
335                                 return ((ClientIdentity)GetRealProxy (obj).ObjectIdentity).EnvoySink;
336                         else
337                                 throw new ArgumentException ("obj must be a proxy.","obj");                     
338                 }
339
340                 [MonoTODO]
341                 [Conditional ("REMOTING_PERF")]
342                 public static void LogRemotingStage (int stage)
343                 {
344                         throw new NotImplementedException ();
345                 }
346
347                 public static string GetSessionIdForMethodMessage(IMethodMessage msg)
348                 {
349                         // It seems that this it what MS returns.
350                         return msg.Uri;
351                 }
352
353                 public static bool IsMethodOverloaded(IMethodMessage msg)
354                 {
355                         // TODO: use internal call for better performance
356                         Type type = msg.MethodBase.DeclaringType;
357                         MemberInfo[] members = type.GetMember (msg.MethodName, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
358                         return members.Length > 1;
359                 }
360
361                 public static bool IsObjectOutOfAppDomain(object tp)
362                 {
363                         // TODO: use internal call for better performance
364                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
365                         if (ident != null) return !ident.IsFromThisAppDomain;
366                         else return false;
367                 }
368
369                 public static bool IsObjectOutOfContext(object tp)
370                 {
371                         // TODO: use internal call for better performance
372                         ServerIdentity ident = GetObjectIdentity((MarshalByRefObject)tp) as ServerIdentity;
373                         if (ident != null) return ident.Context != System.Threading.Thread.CurrentContext;
374                         else return false;
375                 }
376
377                 public static bool IsOneWay(MethodBase method)
378                 {
379                         // TODO: use internal call for better performance
380                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
381                         return atts.Length > 0;
382                 }
383
384                 internal static bool IsAsyncMessage(IMessage msg)
385                 {
386                         if (! (msg is MonoMethodMessage)) return false;
387                         else if (((MonoMethodMessage)msg).IsAsync) return true;
388                         else if (IsOneWay (((MonoMethodMessage)msg).MethodBase)) return true;
389                         else return false;
390                 }
391
392                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
393                 {
394                         if (IsTransparentProxy (obj)) throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
395                         Marshal (obj, uri);
396                 }
397
398                 #region Internal Methods
399                 
400                 internal static object CreateClientProxy (ActivatedClientTypeEntry entry, object[] activationAttributes)
401                 {
402                         if (entry.ContextAttributes != null || activationAttributes != null)
403                         {
404                                 ArrayList props = new ArrayList ();
405                                 if (entry.ContextAttributes != null) props.AddRange (entry.ContextAttributes);
406                                 if (activationAttributes != null) props.AddRange (activationAttributes);
407                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, props.ToArray ());
408                         }
409                         else
410                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, null);
411                 }
412         
413                 internal static object CreateClientProxy (Type objectType, string url, object[] activationAttributes)
414                 {
415                         string activationUrl = url + "/RemoteActivationService.rem";
416
417                         string objectUri;
418                         IMessageSink sink = GetClientChannelSinkChain (activationUrl, null, out objectUri);
419
420                         RemotingProxy proxy = new RemotingProxy (objectType, activationUrl, activationAttributes);
421                         return proxy.GetTransparentProxy();
422                 }
423         
424                 internal static object CreateClientProxy (WellKnownClientTypeEntry entry)
425                 {
426                         return Connect (entry.ObjectType, entry.ObjectUrl, null);
427                 }
428         
429                 internal static object CreateClientProxyForContextBound (Type type, object[] activationAttributes)
430                 {
431                         if (type.IsContextful)
432                         {
433                                 // Look for a ProxyAttribute
434                                 ProxyAttribute att = (ProxyAttribute) Attribute.GetCustomAttribute (type, typeof(ProxyAttribute), true);
435                                 if (att != null)
436                                         return att.CreateInstance (type);
437                         }
438                         RemotingProxy proxy = new RemotingProxy (type, ChannelServices.CrossContextUrl, activationAttributes);
439                         return proxy.GetTransparentProxy();
440                 }
441         
442                 internal static Identity GetIdentityForUri (string uri)
443                 {
444                         lock (uri_hash)
445                         {
446                                 return (Identity)uri_hash [GetNormalizedUri(uri)];
447                         }
448                 }
449
450                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
451                 {
452                         if (IsTransparentProxy(obj))
453                                 return GetRealProxy (obj).ObjectIdentity;
454                         else
455                                 return obj.ObjectIdentity;
456                 }
457
458                 internal static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef, Type proxyType, out object clientProxy)
459                 {
460                         // This method looks for an identity for the given url. 
461                         // If an identity is not found, it creates the identity and 
462                         // assigns it a proxy to the remote object.
463
464                         // Creates the client sink chain for the given url or channelData.
465                         // It will also get the object uri from the url.
466
467                         object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
468                         string url = (channelData == null) ? objRef.URI : null;
469
470                         string objectUri;
471                         IMessageSink sink = GetClientChannelSinkChain (url, channelData, out objectUri);
472
473                         if (objectUri == null) objectUri = objRef.URI;
474
475                         lock (uri_hash)
476                         {
477                                 clientProxy = null;
478                                 string uri = GetNormalizedUri (objRef.URI);
479                                 
480                                 ClientIdentity identity = uri_hash [uri] as ClientIdentity;
481                                 if (identity != null)
482                                 {
483                                         // Object already registered
484                                         clientProxy = identity.ClientProxy;
485                                         if (clientProxy != null) return identity;
486                                         
487                                         // The proxy has just been GCed, so its identity cannot
488                                         // be reused. Just dispose it.
489                                         DisposeIdentity (identity);
490                                 }
491
492                                 // Creates an identity and a proxy for the remote object
493
494                                 identity = new ClientIdentity (objectUri, objRef);
495                                 identity.ChannelSink = sink;
496
497                                 // Registers the identity
498                                 uri_hash [uri] = identity;
499                                 
500                                 if (proxyType != null)
501                                 {
502                                         RemotingProxy proxy = new RemotingProxy (proxyType, identity);
503                                         clientProxy = proxy.GetTransparentProxy();
504                                         identity.ClientProxy = (MarshalByRefObject) clientProxy;
505                                 }
506
507                                 return identity;
508                         }
509                 }
510
511                 static IMessageSink GetClientChannelSinkChain(string url, object channelData, out string objectUri)
512                 {
513                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
514                         if (sink == null) 
515                         {
516                                 if (url != null) 
517                                 {
518                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
519                                         throw new RemotingException (msg);
520                                 }
521                                 else 
522                                 {
523                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
524                                         throw new RemotingException (msg);
525                                 }
526                         }
527                         return sink;
528                 }
529
530                 internal static ClientActivatedIdentity CreateContextBoundObjectIdentity(Type objectType)
531                 {
532                         ClientActivatedIdentity identity = new ClientActivatedIdentity (null, objectType);
533                         identity.ChannelSink = ChannelServices.CrossContextChannel;
534                         return identity;
535                 }
536
537                 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
538                 {
539                         ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, objectType);
540                         identity.AttachServerObject (realObject, Context.DefaultContext);
541                         RegisterServerIdentity (identity);
542                         identity.StartTrackingLifetime ((ILease)realObject.InitializeLifetimeService ());
543                         return identity;
544                 }
545
546                 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
547                 {
548                         ServerIdentity identity;
549
550                         if (mode == WellKnownObjectMode.SingleCall)
551                                 identity = new  SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
552                         else
553                                 identity = new  SingletonIdentity(objectUri, Context.DefaultContext, objectType);
554
555                         RegisterServerIdentity (identity);
556                         return identity;
557                 }
558
559                 private static void RegisterServerIdentity(ServerIdentity identity)
560                 {
561                         lock (uri_hash)
562                         {
563                                 if (uri_hash.ContainsKey (identity.ObjectUri)) 
564                                         throw new RemotingException ("Uri already in use: " + identity.ObjectUri + ".");
565
566                                 uri_hash[identity.ObjectUri] = identity;
567                         }
568                 }
569
570                 internal static object GetProxyForRemoteObject (ObjRef objref, Type classToProxy)
571                 {
572                         ClientActivatedIdentity identity = GetIdentityForUri (objref.URI) as ClientActivatedIdentity;
573                         if (identity != null) return identity.GetServerObject ();
574                         else return GetRemoteObject (objref, classToProxy);
575                 }
576
577                 internal static object GetRemoteObject(ObjRef objRef, Type proxyType)
578                 {
579                         object proxy;
580                         GetOrCreateClientIdentity (objRef, proxyType, out proxy);
581                         return proxy;
582                 }
583
584                 internal static object GetDomainProxy(AppDomain domain) 
585                 {
586                         byte[] data = null;
587
588                         Context currentContext = Thread.CurrentContext;
589
590                         try
591                         {
592                                 data = (byte[])AppDomain.InvokeInDomain (domain, typeof (AppDomain).GetMethod ("GetMarshalledDomainObjRef", BindingFlags.Instance|BindingFlags.NonPublic), domain, null);
593                         }
594                         finally
595                         {
596                                 AppDomain.InternalSetContext (currentContext);
597                         }                               
598
599                         MemoryStream stream = new MemoryStream (data);
600                         ObjRef appref = (ObjRef) CADSerializer.DeserializeObject (stream);
601                         return (AppDomain) RemotingServices.Unmarshal(appref);
602                 }
603
604                 private static void RegisterInternalChannels() 
605                 {
606                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();
607                 }
608                 
609                 internal static void DisposeIdentity (Identity ident)
610                 {
611                         lock (uri_hash)
612                         {
613                                 if (!ident.Disposed) {
614                                         ClientIdentity clientId = ident as ClientIdentity;
615                                         if (clientId != null)
616                                                 uri_hash.Remove (GetNormalizedUri (clientId.TargetUri));
617                                         else
618                                                 uri_hash.Remove (ident.ObjectUri);
619                                                 
620                                         ident.Disposed = true;
621                                 }
622                         }
623                 }
624
625                 internal static Identity GetMessageTargetIdentity (IMessage msg)
626                 {
627                         // Returns the identity where the message is sent
628
629                         if (msg is IInternalMessage) 
630                                 return ((IInternalMessage)msg).TargetIdentity;
631
632                         lock (uri_hash)
633                         {
634                                 string uri = GetNormalizedUri (((IMethodMessage)msg).Uri);
635                                 return uri_hash [uri] as ServerIdentity;
636                         }
637                 }
638
639                 internal static void SetMessageTargetIdentity (IMessage msg, Identity ident)
640                 {
641                         if (msg is IInternalMessage) 
642                                 ((IInternalMessage)msg).TargetIdentity = ident;
643                 }
644                 
645                 internal static bool UpdateOutArgObject (ParameterInfo pi, object local, object remote)
646                 {
647                         if (local is StringBuilder) 
648                         {
649                                 StringBuilder sb = local as StringBuilder;
650                                 sb.Remove (0, sb.Length);
651                                 sb.Append (remote.ToString());
652                                 return true;
653                         }
654                         else if (pi.ParameterType.IsArray && ((Array)local).Rank == 1)
655                         {
656                                 Array alocal = (Array) local;
657                                 if (alocal.Rank == 1)
658                                 {
659                                         Array.Copy ((Array) remote, alocal, alocal.Length);
660                                         return true;
661                                 }
662                                 else
663                                 {
664                                         // TODO
665                                 }
666                         }
667                         return false;
668                 }
669                 
670                 static string GetNormalizedUri (string uri)
671                 {
672                         if (uri.StartsWith ("/")) return uri.Substring (1);
673                         else return uri;
674                 }
675
676                 #endregion
677         }
678 }