aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/src
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2011-11-27 17:22:05 +0100
committerLukas Larsson <[email protected]>2011-12-02 10:39:34 +0100
commit836410f5c9e092be4b77b26b3fc9f7abde0c89de (patch)
tree5f7a42db276f5bffebf1c7baedbea3ade3d73a82 /lib/kernel/src
parenta5b3d81936ab85edb8713f29baf85307ae0b25b8 (diff)
downloadotp-836410f5c9e092be4b77b26b3fc9f7abde0c89de.tar.gz
otp-836410f5c9e092be4b77b26b3fc9f7abde0c89de.tar.bz2
otp-836410f5c9e092be4b77b26b3fc9f7abde0c89de.zip
Move sendfile api to file module
Since sendfile could in theory be used to send to any type of file descriptor in *nix, it is a better fit to have it in file.
Diffstat (limited to 'lib/kernel/src')
-rw-r--r--lib/kernel/src/file.erl142
-rw-r--r--lib/kernel/src/gen_tcp.erl146
2 files changed, 143 insertions, 145 deletions
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 706c60caaf..ef1d20b53b 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -51,6 +51,9 @@
-export([pid2name/1]).
+%% Sendfile functions
+-export([sendfile/2,sendfile/5]).
+
%%% Obsolete exported functions
-export([raw_read_file_info/1, raw_write_file_info/2]).
@@ -103,7 +106,10 @@
-type date_time() :: calendar:datetime().
-type posix_file_advise() :: 'normal' | 'sequential' | 'random'
| 'no_reuse' | 'will_need' | 'dont_need'.
-
+-type sendfile_option() :: {chunk_size, non_neg_integer()} |
+ {headers, Hdrs :: list(iodata())} |
+ {trailers, Tlrs :: list(iodata())} |
+ sf_nodiskio | sf_mnowait | sf_sync.
%%%-----------------------------------------------------------------
%%% General functions
@@ -1114,6 +1120,140 @@ change_time(Name, Atime, Mtime)
when is_tuple(Atime), is_tuple(Mtime) ->
write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}).
+%%
+%% Send data using sendfile
+%%
+
+-define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory
+
+-spec sendfile(File, Sock, Offset, Bytes, Opts) ->
+ {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner} when
+ File :: file:fd(),
+ Sock :: inet:socket(),
+ Offset :: non_neg_integer(),
+ Bytes :: non_neg_integer(),
+ Opts :: [sendfile_option()].
+sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
+ {error, badarg};
+sendfile(File, Sock, Offset, Bytes, []) ->
+ sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [],
+ false, false, false);
+sendfile(File, Sock, Offset, Bytes, Opts) ->
+ ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
+ ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE ->
+ ?MAX_CHUNK_SIZE;
+ true -> ChunkSize0
+ end,
+ Headers = proplists:get_value(headers, Opts, []),
+ Trailers = proplists:get_value(trailers, Opts, []),
+ sendfile(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
+ lists:member(sf_nodiskio,Opts),lists:member(sf_mnowait,Opts),
+ lists:member(sf_sync,Opts)).
+
+%% sendfile/2
+-spec sendfile(File, Sock) ->
+ {'ok', non_neg_integer()} | {'error', inet:posix() | badarg | not_owner}
+ when File :: file:name(),
+ Sock :: inet:socket().
+sendfile(File, Sock) ->
+ case file:open(File, [read, raw, binary]) of
+ {error, Reason} ->
+ {error, Reason};
+ {ok, Fd} ->
+ Res = sendfile(Fd, Sock, 0, 0, []),
+ file:close(Fd),
+ Res
+ end.
+
+%% Internal sendfile functions
+sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
+ ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync)
+ when is_port(Sock) ->
+ case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
+ Nodiskio, MNowait, Sync) of
+ {error, enotsup} ->
+ sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize,
+ Headers, Trailers);
+ Else ->
+ Else
+ end;
+sendfile(_,_,_,_,_,_,_,_,_,_) ->
+ {error, badarg}.
+
+%%%
+%% Sendfile Fallback
+%%%
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
+ Headers, Trailers)
+ when Headers == []; is_integer(Headers) ->
+ case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
+ {ok, BytesSent} when is_list(Trailers),
+ Trailers =/= [],
+ is_integer(Headers) ->
+ sendfile_send(Sock, Trailers, BytesSent+Headers);
+ {ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
+ sendfile_send(Sock, Trailers, BytesSent);
+ {ok, BytesSent} when is_integer(Headers) ->
+ {ok, BytesSent + Headers};
+ Else ->
+ Else
+ end;
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) ->
+ case sendfile_send(Sock, Headers, 0) of
+ {ok, BytesSent} ->
+ sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent,
+ Trailers);
+ Else ->
+ Else
+ end.
+
+
+sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) ->
+ {ok, CurrPos} = file:position(File, {cur, 0}),
+ {ok, _NewPos} = file:position(File, {bof, Offset}),
+ Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
+ file:position(File, {bof, CurrPos}),
+ Res.
+
+
+sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
+ when Bytes > BytesSent; Bytes == 0 ->
+ Size = if Bytes == 0 ->
+ ChunkSize;
+ (Bytes - BytesSent + ChunkSize) > 0 ->
+ Bytes - BytesSent;
+ true ->
+ ChunkSize
+ end,
+ case file:read(File, Size) of
+ {ok, Data} ->
+ case sendfile_send(Sock, Data, BytesSent) of
+ {ok,NewBytesSent} ->
+ sendfile_fallback_int(
+ File, Sock, Bytes, ChunkSize,
+ NewBytesSent);
+ Error ->
+ Error
+ end;
+ eof ->
+ {ok, BytesSent};
+ Error ->
+ Error
+ end;
+sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) ->
+ {ok, BytesSent}.
+
+sendfile_send(Sock, Data, Old) ->
+ Len = iolist_size(Data),
+ case gen_tcp:send(Sock, Data) of
+ ok ->
+ {ok, Len+Old};
+ Else ->
+ Else
+ end.
+
+
+
%%%-----------------------------------------------------------------
%%% Helpers
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index 78e3ab3697..4d6c7f5f1d 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -22,7 +22,7 @@
-export([connect/3, connect/4, listen/2, accept/1, accept/2,
shutdown/2, close/1]).
--export([send/2, recv/2, recv/3, unrecv/2, sendfile/2, sendfile/5]).
+-export([send/2, recv/2, recv/3, unrecv/2]).
-export([controlling_process/2]).
-export([fdopen/2]).
@@ -106,13 +106,8 @@
{tcp_module, module()} |
option().
-type socket() :: port().
--type sendfile_option() :: {chunk_size, non_neg_integer()} |
- {headers, Hdrs :: list(iodata())} |
- {trailers, Tlrs :: list(iodata())} |
- sf_nodiskio | sf_mnowait | sf_sync.
--export_type([option/0, option_name/0, connect_option/0, listen_option/0,
- sendfile_option/0]).
+-export_type([option/0, option_name/0, connect_option/0, listen_option/0]).
%%
%% Connect a socket
@@ -308,52 +303,6 @@ unrecv(S, Data) when is_port(S) ->
Mod:unrecv(S, Data);
Error ->
Error
- end.
-
-%%
-%% Send data using sendfile
-%%
-
--define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory
-
--spec sendfile(File, Sock, Offset, Bytes, Opts) ->
- {'ok', non_neg_integer()} | {'error', inet:posix() } |
- {'error', not_owner} when
- File :: file:fd(),
- Sock :: socket(),
- Offset :: non_neg_integer(),
- Bytes :: non_neg_integer(),
- Opts :: [sendfile_option()].
-sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) ->
- {error, badarg};
-sendfile(File, Sock, Offset, Bytes, []) ->
- sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [],
- false, false, false);
-sendfile(File, Sock, Offset, Bytes, Opts) ->
- ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE),
- ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE ->
- ?MAX_CHUNK_SIZE;
- true -> ChunkSize0
- end,
- Headers = proplists:get_value(headers, Opts, []),
- Trailers = proplists:get_value(trailers, Opts, []),
- sendfile(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers,
- lists:member(sf_nodiskio,Opts),lists:member(sf_mnowait,Opts),
- lists:member(sf_sync,Opts)).
-
-%% sendfile/2
--spec sendfile(File, Sock) ->
- {'ok', non_neg_integer()} | {'error', inet:posix() | badarg}
- when File :: file:name(),
- Sock :: socket().
-sendfile(File, Sock) ->
- case file:open(File, [read, raw, binary]) of
- {error, Reason} ->
- {error, Reason};
- {ok, Fd} ->
- Res = sendfile(Fd, Sock, 0, 0, []),
- file:close(Fd),
- Res
end.
%%
@@ -407,94 +356,3 @@ mod([_|Opts], Address) ->
mod([], Address) ->
mod(Address).
-
-%% Internal sendfile functions
-sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes,
- ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync)
- when is_port(Sock) ->
- ok = inet:lock_socket(Sock,true),
- {ok, SockFd} = prim_inet:getfd(Sock),
- case Mod:sendfile(Fd, SockFd, Offset, Bytes, ChunkSize, Headers, Trailers,
- Nodiskio, MNowait, Sync) of
- {error, enotsup} ->
- ok = inet:lock_socket(Sock,false),
- sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize,
- Headers, Trailers);
- Else ->
- ok = inet:lock_socket(Sock,false),
- Else
- end;
-sendfile(_,_,_,_,_,_,_,_,_,_) ->
- {error, badarg}.
-
-%%%
-%% Sendfile Fallback
-%%%
-sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize,
- Headers, Trailers)
- when Headers == []; is_integer(Headers) ->
- case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of
- {ok, BytesSent} when is_list(Trailers),
- Trailers =/= [],
- is_integer(Headers) ->
- sendfile_send(Sock, Trailers, BytesSent+Headers);
- {ok, BytesSent} when is_list(Trailers), Trailers =/= [] ->
- sendfile_send(Sock, Trailers, BytesSent);
- {ok, BytesSent} when is_integer(Headers) ->
- {ok, BytesSent + Headers};
- Else ->
- Else
- end;
-sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) ->
- case sendfile_send(Sock, Headers, 0) of
- {ok, BytesSent} ->
- sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent,
- Trailers);
- Else ->
- Else
- end.
-
-
-sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) ->
- {ok, CurrPos} = file:position(File, {cur, 0}),
- {ok, _NewPos} = file:position(File, {bof, Offset}),
- Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0),
- file:position(File, {bof, CurrPos}),
- Res.
-
-
-sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent)
- when Bytes > BytesSent; Bytes == 0 ->
- Size = if Bytes == 0 ->
- ChunkSize;
- (Bytes - BytesSent + ChunkSize) > 0 ->
- Bytes - BytesSent;
- true ->
- ChunkSize
- end,
- case file:read(File, Size) of
- {ok, Data} ->
- case sendfile_send(Sock, Data, BytesSent) of
- {ok,NewBytesSent} ->
- sendfile_fallback_int(
- File, Sock, Bytes, ChunkSize,
- NewBytesSent);
- Error ->
- Error
- end;
- eof ->
- {ok, BytesSent};
- Error ->
- Error
- end;
-sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) ->
- {ok, BytesSent}.
-
-sendfile_send(Sock, Data, Old) ->
- Len = iolist_size(Data),
- case send(Sock, Data) of
- ok ->
- {ok, Len+Old};
- Else ->
- Else
- end.