summaryrefslogtreecommitdiff
path: root/src/ejabberd_router.erl
blob: e28eeb7416f708da9ee58562face0c2ef5c4455e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
%%%----------------------------------------------------------------------
%%% File    : ejabberd_router.erl
%%% Author  : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose : 
%%% Created : 27 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id      : $Id$
%%%----------------------------------------------------------------------

-module(ejabberd_router).
-author('alexey@sevcom.net').
-vsn('$Revision$ ').

-export([route/3, register_route/1, register_local_route/1]).

-export([start/0, init/0]).

-include("ejabberd.hrl").

-record(route, {domain, node, pid}).
-record(local_route, {domain, pid}).


start() ->
    spawn(ejabberd_router, init, []).

init() ->
    register(ejabberd_router, self()),
    mnesia:create_table(route,
			[{ram_copies, [node()]},
			 {attributes,
			  record_info(fields, route)}]),
    mnesia:create_table(local_route,
			[{ram_copies, [node()]},
			 {local_content, true},
			 {attributes,
			  record_info(fields, local_route)}]),
    loop().

loop() ->
    receive
	{route, From, To, Packet} ->
	    % TODO
	    do_route(From, To, Packet),
	    loop();
	{register_route, Domain, Pid, Node} ->
	    F = fun() ->
			case mnesia:wread({route, Domain}) of
			    [] ->
				ok;
			    [Old] ->
				% TODO: notify
				ok
			end,
			mnesia:write(#route{domain = Domain,
					    node = Node,
					    pid = Pid})
		end,
	    mnesia:transaction(F),
	    loop();
	{register_local_route, Domain, Pid} ->
	    F = fun() ->
			mnesia:write(#local_route{domain = Domain,
						  pid = Pid})
		end,
	    mnesia:transaction(F),
	    loop();
	{unregister_route, Domain} ->
	    F = fun() ->
			case mnesia:wread({route, Domain}) of
			    [] ->
				ok;
			    [Old] ->
				% TODO: notify
				ok
			end,
			mnesia:delete({route, Domain})
		end,
	    mnesia:transaction(F),
	    loop();
	_ ->
	    loop()
    end.


do_route(From, To, Packet) ->
    ?DEBUG("route~n\tfrom ~p~n\tto ~p~n\tpacket ~p~n", [From, To, Packet]),
    {DstNode, DstDomain, DstResourse} = To,
    F = fun() ->
		case mnesia:read({local_route, DstDomain}) of
		    [] ->
			case mnesia:read({route, DstDomain}) of
			    [] ->
				error;
			    [R] ->
				{ok, R#route.node, R#route.pid}
			end;
		    [R] ->
			{ok, node(), R#local_route.pid}
		end
	end,
    case mnesia:transaction(F) of
	{atomic, error} ->
	    ejabberd_s2s ! {route, From, To, Packet};
	{atomic, {ok, Node, Pid}} ->
	    case node() of
		Node ->
		    ?DEBUG("routed to process ~p~n", [Pid]),
		    Pid ! {route, From, To, Packet};
		_ ->
		    ?DEBUG("routed to node ~p~n", [Node]),
		    {ejabberd_router, Node} ! {route, From, To, Packet}
	    end;
	_ ->
	    % TODO
	    error
    end.


route(From, To, Packet) ->
    ejabberd_router ! {route, From, To, Packet}.

register_route(Domain) ->
    ejabberd_router ! {register_route, Domain, self(), node()}.

register_local_route(Domain) ->
    ejabberd_router ! {register_local_route, Domain, self()}.