From 206b5cd2fbf952db0d015f09e94f09a325d0624a Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Sat, 30 Nov 2002 18:46:16 +0000 Subject: [PATCH] *** empty log message *** SVN Revision: 10 --- src/ejabberd.erl | 1 + src/ejabberd_c2s.erl | 41 +++++++++++++++++++---- src/ejabberd_local.erl | 45 +++++++++++++++++++++++++ src/ejabberd_router.erl | 43 ++++++++++++++++++++---- src/ejabberd_sm.erl | 74 ++++++++++++++++++++++++++++++++++++++++- src/jlib.erl | 53 +++++++++++++++++++++++++++-- 6 files changed, 240 insertions(+), 17 deletions(-) create mode 100644 src/ejabberd_local.erl diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 34cabc42d..c0d164c9f 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -25,6 +25,7 @@ init() -> ejabberd_auth:start(), ejabberd_router:start(), ejabberd_sm:start(), + ejabberd_local:start(), ejabberd_listener:start(), loop(Port). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index d8855b166..f536fe32c 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -13,13 +13,14 @@ -behaviour(gen_fsm). %% External exports --export([start/1, receiver/2, sender/1, send_text/2]). +-export([start/1, receiver/2, sender/1, send_text/2, send_element/2]). %% gen_fsm callbacks %-export([init/1, state_name/2, state_name/3, handle_event/3, % handle_sync_event/4, handle_info/3, terminate/3]). % -export([init/1, wait_for_stream/2, wait_for_auth/2, session_established/2, + handle_info/3, terminate/3]). -record(state, {socket, sender, receiver, streamid, @@ -106,6 +107,9 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> case ejabberd_auth:check_password(U, P) of true -> % TODO + ejabberd_sm:open_session(U, R), + Res = jlib:make_result_iq_reply(El), + send_element(StateData#state.sender, Res), {next_state, session_established, StateData#state{user = U, resource = R}}; _ -> @@ -127,9 +131,24 @@ wait_for_auth(closed, StateData) -> session_established({xmlstreamelement, El}, StateData) -> {xmlelement, Name, Attrs, Els} = El, % TODO - FromJID = {StateData#state.user, "localhost", StateData#state.resource}, - ToJID = jlib:string_to_jid(xml:get_attr_s("to", Attrs)), - ejabberd_router:route(FromJID, ToJID, El), + FromJID = {StateData#state.user, + StateData#state.server, + StateData#state.resource}, + To = xml:get_attr_s("to", Attrs), + ToJID = case To of + "" -> + {"", StateData#state.server, ""}; + _ -> + jlib:string_to_jid(To) + end, + case ToJID of + error -> + % TODO + error; + _ -> + %?DEBUG("FromJID=~w, ToJID=~w, El=~w~n", [FromJID, ToJID, El]), + ejabberd_router:route(FromJID, ToJID, El) + end, {next_state, session_established, StateData}; session_established(closed, StateData) -> @@ -179,7 +198,8 @@ handle_sync_event(Event, From, StateName, StateData) -> %% {next_state, NextStateName, NextStateData, Timeout} | %% {stop, Reason, NewStateData} %%---------------------------------------------------------------------- -handle_info(Info, StateName, StateData) -> +handle_info({send_text, Text}, StateName, StateData) -> + send_text(StateData#state.sender, Text), {next_state, StateName, StateData}. %%---------------------------------------------------------------------- @@ -188,6 +208,13 @@ handle_info(Info, StateName, StateData) -> %% Returns: any %%---------------------------------------------------------------------- terminate(Reason, StateName, StateData) -> + case StateData#state.user of + "" -> + ok; + _ -> + ejabberd_sm:close_session(StateData#state.user, + StateData#state.resource) + end, StateData#state.sender ! close, ok. @@ -212,7 +239,7 @@ receiver(Socket, C2SPid, XMLStreamPid) -> sender(Socket) -> receive - {text, Text} -> + {send_text, Text} -> gen_tcp:send(Socket,Text), sender(Socket); close -> @@ -221,7 +248,7 @@ sender(Socket) -> end. send_text(Pid, Text) -> - Pid ! {text, Text}. + Pid ! {send_text, Text}. send_element(Pid, El) -> send_text(Pid, xml:element_to_string(El)). diff --git a/src/ejabberd_local.erl b/src/ejabberd_local.erl new file mode 100644 index 000000000..4241088a5 --- /dev/null +++ b/src/ejabberd_local.erl @@ -0,0 +1,45 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_local.erl +%%% Author : Alexey Shchepin +%%% Purpose : +%%% Created : 30 Nov 2002 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_local). +-author('alexey@sevcom.net'). +-vsn('$Revision$ '). + +%%-export([Function/Arity, ...]). + +-export([start/0,init/0]). + +-include("ejabberd.hrl"). + + +start() -> + spawn(ejabberd_local, init, []). + +init() -> + ejabberd_router:register_local_route("localhost"), + loop(). + +loop() -> + receive + {route, From, To, Packet} -> + do_route(From, To, Packet), + loop() + end. + + +do_route(From, To, Packet) -> + ?DEBUG("local route~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", + [From, To, Packet, 8]), + case To of + {"", _, _} -> + ok; + _ -> + ejabberd_sm ! {route, From, To, Packet} + end, + ok. + diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 1706eace5..9ab3d1810 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -10,13 +10,14 @@ -author('alexey@sevcom.net'). -vsn('$Revision$ '). --export([route/3]). +-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() -> @@ -28,6 +29,11 @@ init() -> [{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() -> @@ -51,6 +57,13 @@ loop() -> 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 @@ -73,11 +86,16 @@ 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({route, DstDomain}) of + case mnesia:read({local_route, DstDomain}) of [] -> - error; + case mnesia:read({route, DstDomain}) of + [] -> + error; + [R] -> + {ok, R#route.node, R#route.pid} + end; [R] -> - {ok, R#route.node, R#route.pid} + {ok, node(), R#local_route.pid} end end, case mnesia:transaction(F) of @@ -89,11 +107,18 @@ do_route(From, To, Packet) -> ok; _ -> Err = jlib:make_error_reply(Packet, - 502, "Service Unavailable"), + "502", "Service Unavailable"), ejabberd_router ! {route, To, From, Err} end; {atomic, {ok, Node, Pid}} -> - {Pid, Node} ! {packet, From, To, Packet}; + 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 @@ -103,3 +128,9 @@ do_route(From, To, Packet) -> 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()}. + diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl index 16505948c..e9f51f992 100644 --- a/src/ejabberd_sm.erl +++ b/src/ejabberd_sm.erl @@ -8,10 +8,12 @@ -module(ejabberd_sm). -author('alexey@sevcom.net'). +-vsn('$Revision$ '). --export([start/0, init/0, open_session/2]). +-export([start/0, init/0, open_session/2, close_session/2]). -include_lib("mnemosyne/include/mnemosyne.hrl"). +-include("ejabberd.hrl"). -record(user_resource, {id, user, resource}). -record(user_resource_id_seq, {name = value, id}). @@ -43,6 +45,7 @@ init() -> {local_content, true}, {attributes, record_info(fields, mysession)}]), mnesia:subscribe(system), + %ejabberd_router:register_local_route("localhost"), loop(). loop() -> @@ -51,12 +54,18 @@ loop() -> replace_and_register_my_connection(User, Resource, From), replace_alien_connection(User, Resource), loop(); + {close_session, User, Resource} -> + remove_connection(User, Resource), + loop(); {replace, User, Resource} -> replace_my_connection(User, Resource), loop(); {mnesia_system_event, {mnesia_down, Node}} -> clean_table_from_bad_node(Node), loop(); + {route, From, To, Packet} -> + do_route(From, To, Packet), + loop(); _ -> loop() end. @@ -65,6 +74,9 @@ loop() -> open_session(User, Resource) -> ejabberd_sm ! {open_session, User, Resource, self()}. +close_session(User, Resource) -> + ejabberd_sm ! {close_session, User, Resource}. + replace_alien_connection(User, Resource) -> F = fun() -> [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource), @@ -112,6 +124,19 @@ replace_my_connection(User, Resource) -> false end. +remove_connection(User, Resource) -> + F = fun() -> + [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource), + X.user = User, + X.resource = Resource] + end), + + mnesia:delete({mysession, ID}), + mnesia:delete({session, ID}), + mnesia:delete({user_resource, ID}) + end, + mnesia:transaction(F). + replace_and_register_my_connection(User, Resource, Pid) -> F = fun() -> IDs = mnemosyne:eval(query [X.id || X <- table(user_resource), @@ -169,3 +194,50 @@ init_seq() -> end, mnesia:transaction(F). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +do_route(From, To, Packet) -> + ?DEBUG("session manager~n\tfrom ~p~n\tto ~p~n\tpacket ~P~n", + [From, To, Packet, 8]), + {User, _, Resource} = To, + F = fun() -> + IDs = mnemosyne:eval(query [X.id || X <- table(user_resource), + X.user = User, + X.resource = Resource] + end), + case IDs of + [] -> + not_exists; + [ID] -> + case mnesia:read({mysession, ID}) of + [] -> + [Er] = mnesia:read({session, ID}), + {remote, Er#session.node}; + [El] -> + {local, (El#mysession.info)#mysession_info.pid} + end + end + end, + case mnesia:transaction(F) of + {atomic, {local, Pid}} -> + ?DEBUG("sending to process ~p~n", [Pid]), + % TODO + {xmlelement, Name, Attrs, Els} = Packet, + NewAttrs = jlib:replace_from_to_attrs(jlib:jid_to_string(From), + jlib:jid_to_string(To), + Attrs), + ejabberd_c2s:send_element(Pid, {xmlelement, Name, NewAttrs, Els}), + ?DEBUG("sended~n", []), + ok; + {atomic, {remote, Node}} -> + ?DEBUG("sending to node ~p~n", [Node]), + {ejabberd_sm, Node} ! {route, From, To, Packet}, + ok; + {atomic, not_exists} -> + ?DEBUG("packet droped~n", []), + ok; + {aborted, Reason} -> + ?DEBUG("delivery failed: ~p~n", [Reason]), + false + end. + diff --git a/src/jlib.erl b/src/jlib.erl index b301378c8..b1262e0ef 100644 --- a/src/jlib.erl +++ b/src/jlib.erl @@ -10,13 +10,43 @@ -author('alexey@sevcom.net'). -vsn('$Revision$ '). --export([make_error_reply/3, make_correct_from_to_attrs/3, - replace_from_to_attrs/3, string_to_jid/1, tolower/1]). +-export([make_result_iq_reply/1, + make_error_reply/3, + make_correct_from_to_attrs/3, + replace_from_to_attrs/3, + string_to_jid/1, + jid_to_string/1, + tolower/1]). %send_iq(From, To, ID, SubTags) -> % ok. +make_result_iq_reply({xmlelement, Name, Attrs, SubTags}) -> + NewAttrs = make_result_iq_reply_attrs(Attrs), + {xmlelement, Name, NewAttrs, SubTags}. + +make_result_iq_reply_attrs(Attrs) -> + To = xml:get_attr("to", Attrs), + From = xml:get_attr("from", Attrs), + Attrs1 = lists:keydelete("to", 1, Attrs), + Attrs2 = lists:keydelete("from", 1, Attrs1), + Attrs3 = case To of + {value, ToVal} -> + [{"from", ToVal} | Attrs2]; + _ -> + Attrs2 + end, + Attrs4 = case From of + {value, FromVal} -> + [{"to", FromVal} | Attrs3]; + _ -> + Attrs3 + end, + Attrs5 = lists:keydelete("type", 1, Attrs4), + Attrs6 = [{"type", "result"} | Attrs5], + Attrs6. + make_error_reply({xmlelement, Name, Attrs, SubTags}, Code, Desc) -> NewAttrs = make_error_reply_attrs(Attrs), {xmlelement, Name, NewAttrs, SubTags ++ [{xmlelement, "error", @@ -56,7 +86,7 @@ make_correct_from_to_attrs(From, To, Attrs) -> Attrs3. -replace_from_to_attrs(From,To,Attrs) -> +replace_from_to_attrs(From, To, Attrs) -> Attrs1 = lists:keydelete("to", 1, Attrs), Attrs2 = lists:keydelete("from", 1, Attrs1), Attrs3 = [{"to", To} | Attrs2], @@ -98,6 +128,23 @@ string_to_jid3([C | J], N, S, R) -> string_to_jid3([], N, S, R) -> {N, S, lists:reverse(R)}. +jid_to_string({Node, Server, Resource}) -> + S1 = case Node of + "" -> + ""; + _ -> + Node ++ "@" + end, + S2 = S1 ++ Server, + S3 = case Resource of + "" -> + S2; + _ -> + S2 ++ "/" ++ Resource + end, + S3. + + % TODO: UNICODE support tolower_c(C) when C >= $A, C =< $Z ->