]> granicus.if.org Git - ejabberd/commitdiff
XEP-0198: Change state on gen_tcp:send/2 failure
authorHolger Weiss <holger@zedat.fu-berlin.de>
Sat, 6 Sep 2014 18:34:32 +0000 (20:34 +0200)
committerHolger Weiss <holger@zedat.fu-berlin.de>
Sat, 6 Sep 2014 18:34:32 +0000 (20:34 +0200)
When Stream Management is enabled and a gen_tcp:send/2 call fails, go
into the 'wait_for_resume' state immediately.  This makes sure that
gen_tcp:send/2 won't be called again, which might avoid an Erlang issue
where gen_tcp:send/2 apparently hangs despite 'send_timeout' (and
'send_timeout_close') being set.

src/ejabberd_c2s.erl

index 822edc0c97f1c3c7546d7bfa7cb5dc1486f7b8e2..c734d91ed82a84add99ad630135f9400d71f3850 100644 (file)
@@ -1838,7 +1838,8 @@ send_text(StateData, Text) when StateData#state.mgmt_state == active ->
     ?DEBUG("Send XML on stream = ~p", [Text]),
     case catch (StateData#state.sockmod):send(StateData#state.socket, Text) of
       {'EXIT', _} ->
-         (StateData#state.sockmod):close(StateData#state.socket);
+         (StateData#state.sockmod):close(StateData#state.socket),
+         error;
       _ ->
          ok
     end;
@@ -1857,8 +1858,13 @@ send_element(StateData, El) ->
 send_stanza(StateData, Stanza) when StateData#state.mgmt_state == pending ->
     mgmt_queue_add(StateData, Stanza);
 send_stanza(StateData, Stanza) when StateData#state.mgmt_state == active ->
-    send_stanza_and_ack_req(StateData, Stanza),
-    mgmt_queue_add(StateData, Stanza);
+    NewStateData = case send_stanza_and_ack_req(StateData, Stanza) of
+                    ok ->
+                        StateData;
+                    error ->
+                        StateData#state{mgmt_state = pending}
+                  end,
+    mgmt_queue_add(NewStateData, Stanza);
 send_stanza(StateData, Stanza) ->
     send_element(StateData, Stanza),
     StateData.
@@ -2455,13 +2461,15 @@ fsm_next_state_gc(StateName, PackedStateData) ->
 
 %% fsm_next_state: Generate the next_state FSM tuple with different
 %% timeout, depending on the future state
+fsm_next_state(session_established, #state{mgmt_state = pending} = StateData) ->
+    fsm_next_state(wait_for_resume, StateData);
 fsm_next_state(session_established, StateData) ->
     {next_state, session_established, StateData,
      ?C2S_HIBERNATE_TIMEOUT};
 fsm_next_state(wait_for_resume, #state{mgmt_timeout = 0} = StateData) ->
     {stop, normal, StateData};
-fsm_next_state(wait_for_resume, StateData)
-    when StateData#state.mgmt_state /= pending ->
+fsm_next_state(wait_for_resume, #state{mgmt_pending_since = undefined} =
+              StateData) ->
     ?INFO_MSG("Waiting for resumption of stream for ~s",
              [jlib:jid_to_string(StateData#state.jid)]),
     {next_state, wait_for_resume,