diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ejabberd_c2s.erl | 24 | ||||
-rw-r--r-- | src/ejabberd_odbc.erl | 2 | ||||
-rw-r--r-- | src/mod_sip.erl | 21 | ||||
-rw-r--r-- | src/mod_sip_proxy.erl | 54 | ||||
-rw-r--r-- | src/mod_sip_registrar.erl | 7 |
5 files changed, 78 insertions, 30 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 1076eb895..6aebefdd6 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1170,8 +1170,7 @@ session_established({xmlstreamerror, _}, StateData) -> {stop, normal, StateData}; session_established(closed, StateData) when StateData#state.mgmt_timeout > 0, - StateData#state.mgmt_state == active orelse - StateData#state.mgmt_state == pending -> + StateData#state.mgmt_state == active -> log_pending_state(StateData), fsm_next_state(wait_for_resume, StateData#state{mgmt_state = pending}); session_established(closed, StateData) -> @@ -1312,8 +1311,8 @@ handle_sync_event(get_subscribed, _From, StateName, StateData) -> Subscribed = (?SETS):to_list(StateData#state.pres_f), {reply, Subscribed, StateName, StateData}; -handle_sync_event(resume_session, _From, _StateName, - StateData) -> +handle_sync_event({resume_session, Time}, _From, _StateName, + StateData) when element(1, StateData#state.sid) == Time -> %% The old session should be closed before the new one is opened, so we do %% this here instead of leaving it to the terminate callback ejabberd_sm:close_session(StateData#state.sid, @@ -1321,6 +1320,9 @@ handle_sync_event(resume_session, _From, _StateName, StateData#state.server, StateData#state.resource), {stop, normal, {ok, StateData}, StateData#state{mgmt_state = resumed}}; +handle_sync_event({resume_session, _Time}, _From, StateName, + StateData) -> + {reply, {error, <<"Previous session not found">>}, StateName, StateData}; handle_sync_event(_Event, _From, StateName, StateData) -> Reply = ok, fsm_reply(Reply, StateName, StateData). @@ -1373,7 +1375,6 @@ handle_info({route, _From, _To, {broadcast, Data}}, fsm_next_state(StateName, StateData); NewPL -> PrivPushIQ = #iq{type = set, - xmlns = ?NS_PRIVACY, id = <<"push", (randoms:get_string())/binary>>, sub_el = @@ -2549,8 +2550,7 @@ route_blocking(What, StateData) -> #xmlel{name = <<"unblock">>, attrs = [{<<"xmlns">>, ?NS_BLOCKING}], children = []} end, - PrivPushIQ = #iq{type = set, xmlns = ?NS_BLOCKING, - id = <<"push">>, sub_el = [SubEl]}, + PrivPushIQ = #iq{type = set, id = <<"push">>, sub_el = [SubEl]}, PrivPushEl = jlib:replace_from_to(jlib:jid_remove_resource(StateData#state.jid), StateData#state.jid, jlib:iq_to_xml(PrivPushIQ)), @@ -2902,8 +2902,8 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) -> {error, <<"Previous session PID not found">>}; OldPID -> OldSID = {Time, OldPID}, - case catch resume_session(OldPID) of - {ok, #state{sid = OldSID} = OldStateData} -> + case catch resume_session(OldSID) of + {ok, OldStateData} -> NewSID = {Time, self()}, % Old time, new PID Priority = case OldStateData#state.pres_last of undefined -> @@ -2935,6 +2935,8 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) -> mgmt_stanzas_in = OldStateData#state.mgmt_stanzas_in, mgmt_stanzas_out = OldStateData#state.mgmt_stanzas_out, mgmt_state = active}}; + {error, Msg} -> + {error, Msg}; _ -> {error, <<"Cannot grab session state">>} end @@ -2943,8 +2945,8 @@ inherit_session_state(#state{user = U, server = S} = StateData, ResumeID) -> {error, <<"Invalid 'previd' value">>} end. -resume_session(FsmRef) -> - (?GEN_FSM):sync_send_all_state_event(FsmRef, resume_session, 3000). +resume_session({Time, PID}) -> + (?GEN_FSM):sync_send_all_state_event(PID, {resume_session, Time}, 3000). make_resume_id(StateData) -> {Time, _} = StateData#state.sid, diff --git a/src/ejabberd_odbc.erl b/src/ejabberd_odbc.erl index 2b852bfaa..49a4f30b4 100644 --- a/src/ejabberd_odbc.erl +++ b/src/ejabberd_odbc.erl @@ -588,7 +588,7 @@ db_opts(Host) -> [odbc, Server]; _ -> Port = ejabberd_config:get_option( - {port, Host}, + {odbc_port, Host}, fun(P) when is_integer(P), P > 0, P < 65536 -> P end, case Type of mysql -> ?MYSQL_PORT; diff --git a/src/mod_sip.erl b/src/mod_sip.erl index 8ed4ed8cf..4b733c623 100644 --- a/src/mod_sip.erl +++ b/src/mod_sip.erl @@ -12,7 +12,7 @@ -behaviour(esip). %% API --export([start/2, stop/1, prepare_request/1, make_response/2, at_my_host/1]). +-export([start/2, stop/1, make_response/2, is_my_host/1, at_my_host/1]). %% esip_callbacks -export([data_in/2, data_out/2, message_in/2, message_out/2, @@ -77,6 +77,13 @@ message_out(_, _) -> response(_Resp, _SIPSock) -> ok. +request(#sip{method = <<"ACK">>} = Req, SIPSock) -> + case action(Req, SIPSock) of + {relay, LServer} -> + mod_sip_proxy:route(Req, LServer, []); + _ -> + error + end; request(_Req, _SIPSock) -> error. @@ -251,18 +258,6 @@ process(Req, _) -> make_response(Req, #sip{type = response, status = 405, hdrs = [{'allow', allow()}]}). -prepare_request(#sip{hdrs = Hdrs1} = Req) -> - MF = esip:get_hdr('max-forwards', Hdrs1), - Hdrs2 = esip:set_hdr('max-forwards', MF-1, Hdrs1), - Hdrs3 = lists:filter( - fun({'proxy-authorization', {_, Params}}) -> - Realm = esip:unquote(esip:get_param(<<"realm">>, Params)), - not is_my_host(jlib:nameprep(Realm)); - (_) -> - true - end, Hdrs2), - Req#sip{hdrs = Hdrs3}. - make_auth_hdr(LServer) -> Realm = jlib:nameprep(LServer), {<<"Digest">>, [{<<"realm">>, esip:quote(Realm)}, diff --git a/src/mod_sip_proxy.erl b/src/mod_sip_proxy.erl index cae75bff8..b05c49061 100644 --- a/src/mod_sip_proxy.erl +++ b/src/mod_sip_proxy.erl @@ -12,7 +12,7 @@ -behaviour(?GEN_FSM). %% API --export([start/2, start_link/2, route/4]). +-export([start/2, start_link/2, route/3, route/4]). %% gen_fsm callbacks -export([init/1, wait_for_request/2, wait_for_response/2, @@ -42,6 +42,19 @@ start_link(LServer, Opts) -> route(SIPMsg, _SIPSock, TrID, Pid) -> ?GEN_FSM:send_event(Pid, {SIPMsg, TrID}). +route(Req, LServer, Opts) -> + Req1 = prepare_request(LServer, Req), + case connect(Req1, add_certfile(LServer, Opts)) of + {ok, SIPSockets} -> + lists:foreach( + fun(SIPSocket) -> + Req2 = add_via(SIPSocket, LServer, Req1), + esip:send(SIPSocket, Req2) + end, SIPSockets); + _ -> + error + end. + %%%=================================================================== %%% gen_fsm callbacks %%%=================================================================== @@ -51,7 +64,7 @@ init([Host, Opts]) -> wait_for_request({#sip{type = request} = Req, TrID}, State) -> Opts = State#state.opts, - Req1 = mod_sip:prepare_request(Req), + Req1 = prepare_request(State#state.host, Req), case connect(Req1, Opts) of {ok, SIPSockets} -> NewState = @@ -59,8 +72,9 @@ wait_for_request({#sip{type = request} = Req, TrID}, State) -> fun(_SIPSocket, {error, _} = Err) -> Err; (SIPSocket, #state{tr_ids = TrIDs} = AccState) -> - Req2 = add_via(SIPSocket, State#state.host, Req1), - case esip:request(SIPSocket, Req2, + Req2 = add_record_route(SIPSocket, State#state.host, Req1), + Req3 = add_via(SIPSocket, State#state.host, Req2), + case esip:request(SIPSocket, Req3, {?MODULE, route, [self()]}) of {ok, ClientTrID} -> NewTrIDs = [ClientTrID|TrIDs], @@ -234,6 +248,11 @@ add_via(#sip_socket{type = Transport}, LServer, #sip{hdrs = Hdrs} = Req) -> {<<"rport">>, <<"">>}]}, Req#sip{hdrs = [{'via', [Via]}|Hdrs]}. +add_record_route(_SIPSocket, LServer, #sip{hdrs = Hdrs} = Req) -> + URI = #uri{host = LServer, params = [{<<"lr">>, <<"">>}]}, + Hdrs1 = [{'record-route', [{<<>>, URI, []}]}|Hdrs], + Req#sip{hdrs = Hdrs1}. + get_configured_vias(LServer) -> gen_mod:get_module_opt( LServer, ?MODULE, via, @@ -275,3 +294,30 @@ choose_best_response(#state{responses = Responses} = State) -> ok end end. + +prepare_request(Host, #sip{hdrs = Hdrs} = Req) -> + Hdrs1 = lists:flatmap( + fun({Hdr, HdrList}) when Hdr == 'route'; + Hdr == 'record-route' -> + case lists:filter( + fun({_, #uri{user = <<"">>, host = Host1}, _}) -> + Host1 /= Host + end, HdrList) of + [] -> + []; + HdrList1 -> + [{Hdr, HdrList1}] + end; + (Hdr) -> + [Hdr] + end, Hdrs), + MF = esip:get_hdr('max-forwards', Hdrs1), + Hdrs2 = esip:set_hdr('max-forwards', MF-1, Hdrs1), + Hdrs3 = lists:filter( + fun({'proxy-authorization', {_, Params}}) -> + Realm = esip:unquote(esip:get_param(<<"realm">>, Params)), + not mod_sip:is_my_host(jlib:nameprep(Realm)); + (_) -> + true + end, Hdrs2), + Req#sip{hdrs = Hdrs3}. diff --git a/src/mod_sip_registrar.erl b/src/mod_sip_registrar.erl index 57c55be08..689efe48e 100644 --- a/src/mod_sip_registrar.erl +++ b/src/mod_sip_registrar.erl @@ -57,8 +57,13 @@ request(#sip{hdrs = Hdrs} = Req, SIPSock) -> ok -> ?INFO_MSG("unregister SIP session for user ~s@~s from ~s", [LUser, LServer, inet_parse:ntoa(PeerIP)]), + Contact = {<<"">>, #uri{user = LUser, host = LServer}, + [{<<"expires">>, <<"0">>}]}, mod_sip:make_response( - Req, #sip{type = response, status = 200}); + Req, + #sip{type = response, + status = 200, + hdrs = [{'contact', [Contact]}]}); {error, Why} -> {Status, Reason} = make_status(Why), mod_sip:make_response( |