1 // 2 // System.Runtime.Remoting.Channels.ChannelServices.cs 3 // 4 // Author: Rodrigo Moya (rodrigo@ximian.com) 5 // Dietmar Maurer (dietmar@ximian.com) 6 // Lluis Sanchez Gual (lluis@ideary.com) 7 // 8 // 2002 (C) Copyright, Ximian, Inc. 9 // 10 11 // 12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com) 13 // 14 // Permission is hereby granted, free of charge, to any person obtaining 15 // a copy of this software and associated documentation files (the 16 // "Software"), to deal in the Software without restriction, including 17 // without limitation the rights to use, copy, modify, merge, publish, 18 // distribute, sublicense, and/or sell copies of the Software, and to 19 // permit persons to whom the Software is furnished to do so, subject to 20 // the following conditions: 21 // 22 // The above copyright notice and this permission notice shall be 23 // included in all copies or substantial portions of the Software. 24 // 25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 32 // 33 34 using System.Collections; 35 using System.Collections.Generic; 36 using System.Reflection; 37 using System.Runtime.Remoting; 38 using System.Runtime.Remoting.Channels; 39 using System.Runtime.Remoting.Messaging; 40 using System.Runtime.Remoting.Contexts; 41 42 namespace System.Runtime.Remoting 43 { 44 [Serializable] 45 internal class ChannelInfo : IChannelInfo 46 { 47 object [] channelData = null; 48 ChannelInfo()49 public ChannelInfo () 50 { 51 channelData = ChannelServices.GetCurrentChannelInfo (); 52 } 53 ChannelInfo(object remoteChannelData)54 public ChannelInfo (object remoteChannelData) 55 { 56 channelData = new object[] { remoteChannelData }; 57 } 58 59 public object[] ChannelData 60 { 61 get { 62 return channelData; 63 } 64 65 set { 66 channelData = value; 67 } 68 } 69 } 70 } 71 72 namespace System.Runtime.Remoting.Channels 73 { 74 [System.Runtime.InteropServices.ComVisible (true)] 75 public sealed class ChannelServices 76 { 77 private static ArrayList registeredChannels = new ArrayList (); 78 private static ArrayList delayedClientChannels = new ArrayList (); 79 80 private static CrossContextChannel _crossContextSink = new CrossContextChannel(); 81 82 internal static string CrossContextUrl = "__CrossContext"; 83 ChannelServices()84 private ChannelServices () 85 { 86 } 87 88 internal static CrossContextChannel CrossContextChannel 89 { 90 get { return _crossContextSink; } 91 } 92 CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)93 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri) 94 { 95 // Locate a channel that can parse the url. This channel will be used to 96 // create the sink chain. 97 98 object[] channelDataArray = (object[])remoteChannelData; 99 100 lock (registeredChannels.SyncRoot) 101 { 102 // First of all, try registered channels 103 foreach (IChannel c in registeredChannels) 104 { 105 IChannelSender sender = c as IChannelSender; 106 if (sender == null) continue; 107 108 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri); 109 if (sink != null) return sink; 110 } 111 112 // Not found. Try now creation delayed channels 113 RemotingConfiguration.LoadDefaultDelayedChannels (); 114 foreach (IChannelSender sender in delayedClientChannels) 115 { 116 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri); 117 if (sink != null) { 118 delayedClientChannels.Remove (sender); 119 RegisterChannel (sender); 120 return sink; 121 } 122 } 123 } 124 125 objectUri = null; 126 return null; 127 } 128 CreateClientChannelSinkChain(IChannelSender sender, string url, object[] channelDataArray, out string objectUri)129 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri) 130 { 131 objectUri = null; 132 if (channelDataArray == null) { 133 return sender.CreateMessageSink (url, null, out objectUri); 134 } 135 else { 136 foreach (object data in channelDataArray) { 137 IMessageSink sink; 138 139 if (data is IChannelDataStore) { 140 // Don't provide the url in this case, since some channels won't 141 // check the channelData parameter if the url is not null. 142 sink = sender.CreateMessageSink (null, data, out objectUri); 143 } else { 144 sink = sender.CreateMessageSink (url, data, out objectUri); 145 } 146 if (sink != null) return sink; 147 } 148 } 149 return null; 150 } 151 152 public static IChannel[] RegisteredChannels 153 { 154 get { 155 lock (registeredChannels.SyncRoot) 156 { 157 var list = new List<IChannel> (); 158 159 for (int i = 0; i < registeredChannels.Count; i++) { 160 IChannel ch = (IChannel) registeredChannels[i]; 161 if (ch is CrossAppDomainChannel) continue; 162 list.Add (ch); 163 } 164 165 return list.ToArray (); 166 } 167 } 168 } 169 CreateServerChannelSinkChain( IServerChannelSinkProvider provider, IChannelReceiver channel)170 public static IServerChannelSink CreateServerChannelSinkChain ( 171 IServerChannelSinkProvider provider, IChannelReceiver channel) 172 { 173 IServerChannelSinkProvider tmp = provider; 174 while (tmp.Next != null) tmp = tmp.Next; 175 tmp.Next = new ServerDispatchSinkProvider (); 176 177 // Every provider has to call CreateSink() of its next provider 178 return provider.CreateSink (channel); 179 } 180 DispatchMessage( IServerChannelSinkStack sinkStack, IMessage msg, out IMessage replyMsg)181 public static ServerProcessing DispatchMessage ( 182 IServerChannelSinkStack sinkStack, 183 IMessage msg, 184 out IMessage replyMsg) 185 { 186 if (msg == null) throw new ArgumentNullException ("msg"); 187 188 // Async processing is not done here because there isn't any way 189 // to know if a message is to be dispatched sync or asynchronously. 190 191 replyMsg = SyncDispatchMessage (msg); 192 193 if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase)) 194 return ServerProcessing.OneWay; 195 else 196 return ServerProcessing.Complete; 197 } 198 GetChannel(string name)199 public static IChannel GetChannel (string name) 200 { 201 lock (registeredChannels.SyncRoot) 202 { 203 foreach (IChannel chnl in registeredChannels) { 204 if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl; 205 } 206 return null; 207 } 208 } 209 GetChannelSinkProperties(object obj)210 public static IDictionary GetChannelSinkProperties (object obj) 211 { 212 if (!RemotingServices.IsTransparentProxy (obj)) 213 throw new ArgumentException ("obj must be a proxy","obj"); 214 215 ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity; 216 IMessageSink sink = ident.ChannelSink; 217 var dics = new List<IDictionary> (); 218 219 while (sink != null && !(sink is IClientChannelSink)) 220 sink = sink.NextSink; 221 222 if (sink == null) 223 return new Hashtable (); 224 225 IClientChannelSink csink = sink as IClientChannelSink; 226 while (csink != null) 227 { 228 dics.Add (csink.Properties); 229 csink = csink.NextChannelSink; 230 } 231 232 IDictionary[] adics = dics.ToArray (); 233 return new AggregateDictionary (adics); 234 } 235 GetUrlsForObject(MarshalByRefObject obj)236 public static string[] GetUrlsForObject (MarshalByRefObject obj) 237 { 238 string uri = RemotingServices.GetObjectUri (obj); 239 if (uri == null) return new string [0]; 240 241 var list = new List<string> (); 242 243 lock (registeredChannels.SyncRoot) 244 { 245 foreach (object chnl_obj in registeredChannels) { 246 if (chnl_obj is CrossAppDomainChannel) continue; 247 248 IChannelReceiver chnl = chnl_obj as IChannelReceiver; 249 250 if (chnl != null) 251 list.AddRange (chnl.GetUrlsForUri (uri)); 252 } 253 } 254 255 return list.ToArray (); 256 } 257 258 [Obsolete ("Use RegisterChannel(IChannel,Boolean)")] RegisterChannel(IChannel chnl)259 public static void RegisterChannel (IChannel chnl) 260 { 261 RegisterChannel (chnl, false); 262 } 263 RegisterChannel(IChannel chnl, bool ensureSecurity)264 public static void RegisterChannel (IChannel chnl, bool ensureSecurity) 265 { 266 if (chnl == null) 267 throw new ArgumentNullException ("chnl"); 268 269 if (ensureSecurity) { 270 ISecurableChannel securable = chnl as ISecurableChannel; 271 if (securable == null) 272 throw new RemotingException (String.Format ("Channel {0} is not securable while ensureSecurity is specified as true", chnl.ChannelName)); 273 securable.IsSecured = true; 274 } 275 276 // Put the channel in the correct place according to its priority. 277 // Since there are not many channels, a linear search is ok. 278 279 lock (registeredChannels.SyncRoot) 280 { 281 int pos = -1; 282 for (int n = 0; n < registeredChannels.Count; n++) 283 { 284 IChannel regc = (IChannel) registeredChannels[n]; 285 286 if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "") 287 throw new RemotingException ("Channel " + regc.ChannelName + " already registered"); 288 289 if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1) 290 pos = n; 291 } 292 293 if (pos != -1) registeredChannels.Insert (pos, chnl); 294 else registeredChannels.Add (chnl); 295 296 IChannelReceiver receiver = chnl as IChannelReceiver; 297 if (receiver != null && oldStartModeTypes.Contains (chnl.GetType().ToString ())) 298 receiver.StartListening (null); 299 } 300 } 301 RegisterChannelConfig(ChannelData channel)302 internal static void RegisterChannelConfig (ChannelData channel) 303 { 304 IServerChannelSinkProvider serverSinks = null; 305 IClientChannelSinkProvider clientSinks = null; 306 307 // Create server providers 308 for (int n=channel.ServerProviders.Count-1; n>=0; n--) 309 { 310 ProviderData prov = channel.ServerProviders[n] as ProviderData; 311 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov); 312 sinkp.Next = serverSinks; 313 serverSinks = sinkp; 314 } 315 316 // Create client providers 317 for (int n=channel.ClientProviders.Count-1; n>=0; n--) 318 { 319 ProviderData prov = channel.ClientProviders[n] as ProviderData; 320 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov); 321 sinkp.Next = clientSinks; 322 clientSinks = sinkp; 323 } 324 325 // Create the channel 326 327 Type type = Type.GetType (channel.Type); 328 if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found"); 329 330 Object[] parms; 331 Type[] signature; 332 bool clienc = typeof (IChannelSender).IsAssignableFrom (type); 333 bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type); 334 335 if (clienc && serverc) { 336 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)}; 337 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks}; 338 } 339 else if (clienc) { 340 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)}; 341 parms = new Object[] {channel.CustomProperties, clientSinks}; 342 } 343 else if (serverc) { 344 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)}; 345 parms = new Object[] {channel.CustomProperties, serverSinks}; 346 } 347 else 348 throw new RemotingException (type + " is not a valid channel type"); 349 350 ConstructorInfo ctor = type.GetConstructor (signature); 351 if (ctor == null) 352 throw new RemotingException (type + " does not have a valid constructor"); 353 354 IChannel ch; 355 try 356 { 357 ch = (IChannel) ctor.Invoke (parms); 358 } 359 catch (TargetInvocationException ex) 360 { 361 throw ex.InnerException; 362 } 363 364 lock (registeredChannels.SyncRoot) 365 { 366 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver)) 367 delayedClientChannels.Add (ch); 368 else 369 RegisterChannel (ch); 370 } 371 } 372 CreateProvider(ProviderData prov)373 static object CreateProvider (ProviderData prov) 374 { 375 Type pvtype = Type.GetType (prov.Type); 376 if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found"); 377 Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData}; 378 379 try 380 { 381 return Activator.CreateInstance (pvtype, pvparms); 382 } 383 catch (Exception ex) 384 { 385 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException; 386 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message); 387 } 388 } 389 SyncDispatchMessage(IMessage msg)390 public static IMessage SyncDispatchMessage (IMessage msg) 391 { 392 IMessage ret = CheckIncomingMessage (msg); 393 if (ret != null) return CheckReturnMessage (msg, ret); 394 ret = _crossContextSink.SyncProcessMessage (msg); 395 return CheckReturnMessage (msg, ret); 396 } 397 AsyncDispatchMessage(IMessage msg, IMessageSink replySink)398 public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink) 399 { 400 IMessage ret = CheckIncomingMessage (msg); 401 if (ret != null) { 402 replySink.SyncProcessMessage (CheckReturnMessage (msg, ret)); 403 return null; 404 } 405 406 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg))) 407 replySink = new ExceptionFilterSink (msg, replySink); 408 409 return _crossContextSink.AsyncProcessMessage (msg, replySink); 410 } 411 CheckIncomingMessage(IMessage msg)412 static ReturnMessage CheckIncomingMessage (IMessage msg) 413 { 414 IMethodMessage call = (IMethodMessage)msg; 415 ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity; 416 417 if (identity == null) 418 return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg); 419 420 RemotingServices.SetMessageTargetIdentity (msg, identity); 421 return null; 422 } 423 CheckReturnMessage(IMessage callMsg, IMessage retMsg)424 internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg) 425 { 426 IMethodReturnMessage ret = retMsg as IMethodReturnMessage; 427 if (ret != null && ret.Exception != null) 428 { 429 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg))) 430 { 431 Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file."); 432 retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg); 433 } 434 } 435 return retMsg; 436 } 437 IsLocalCall(IMessage callMsg)438 static bool IsLocalCall (IMessage callMsg) 439 { 440 return true; 441 442 /* How can I know if a call is local?!? 443 444 object isLocal = callMsg.Properties ["__isLocalCall"]; 445 if (isLocal == null) return false; 446 return (bool)isLocal; 447 */ 448 } 449 UnregisterChannel(IChannel chnl)450 public static void UnregisterChannel (IChannel chnl) 451 { 452 if (chnl == null) 453 throw new ArgumentNullException (); 454 455 lock (registeredChannels.SyncRoot) 456 { 457 for (int n=0; n<registeredChannels.Count; n++) 458 { 459 if (registeredChannels [n] == (object)chnl) { 460 registeredChannels.RemoveAt (n); 461 IChannelReceiver chnlReceiver = chnl as IChannelReceiver; 462 if(chnlReceiver != null) 463 chnlReceiver.StopListening(null); 464 return; 465 } 466 } 467 468 throw new RemotingException ("Channel not registered"); 469 470 } 471 } 472 GetCurrentChannelInfo()473 internal static object [] GetCurrentChannelInfo () 474 { 475 var list = new List<object> (); 476 477 lock (registeredChannels.SyncRoot) 478 { 479 foreach (object chnl_obj in registeredChannels) { 480 IChannelReceiver chnl = chnl_obj as IChannelReceiver; 481 482 if (chnl != null) { 483 object chnl_data = chnl.ChannelData; 484 if (chnl_data != null) 485 list.Add (chnl_data); 486 } 487 } 488 } 489 490 return list.ToArray (); 491 } 492 493 // Back compatibility fix. StartListener will be called for the types listed here 494 static IList oldStartModeTypes = new string[] { 495 "Novell.Zenworks.Zmd.Public.UnixServerChannel", 496 "Novell.Zenworks.Zmd.Public.UnixChannel" 497 }; 498 } 499 500 internal class ExceptionFilterSink: IMessageSink 501 { 502 IMessageSink _next; 503 IMessage _call; 504 ExceptionFilterSink(IMessage call, IMessageSink next)505 public ExceptionFilterSink (IMessage call, IMessageSink next) 506 { 507 _call = call; 508 _next = next; 509 } 510 SyncProcessMessage(IMessage msg)511 public IMessage SyncProcessMessage (IMessage msg) 512 { 513 return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg)); 514 } 515 AsyncProcessMessage(IMessage msg, IMessageSink replySink)516 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink) 517 { 518 throw new InvalidOperationException(); 519 } 520 521 public IMessageSink NextSink 522 { 523 get { return _next; } 524 } 525 } 526 } 527