aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2011-12-07 14:46:26 +0100
committerLukas Larsson <[email protected]>2011-12-07 19:19:17 +0100
commit1137c0a08b25ab5e38286260f0b7c51ba015afbb (patch)
tree4258119045dc70037e41fd55e16cdd55724c53a9
parentf34a89e0c0cc92226d5fe3fb257c62251068392b (diff)
downloadotp-1137c0a08b25ab5e38286260f0b7c51ba015afbb.tar.gz
otp-1137c0a08b25ab5e38286260f0b7c51ba015afbb.tar.bz2
otp-1137c0a08b25ab5e38286260f0b7c51ba015afbb.zip
Return {error,closed} from sendfile if closed
If the socket is closed by the remote end, sendfile now returns {error,closed}.
-rw-r--r--erts/emulator/drivers/common/efile_drv.c16
-rw-r--r--lib/kernel/src/file.erl6
-rw-r--r--lib/kernel/test/sendfile_SUITE.erl41
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) ->