From c10e43f95f72ee0a2b26b40bcd170ffaadd5025a Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Thu, 14 Oct 2010 15:59:23 +0300 Subject: [PATCH 1/5] Improved behaviour on SSL handshake failure --- src/mod_applepush_service.erl | 59 ++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/mod_applepush_service.erl b/src/mod_applepush_service.erl index 7c5ab711f..43eae897e 100644 --- a/src/mod_applepush_service.erl +++ b/src/mod_applepush_service.erl @@ -22,6 +22,7 @@ -include("ejabberd.hrl"). -include("jlib.hrl"). +-include_lib("kernel/include/file.hrl"). -record(state, {host, socket, @@ -32,6 +33,8 @@ feedback_port, feedback_buf = <<>>, certfile, + certfile_mtime, + failure_script, queue, soundfile, cmd_id = 0, @@ -41,6 +44,7 @@ -define(PROCNAME, ejabberd_mod_applepush_service). -define(RECONNECT_TIMEOUT, 5000). -define(FEEDBACK_RECONNECT_TIMEOUT, 30000). +-define(HANDSHAKE_TIMEOUT, 60000). -define(MAX_QUEUE_SIZE, 1000). -define(CACHE_SIZE, 4096). -define(MAX_PAYLOAD_SIZE, 255). @@ -116,6 +120,7 @@ init([MyHost, Opts]) -> Feedback = gen_mod:get_opt(feedback, Opts, undefined), Port = gen_mod:get_opt(port, Opts, 2195), FeedbackPort = gen_mod:get_opt(feedback_port, Opts, 2196), + FailureScript = gen_mod:get_opt(failure_script, Opts, undefined), %MyHost = gen_mod:get_opt_host(Host, Opts, "applepush.@HOST@"), self() ! connect, case Feedback of @@ -131,6 +136,7 @@ init([MyHost, Opts]) -> feedback = Feedback, feedback_port = FeedbackPort, certfile = CertFile, + failure_script = FailureScript, queue = {0, queue:new()}, soundfile = SoundFile}}. @@ -171,6 +177,11 @@ handle_info({route, From, To, Packet}, State) -> end; handle_info(connect, State) -> connect(State); +handle_info(connect_feedback, #state{certfile_mtime = MTime} = State) + when MTime /= undefined -> + erlang:send_after(?FEEDBACK_RECONNECT_TIMEOUT, self(), + connect_feedback), + {noreply, State}; handle_info(connect_feedback, State) when State#state.feedback /= undefined, State#state.feedback_socket == undefined -> @@ -447,7 +458,7 @@ make_payload(State, Msg, Badge, Sound, Sender) -> Payload end. -connect(#state{socket = undefined} = State) -> +connect(#state{socket = undefined, certfile_mtime = undefined} = State) -> Gateway = State#state.gateway, Port = State#state.port, CertFile = State#state.certfile, @@ -457,16 +468,56 @@ connect(#state{socket = undefined} = State) -> {ok, Socket} -> {noreply, resend_messages(State#state{socket = Socket})}; {error, Reason} -> + {Timeout, State2} = + case Reason of + esslconnect -> + MTime = get_mtime(CertFile), + case State#state.failure_script of + undefined -> + ok; + FailureScript -> + os:cmd(FailureScript ++ " " ++ Gateway) + end, + {?HANDSHAKE_TIMEOUT, + State#state{certfile_mtime = MTime}}; + _ -> + {?RECONNECT_TIMEOUT, State} + end, ?ERROR_MSG("(~p) Connection to ~p:~p failed: ~p, " + "retrying after ~p seconds", + [State2#state.host, Gateway, Port, + Reason, Timeout div 1000]), + erlang:send_after(Timeout, self(), connect), + {noreply, State2} + end; +connect(#state{socket = undefined, certfile_mtime = MTime} = State) -> + CertFile = State#state.certfile, + case get_mtime(CertFile) of + MTime -> + Gateway = State#state.gateway, + Port = State#state.port, + Timeout = ?HANDSHAKE_TIMEOUT, + ?ERROR_MSG("(~p) Connection to ~p:~p postponed: " + "waiting for ~p update, " "retrying after ~p seconds", [State#state.host, Gateway, Port, - Reason, ?RECONNECT_TIMEOUT div 1000]), - erlang:send_after(?RECONNECT_TIMEOUT, self(), connect), - {noreply, State} + CertFile, Timeout div 1000]), + erlang:send_after(Timeout, self(), connect), + {noreply, State}; + _ -> + connect(State#state{certfile_mtime = undefined}) end; connect(State) -> {noreply, State}. +get_mtime(File) -> + case file:read_file_info(File) of + {ok, FileInfo} -> + FileInfo#file_info.mtime; + {error, _} -> + no_certfile + end. + bounce_message(From, To, Packet, Reason) -> {xmlelement, _, Attrs, _} = Packet, Type = xml:get_attr_s("type", Attrs), From a5166f394620763e35afa3736ba02c80e8cc64bd Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Fri, 15 Oct 2010 23:13:29 +1000 Subject: [PATCH 2/5] copied feature_inspect_packet hook from iphone svn repo --- src/ejabberd_c2s.erl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 2b0ef2237..e8c37b740 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1678,9 +1678,19 @@ send_text(StateData, Text) -> (StateData#state.sockmod):send(StateData#state.socket, Text). send_element(StateData, El) when StateData#state.xml_socket -> + ejabberd_hooks:run(feature_inspect_packet, + StateData#state.server, + [StateData#state.jid, + StateData#state.server, + StateData#state.pres_last, El]), (StateData#state.sockmod):send_xml(StateData#state.socket, {xmlstreamelement, El}); send_element(StateData, El) -> + ejabberd_hooks:run(feature_inspect_packet, + StateData#state.server, + [StateData#state.jid, + StateData#state.server, + StateData#state.pres_last, El]), send_text(StateData, xml:element_to_binary(El)). send_header(StateData, Server, Version, Lang) From aea394861de676ba0e15685a18f22f52afe7a94e Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Mon, 25 Oct 2010 08:46:38 +0200 Subject: [PATCH 3/5] Added a protocol for a client to send the number of local unread messages Conflicts: src/ejabberd_c2s.erl --- src/ejabberd_c2s.erl | 14 +++++++++++++- src/ejabberd_c2s.hrl | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 570f4f636..ca94a5245 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -2772,7 +2772,7 @@ send_out_of_reception_message(StateData, From, To, StateData#state.jid, StateData#state.oor_notification, Msg, - Unread, + Unread + StateData#state.oor_unread_client, Sound, AppID, SFrom]), @@ -3145,6 +3145,18 @@ process_push_iq(From, To, oor_send_body = all}, NSD2 = start_keepalive_timer(NSD1), {{result, []}, NSD2}; + {xmlelement, "badge", _, _} -> + SBadge = xml:get_path_s(El, [{attr, "unread"}]), + Badge = + case catch list_to_integer(SBadge) of + B when is_integer(B) -> + B; + _ -> + 0 + end, + NSD1 = + StateData#state{oor_unread_client = Badge}, + {{result, []}, NSD1}; _ -> {{error, ?ERR_BAD_REQUEST}, StateData} end, diff --git a/src/ejabberd_c2s.hrl b/src/ejabberd_c2s.hrl index 381e042ba..a3689d8d0 100644 --- a/src/ejabberd_c2s.hrl +++ b/src/ejabberd_c2s.hrl @@ -78,8 +78,9 @@ oor_appid = "", oor_unread = 0, oor_unread_users = ?SETS:new(), + oor_unread_client = 0, oor_offline = false, ack_enabled = false, ack_counter = 0, ack_queue = queue:new(), - ack_timer}). \ No newline at end of file + ack_timer}). From 931866ee33e3b18bf683678f6054edcfd3a13403 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Wed, 1 Dec 2010 15:11:36 +0200 Subject: [PATCH 4/5] Added ssl:connect timeout --- src/mod_applepush_service.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mod_applepush_service.erl b/src/mod_applepush_service.erl index 43eae897e..3a0062782 100644 --- a/src/mod_applepush_service.erl +++ b/src/mod_applepush_service.erl @@ -45,6 +45,7 @@ -define(RECONNECT_TIMEOUT, 5000). -define(FEEDBACK_RECONNECT_TIMEOUT, 30000). -define(HANDSHAKE_TIMEOUT, 60000). +-define(SSL_TIMEOUT, 5000). -define(MAX_QUEUE_SIZE, 1000). -define(CACHE_SIZE, 4096). -define(MAX_PAYLOAD_SIZE, 255). @@ -191,7 +192,7 @@ handle_info(connect_feedback, State) case ssl:connect(Feedback, FeedbackPort, [{certfile, CertFile}, {active, true}, - binary]) of + binary], ?SSL_TIMEOUT) of {ok, Socket} -> {noreply, State#state{feedback_socket = Socket}}; {error, Reason} -> @@ -464,7 +465,8 @@ connect(#state{socket = undefined, certfile_mtime = undefined} = State) -> CertFile = State#state.certfile, case ssl:connect(Gateway, Port, [{certfile, CertFile}, {active, true}, - binary]) of + binary], + ?SSL_TIMEOUT) of {ok, Socket} -> {noreply, resend_messages(State#state{socket = Socket})}; {error, Reason} -> From 9f3cdad3f7e4dce718317281c7d9223c8cab98ed Mon Sep 17 00:00:00 2001 From: Evgeniy Khramtsov Date: Wed, 27 Oct 2010 21:05:19 +1000 Subject: [PATCH 5/5] Do not add "jabber:x:delay" more than once --- src/ejabberd_c2s.erl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index ca94a5245..1fc0c5d92 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -1926,7 +1926,8 @@ process_presence_probe(From, To, StateData) -> end, Timestamp = StateData#state.pres_timestamp, Packet1 = xml:append_subtags( - Packet, + xml:remove_subtags( + Packet, "x", {"xmlns", ?NS_DELAY91}), %% To is the one sending the presence (the target of the probe) [jlib:timestamp_to_xml(Timestamp, utc, To, ""), %% TODO: Delete the next line once XEP-0091 is Obsolete @@ -2855,7 +2856,9 @@ enqueue(StateData, From, To, Packet) -> StateData#state{pres_queue = NewQueue} end; true -> - CleanPacket = xml:remove_subtags(Packet, "x", {"xmlns", ?NS_P1_PUSHED}), + CleanPacket = xml:remove_subtags( + xml:remove_subtags(Packet, "x", {"xmlns", ?NS_P1_PUSHED}), + "x", {"xmlns", ?NS_DELAY91}), Packet2 = case CleanPacket of {xmlelement, "message" = Name, Attrs, Els} ->