Skip to content

Latest commit

 

History

History
252 lines (175 loc) · 8.41 KB

registrar.md

File metadata and controls

252 lines (175 loc) · 8.41 KB

Registrar Server Plugin

Name

nksip_registrar

Description

This plugin provides a full registrar server implementation according to RFC3261. Path is also supported, according to RFC3327. It uses by default the built-in, RAM-only store, but can be configured to use any other database implementing callback sip_registrar_store/2. Each started Service activating this plugin maintains a fully independent set of registrations.

Once activated, the following happens:

  • When a new _REGISTER_request arrives, you have two options:
    • Not implementing sip_register/2 in you Service callback function. In this case, the request will be processed automatically.
    • Implementing your own sip_register/. You must inspect the request, and, in case you want it to be process, call request/1

When a new REGISTER request arrives at a Service, and if you order to process the request in sip_route/6 callback, NkSIP will try to call sip_register/2 callback if it is defined in yor Service's callback module. If it is not defined there, NkSIP will process the request automatically. If you implement sip_register/3 to customize the registration process you should call request/1 directly.

Use find/4 or qfind/4 to search for a specific registration's contacts, and is_registered/1 to check if the Request-URI of a specific request is registered.

REGISTER will also be added to all generated Allow headers.

Dependant Plugins

None

Configuration Values

Service configuration values

Option Default Description
sip_registrar_default_time 3600 (1h) Default registration expiration
sip_registrar_min_time 60 (1m) Minimum registration expiration
sip_registrar_max_time 86400 (24h) Maximum registration expiration

API functions

find/2

find(nksip:srv_name()|nksip:srv_id(), nksip:aor() | nksip:uri()) ->
    [nksip:uri()].

Finds the registered contacts for this Service and AOR or Uri, for example nksip_registrar:find(my_app, "sip:user@domain") or nksip_registrar:find("my_other_app", {sip, <<"user">>, <<"domain">>})

find/4

find(nksip:srv_name()|nksip:srv_id(), nksip:scheme(), binary(), binary()) ->
    [nksip:uri()].

Similar to find/2.

qfind/2

qfind(nksip:srv_name()|nksip:srv_id(), AOR::nksip:aor()) ->
    nksip:uri_set().

Gets all current registered contacts for an AOR, aggregated on Q values. You can use this function to generate a parallel and/o serial proxy request. For example, you could implement the following sip_route/6 callback function:

sip_route(Scheme, User, Domain, Req, _Call) -> 
    case Domain of
    	<<"nksip">> when User == <<>> ->
            process;
        <<"nksip">> ->
            case nksip_registrar:qfind(my_registrar, Scheme, User, Domain) of
                [] -> {reply, temporarily_unavailable};
                UriList -> {proxy, UriList, Opts}
            end;
        false ->
            {reply, forbidden}
    end.

Using this example, when a new request arrives at our proxy for domain 'nksip' and having an user, will be forked to all registered contacts, launching in parallel contacts having the same 'q' value.

qfind/4

qfind(nksip:srv_name()|nksip:srv_id(), nksip:scheme(), binary(), binary()) ->
    nksip:uri_set().

Similar to qfind/2

delete/4

delete(nksip:srv_name()|nksip:srv_id(), nksip:scheme(), binary(), binary()) ->
    ok | not_found | callback_error.

Deletes all registered contacts for an AOR.

is_registered/1

is_registered(Req::nksip:request()) ->
    boolean().

Finds if a the request has a From header that has been already registered using the same transport, ip and port, or have a registered Contact header having the same received transport, ip and port.

process/1

request(nksip:request()) ->
    nksip:sipreply().

Call this function to process and incoming REGISTER request. It returns an appropiate response, depending on the registration result. If the Expires_ header is 0, the indicated Contact will be unregistered. If Contact header is *, all previous contacts will be unregistered. The requested Contact will replace a previous registration if it has the same reg-id and +sip_instance values, or has the same transport scheme, protocol, user, domain and port.

If the request is successful, a 200-code nksip:sipreply() is returned, including one or more Contact headers (for all of the current registered contacts), Date and Allow headers.

For example, you could implement the following sip_register/2 callback function:

sip_register(Req, _Call) ->
	case nksip_request:meta(domain, Req) of
		{ok, <<"nksip">>} -> {reply, nksip_registrar:process(Req)};
		_ -> {reply, forbidden}
	end.

Callback functions

You can implement any of these callback functions in your Service callback module.

sip_registrar_store/2

sip_registrar_store(StoreOp, AppId) ->
    [RegContact] | ok | not_found when 
        StoreOp :: {get, AOR} | {put, AOR, [RegContact], TTL} | 
                   {del, AOR} | del_all,
        AppId :: nksip:srv_id(),
        AOR :: nksip:aor(),
        RegContact :: nksip_registrar_lib:reg_contact(),
        TTL :: integer().

Called when a operation database must be done on the registrar database. By default the in-memory database is used, but you can impement it to use your own database.

Op Response Comments
{get, AOR} [RegContact] Retrieve all stored contacts for this AOR and AppId.
{put, AOR, [RegContact], TTL} ok Store the list of contacts for this AOR and AppId. The record must be automatically deleted after TTL seconds.
{del, AOR} ok | not_found Delete all stored contacts for this AOR and AppIdp, returning ok or not_found if the AOR is not found.
del_all ok Delete all stored information for this AppId.

See the default implementation as a basis.

Examples

-module(example).
-compile([export_all]).

-include_lib("nksip/include/nksip.hrl").


start() ->
    {ok, _} = nksip:start(server, [
        {sip_from, "sip:server@nksip"},
        {sip_registrar_min_time, 60},
        {plugins, [nksip_registrar]},
        {sip_listen, "sip:all:5060, sips:all:5061"}
    ]),
    {ok, _} = nksip:start(client, ?MODULE, [], [
        {sip_from, "sip:client@nksip"},
        {sip_local_host, "127.0.0.1"},
        {sip_listen, "sip:all:5070, sips:all:5071"}
    ]).

stop() ->
    ok = nksip:stop(server),
    ok = nksip:stop(client).


test1() ->
    {ok, 200, []} = nksip_uac:register(client, "sip:127.0.0.1", [unregister_all]),
    [] = nksip_registrar:find(server, sip, <<"client">>, <<"nksip">>),
    
    {ok, 200, []} = nksip_uac:register(client, "sip:127.0.0.1", [contact]),
    [
        #uri{
            user = <<"client">>,
            domain = <<"127.0.0.1">>,
            port = 5070
        }
    ] = nksip_registrar:find(server, sip, "client", "nksip"),
    {ok, 200, []} = nksip_uac:register(client, "sip:127.0.0.1", [unregister_all]),
    [] = nksip_registrar:find(server, sip, <<"client">>, <<"nksip">>),
    ok.



%%%%%%%%%%%%%%%%%%%%%%%  CallBacks (servers and clients) %%%%%%%%%%%%%%%%%%%%%


sip_route(Scheme, User, Domain, Req, _Call) ->
    case nksip_request:srv_name(Req) of
        {ok, server} ->
            Opts = [record_route, {insert, "x-nk-server", "server"}],
            case lists:member(Domain, [<<"nksip">>, <<"127.0.0.1">>]) of
                true when User =:= <<>> ->
                    process;
                true when Domain =:= <<"nksip">> ->
                    case nksip_registrar:find(server, Scheme, User, Domain) of
                        [] -> {reply, temporarily_unavailable};
                        UriList -> {proxy, UriList, Opts}
                    end;
                _ ->
                    {proxy, ruri, Opts}
            end;
        {ok, client} ->
            process
    end.