diff options
author | Christophe Romain <christophe.romain@process-one.net> | 2012-09-11 15:45:59 +0200 |
---|---|---|
committer | Christophe Romain <christophe.romain@process-one.net> | 2012-09-11 15:45:59 +0200 |
commit | 011535f0de1a14d6f5f411035bff9eeafec1c612 (patch) | |
tree | e60951904fbdc14dc126450c4d7515f51188d4b7 /src/mod_proxy65/mod_proxy65_service.erl | |
parent | Merge branch '2.1.x' into 2.2.x (diff) |
binary refactoring
Diffstat (limited to 'src/mod_proxy65/mod_proxy65_service.erl')
-rw-r--r-- | src/mod_proxy65/mod_proxy65_service.erl | 323 |
1 files changed, 178 insertions, 145 deletions
diff --git a/src/mod_proxy65/mod_proxy65_service.erl b/src/mod_proxy65/mod_proxy65_service.erl index fc4245d9f..a398afa9c 100644 --- a/src/mod_proxy65/mod_proxy65_service.erl +++ b/src/mod_proxy65/mod_proxy65_service.erl @@ -25,37 +25,33 @@ %%%---------------------------------------------------------------------- -module(mod_proxy65_service). + -author('xram@jabber.ru'). -behaviour(gen_server). %% gen_server callbacks. --export([init/1, - handle_info/2, - handle_call/3, - handle_cast/2, - terminate/2, - code_change/3 - ]). +-export([init/1, handle_info/2, handle_call/3, + handle_cast/2, terminate/2, code_change/3]). %% API. --export([start_link/2, add_listener/2, delete_listener/1]). +-export([start_link/2, add_listener/2, + delete_listener/1]). -include("ejabberd.hrl"). + -include("jlib.hrl"). -define(PROCNAME, ejabberd_mod_proxy65_service). --record(state, { - myhost, - serverhost, - name, - stream_addr, - port, - ip, - acl - }). - +-record(state, + {myhost = <<"">> :: binary(), + serverhost = <<"">> :: binary(), + name = <<"">> :: binary(), + stream_addr = [] :: [attr()], + port = 0 :: inet:port_number(), + ip = {127,0,0,1} :: inet:ip_address(), + acl = none :: atom()}). %%%------------------------ %%% gen_server callbacks @@ -63,43 +59,44 @@ start_link(Host, Opts) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - gen_server:start_link({local, Proc}, ?MODULE, [Host, Opts], []). + gen_server:start_link({local, Proc}, ?MODULE, + [Host, Opts], []). init([Host, Opts]) -> State = parse_options(Host, Opts), ejabberd_router:register_route(State#state.myhost), {ok, State}. -terminate(_Reason, #state{myhost=MyHost}) -> - ejabberd_router:unregister_route(MyHost), - ok. +terminate(_Reason, #state{myhost = MyHost}) -> + ejabberd_router:unregister_route(MyHost), ok. -handle_info({route, From, To, {xmlelement, "iq", _, _} = Packet}, State) -> +handle_info({route, From, To, + #xmlel{name = <<"iq">>} = Packet}, + State) -> IQ = jlib:iq_query_info(Packet), case catch process_iq(From, IQ, State) of - Result when is_record(Result, iq) -> - ejabberd_router:route(To, From, jlib:iq_to_xml(Result)); - {'EXIT', Reason} -> - ?ERROR_MSG("Error when processing IQ stanza: ~p", [Reason]), - Err = jlib:make_error_reply(Packet, ?ERR_INTERNAL_SERVER_ERROR), - ejabberd_router:route(To, From, Err); - _ -> - ok + Result when is_record(Result, iq) -> + ejabberd_router:route(To, From, jlib:iq_to_xml(Result)); + {'EXIT', Reason} -> + ?ERROR_MSG("Error when processing IQ stanza: ~p", + [Reason]), + Err = jlib:make_error_reply(Packet, + ?ERR_INTERNAL_SERVER_ERROR), + ejabberd_router:route(To, From, Err); + _ -> ok end, {noreply, State}; -handle_info(_Info, State) -> - {noreply, State}. +handle_info(_Info, State) -> {noreply, State}. handle_call(get_port_ip, _From, State) -> - {reply, {port_ip, State#state.port, State#state.ip}, State}; + {reply, {port_ip, State#state.port, State#state.ip}, + State}; handle_call(_Request, _From, State) -> {reply, ok, State}. -handle_cast(_Request, State) -> - {noreply, State}. +handle_cast(_Request, State) -> {noreply, State}. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. +code_change(_OldVsn, State, _Extra) -> {ok, State}. %%%------------------------ %%% Listener management @@ -108,141 +105,177 @@ code_change(_OldVsn, State, _Extra) -> add_listener(Host, Opts) -> State = parse_options(Host, Opts), NewOpts = [Host | Opts], - ejabberd_listener:add_listener({State#state.port, State#state.ip}, mod_proxy65_stream, NewOpts). + ejabberd_listener:add_listener({State#state.port, + State#state.ip}, + mod_proxy65_stream, NewOpts). delete_listener(Host) -> Proc = gen_mod:get_module_proc(Host, ?PROCNAME), - {port_ip, Port, IP} = gen_server:call(Proc, get_port_ip), - catch ejabberd_listener:delete_listener({Port, IP}, mod_proxy65_stream). + {port_ip, Port, IP} = gen_server:call(Proc, + get_port_ip), + catch ejabberd_listener:delete_listener({Port, IP}, + mod_proxy65_stream). %%%------------------------ %%% IQ Processing %%%------------------------ -%% disco#info request -process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = IQ, - #state{name=Name, serverhost=ServerHost}) -> - Info = ejabberd_hooks:run_fold( - disco_info, ServerHost, [], [ServerHost, ?MODULE, "", ""]), - IQ#iq{type = result, sub_el = - [{xmlelement, "query", [{"xmlns", ?NS_DISCO_INFO}], - iq_disco_info(Lang, Name) ++ Info}]}; - +process_iq(_, + #iq{type = get, xmlns = ?NS_DISCO_INFO, lang = Lang} = + IQ, + #state{name = Name, serverhost = ServerHost}) -> + Info = ejabberd_hooks:run_fold(disco_info, ServerHost, + [], [ServerHost, ?MODULE, <<"">>, <<"">>]), + IQ#iq{type = result, + sub_el = + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_DISCO_INFO}], + children = iq_disco_info(Lang, Name) ++ Info}]}; %% disco#items request -process_iq(_, #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) -> - IQ#iq{type = result, sub_el = - [{xmlelement, "query", [{"xmlns", ?NS_DISCO_ITEMS}], []}]}; - +process_iq(_, + #iq{type = get, xmlns = ?NS_DISCO_ITEMS} = IQ, _) -> + IQ#iq{type = result, + sub_el = + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_DISCO_ITEMS}], + children = []}]}; %% vCard request -process_iq(_, #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, _) -> - IQ#iq{type = result, sub_el = - [{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}], iq_vcard(Lang)}]}; - +process_iq(_, + #iq{type = get, xmlns = ?NS_VCARD, lang = Lang} = IQ, + _) -> + IQ#iq{type = result, + sub_el = + [#xmlel{name = <<"vCard">>, + attrs = [{<<"xmlns">>, ?NS_VCARD}], + children = iq_vcard(Lang)}]}; %% bytestreams info request -process_iq(JID, #iq{type = get, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ, - #state{acl = ACL, stream_addr = StreamAddr, serverhost = ServerHost}) -> +process_iq(JID, + #iq{type = get, sub_el = SubEl, + xmlns = ?NS_BYTESTREAMS} = + IQ, + #state{acl = ACL, stream_addr = StreamAddr, + serverhost = ServerHost}) -> case acl:match_rule(ServerHost, ACL, JID) of - allow -> - StreamHostEl = [{xmlelement, "streamhost", StreamAddr, []}], - IQ#iq{type = result, sub_el = - [{xmlelement, "query", [{"xmlns", ?NS_BYTESTREAMS}], StreamHostEl}]}; - deny -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} + allow -> + StreamHostEl = [#xmlel{name = <<"streamhost">>, + attrs = StreamAddr, children = []}], + IQ#iq{type = result, + sub_el = + [#xmlel{name = <<"query">>, + attrs = [{<<"xmlns">>, ?NS_BYTESTREAMS}], + children = StreamHostEl}]}; + deny -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} end; - %% bytestream activation request -process_iq(InitiatorJID, #iq{type = set, sub_el = SubEl, xmlns = ?NS_BYTESTREAMS} = IQ, +process_iq(InitiatorJID, + #iq{type = set, sub_el = SubEl, + xmlns = ?NS_BYTESTREAMS} = + IQ, #state{acl = ACL, serverhost = ServerHost}) -> case acl:match_rule(ServerHost, ACL, InitiatorJID) of - allow -> - ActivateEl = xml:get_path_s(SubEl, [{elem, "activate"}]), - SID = xml:get_tag_attr_s("sid", SubEl), - case catch jlib:string_to_jid(xml:get_tag_cdata(ActivateEl)) of - TargetJID when is_record(TargetJID, jid), SID /= "", - length(SID) =< 128, TargetJID /= InitiatorJID -> - Target = jlib:jid_to_string(jlib:jid_tolower(TargetJID)), - Initiator = jlib:jid_to_string(jlib:jid_tolower(InitiatorJID)), - SHA1 = sha:sha(SID ++ Initiator ++ Target), - case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, TargetJID, ServerHost) of - ok -> - IQ#iq{type = result, sub_el = []}; - false -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; - limit -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_RESOURCE_CONSTRAINT]}; - conflict -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_CONFLICT]}; - _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} - end; - _ -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]} - end; - deny -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} + allow -> + ActivateEl = xml:get_path_s(SubEl, + [{elem, <<"activate">>}]), + SID = xml:get_tag_attr_s(<<"sid">>, SubEl), + case catch + jlib:string_to_jid(xml:get_tag_cdata(ActivateEl)) + of + TargetJID + when is_record(TargetJID, jid), SID /= <<"">>, + byte_size(SID) =< 128, TargetJID /= InitiatorJID -> + Target = + jlib:jid_to_string(jlib:jid_tolower(TargetJID)), + Initiator = + jlib:jid_to_string(jlib:jid_tolower(InitiatorJID)), + SHA1 = sha:sha(<<SID/binary, Initiator/binary, Target/binary>>), + case mod_proxy65_sm:activate_stream(SHA1, InitiatorJID, + TargetJID, ServerHost) + of + ok -> IQ#iq{type = result, sub_el = []}; + false -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_ITEM_NOT_FOUND]}; + limit -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_RESOURCE_CONSTRAINT]}; + conflict -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_CONFLICT]}; + _ -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_INTERNAL_SERVER_ERROR]} + end; + _ -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_BAD_REQUEST]} + end; + deny -> + IQ#iq{type = error, sub_el = [SubEl, ?ERR_FORBIDDEN]} end; - %% Unknown "set" or "get" request -process_iq(_, #iq{type=Type, sub_el=SubEl} = IQ, _) when Type==get; Type==set -> - IQ#iq{type = error, sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; - +process_iq(_, #iq{type = Type, sub_el = SubEl} = IQ, _) + when Type == get; Type == set -> + IQ#iq{type = error, + sub_el = [SubEl, ?ERR_SERVICE_UNAVAILABLE]}; %% IQ "result" or "error". -process_iq(_, _, _) -> - ok. +process_iq(_, _, _) -> ok. -%%%------------------------- -%%% Auxiliary functions. -%%%------------------------- --define(FEATURE(Feat), {xmlelement,"feature",[{"var", Feat}],[]}). +-define(FEATURE(Feat), + #xmlel{name = <<"feature">>, + attrs = [{<<"var">>, Feat}], children = []}). iq_disco_info(Lang, Name) -> - [{xmlelement, "identity", - [{"category", "proxy"}, - {"type", "bytestreams"}, - {"name", translate:translate(Lang, Name)}], []}, - ?FEATURE(?NS_DISCO_INFO), - ?FEATURE(?NS_VCARD), - ?FEATURE(?NS_BYTESTREAMS)]. + [#xmlel{name = <<"identity">>, + attrs = + [{<<"category">>, <<"proxy">>}, + {<<"type">>, <<"bytestreams">>}, + {<<"name">>, translate:translate(Lang, Name)}], + children = []}, + ?FEATURE((?NS_DISCO_INFO)), ?FEATURE((?NS_VCARD)), + ?FEATURE((?NS_BYTESTREAMS))]. iq_vcard(Lang) -> - [{xmlelement, "FN", [], - [{xmlcdata, "ejabberd/mod_proxy65"}]}, - {xmlelement, "URL", [], - [{xmlcdata, ?EJABBERD_URI}]}, - {xmlelement, "DESC", [], - [{xmlcdata, translate:translate(Lang, "ejabberd SOCKS5 Bytestreams module") ++ - "\nCopyright (c) 2003-2012 ProcessOne"}]}]. + [#xmlel{name = <<"FN">>, attrs = [], + children = [{xmlcdata, <<"ejabberd/mod_proxy65">>}]}, + #xmlel{name = <<"URL">>, attrs = [], + children = [{xmlcdata, ?EJABBERD_URI}]}, + #xmlel{name = <<"DESC">>, attrs = [], + children = + [{xmlcdata, + <<(translate:translate(Lang, + <<"ejabberd SOCKS5 Bytestreams module">>))/binary, + "\nCopyright (c) 2003-2012 ProcessOne">>}]}]. parse_options(ServerHost, Opts) -> - MyHost = gen_mod:get_opt_host(ServerHost, Opts, "proxy.@HOST@"), - Port = gen_mod:get_opt(port, Opts, 7777), - ACL = gen_mod:get_opt(access, Opts, all), - Name = gen_mod:get_opt(name, Opts, "SOCKS5 Bytestreams"), - IP = case gen_mod:get_opt(ip, Opts, none) of - none -> get_my_ip(); - Addr -> Addr - end, - HostName = case gen_mod:get_opt(hostname, Opts, none) of - none -> - inet_parse:ntoa(IP); - HostAddr when is_tuple(HostAddr) -> - inet_parse:ntoa(HostAddr); - HostNameStr -> - HostNameStr - end, - StreamAddr = [{"jid", MyHost}, {"host", HostName}, - {"port", integer_to_list(Port)}], - #state{myhost = MyHost, - serverhost = ServerHost, - name = Name, - port = Port, - ip = IP, - stream_addr = StreamAddr, - acl = ACL}. + MyHost = gen_mod:get_opt_host(ServerHost, Opts, + <<"proxy.@HOST@">>), + Port = gen_mod:get_opt(port, Opts, + fun(P) when is_integer(P), P>0, P<65536 -> P end, + 7777), + ACL = gen_mod:get_opt(access, Opts, fun(A) when is_atom(A) -> A end, + all), + Name = gen_mod:get_opt(name, Opts, fun iolist_to_binary/1, + <<"SOCKS5 Bytestreams">>), + IP = gen_mod:get_opt(ip, Opts, + fun(Addr) -> + jlib:ip_to_list(Addr), + Addr + end, get_my_ip()), + HostName = gen_mod:get_opt(hostname, Opts, + fun(Addr) when is_tuple(Addr) -> + jlib:ip_to_list(Addr); + (S) -> + iolist_to_binary(S) + end, jlib:ip_to_list(IP)), + StreamAddr = [{<<"jid">>, MyHost}, + {<<"host">>, HostName}, + {<<"port">>, jlib:integer_to_binary(Port)}], + #state{myhost = MyHost, serverhost = ServerHost, + name = Name, port = Port, ip = IP, + stream_addr = StreamAddr, acl = ACL}. get_my_ip() -> {ok, MyHostName} = inet:gethostname(), case inet:getaddr(MyHostName, inet) of - {ok, Addr} -> Addr; - {error, _} -> {127,0,0,1} + {ok, Addr} -> Addr; + {error, _} -> {127, 0, 0, 1} end. |