Skip to content

Interception

c80k edited this page May 6, 2020 · 4 revisions

Interception is conceptually very close to membranes (if not the same), although the APIs look different. It can be thought as a universal capability hook mechanism which enables an interception policy to control (monitor, defer, modify, redirect, reject) any calls on its intercepted capabilities. There is also the possibility to transitively intercept capabilities which are passed to or from the target capability during the method call.

Enough of theory. For using interception, implement Capnp.Rpc.Interception.IInterceptionPolicy:

public interface IInterceptionPolicy: IEquatable<IInterceptionPolicy>
{
    void OnCallFromAlice(CallContext callContext);
    void OnReturnFromBob(CallContext callContext);
}

The IEquatable<IInterceptionPolicy> contract helps the Capnp.Net.Runtime identifying whether a given capability is already intercepted or not in the presence of multiple interception policies. There is an extension method Attach for attaching the policy to a capability. Intercepting the bootstrap capability on client side would look like this: `

TcpRpcClient client = ...;
IInterceptionPolicy policy = ...;
var interceptedMain = policy.Attach(client.GetMain<IYourInterface>());

Server side:

TcpRpcServer server = ...;
IInterceptionPolicy policy = ...;
server.Main = policy.Attach<IYourInterface>(new YourInterfaceImpl());

Once you did this, the policy's two callback methods get notify as follows:

  • OnCallFromAlice gets invoked when a caller attempts to call a method.
  • OnReturnFromBob gets invoked when the callee has returned.

It is important to understand that it is completely up to the policy what happens in turn. Indeed, explicit action is required for anything to happen. I.e. leaving OnCallFromAlice with an empty implementation means "never deliver that call".

Both OnCallFromAlice and OnReturnFromBob receive a CallContext parameter which encapsulates the intercepted call. It provides you with several properties and methods for taking control. When inside OnCallFromAlice(CallContext cc) you may choose from the following:

  • Inspect or modify input arguments from InArgs.
  • Intercept all input arguments' capabilities: InterceptInCaps()
  • Forward the call to its original target: ForwardToBob()
  • Redirect the call to a different target: Overwrite Bob, then ForwardToBob().
  • Answer the call by yourself: Set OutArgs, then call ReturnToAlice().
  • Return the call in canceled or faulted state: Set ReturnCanceled or Exception, respectively, then call ReturnToAlice().

Inside OnReturnFromBob(CallContext cc) you'll have another bunch of options:

  • Inspect or modify output arguments from OutArgs.
  • Intercept all output arguments' capabilities: InterceptOutCaps()
  • Choose whether the call should appear returned, faulted, or canceled (yes, you may also "heal" an originally faulted call by setting appropriate OutArgs and setting Exception to null, if you find that useful).

Of course, you may also put the CallContext object in a queue, pull it out later and then do something with it. The sky is the limit.