aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/ftp/ftp.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/inets/src/ftp/ftp.erl')
-rw-r--r--lib/inets/src/ftp/ftp.erl73
1 files changed, 64 insertions, 9 deletions
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index 9d0c59eda8..e0430654eb 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -100,6 +100,12 @@
ftp_extension = ?FTP_EXT_DEFAULT
}).
+-record(recv_chunk_closing, {
+ dconn_closed = false,
+ pos_compl_received = false,
+ client_called_us = false
+ }).
+
-type shortage_reason() :: 'etnospc' | 'epnospc'.
-type restriction_reason() :: 'epath' | 'efnamena' | 'elogin' | 'enotbinary'.
@@ -108,7 +114,7 @@
-define(DBG(F,A), 'n/a').
%%-define(DBG(F,A), io:format(F,A)).
-%%-define(DBG(F,A), if is_list(F) -> ct:pal(F,A); is_atom(F)->ct:pal(atom_to_list(F),A) end).
+%%-define(DBG(F,A), ct:pal("~p:~p " ++ if is_list(F) -> F; is_atom(F) -> atom_to_list(F) end, [?MODULE,?LINE|A])).
%%%=========================================================================
%%% API - CLIENT FUNCTIONS
@@ -1343,6 +1349,25 @@ handle_call({_,{recv_chunk_start, RemoteFile}}, From, #state{chunk = false}
handle_call({_, recv_chunk}, _, #state{chunk = false} = State) ->
{reply, {error, "ftp:recv_chunk_start/2 not called"}, State};
+handle_call({_, recv_chunk}, _From, #state{chunk = true,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ pos_compl_received = true
+ }
+ } = State0) ->
+ %% The ftp:recv_chunk call was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing ftp:recv_chunk, last event",[]),
+ activate_ctrl_connection(State0),
+ {reply, ok, State0#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_call({_, recv_chunk}, From, #state{chunk = true,
+ caller = #recv_chunk_closing{} = R
+ } = State) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing ftp:recv_chunk, get more",[]),
+ {noreply, State#state{client = From, caller = R#recv_chunk_closing{client_called_us=true}}};
+
handle_call({_, recv_chunk}, From, #state{chunk = true} = State0) ->
State = activate_data_connection(State0),
{noreply, State#state{client = From, caller = recv_chunk}};
@@ -1480,19 +1505,24 @@ handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
file_close(Fd),
progress_report({transfer_size, 0}, State),
activate_ctrl_connection(State),
+ ?DBG("Data channel close",[]),
{noreply, State#state{dsock = undefined, data = <<>>}};
-handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, client = From,
+handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket},
+ client = Client,
caller = recv_chunk} = State)
when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
- gen_server:reply(From, ok),
- {noreply, State#state{dsock = undefined, client = undefined,
- data = <<>>, caller = undefined,
- chunk = false}};
+ ?DBG("Data channel close recv_chunk",[]),
+ activate_ctrl_connection(State),
+ {noreply, State#state{dsock = undefined,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = Client =/= undefined}
+ }};
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
data = Data} = State)
when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
activate_ctrl_connection(State),
{noreply, State#state{dsock = undefined, data = <<>>,
caller = {recv_bin, Data}}};
@@ -1500,6 +1530,7 @@ handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, caller = recv_bin,
handle_info({Cls, Socket}, #state{dsock = {Trpt,Socket}, data = Data,
caller = {handle_dir_result, Dir}}
= State) when {Cls,Trpt}=={tcp_closed,tcp} ; {Cls,Trpt}=={ssl_closed,ssl} ->
+ ?DBG("Data channel close",[]),
activate_ctrl_connection(State),
{noreply, State#state{dsock = undefined,
caller = {handle_dir_result, Dir, Data},
@@ -1601,13 +1632,13 @@ terminate(normal, State) ->
%% If terminate reason =/= normal the progress reporting process will
%% be killed by the exit signal.
progress_report(stop, State),
- do_termiante({error, econn}, State);
+ do_terminate({error, econn}, State);
terminate(Reason, State) ->
Report = io_lib:format("Ftp connection closed due to: ~p~n", [Reason]),
error_logger:error_report(Report),
- do_termiante({error, eclosed}, State).
+ do_terminate({error, eclosed}, State).
-do_termiante(ErrorMsg, State) ->
+do_terminate(ErrorMsg, State) ->
close_data_connection(State),
close_ctrl_connection(State),
case State#state.client of
@@ -2046,6 +2077,30 @@ handle_ctrl_result({pos_prel, _}, #state{client = From,
end;
%%--------------------------------------------------------------------------
+%% File handling - chunk_transfer complete
+
+handle_ctrl_result({pos_compl, _}, #state{client = From,
+ caller = #recv_chunk_closing{dconn_closed = true,
+ client_called_us = true,
+ pos_compl_received = false
+ }}
+ = State0) when From =/= undefined ->
+ %% The pos_compl was the last event we waited for, finnish and clean up
+ ?DBG("recv_chunk_closing pos_compl, last event",[]),
+ gen_server:reply(From, ok),
+ activate_ctrl_connection(State0),
+ {noreply, State0#state{caller = undefined,
+ chunk = false,
+ client = undefined}};
+
+handle_ctrl_result({pos_compl, _}, #state{caller = #recv_chunk_closing{}=R}
+ = State0) ->
+ %% Waiting for more, don't care what
+ ?DBG("recv_chunk_closing pos_compl, wait more",[]),
+ {noreply, State0#state{caller = R#recv_chunk_closing{pos_compl_received=true}}};
+
+
+%%--------------------------------------------------------------------------
%% File handling - recv_file
handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State0) ->
case accept_data_connection(State0) of