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