diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl index 7cfb68d7a..907bdd65a 100644 --- a/src/ejabberd_s2s_out.erl +++ b/src/ejabberd_s2s_out.erl @@ -44,6 +44,7 @@ wait_for_features/2, wait_for_auth_result/2, wait_for_starttls_proceed/2, + relay_to_bridge/2, reopen_socket/2, wait_before_retry/2, stream_established/2, @@ -72,6 +73,7 @@ myname, server, queue, delay_to_retry = undefined_delay, new = false, verify = false, + bridge, timer}). %%-define(DBGFSM, true). @@ -228,8 +230,19 @@ open_socket(init, StateData) -> {error, _Reason} -> ?INFO_MSG("s2s connection: ~s -> ~s (remote server not found)", [StateData#state.myname, StateData#state.server]), - wait_before_reconnect(StateData) - %%{stop, normal, StateData} + case ejabberd_hooks:run_fold(find_s2s_bridge, + undefined, + [StateData#state.myname, + StateData#state.server]) of + {Mod, Fun, Type} -> + ?INFO_MSG("found a bridge to ~s for: ~s -> ~s", + [Type, StateData#state.myname, + StateData#state.server]), + NewStateData = StateData#state{bridge={Mod, Fun}}, + {next_state, relay_to_bridge, NewStateData}; + _ -> + wait_before_reconnect(StateData) + end end; open_socket(stop, StateData) -> ?INFO_MSG("s2s connection: ~s -> ~s (stopped in open socket)", @@ -677,6 +690,15 @@ reopen_socket(closed, StateData) -> wait_before_retry(_Event, StateData) -> {next_state, wait_before_retry, StateData, ?FSMTIMEOUT}. +relay_to_bridge(stop, StateData) -> + wait_before_reconnect(StateData); +relay_to_bridge(closed, StateData) -> + ?INFO_MSG("relay to bridge: ~s -> ~s (closed)", + [StateData#state.myname, StateData#state.server]), + {stop, normal, StateData}; +relay_to_bridge(_Event, StateData) -> + {next_state, relay_to_bridge, StateData}. + stream_established({xmlstreamelement, El}, StateData) -> ?DEBUG("s2S stream established", []), case is_verify_res(El) of @@ -827,6 +849,19 @@ handle_info({send_element, El}, StateName, StateData) -> wait_before_retry -> bounce_element(El, ?ERR_REMOTE_SERVER_NOT_FOUND), {next_state, StateName, StateData}; + relay_to_bridge -> + %% In this state we relay all outbound messages + %% to a foreign protocol bridge such as SMTP, SIP, etc. + {Mod, Fun} = StateData#state.bridge, + ?DEBUG("relaying stanza via ~p:~p/1", [Mod, Fun]), + case catch Mod:Fun(El) of + {'EXIT', Reason} -> + ?ERROR_MSG("Error while relaying to bridge: ~p", [Reason]), + bounce_element(El, ?ERR_INTERNAL_SERVER_ERROR), + wait_before_reconnect(StateData); + _ -> + {next_state, StateName, StateData} + end; _ -> Q = queue:in(El, StateData#state.queue), {next_state, StateName, StateData#state{queue = Q},