// // InterceptorChannel.cs: // // Author: // Lluis Sanchez Gual (lluis@ximian.com) // // (C) 2003 Lluis Sanchez Gual // using System; using System.Collections; using System.IO; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Activation; using System.Runtime.Remoting.Services; using System.Runtime.Serialization; using System.Text.RegularExpressions; using System.Reflection; namespace Interception { // // Base interface for interception sinks // public interface IInterceptionSink { IInterceptionSink Next {get;set;} } // // Sink for intercepting the creation of objects // public interface ICreationInterceptionSink : IInterceptionSink { object CreateInstance (IConstructionCallMessage ctorCall); } // // Sink for intercepting method calls // public interface IMethodInterceptionSink : IInterceptionSink { IMessage ExecuteMessage (IMethodCallMessage call); } // // Sink for intercepting both creation and method calls // public interface ITypeInterceptionSink : ICreationInterceptionSink, IMethodInterceptionSink { } // // Some useful delegates // public delegate object CreateObjectDelegate (IConstructionCallMessage ctorCall, ICreationInterceptionSink creationSink); public delegate IMessage ExecuteMessageDelegate (IMethodCallMessage call, IMethodInterceptionSink execSink); // // Main class that manages the types to be intercepted and the // interception sinks // public class InterceptionManager { static Hashtable _objects = new Hashtable(); static int _objCount; static Hashtable _typeSinks = new Hashtable (); static ITypeInterceptionSink _typeTerminatorSink = new TypeTerminatorSink (); static object[] _channelData; static InterceptionManager () { _channelData = new object[1]; _channelData[0] = new ChannelDataStore (new String[] {"interceptor"}); ChannelServices.RegisterChannel (new InterceptorChannel ()); } // Activates object creation interception for the given type. // Creation messages will be processed by the provided sink. public static void Intercept (Type type, ICreationInterceptionSink sink) { AddSink (type, sink, 0); } // Activates method call interception for the given type. // Call messages will be processed by the provided sink. public static void Intercept (Type type, IMethodInterceptionSink sink) { AddSink (type, sink, 1); } // Activates type and method call interception for the given type. // Both type of messages will be forwarded to the provided sink. public static void Intercept (Type type, ITypeInterceptionSink sink) { AddSink (type, sink, 0); AddSink (type, sink, 1); } // Activates object creation interception for the given type. // Construction messages will be processed by calling the provided delegate. public static void Intercept (Type type, CreateObjectDelegate deleg) { CreationInterceptionDelegateSink sink = new CreationInterceptionDelegateSink (deleg); Intercept (type, sink); } // Activates method call interception for the given type. // Call messages will be processed by calling the provided delegate. public static void Intercept (Type type, ExecuteMessageDelegate deleg) { MethodInterceptionDelegateSink sink = new MethodInterceptionDelegateSink (deleg); Intercept (type, sink); } // Sets a replacement for a type. When an new instace of oldType is requested // an instance of newType will be created. public static void ReplaceType (Type oldType, Type newType) { if (!oldType.IsAssignableFrom (newType)) throw new InvalidOperationException ("Invalid replacement type"); Intercept (oldType, new ReplaceTypeSink (newType)); } private static void AddSink (Type type, IInterceptionSink sink, int id) { lock (_typeSinks.SyncRoot) { IInterceptionSink[] sinks = _typeSinks [type.AssemblyQualifiedName] as IInterceptionSink[]; if (sinks == null) { sinks = new IInterceptionSink[2]; _typeSinks.Add (type.AssemblyQualifiedName, sinks); sinks [0] = sinks [1] = _typeTerminatorSink; RemotingConfiguration.RegisterActivatedClientType (type, "interceptor"); } sink.Next = sinks [id]; sinks [id] = sink; } } internal static IConstructionReturnMessage CreateInstance (IConstructionCallMessage ctorCall) { ICreationInterceptionSink sink = (ICreationInterceptionSink) GetTypeSinkChain (ctorCall.TypeName, 0); object target = sink.CreateInstance (ctorCall); ObjRef or = RemotingServices.Marshal ((MarshalByRefObject) target); ObjRef retref = new InterceptObjRef(); retref.ChannelInfo = or.ChannelInfo; retref.ChannelInfo.ChannelData = _channelData; retref.EnvoyInfo = or.EnvoyInfo; retref.TypeInfo = or.TypeInfo; retref.URI = "interceptor_" + (_objCount++); RegisterObject (retref.URI, target); return new CustomConstructionReturnMessage(retref, ctorCall); } internal static IMessage ExecuteMessage (IMethodCallMessage call) { try { IMethodInterceptionSink sink = (IMethodInterceptionSink) GetTypeSinkChain (call.TypeName, 1); return sink.ExecuteMessage (call); } catch (Exception ex) { return new ReturnMessage (ex, call); } } static IInterceptionSink GetTypeSinkChain (string type, int sinkType) { lock (_typeSinks.SyncRoot) { IInterceptionSink[] sinks = _typeSinks [type] as IInterceptionSink[]; if (sinks == null) return _typeTerminatorSink; else return (IInterceptionSink) sinks [sinkType]; } } internal static void RegisterObject (string uri, object ob) { lock (_objects.SyncRoot) { _objects[uri] = ob; } } internal static void DisposeObject (string uri) { lock (_objects.SyncRoot) { _objects.Remove (uri); } } internal static MarshalByRefObject GetObject (string uri) { lock (_objects.SyncRoot) { return _objects [uri] as MarshalByRefObject; } } internal static object CreateInternalInstance (Type t, IConstructionCallMessage ctorCall) { object target = FormatterServices.GetUninitializedObject (t); Type[] signature = (Type[])ctorCall.MethodSignature; ConstructorInfo ctor = t.GetConstructor (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, signature, null); ctor.Invoke (target, ctorCall.Args); return target; } } public class BaseInterceptionSink { protected IInterceptionSink _next; public IInterceptionSink Next { get { return _next; } set { _next = value; } } } // // Terminator sink that performs the default operation for object // creation and message dispatch // internal class TypeTerminatorSink: BaseInterceptionSink, ITypeInterceptionSink { public object CreateInstance (IConstructionCallMessage ctorCall) { return InterceptionManager.CreateInternalInstance (ctorCall.ActivationType, ctorCall); } public IMessage ExecuteMessage (IMethodCallMessage call) { MarshalByRefObject target = InterceptionManager.GetObject (call.Uri); if (target == null) throw new InvalidOperationException ("Object for uri '" + call.Uri + "' not found"); return RemotingServices.ExecuteMessage (target, call); } } internal class CreationInterceptionDelegateSink : BaseInterceptionSink, ICreationInterceptionSink { CreateObjectDelegate _creationDelegate; public CreationInterceptionDelegateSink (CreateObjectDelegate creationDelegate) { _creationDelegate = creationDelegate; } public object CreateInstance (IConstructionCallMessage ctorCall) { return _creationDelegate (ctorCall, (ICreationInterceptionSink) _next); } } internal class MethodInterceptionDelegateSink : BaseInterceptionSink, IMethodInterceptionSink { ExecuteMessageDelegate _messageDelegate; public MethodInterceptionDelegateSink (ExecuteMessageDelegate messageDelegate) { _messageDelegate = messageDelegate; } public IMessage ExecuteMessage (IMethodCallMessage call) { return _messageDelegate (call, (IMethodInterceptionSink) _next); } } internal class ReplaceTypeSink: BaseInterceptionSink, ICreationInterceptionSink { Type _newType; public ReplaceTypeSink (Type type) { _newType = type; } public object CreateInstance (IConstructionCallMessage ctorCall) { return InterceptionManager.CreateInternalInstance (_newType, ctorCall); } } /// /// Summary description for InterceptorChannel. /// public class InterceptorChannel : IChannelSender, IChannel { public InterceptorChannel () { } public string ChannelName { get { return "Interceptor"; } } public int ChannelPriority { get { return 1; } } public IMessageSink CreateMessageSink (string url, object remoteChannelData, out string objectURI) { if (url == null && remoteChannelData != null) { IChannelDataStore ds = remoteChannelData as IChannelDataStore; if (ds != null && ds.ChannelUris.Length > 0) url = ds.ChannelUris [0]; else { objectURI = null; return null; } } if (Parse (url, out objectURI) == null) return null; return (IMessageSink) new InterceptorSink (url); } public string Parse (string url, out string objectURI) { // format: interceptor/objectUri Match m = Regex.Match (url, "interceptor/?(.*)"); if (!m.Success) { objectURI = null; return null; } objectURI = m.Groups[1].Value; if (objectURI == string.Empty) objectURI = null; return "interceptor"; } } public class InterceptorSink : IClientChannelSink, IMessageSink { static ChannelDataStore _thisChannelDataStore = new ChannelDataStore (new string[] {"interceptor/"}); internal InterceptorSink (string uri) { } public IClientChannelSink NextChannelSink { get { return null; } } public IMessageSink NextSink { get { return null; } } public IDictionary Properties { get { return null; } } public IMessage SyncProcessMessage (IMessage msg) { IMethodCallMessage call = (IMethodCallMessage)msg; try { if (call.Uri == "interceptor/RemoteActivationService.rem") { IConstructionCallMessage ctorCall = (IConstructionCallMessage)call.Args[0]; IConstructionReturnMessage ret = InterceptionManager.CreateInstance (ctorCall); return new ReturnMessage (ret, new object[0],0,null, call); } else { return InterceptionManager.ExecuteMessage (call); } } catch (Exception ex) { Console.WriteLine (ex); return new ReturnMessage (ex, call); } } public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink) { // TODO throw new NotImplementedException (); } public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream stream) { throw new NotSupportedException(); } public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream) { throw new NotSupportedException(); } public Stream GetRequestStream (IMessage msg, ITransportHeaders headers) { throw new NotSupportedException(); } public void ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, out ITransportHeaders responseHeaders, out Stream responseStream) { throw new NotSupportedException(); } } class CustomConstructionReturnMessage : ReturnMessage, IConstructionReturnMessage { public CustomConstructionReturnMessage (object result, IMethodCallMessage call) : base (result, new object[0],0,null, call) { } } class InterceptObjRef : ObjRef { ~InterceptObjRef () { InterceptionManager.DisposeObject (URI); } } }