diff options
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 16 | ||||
-rw-r--r-- | lib/kernel/src/file.erl | 6 | ||||
-rw-r--r-- | lib/kernel/test/sendfile_SUITE.erl | 41 |
3 files changed, 58 insertions, 5 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 5c52b99348..32914d3b22 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -799,7 +799,16 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, driver_output2(desc->port, response, t-response, NULL, 0); } +static void reply_string_error(file_descriptor *desc, char* str) { + char response[256]; /* Response buffer. */ + char* s; + char* t; + response[0] = FILE_RESP_ERROR; + for (s = str, t = response+1; *s; s++, t++) + *t = tolower(*s); + driver_output2(desc->port, response, t-response, NULL, 0); +} static int reply_error(file_descriptor *desc, Efile_error *errInfo) /* The error codes. */ @@ -2208,7 +2217,12 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) case FILE_SENDFILE: if (d->result_ok == -1) { desc->sendfile_state = not_sending; - reply_error(desc, &d->errInfo); + if (d->errInfo.posix_errno == ECONNRESET || + d->errInfo.posix_errno == ENOTCONN || + d->errInfo.posix_errno == EPIPE) + reply_string_error(desc,"closed"); + else + reply_error(desc, &d->errInfo); if (sys_info.async_threads != 0) { SET_NONBLOCKING(d->c.sendfile.out_fd); free_sendfile(data); diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 0b0f91d86a..a3c0e7da26 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1124,7 +1124,8 @@ change_time(Name, Atime, Mtime) -define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory -spec sendfile(RawFile, Socket, Offset, Bytes, Opts) -> - {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} when + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when RawFile :: file:fd(), Socket :: inet:socket(), Offset :: non_neg_integer(), @@ -1149,7 +1150,8 @@ sendfile(File, Sock, Offset, Bytes, Opts) -> %% sendfile/2 -spec sendfile(Filename, Socket) -> - {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when Filename :: file:name(), Socket :: inet:socket(). sendfile(Filename, Sock) -> diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 4a6cd604e0..483290b91a 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -33,6 +33,7 @@ all() -> ,t_sendfile_recvafter ,t_sendfile_sendduring ,t_sendfile_recvduring + ,t_sendfile_closeduring ]. init_per_suite(Config) -> @@ -212,19 +213,52 @@ t_sendfile_recvduring(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). +t_sendfile_closeduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock,SFServPid) -> + spawn_link(fun() -> + timer:sleep(50), + SFServPid ! stop + end), + case erlang:system_info(thread_pool_size) of + 0 -> + {error, closed} = file:sendfile(Filename, Sock); + _Else -> + %% This can return how much has been sent or + %% {error,closed} depending on OS. + %% How much is sent impossible to know as + %% the socket was closed mid sendfile + case file:sendfile(Filename, Sock) of + {error, closed} -> + ok; + {ok, Size} when is_integer(Size) -> + ok + end + end, + -1 + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + %% Generic sendfile server code sendfile_send(Send) -> sendfile_send({127,0,0,1},Send). sendfile_send(Host, Send) -> sendfile_send(Host, Send, []). sendfile_send(Host, Send, Orig) -> - spawn_link(?MODULE, sendfile_server, [self(), Orig]), + SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]), receive {server, Port} -> {ok, Sock} = gen_tcp:connect(Host, Port, [binary,{packet,0}, {active,false}]), - Data = Send(Sock), + Data = case proplists:get_value(arity,erlang:fun_info(Send)) of + 1 -> + Send(Sock); + 2 -> + Send(Sock, SFServer) + end, ok = gen_tcp:close(Sock), receive {ok, Bin} -> @@ -247,6 +281,9 @@ sendfile_server(ClientPid, Orig) -> -define(SENDFILE_TIMEOUT, 10000). sendfile_do_recv(Sock, Bs) -> receive + stop when Bs /= 0,is_integer(Bs) -> + gen_tcp:close(Sock), + {ok, -1}; {tcp, Sock, B} -> case binary:match(B,<<1>>) of nomatch when is_list(Bs) -> |