PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/corlib/System.Runtime.Remoting.Channels/ChannelServices.cs

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