aboutsummaryrefslogtreecommitdiff
path: root/src/ejabberd_router.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ejabberd_router.erl')
-rw-r--r--src/ejabberd_router.erl268
1 files changed, 168 insertions, 100 deletions
diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl
index 4fd85f2c9..20f0c998c 100644
--- a/src/ejabberd_router.erl
+++ b/src/ejabberd_router.erl
@@ -10,6 +10,9 @@
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
+-behaviour(gen_server).
+
+%% API
-export([route/3,
register_route/1,
register_route/2,
@@ -20,114 +23,28 @@
dirty_get_all_domains/0
]).
--export([start_link/0, init/0]).
+-export([start_link/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-record(route, {domain, pid, local_hint}).
+-record(state, {}).
-
+%%====================================================================
+%% API
+%%====================================================================
+%%--------------------------------------------------------------------
+%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+%% Description: Starts the server
+%%--------------------------------------------------------------------
start_link() ->
- update_tables(),
- mnesia:create_table(route,
- [{ram_copies, [node()]},
- {type, bag},
- {attributes,
- record_info(fields, route)}]),
- mnesia:add_table_copy(route, node(), ram_copies),
- Pid = proc_lib:spawn_link(ejabberd_router, init, []),
- register(ejabberd_router, Pid),
- {ok, Pid}.
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-init() ->
- mnesia:subscribe({table, route, simple}),
- lists:foreach(
- fun(Pid) ->
- erlang:monitor(process, Pid)
- end,
- mnesia:dirty_select(route, [{{route, '_', '$1', '_'}, [], ['$1']}])),
- loop().
-
-loop() ->
- receive
- {route, From, To, Packet} ->
- case catch do_route(From, To, Packet) of
- {'EXIT', Reason} ->
- ?ERROR_MSG("~p~nwhen processing: ~p",
- [Reason, {From, To, Packet}]);
- _ ->
- ok
- end,
- loop();
- {mnesia_table_event, {write, #route{pid = Pid}, _ActivityId}} ->
- erlang:monitor(process, Pid),
- loop();
- {'DOWN', _Ref, _Type, Pid, _Info} ->
- F = fun() ->
- Es = mnesia:select(
- route,
- [{#route{pid = Pid, _ = '_'},
- [],
- ['$_']}]),
- lists:foreach(fun(E) ->
- mnesia:delete_object(E)
- end, Es)
- end,
- mnesia:transaction(F),
- loop();
- _ ->
- loop()
- end.
-
-do_route(OrigFrom, OrigTo, OrigPacket) ->
- ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket ~p~n",
- [OrigFrom, OrigTo, OrigPacket]),
- LOrigDstDomain = OrigTo#jid.lserver,
- case ejabberd_hooks:run_fold(filter_packet, LOrigDstDomain,
- {OrigFrom, OrigTo, OrigPacket}, []) of
- {From, To, Packet} ->
- LDstDomain = To#jid.lserver,
- case mnesia:dirty_read(route, LDstDomain) of
- [] ->
- ejabberd_s2s:route(From, To, Packet);
- [R] ->
- Pid = R#route.pid,
- if
- node(Pid) == node() ->
- case R#route.local_hint of
- {apply, Module, Function} ->
- Module:Function(From, To, Packet);
- _ ->
- Pid ! {route, From, To, Packet}
- end;
- true ->
- Pid ! {route, From, To, Packet}
- end;
- Rs ->
- case [R || R <- Rs, node(R#route.pid) == node()] of
- [] ->
- R = lists:nth(erlang:phash(now(), length(Rs)), Rs),
- Pid = R#route.pid,
- Pid ! {route, From, To, Packet};
- LRs ->
- LRs,
- R = lists:nth(erlang:phash(now(), length(LRs)), LRs),
- Pid = R#route.pid,
- case R#route.local_hint of
- {apply, Module, Function} ->
- Module:Function(From, To, Packet);
- _ ->
- Pid ! {route, From, To, Packet}
- end
- end
- end;
- drop ->
- ok
- end.
-
-%route(From, To, Packet) ->
-% ejabberd_router ! {route, From, To, Packet}.
route(From, To, Packet) ->
case catch do_route(From, To, Packet) of
@@ -196,6 +113,157 @@ dirty_get_all_domains() ->
lists:usort(mnesia:dirty_all_keys(route)).
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([]) ->
+ update_tables(),
+ mnesia:create_table(route,
+ [{ram_copies, [node()]},
+ {type, bag},
+ {attributes,
+ record_info(fields, route)}]),
+ mnesia:add_table_copy(route, node(), ram_copies),
+ mnesia:subscribe({table, route, simple}),
+ lists:foreach(
+ fun(Pid) ->
+ erlang:monitor(process, Pid)
+ end,
+ mnesia:dirty_select(route, [{{route, '_', '$1', '_'}, [], ['$1']}])),
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% Description: Handling call messages
+%%--------------------------------------------------------------------
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info({route, From, To, Packet}, State) ->
+ case catch do_route(From, To, Packet) of
+ {'EXIT', Reason} ->
+ ?ERROR_MSG("~p~nwhen processing: ~p",
+ [Reason, {From, To, Packet}]);
+ _ ->
+ ok
+ end,
+ {noreply, State};
+handle_info({mnesia_table_event, {write, #route{pid = Pid}, _ActivityId}},
+ State) ->
+ erlang:monitor(process, Pid),
+ {noreply, State};
+handle_info({'DOWN', _Ref, _Type, Pid, _Info}, State) ->
+ F = fun() ->
+ Es = mnesia:select(
+ route,
+ [{#route{pid = Pid, _ = '_'},
+ [],
+ ['$_']}]),
+ lists:foreach(fun(E) ->
+ mnesia:delete_object(E)
+ end, Es)
+ end,
+ mnesia:transaction(F),
+ {noreply, State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate(Reason, State) -> void()
+%% Description: This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any necessary
+%% cleaning up. When it returns, the gen_server terminates with Reason.
+%% The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+do_route(OrigFrom, OrigTo, OrigPacket) ->
+ ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket ~p~n",
+ [OrigFrom, OrigTo, OrigPacket]),
+ LOrigDstDomain = OrigTo#jid.lserver,
+ case ejabberd_hooks:run_fold(filter_packet, LOrigDstDomain,
+ {OrigFrom, OrigTo, OrigPacket}, []) of
+ {From, To, Packet} ->
+ LDstDomain = To#jid.lserver,
+ case mnesia:dirty_read(route, LDstDomain) of
+ [] ->
+ ejabberd_s2s:route(From, To, Packet);
+ [R] ->
+ Pid = R#route.pid,
+ if
+ node(Pid) == node() ->
+ case R#route.local_hint of
+ {apply, Module, Function} ->
+ Module:Function(From, To, Packet);
+ _ ->
+ Pid ! {route, From, To, Packet}
+ end;
+ true ->
+ Pid ! {route, From, To, Packet}
+ end;
+ Rs ->
+ case [R || R <- Rs, node(R#route.pid) == node()] of
+ [] ->
+ R = lists:nth(erlang:phash(now(), length(Rs)), Rs),
+ Pid = R#route.pid,
+ Pid ! {route, From, To, Packet};
+ LRs ->
+ LRs,
+ R = lists:nth(erlang:phash(now(), length(LRs)), LRs),
+ Pid = R#route.pid,
+ case R#route.local_hint of
+ {apply, Module, Function} ->
+ Module:Function(From, To, Packet);
+ _ ->
+ Pid ! {route, From, To, Packet}
+ end
+ end
+ end;
+ drop ->
+ ok
+ end.
+
+
update_tables() ->
case catch mnesia:table_info(route, attributes) of