* ServerIdentity.cs: When disposing an identity, detach the identity from
[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                         return ident is ClientIdentity;
366                 }
367
368                 public static bool IsObjectOutOfContext(object tp)
369                 {
370                         // TODO: use internal call for better performance
371                         Identity ident = GetObjectIdentity((MarshalByRefObject)tp);
372                         if (ident == null) return false;
373                         
374                         ServerIdentity sident = ident as ServerIdentity;
375                         if (sident != null) return sident.Context != System.Threading.Thread.CurrentContext;
376                         else return true;
377                 }
378
379                 public static bool IsOneWay(MethodBase method)
380                 {
381                         // TODO: use internal call for better performance
382                         object[] atts = method.GetCustomAttributes (typeof (OneWayAttribute), false);
383                         return atts.Length > 0;
384                 }
385
386                 internal static bool IsAsyncMessage(IMessage msg)
387                 {
388                         if (! (msg is MonoMethodMessage)) return false;
389                         else if (((MonoMethodMessage)msg).IsAsync) return true;
390                         else if (IsOneWay (((MonoMethodMessage)msg).MethodBase)) return true;
391                         else return false;
392                 }
393
394                 public static void SetObjectUriForMarshal(MarshalByRefObject obj, string uri)
395                 {
396                         if (IsTransparentProxy (obj)) {
397                                 RealProxy proxy = RemotingServices.GetRealProxy(obj);
398                                 Identity identity = proxy.ObjectIdentity;
399
400                                 if (identity != null && !(identity is ServerIdentity) && !proxy.GetProxiedType().IsContextful)
401                                         throw new RemotingException ("SetObjectUriForMarshal method should only be called for MarshalByRefObjects that exist in the current AppDomain.");
402                         }
403                         
404                         Marshal (obj, uri);
405                 }
406
407                 #region Internal Methods
408                 
409                 internal static object CreateClientProxy (ActivatedClientTypeEntry entry, object[] activationAttributes)
410                 {
411                         if (entry.ContextAttributes != null || activationAttributes != null)
412                         {
413                                 ArrayList props = new ArrayList ();
414                                 if (entry.ContextAttributes != null) props.AddRange (entry.ContextAttributes);
415                                 if (activationAttributes != null) props.AddRange (activationAttributes);
416                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, props.ToArray ());
417                         }
418                         else
419                                 return CreateClientProxy (entry.ObjectType, entry.ApplicationUrl, null);
420                 }
421         
422                 internal static object CreateClientProxy (Type objectType, string url, object[] activationAttributes)
423                 {
424                         string activationUrl = url + "/RemoteActivationService.rem";
425
426                         string objectUri;
427                         IMessageSink sink = GetClientChannelSinkChain (activationUrl, null, out objectUri);
428
429                         RemotingProxy proxy = new RemotingProxy (objectType, activationUrl, activationAttributes);
430                         return proxy.GetTransparentProxy();
431                 }
432         
433                 internal static object CreateClientProxy (WellKnownClientTypeEntry entry)
434                 {
435                         return Connect (entry.ObjectType, entry.ObjectUrl, null);
436                 }
437         
438                 internal static object CreateClientProxyForContextBound (Type type, object[] activationAttributes)
439                 {
440                         if (type.IsContextful)
441                         {
442                                 // Look for a ProxyAttribute
443                                 ProxyAttribute att = (ProxyAttribute) Attribute.GetCustomAttribute (type, typeof(ProxyAttribute), true);
444                                 if (att != null)
445                                         return att.CreateInstance (type);
446                         }
447                         RemotingProxy proxy = new RemotingProxy (type, ChannelServices.CrossContextUrl, activationAttributes);
448                         return proxy.GetTransparentProxy();
449                 }
450         
451                 internal static Identity GetIdentityForUri (string uri)
452                 {
453                         lock (uri_hash)
454                         {
455                                 return (Identity)uri_hash [GetNormalizedUri(uri)];
456                         }
457                 }
458
459                 internal static Identity GetObjectIdentity (MarshalByRefObject obj)
460                 {
461                         if (IsTransparentProxy(obj))
462                                 return GetRealProxy (obj).ObjectIdentity;
463                         else
464                                 return obj.ObjectIdentity;
465                 }
466
467                 internal static ClientIdentity GetOrCreateClientIdentity(ObjRef objRef, Type proxyType, out object clientProxy)
468                 {
469                         // This method looks for an identity for the given url. 
470                         // If an identity is not found, it creates the identity and 
471                         // assigns it a proxy to the remote object.
472
473                         // Creates the client sink chain for the given url or channelData.
474                         // It will also get the object uri from the url.
475
476                         object channelData = objRef.ChannelInfo != null ? objRef.ChannelInfo.ChannelData : null;
477                         string url = (channelData == null) ? objRef.URI : null;
478
479                         string objectUri;
480                         IMessageSink sink = GetClientChannelSinkChain (url, channelData, out objectUri);
481
482                         if (objectUri == null) objectUri = objRef.URI;
483
484                         lock (uri_hash)
485                         {
486                                 clientProxy = null;
487                                 string uri = GetNormalizedUri (objRef.URI);
488                                 
489                                 ClientIdentity identity = uri_hash [uri] as ClientIdentity;
490                                 if (identity != null)
491                                 {
492                                         // Object already registered
493                                         clientProxy = identity.ClientProxy;
494                                         if (clientProxy != null) return identity;
495                                         
496                                         // The proxy has just been GCed, so its identity cannot
497                                         // be reused. Just dispose it.
498                                         DisposeIdentity (identity);
499                                 }
500
501                                 // Creates an identity and a proxy for the remote object
502
503                                 identity = new ClientIdentity (objectUri, objRef);
504                                 identity.ChannelSink = sink;
505
506                                 // Registers the identity
507                                 uri_hash [uri] = identity;
508                                 
509                                 if (proxyType != null)
510                                 {
511                                         RemotingProxy proxy = new RemotingProxy (proxyType, identity);
512                                         clientProxy = proxy.GetTransparentProxy();
513                                         identity.ClientProxy = (MarshalByRefObject) clientProxy;
514                                 }
515
516                                 return identity;
517                         }
518                 }
519
520                 static IMessageSink GetClientChannelSinkChain(string url, object channelData, out string objectUri)
521                 {
522                         IMessageSink sink = ChannelServices.CreateClientChannelSinkChain (url, channelData, out objectUri);
523                         if (sink == null) 
524                         {
525                                 if (url != null) 
526                                 {
527                                         string msg = String.Format ("Cannot create channel sink to connect to URL {0}. An appropriate channel has probably not been registered.", url); 
528                                         throw new RemotingException (msg);
529                                 }
530                                 else 
531                                 {
532                                         string msg = String.Format ("Cannot create channel sink to connect to the remote object. An appropriate channel has probably not been registered.", url); 
533                                         throw new RemotingException (msg);
534                                 }
535                         }
536                         return sink;
537                 }
538
539                 internal static ClientActivatedIdentity CreateContextBoundObjectIdentity(Type objectType)
540                 {
541                         ClientActivatedIdentity identity = new ClientActivatedIdentity (null, objectType);
542                         identity.ChannelSink = ChannelServices.CrossContextChannel;
543                         return identity;
544                 }
545
546                 internal static ClientActivatedIdentity CreateClientActivatedServerIdentity(MarshalByRefObject realObject, Type objectType, string objectUri)
547                 {
548                         ClientActivatedIdentity identity = new ClientActivatedIdentity (objectUri, objectType);
549                         identity.AttachServerObject (realObject, Context.DefaultContext);
550                         RegisterServerIdentity (identity);
551                         identity.StartTrackingLifetime ((ILease)realObject.InitializeLifetimeService ());
552                         return identity;
553                 }
554
555                 internal static ServerIdentity CreateWellKnownServerIdentity(Type objectType, string objectUri, WellKnownObjectMode mode)
556                 {
557                         ServerIdentity identity;
558
559                         if (mode == WellKnownObjectMode.SingleCall)
560                                 identity = new  SingleCallIdentity(objectUri, Context.DefaultContext, objectType);
561                         else
562                                 identity = new  SingletonIdentity(objectUri, Context.DefaultContext, objectType);
563
564                         RegisterServerIdentity (identity);
565                         return identity;
566                 }
567
568                 private static void RegisterServerIdentity(ServerIdentity identity)
569                 {
570                         lock (uri_hash)
571                         {
572                                 if (uri_hash.ContainsKey (identity.ObjectUri)) 
573                                         throw new RemotingException ("Uri already in use: " + identity.ObjectUri + ".");
574
575                                 uri_hash[identity.ObjectUri] = identity;
576                         }
577                 }
578
579                 internal static object GetProxyForRemoteObject (ObjRef objref, Type classToProxy)
580                 {
581                         ClientActivatedIdentity identity = GetIdentityForUri (objref.URI) as ClientActivatedIdentity;
582                         if (identity != null) return identity.GetServerObject ();
583                         else return GetRemoteObject (objref, classToProxy);
584                 }
585
586                 internal static object GetRemoteObject(ObjRef objRef, Type proxyType)
587                 {
588                         object proxy;
589                         GetOrCreateClientIdentity (objRef, proxyType, out proxy);
590                         return proxy;
591                 }
592
593                 internal static object GetDomainProxy(AppDomain domain) 
594                 {
595                         byte[] data = null;
596
597                         Context currentContext = Thread.CurrentContext;
598
599                         try
600                         {
601                                 data = (byte[])AppDomain.InvokeInDomain (domain, typeof (AppDomain).GetMethod ("GetMarshalledDomainObjRef", BindingFlags.Instance|BindingFlags.NonPublic), domain, null);
602                         }
603                         finally
604                         {
605                                 AppDomain.InternalSetContext (currentContext);
606                         }                               
607
608                         MemoryStream stream = new MemoryStream (data);
609                         ObjRef appref = (ObjRef) CADSerializer.DeserializeObject (stream);
610                         return (AppDomain) RemotingServices.Unmarshal(appref);
611                 }
612
613                 private static void RegisterInternalChannels() 
614                 {
615                         CrossAppDomainChannel.RegisterCrossAppDomainChannel();
616                 }
617                 
618                 internal static void DisposeIdentity (Identity ident)
619                 {
620                         lock (uri_hash)
621                         {
622                                 if (!ident.Disposed) {
623                                         ClientIdentity clientId = ident as ClientIdentity;
624                                         if (clientId != null)
625                                                 uri_hash.Remove (GetNormalizedUri (clientId.TargetUri));
626                                         else
627                                                 uri_hash.Remove (ident.ObjectUri);
628                                                 
629                                         ident.Disposed = true;
630                                 }
631                         }
632                 }
633
634                 internal static Identity GetMessageTargetIdentity (IMessage msg)
635                 {
636                         // Returns the identity where the message is sent
637
638                         if (msg is IInternalMessage) 
639                                 return ((IInternalMessage)msg).TargetIdentity;
640
641                         lock (uri_hash)
642                         {
643                                 string uri = GetNormalizedUri (((IMethodMessage)msg).Uri);
644                                 return uri_hash [uri] as ServerIdentity;
645                         }
646                 }
647
648                 internal static void SetMessageTargetIdentity (IMessage msg, Identity ident)
649                 {
650                         if (msg is IInternalMessage) 
651                                 ((IInternalMessage)msg).TargetIdentity = ident;
652                 }
653                 
654                 internal static bool UpdateOutArgObject (ParameterInfo pi, object local, object remote)
655                 {
656                         if (local is StringBuilder) 
657                         {
658                                 StringBuilder sb = local as StringBuilder;
659                                 sb.Remove (0, sb.Length);
660                                 sb.Append (remote.ToString());
661                                 return true;
662                         }
663                         else if (pi.ParameterType.IsArray && ((Array)local).Rank == 1)
664                         {
665                                 Array alocal = (Array) local;
666                                 if (alocal.Rank == 1)
667                                 {
668                                         Array.Copy ((Array) remote, alocal, alocal.Length);
669                                         return true;
670                                 }
671                                 else
672                                 {
673                                         // TODO
674                                 }
675                         }
676                         return false;
677                 }
678                 
679                 static string GetNormalizedUri (string uri)
680                 {
681                         if (uri.StartsWith ("/")) return uri.Substring (1);
682                         else return uri;
683                 }
684
685                 #endregion
686         }
687 }