Introducing tagged inbound connections

Till now, there have been two ways of connecting your Node.js application to a drachtio server.

Let's review:

Inbound connections

When using inbound connections, your application connects to a drachtio server at a specified IP address and port, authenticating via a shared secret.

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.connect({
    host: '10.100.233.4',
    port: 9022,
    secret: 'cymru'
});

Inbound connections are great because of their relative simplicity to manage. You establish a single long-lived connection when your app starts, and then use it to control and interact with the server for as long as your app is running. If the connection is broken for some reason (e.g. temporary network condition), the connection will automatically be re-established (note: so long as you have an 'error' handler on the Srf instance!).

When you have several apps that connect to the same drachtio server, and they all register for the same SIP method (e.g., they all want to receive SIP INVITEs), the server will distribute new calls to them on a round robin basis. This works great for servers serving mainly a single purpose.

Outbound connections

Yes, inbound connections are simple, in terms of connection management, but what if you want to run many different applications off of the same drachtio server, and dispatch calls intelligently to them -- for instance, calls to some telephone numbers go to your conferencing app, while calls from certain IP addresses go to your webrtc media proxy app, etc?

With inbound connections, since new calls are round-robin (blindly) distributed to all connected apps, you could have a call meant to go to your conferencing app instead go to your webrtc media proxy app. Yikes!

Outbound connections were introduced to provide a mechanism for routing calls (or any SIP request type) to applications, and providing better support for multi-tenant systems, where multiple applications all run against one drachtio SIP server (or cluster thereof).

A new element is added to the drachtio config file to enable this functionality: a web callback that is invoked by the server when a new SIP request arrives. You must implement a web app that receives an HTTP request with details about the arriving request and provides a JSON response that indicates how to route the call to an application.

On the application side, instead of connecting to a server, you now listen for connections from a server:

make an outbound connection from the server

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.listen({
    port: 3005,
    secret: 'cymru'
});

To enable the callback, configure the follow stanza in your drachtio server config file:

<request-handlers>
<request-handler
   sip-method="INVITE">http://my-web-callback.wherever.com</request-handler>
</request-handlers>

Note: you can use http:// or https:// for your callback.

This will result in the drachtio server invoking your web callback at the supplied address:port for any new INVITE requests. You can add multiple <request-handler/> elements for each type of SIP request you want handled by your web callback, or you can simply put sip-method="*" to have all new SIP requests routed to your web callback.

Note that you can also mix and match outbound connections: in the example above where I route INVITEs via my web callback, I could have a SIP Registrar application using an inbound connection to handle all incoming REGISTER requests, at the same time that incoming INVITEs are dispatched via my web callback.

Lifetime of outbound connections

Whereas inbound connections are long-lived, outbound connections are transient - an outbound connection is made when the new SIP request arrives, and stays up until YOUR APP decides that it is done with it.

That last point is important -- it is up to you to manage the lifetime of this connection, and destroy it when you are done with it. The server won't do it for you. The reason is that the server can't be aware of your application logic, and thus can't know when you are done with the connection.
For example, consider a callback application: the app receives an incoming call, notes down the calling number, then hangs up and 30 seconds later wants to outdial that same number. If that connection was torn down by the server when the initial SIP dialog was destroyed, the app would not be able to do the follow-on outdial because it would not have a connection to the server.

So for that reason, when using outbound connections, you must destroy the connection by calling srf.endSession whenever you are completely done with it. In the example below, when the caller hangs up I destroy the connection since I have no further work to do that would require it.

srf.invite((req, res) => {
    srf.createUAS(..).then((uas) => {
        uas.on('destroy', () => srf.endSession(req));
    });
});

Note that calling 'srf.endSession' is a no-op if the underlying connection is an inbound connection (i.e. it's harmless to call it in that case).

Tagged Inbound Connections

As of drachtio server v0.7.3 and drachtio-srf v4.3.0 tagged inbound connections are supported. These are a bit of a hybrid, in that they are inbound connections (the drachtio application connects to the server), but they also make use of the web callback to dispatch calls to applications.

There is one small change to your drachtio application to move add tagging to your inbound connections: simply pass a tag (or array of tags) to the Srf constructor, e.g.,

const Srf = require('drachtio-srf');
const srf = new Srf('conference-app');

srf.connect({..usual connect opts..});

The second change is in the drachtio-server config file - you must specify a <request-handler/> element that points to your webapp that will be dispatching sip requests.

The final change is in your webapp itself: you now have the ability to examine the information provided about the sip request and return a tag value to route to, i.e

{
    "action": "route",
    "data" : {
        "tag": "conference-app"
    }
}

This will cause the incoming request to be routed to an app that registered the 'conference-app' in its constructor. You can run multiple different types of application against the same server and use tags to dispatch incoming requests to the appropriate app.

Note that you can mix and match dispatching strategies: you can have some incoming requests routed based on tags, others based on service uris (i.e. to an outbound connection), and still other request types dispactched to inbound (non-tagged) connections (if it wasn't clear above, passing a tag(s) to the constructor is completely optional, and you can still use good, old-fashioned non-tagged inbound connections).

When to use tagged inbound connections

The main advantage of tagged inbound connections is that provides a similar ability to outbound connections in terms of supporting multi-tenant scenarios, without the overhead of managing connection lifetimes.

There are still scenarios where you may prefer outbound connections (for example, if you are going to be scaling up and down the number of drachtio servers dynamically, outbound connections are still preferred), but tagged inbound connections offer a useful alternative for many use cases.