From 9c38be6ca249740e638eb3913930410ca4891739 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Sun, 24 Nov 2002 20:36:57 +0000 Subject: [PATCH] *** empty log message *** SVN Revision: 6 --- src/ejabberd.erl | 4 +- src/ejabberd_c2s.erl | 9 +-- src/ejabberd_sm.erl | 171 +++++++++++++++++++++++++++++++++++++++++++ src/xml.erl | 30 +++++++- 4 files changed, 205 insertions(+), 9 deletions(-) create mode 100644 src/ejabberd_sm.erl diff --git a/src/ejabberd.erl b/src/ejabberd.erl index 40d0bc448..4036e92e8 100644 --- a/src/ejabberd.erl +++ b/src/ejabberd.erl @@ -23,6 +23,7 @@ init() -> Port = open_port({spawn, expat_erl}, [binary]), db_init(), ejabberd_auth:start(), + ejabberd_sm:start(), ejabberd_listener:start(), loop(Port). @@ -35,4 +36,5 @@ loop(Port) -> db_init() -> mnesia:create_schema([node()]), - mnesia:start(). + mnesia:start(), + mnesia:wait_for_tables(mnesia:system_info(tables), infinity). diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 518f5a488..6cce2f261 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -103,14 +103,10 @@ wait_for_auth({xmlstreamelement, El}, StateData) -> io:format("AUTH: ~p~n", [{U, P, D, R}]), case ejabberd_auth:check_password(U, P) of true -> + % TODO {next_state, session_established, StateData}; _ -> - {xmlelement, _, _, SubTags} = El, - Err = {xmlelement, "iq", - [{"id", "0"}, {"type", "error"}], - SubTags ++ [{xmlelement, "error", - [{"code", "404"}], - [{xmlcdata, "Unauthorized"}]}]}, + Err = xml:make_error_iq_reply(El, "404", "Unauthorized"), send_element(StateData#state.sender, Err), {next_state, wait_for_auth, StateData} end; @@ -238,7 +234,6 @@ is_auth_packet({xmlelement, Name, Attrs, Els}) when Name == "iq" -> true -> false end; - is_auth_packet(_) -> false. diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl new file mode 100644 index 000000000..16505948c --- /dev/null +++ b/src/ejabberd_sm.erl @@ -0,0 +1,171 @@ +%%%---------------------------------------------------------------------- +%%% File : ejabberd_sm.erl +%%% Author : Alexey Shchepin +%%% Purpose : +%%% Created : 24 Nov 2002 by Alexey Shchepin +%%% Id : $Id$ +%%%---------------------------------------------------------------------- + +-module(ejabberd_sm). +-author('alexey@sevcom.net'). + +-export([start/0, init/0, open_session/2]). + +-include_lib("mnemosyne/include/mnemosyne.hrl"). + +-record(user_resource, {id, user, resource}). +-record(user_resource_id_seq, {name = value, id}). +-record(session, {id, node}). +-record(mysession, {id, info}). + +-record(mysession_info, {pid}). + + +start() -> + spawn(ejabberd_sm, init, []). + +init() -> + register(ejabberd_sm, self()), + mnesia:create_table(user_resource_id_seq, + [{ram_copies, [node()]}, + {attributes, + record_info(fields, user_resource_id_seq)}]), + init_seq(), + mnesia:create_table(user_resource,[{ram_copies, [node()]}, + {attributes, + record_info(fields, user_resource)}]), + mnesia:add_table_index(user_resource, user), + mnesia:create_table(session,[{ram_copies, [node()]}, + {attributes, record_info(fields, session)}]), + mnesia:add_table_index(session, node), + mnesia:create_table(mysession, + [{ram_copies, [node()]}, + {local_content, true}, + {attributes, record_info(fields, mysession)}]), + mnesia:subscribe(system), + loop(). + +loop() -> + receive + {open_session, User, Resource, From} -> + replace_and_register_my_connection(User, Resource, From), + replace_alien_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(); + _ -> + loop() + end. + + +open_session(User, Resource) -> + ejabberd_sm ! {open_session, User, Resource, self()}. + +replace_alien_connection(User, Resource) -> + F = fun() -> + [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource), + X.user = User, + X.resource = Resource] + end), + Es = mnesia:read({session, ID}), + mnesia:write(#session{id = ID, node = node()}), + Es + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + lists:foreach( + fun(R) -> + if R#session.node /= node() -> + {ejabberd_sm, R#session.node} ! + {replace, User, Resource}; + true -> + ok + end + end, Rs); + _ -> + false + end. + + +replace_my_connection(User, Resource) -> + F = fun() -> + [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource), + X.user = User, + X.resource = Resource] + end), + + Es = mnesia:read({mysession, ID}), + mnesia:delete({mysession, ID}), + Es + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + lists:foreach( + fun(R) -> + (R#mysession.info)#mysession_info.pid ! replaced + end, Rs); + _ -> + false + end. + +replace_and_register_my_connection(User, Resource, Pid) -> + F = fun() -> + IDs = mnemosyne:eval(query [X.id || X <- table(user_resource), + X.user = User, + X.resource = Resource] + end), + + ID = case IDs of + [Id] -> Id; + [] -> + [CurID] = + mnemosyne:eval( + query [X.id || + X <- table(user_resource_id_seq)] + end), + mnesia:write( + #user_resource_id_seq{id = CurID + 1}), + mnesia:write( + #user_resource{id = CurID, + user = User, + resource = Resource}), + CurID + end, + Es = mnesia:read({mysession, ID}), + mnesia:write(#mysession{id = ID, + info = #mysession_info{pid = Pid}}), + Es + end, + case mnesia:transaction(F) of + {atomic, Rs} -> + lists:foreach( + fun(R) -> + (R#mysession.info)#mysession_info.pid ! replaced + end, Rs); + _ -> + false + end. + + +clean_table_from_bad_node(Node) -> + F = fun() -> + Es = mnesia:index_read(session, Node, #session.node), + lists:foreach(fun(E) -> + mnesia:delete_object(session, E, write), + mnesia:delete( + {user_resource, E#session.id}) + end, Es) + end, + mnesia:transaction(F). + +init_seq() -> + F = fun() -> + [] = mnesia:read({user_resource_id_seq, value}), + mnesia:write(#user_resource_id_seq{id = 0}) + end, + mnesia:transaction(F). + diff --git a/src/xml.erl b/src/xml.erl index e1ae3b1ba..5ae3cb593 100644 --- a/src/xml.erl +++ b/src/xml.erl @@ -11,7 +11,7 @@ -vsn('$Revision$ '). -export([element_to_string/1, crypt/1, remove_cdata/1, get_cdata/1, - get_attr/2, get_attr_s/2]). + get_attr/2, get_attr_s/2, make_error_iq_reply/3]). element_to_string(El) -> case El of @@ -90,3 +90,31 @@ get_attr_s(AttrName, Attrs) -> "" end. + +make_error_iq_reply({xmlelement, Name, Attrs, SubTags}, Code, Desc) + when Name == "iq" -> + NewAttrs = make_error_iq_reply_attrs(Attrs), + {xmlelement, Name, NewAttrs, SubTags ++ [{xmlelement, "error", + [{"code", Code}], + [{xmlcdata, Desc}]}]}. + +make_error_iq_reply_attrs(Attrs) -> + To = get_attr("to", Attrs), + From = 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", "error"} | Attrs5], + Attrs6.