mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-26 17:38:45 +01:00
Forking support
This commit is contained in:
parent
f8417f7c1f
commit
ebd760b7c9
@ -26,8 +26,9 @@
|
|||||||
-record(state, {host = <<"">> :: binary(),
|
-record(state, {host = <<"">> :: binary(),
|
||||||
opts = [] :: [{certfile, binary()}],
|
opts = [] :: [{certfile, binary()}],
|
||||||
orig_trid,
|
orig_trid,
|
||||||
orig_req :: #sip{},
|
responses = [] :: [#sip{}],
|
||||||
client_trid}).
|
tr_ids = [] :: list(),
|
||||||
|
orig_req :: #sip{}}).
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
@ -56,21 +57,34 @@ wait_for_request({#sip{type = request} = Req, TrID}, State) ->
|
|||||||
Opts = State#state.opts,
|
Opts = State#state.opts,
|
||||||
Req1 = mod_sip:prepare_request(Req),
|
Req1 = mod_sip:prepare_request(Req),
|
||||||
case connect(Req1, Opts) of
|
case connect(Req1, Opts) of
|
||||||
{ok, SIPSocket} ->
|
{ok, SIPSockets} ->
|
||||||
|
NewState =
|
||||||
|
lists:foldl(
|
||||||
|
fun(_SIPSocket, {error, _} = Err) ->
|
||||||
|
Err;
|
||||||
|
(SIPSocket, #state{tr_ids = TrIDs} = AccState) ->
|
||||||
Req2 = add_via(SIPSocket, State#state.host, Req1),
|
Req2 = add_via(SIPSocket, State#state.host, Req1),
|
||||||
case esip:request(SIPSocket, Req2, {?MODULE, route, [self()]}) of
|
case esip:request(SIPSocket, Req2,
|
||||||
|
{?MODULE, route, [self()]}) of
|
||||||
{ok, ClientTrID} ->
|
{ok, ClientTrID} ->
|
||||||
{next_state, wait_for_response,
|
NewTrIDs = [ClientTrID|TrIDs],
|
||||||
State#state{orig_trid = TrID,
|
AccState#state{tr_ids = NewTrIDs};
|
||||||
orig_req = Req,
|
|
||||||
client_trid = ClientTrID}};
|
|
||||||
Err ->
|
Err ->
|
||||||
|
cancel_pending_transactions(AccState),
|
||||||
|
Err
|
||||||
|
end
|
||||||
|
end, State, SIPSockets),
|
||||||
|
case NewState of
|
||||||
|
{error, _} = Err ->
|
||||||
{Status, Reason} = esip:error_status(Err),
|
{Status, Reason} = esip:error_status(Err),
|
||||||
esip:reply(TrID, mod_sip:make_response(
|
esip:reply(TrID, mod_sip:make_response(
|
||||||
Req, #sip{type = response,
|
Req, #sip{type = response,
|
||||||
status = Status,
|
status = Status,
|
||||||
reason = Reason})),
|
reason = Reason})),
|
||||||
{stop, normal, State}
|
{stop, normal, State};
|
||||||
|
_ ->
|
||||||
|
{next_state, wait_for_response,
|
||||||
|
NewState#state{orig_req = Req, orig_trid = TrID}}
|
||||||
end;
|
end;
|
||||||
{error, notfound} ->
|
{error, notfound} ->
|
||||||
esip:reply(TrID, mod_sip:make_response(
|
esip:reply(TrID, mod_sip:make_response(
|
||||||
@ -90,40 +104,67 @@ wait_for_request(_Event, State) ->
|
|||||||
{next_state, wait_for_request, State}.
|
{next_state, wait_for_request, State}.
|
||||||
|
|
||||||
wait_for_response({#sip{method = <<"CANCEL">>, type = request}, _TrID}, State) ->
|
wait_for_response({#sip{method = <<"CANCEL">>, type = request}, _TrID}, State) ->
|
||||||
esip:cancel(State#state.client_trid),
|
cancel_pending_transactions(State),
|
||||||
{next_state, wait_for_response, State};
|
{next_state, wait_for_response, State};
|
||||||
wait_for_response({Resp, _TrID}, State) ->
|
wait_for_response({Resp, TrID},
|
||||||
|
#state{orig_req = #sip{method = Method} = Req} = State) ->
|
||||||
case Resp of
|
case Resp of
|
||||||
{error, _} ->
|
{error, timeout} when Method /= <<"INVITE">> ->
|
||||||
Req = State#state.orig_req,
|
|
||||||
{Status, Reason} = esip:error_status(Resp),
|
|
||||||
case Status of
|
|
||||||
408 when Req#sip.method /= <<"INVITE">> ->
|
|
||||||
%% Absorb useless 408. See RFC4320
|
%% Absorb useless 408. See RFC4320
|
||||||
esip:stop_transaction(State#state.orig_trid);
|
choose_best_response(State),
|
||||||
_ ->
|
esip:stop_transaction(State#state.orig_trid),
|
||||||
ErrResp = mod_sip:make_response(
|
{stop, normal, State};
|
||||||
Req,
|
{error, _} ->
|
||||||
|
{Status, Reason} = esip:error_status(Resp),
|
||||||
|
State1 = mark_transaction_as_complete(TrID, State),
|
||||||
|
SIPResp = mod_sip:make_response(Req,
|
||||||
#sip{type = response,
|
#sip{type = response,
|
||||||
status = Status,
|
status = Status,
|
||||||
reason = Reason}),
|
reason = Reason}),
|
||||||
esip:reply(State#state.orig_trid, ErrResp)
|
State2 = collect_response(SIPResp, State1),
|
||||||
end,
|
case State2#state.tr_ids of
|
||||||
{stop, normal, State};
|
[] ->
|
||||||
|
choose_best_response(State2),
|
||||||
|
{stop, normal, State2};
|
||||||
|
_ ->
|
||||||
|
{next_state, wait_for_response, State2}
|
||||||
|
end;
|
||||||
#sip{status = 100} ->
|
#sip{status = 100} ->
|
||||||
{next_state, wait_for_response, State};
|
{next_state, wait_for_response, State};
|
||||||
#sip{status = Status} ->
|
#sip{status = Status} ->
|
||||||
case esip:split_hdrs('via', Resp#sip.hdrs) of
|
{[_|Vias], NewHdrs} = esip:split_hdrs('via', Resp#sip.hdrs),
|
||||||
{[_], _} ->
|
NewResp = case Vias of
|
||||||
{stop, normal, State};
|
[] ->
|
||||||
{[_|Vias], NewHdrs} ->
|
Resp#sip{hdrs = NewHdrs};
|
||||||
esip:reply(State#state.orig_trid,
|
_ ->
|
||||||
Resp#sip{hdrs = [{'via', Vias}|NewHdrs]}),
|
Resp#sip{hdrs = [{'via', Vias}|NewHdrs]}
|
||||||
if Status < 200 ->
|
end,
|
||||||
{next_state, wait_for_response, State};
|
if Status < 300 ->
|
||||||
|
esip:reply(State#state.orig_trid, NewResp);
|
||||||
true ->
|
true ->
|
||||||
{stop, normal, State}
|
ok
|
||||||
end
|
end,
|
||||||
|
State1 = if Status >= 200 ->
|
||||||
|
mark_transaction_as_complete(TrID, State);
|
||||||
|
true ->
|
||||||
|
State
|
||||||
|
end,
|
||||||
|
State2 = if Status >= 300 ->
|
||||||
|
collect_response(NewResp, State1);
|
||||||
|
true ->
|
||||||
|
State1
|
||||||
|
end,
|
||||||
|
if Status >= 600 ->
|
||||||
|
cancel_pending_transactions(State2);
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
|
case State2#state.tr_ids of
|
||||||
|
[] ->
|
||||||
|
choose_best_response(State2),
|
||||||
|
{stop, normal, State2};
|
||||||
|
_ ->
|
||||||
|
{next_state, wait_for_response, State2}
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
wait_for_response(_Event, State) ->
|
wait_for_response(_Event, State) ->
|
||||||
@ -155,15 +196,23 @@ connect(#sip{hdrs = Hdrs} = Req, Opts) ->
|
|||||||
LUser = jlib:nodeprep(ToURI#uri.user),
|
LUser = jlib:nodeprep(ToURI#uri.user),
|
||||||
LServer = jlib:nameprep(ToURI#uri.host),
|
LServer = jlib:nameprep(ToURI#uri.host),
|
||||||
case mod_sip_registrar:find_sockets(LUser, LServer) of
|
case mod_sip_registrar:find_sockets(LUser, LServer) of
|
||||||
[SIPSock|_] ->
|
[_|_] = SIPSocks ->
|
||||||
{ok, SIPSock};
|
{ok, SIPSocks};
|
||||||
[] ->
|
[] ->
|
||||||
{error, notfound}
|
{error, notfound}
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
esip:connect(Req, Opts)
|
case esip:connect(Req, Opts) of
|
||||||
|
{ok, SIPSock} ->
|
||||||
|
{ok, [SIPSock]};
|
||||||
|
{error, _} = Err ->
|
||||||
|
Err
|
||||||
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
cancel_pending_transactions(State) ->
|
||||||
|
lists:foreach(fun esip:cancel/1, State#state.tr_ids).
|
||||||
|
|
||||||
add_certfile(LServer, Opts) ->
|
add_certfile(LServer, Opts) ->
|
||||||
case ejabberd_config:get_option({domain_certfile, LServer},
|
case ejabberd_config:get_option({domain_certfile, LServer},
|
||||||
fun iolist_to_binary/1) of
|
fun iolist_to_binary/1) of
|
||||||
@ -206,3 +255,27 @@ get_configured_vias(LServer) ->
|
|||||||
{Type, {Host, Port}}
|
{Type, {Host, Port}}
|
||||||
end, L)
|
end, L)
|
||||||
end, []).
|
end, []).
|
||||||
|
|
||||||
|
mark_transaction_as_complete(TrID, State) ->
|
||||||
|
NewTrIDs = lists:delete(TrID, State#state.tr_ids),
|
||||||
|
State#state{tr_ids = NewTrIDs}.
|
||||||
|
|
||||||
|
collect_response(Resp, #state{responses = Resps} = State) ->
|
||||||
|
State#state{responses = [Resp|Resps]}.
|
||||||
|
|
||||||
|
choose_best_response(#state{responses = Responses} = State) ->
|
||||||
|
SortedResponses = lists:keysort(#sip.status, Responses),
|
||||||
|
case lists:filter(
|
||||||
|
fun(#sip{status = Status}) ->
|
||||||
|
Status >= 600
|
||||||
|
end, SortedResponses) of
|
||||||
|
[Resp|_] ->
|
||||||
|
esip:reply(State#state.orig_trid, Resp);
|
||||||
|
[] ->
|
||||||
|
case SortedResponses of
|
||||||
|
[Resp|_] ->
|
||||||
|
esip:reply(State#state.orig_trid, Resp);
|
||||||
|
[] ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
Loading…
Reference in New Issue
Block a user