Login | Register

Documentation

Documentation -> Tutorials -> B2BUA

Back-to-Back User Agent

1.  Overview

OpenSIPS has many features but in the way it behaves when a media session is established, it is not more than a proxy, meaning that it only takes the messages from one side and passes them on the other side. However, this has proven not to be enough to provide certain services required for the server to be aware of the state of the sessions, monitor and control them. A Back-to-Back User Agent is exactly this, a entity in the SIP network which has the ability to control or start media sessions. The name comes from the behavior, since in fact what is required is for the B2BUA to stand in the middle and establish two dialogs with both end points that will eventually exchange media.

The B2BUA in OpenSIPS is an implementation of the behavior of a B2BUA as defined in RFC 3261 that offers the possibility to build certain services on top of it. It consists of two modules:

  • b2b_entities - the bottom half, implementing the basic functions of a UAC and UAS, by dealing with the actual network message exchange;
  • b2b_logic - the upper half, providing to the script and exterior the necessary functions for implementing the logic of the B2BUA services.

The two parts composing the B2BUA in OpenSIPS are bound to each other in a control-notify relationship. The b2b_logic module controls the b2b_entities by sending commands and telling it what messages to send and the b2b_entities modules notifies the b2b_logic module when a request or a reply is received for a dialog that the B2B is handling.

1.1 B2B Entities

B2B entities are internal OpenSIPS records corresponding to the dialogs in which the B2BUA is involved. More loosely, we use the term "entity" to refer to the SIP entity that is the peer user agent of OpenSIPS in these dialogs. Depending on how OpenSIPS acts for the first transaction (as a UAS or UAC), we have two types of entities:

  • b2b server entity, if it is created for a received initial INVITE;
  • b2b client entity, if OpenSIPS will have to start a dialog itself by sending an initial message.

2.  Implementing B2BUA services

2.1 Initiating B2B sessions

There are two ways to trigger a new B2B session corresponding to a desired B2BUA scenario:

  • from the script, at the receipt of an initial INVITE, using the b2b_init_request function
  • with the b2b_trigger_scenario MI command , when OpenSIPS has to start the calls from the middle.

The initial details for the first entities that have to be connected are provided directly as parameters to the b2b_trigger_scenario MI command. In the case of the b2b_init_request function, the b2b entities records have to be created beforehand, with the b2b_server_new and b2b_client_new script functions.

2.2 Dedicated script routes

After initializing a B2B session, the call legs will be handled by the b2b_logic module and the first step will be to put the two initial entities in contact. Requests and replies belonging to these dialogs will not enter the script through the standard OpenSIPS routes but instead will be handled in b2b_logic dedicated routes (defined through the script_req_route and script_reply_route modparams or, the custom routes given as parameters to the b2b_init_request function). The further steps of the scenario can be implemented in these routes, by calling specific b2b_logic script functions in order to perform various actions (eg. bridging existing entities with new ones). Normal "proxy-like" OpenSIPS functions should not be executed in the b2b_logic routes.

Some messages will be handled automatically by the module and will not enter the b2b_logic routes at all (BYE requests received while in the process of bridging two entities, ACKs/BYEs/replies for disconnected entities). Also, if no dedicated b2b_logic reply route is defined, replies will be handled internally by the module, with the same effects as calling the b2b_handle_reply function from such a route if it were defined.

3.  Scenario Examples

3.1  Topology Hiding

No scenario document must be defined for this usage case. This is a built in mechanism and it can be requested to the B2B Logic by specifying the name "top hiding". The functionality is a simple pass through with the creation of a new dialog on the other side and transferring all the messages received on one side to the other side taking care only to change the dialog information.

Scenario Schema

Here is the theoretical expected message trace:

3.2  Prepaid

This scenario can be used by a company for prepaid users to announce them at the beginning of the call what their credit is and at the end of the call what their remaining credit is.

What must happen at session level is:

  1. the caller is connected to a media server
  2. the caller is connected to the callee
  3. if the callee hangs up the phone before the caller, the caller is connected to a media server (the same or other).

Scenario Schema

To establish this sessions the SIP message flow has to look like this( it is assumed that the same media server is used):

Scenario Document

The relevent part of an OpenSIPS config that implements this scenario is shown below:

modparam("b2b_logic", "script_req_route", "b2b_logic_request")

route {
    ...
    if (is_method("INVITE") && !has_totag()) {
        # choose an initial state and save it in context
        $b2b_logic.ctx(state) = "1";
        # save the original destination in context
        $b2b_logic.ctx(callee_uri) = $tu;

        # create the server entity
        b2b_server_new("caller");
        # create the initial client entity, to connect the caller to the media server
        b2b_client_new("media", "sip:808@opensips.org");

        # initialize B2B session for the "prepaid" scenario
        b2b_init_request("prepaid");
        exit;
    }
    ...
}

route[b2b_logic_request] {
    if ($rm != "BYE") {
        # for requests other than BYE, no special actions needs to be done,
        # just pass the request to the peer
        b2b_pass_request();
        exit;
    }

    if ($b2b_logic.ctx(state) == "1" && $b2b_logic.entity(id) == "media") {
        # if we are in the initial state (caller connected to media server)
        # and the BYE is from the media server, we connect the caller with the callee

        # end dialog with the media server
        b2b_send_reply(200, "OK");
        b2b_delete_entity();

        # create the client entity corresponding to the callee
        b2b_client_new("callee", $b2b_logic.ctx(calle_uri));

        # trigger the bridge action
        b2b_bridge("caller", "callee");

        # save the next state in context
        $b2b_logic.ctx(state) = "2";
    } else  if ($b2b_logic.ctx(state) == "2" && $b2b_logic.entity(id) == "callee") {
        # if we are in the second state (caller is connected with the callee)
        # and the callee hanged up first, we connect the caller with the media server again

        # end dialog with the callee
        b2b_send_reply(200, "OK");
        b2b_delete_entity();

        # create a new client entity corresponding to the media server
        b2b_client_new("media_end", "sip:808@opensips.org");

        # trigger the bridging action
        b2b_bridge("caller", "media_end");

        # save the next state in context
        $b2b_logic.ctx(state) = "3";
    } else {
        # a normal BYE request, for which no special scenario action is required,
        # just pass the request to the peer
        b2b_pass_request();
    }
}

3.3  Marketing

The last test case is called “Marketing”, because it suits very well to the requirements of a marketing campaign through phone. The company might choose a list of potential costumers to call and announce about a new product/offer/discount. The message will be a recorded one, but the costumer will also be offered the possibility to talk to a human operator. If the costumer does not hung up the phone before the recorded message ends, it will be connected to a human operator. This is also a good means to filter the interested costumers and make the process more efficient with less resources used.

The OpenSIPS B2BUA must connect two end points, start the call from the middle. It is different from the other examples, since the call is initiated by the B2BUA and it is triggered by a MI command.

Scenario Schema

Below is the theoretical message flow that should occur for this functionality to be achieved.

Scenario Document

The relevent part of an OpenSIPS config that implements this scenario is shown below:

modparam("b2b_logic", "script_req_route", "b2b_logic_request")

route[b2b_logic_request] {
    if ($rm != "BYE") {
        # for requests other than BYE, no special actions needs to be done,
        # just pass the request to the peer
        b2b_pass_request();
        exit;
    }

    if ($b2b_logic.ctx(state) != "2" && $b2b_logic.entity(id) == "media") {
        # if we are in the initial state (customer connected to media server)
        # and the BYE is from the media server, we connect the customer with the operator

         # end dialog with the media server
        b2b_send_reply(200, "OK");
        b2b_delete_entity();

        # create the client entity corresponding to the operator,
        # take the URI of the destination from the context
        b2b_client_new("operator", $b2b_logic.ctx(operator_uri));

        # trigger the bridging action
        b2b_bridge("customer", "operator");

        # save the next state in context
        $b2b_logic.ctx(state) = "2";
    }  else {
        # a normal BYE request, for which no special scenario action is required,
        # just pass the request to the peer
        b2b_pass_request();
    }
}

MI command example:

opensips-cli -x mi b2b_trigger_scenario marketing customer,sip:bob@opensips.org media,sip:808@opensips.org:5070 operator_uri=sip:alice@opensips.org

3.4  REFER Scenario

The B2BUA component can also be configured to handle blind transfers(with REFER SIP message). This is useful when in the platform there are devices that do not accept the REFER method. The scenario for this case is very simple and has one rule for when a REFER is received. This rule tells the B2BUA to end the call with the user agent that sent the refer message and to bridge the peer with the user specified in the 'Refer-To' header.

Scenario Document

The relevent part of an OpenSIPS config that implements this scenario is shown below:

modparam("b2b_logic", "script_req_route", "b2b_logic_request")

route {
    ...
    if (is_method("INVITE") && !has_totag()) {
        # create the server entity
        b2b_server_new("caller");
        # create the initial client entity, to connect the caller with the callee
        b2b_client_new("callee", $ru);

        # initialize B2B session for the "refer" scenario
        b2b_init_request("refer");
        exit;
    }
    ...
}

route[b2b_logic_request] {
    if ($rm != "REFER") {
        # for requests other than REFER, no special actions needs to be done,
        # just pass the request to the peer
        b2b_pass_request();
        exit;
    }

    # end dialog with the referrer
    b2b_send_reply(202, "Accepted");
    b2b_end_dlg_leg();

    # create the client entity corresponding to
    # the user specified in the 'Refer-To' header
    b2b_client_new("referee", $hdr(Refer-To));

    # bridge the referrer's peer with the referee
    b2b_bridge("peer", "referee");
}

Page last modified on January 19, 2023, at 06:12 PM