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
- Not implementing
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.
None
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 |
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(nksip:srv_name()|nksip:srv_id(), nksip:scheme(), binary(), binary()) ->
[nksip:uri()].
Similar to find/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(nksip:srv_name()|nksip:srv_id(), nksip:scheme(), binary(), binary()) ->
nksip:uri_set().
Similar to qfind/2
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(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.
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.
You can implement any of these callback functions in your Service callback module.
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.
-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.