Process bindings from multiple UACs correctly

This commit is contained in:
Evgeniy Khramtsov 2014-05-31 09:06:28 +04:00
parent da22da23cd
commit 86f2af6fdc
1 changed files with 41 additions and 40 deletions

View File

@ -85,17 +85,9 @@ request(#sip{hdrs = Hdrs} = Req, SIPSock) ->
case register_session(US, SIPSock, CallID, CSeq, case register_session(US, SIPSock, CallID, CSeq,
ContactsWithExpires) of ContactsWithExpires) of
{ok, Res} -> {ok, Res} ->
if Res == updated -> ?INFO_MSG("~s SIP session for user ~s@~s from ~s",
?INFO_MSG("register SIP session for user " [Res, LUser, LServer,
"~s@~s from ~s", inet_parse:ntoa(PeerIP)]),
[LUser, LServer,
inet_parse:ntoa(PeerIP)]);
Res == deleted ->
?INFO_MSG("unregister SIP session for user "
"~s@~s from ~s",
[LUser, LServer,
inet_parse:ntoa(PeerIP)])
end,
Cs = prepare_contacts_to_send(ContactsWithExpires), Cs = prepare_contacts_to_send(ContactsWithExpires),
mod_sip:make_response( mod_sip:make_response(
Req, Req,
@ -219,48 +211,57 @@ write_session(#sip_session{us = {U, S} = US, bindings = NewBindings}) ->
Err; Err;
(#binding{call_id = CallID, (#binding{call_id = CallID,
expires = Expires, expires = Expires,
cseq = CSeq} = Binding, {Add, Del}) -> cseq = CSeq} = Binding, {Add, Keep, Del}) ->
case find_binding(Binding, PrevBindings) of case find_binding(Binding, PrevBindings) of
{ok, #binding{call_id = CallID, cseq = PrevCSeq}} {ok, #binding{call_id = CallID, cseq = PrevCSeq}}
when PrevCSeq > CSeq -> when PrevCSeq > CSeq ->
{error, cseq_out_of_order}; {error, cseq_out_of_order};
{ok, PrevBinding} when Expires == 0 -> {ok, PrevBinding} when Expires == 0 ->
{Add, [PrevBinding|Del]}; {Add, Keep -- [PrevBinding], [PrevBinding|Del]};
{ok, _} -> {ok, PrevBinding} ->
{[Binding|Add], Del}; {[Binding|Add], Keep -- [PrevBinding], Del};
{error, notfound} when Expires == 0 -> {error, notfound} when Expires == 0 ->
{error, notfound}; {error, notfound};
{error, notfound} -> {error, notfound} ->
{[Binding|Add], Del} {[Binding|Add], Keep, Del}
end end
end, {[], []}, NewBindings), end, {[], PrevBindings, []}, NewBindings),
MaxSessions = ejabberd_sm:get_max_user_sessions(U, S), MaxSessions = ejabberd_sm:get_max_user_sessions(U, S),
case Res of case Res of
{error, Why} -> {error, Why} ->
{error, Why}; {error, Why};
{AddBindings, _} when length(AddBindings) > MaxSessions -> {AddBindings, KeepBindings, DelBindings} ->
{error, too_many_sessions}; MaxSessions = ejabberd_sm:get_max_user_sessions(U, S),
{AddBindings, DelBindings} -> AllBindings = AddBindings ++ KeepBindings,
lists:foreach( if length(AllBindings) > MaxSessions ->
fun(#binding{tref = TRef}) -> {error, too_many_sessions};
erlang:cancel_timer(TRef) true ->
end, DelBindings), lists:foreach(
Bindings = lists:map( fun(#binding{tref = TRef}) ->
fun(#binding{tref = TRef, erlang:cancel_timer(TRef)
expires = Expires} = Binding) -> end, DelBindings),
erlang:cancel_timer(TRef), AddBindings1 = lists:map(
NewTRef = erlang:start_timer( fun(#binding{tref = TRef,
Expires * 1000, self(), US), expires = Expires} = Binding) ->
Binding#binding{tref = NewTRef} erlang:cancel_timer(TRef),
end, AddBindings), NewTRef = erlang:start_timer(
case Bindings of Expires * 1000, self(), US),
[] -> Binding#binding{tref = NewTRef}
mnesia:dirty_delete(sip_session, US), end, AddBindings),
{ok, deleted}; AllBindings1 = AddBindings1 ++ KeepBindings,
_ -> case AllBindings1 of
mnesia:dirty_write( [] ->
#sip_session{us = US, bindings = Bindings}), mnesia:dirty_delete(sip_session, US),
{ok, updated} {ok, unregister};
_ ->
mnesia:dirty_write(
#sip_session{us = US, bindings = AllBindings1}),
if length(DelBindings) == length(NewBindings) ->
{ok, unregister};
true ->
{ok, register}
end
end
end end
end. end.