From ca6817880ee5592cf890fb5a71da41f52818d29a Mon Sep 17 00:00:00 2001 From: James Fish Date: Tue, 2 Apr 2013 00:49:07 +0100 Subject: Add Transport:sendfile/4,/5 Adds offset based sendfile to transports. Same behaviour as file:sendfile/4,/5 except socket and file arguments are reversed and either a raw file or a filename can be used. sendfile/2,/4,/5 now compulsory callbacks in ranch_transport. ranch_tcp:sendfile/2 now defaults to a chunk_size of 8191 - the default for ranch_ssl:sendfile/2. The same default is used for both ranch_tcp:sendfile/4,5 and ranch_ssl:sendfile/4,5. --- src/ranch_tcp.erl | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 9 deletions(-) (limited to 'src/ranch_tcp.erl') diff --git a/src/ranch_tcp.erl b/src/ranch_tcp.erl index 11a0843..6bdcdd0 100644 --- a/src/ranch_tcp.erl +++ b/src/ranch_tcp.erl @@ -28,6 +28,8 @@ -export([recv/3]). -export([send/2]). -export([sendfile/2]). +-export([sendfile/4]). +-export([sendfile/5]). -export([setopts/2]). -export([controlling_process/2]). -export([peername/1]). @@ -110,21 +112,52 @@ recv(Socket, Length, Timeout) -> send(Socket, Packet) -> gen_tcp:send(Socket, Packet). -%% @doc Send a file on a socket. +%% @equiv sendfile(Socket, File, Offset, Bytes, []) +-spec sendfile(inet:socket(), file:name_all()) + -> {ok, non_neg_integer()} | {error, atom()}. +sendfile(Socket, Filename) -> + sendfile(Socket, Filename, 0, 0, []). + +%% @equiv sendfile(Socket, File, Offset, Bytes, []) +-spec sendfile(inet:socket(), file:name_all() | file:fd(), non_neg_integer(), + non_neg_integer()) + -> {ok, non_neg_integer()} | {error, atom()}. +sendfile(Socket, File, Offset, Bytes) -> + sendfile(Socket, File, Offset, Bytes, []). + +%% @doc Send part of a file on a socket. %% -%% This is the optimal way to send files using TCP. It uses a syscall -%% which means there is no context switch between opening the file -%% and writing its contents on the socket. +%% As with sendfile/2 this is the optimal way to send (parts) of files using +%% TCP. Note that unlike file:sendfile/5 this function accepts either a raw file +%% or a file name and the ordering of arguments is different. %% -%% @see file:sendfile/2 --spec sendfile(inet:socket(), file:name()) +%% @see file:sendfile/5 +-spec sendfile(inet:socket(), file:name_all() | file:fd(), non_neg_integer(), + non_neg_integer(), [{chunk_size, non_neg_integer()}]) -> {ok, non_neg_integer()} | {error, atom()}. -sendfile(Socket, Filename) -> - try file:sendfile(Filename, Socket) of +sendfile(Socket, Filename, Offset, Bytes, Opts) + when is_list(Filename) orelse is_atom(Filename) + orelse is_binary(Filename) -> + case file:open(Filename, [read, raw, binary]) of + {ok, RawFile} -> + try sendfile(Socket, RawFile, Offset, Bytes, Opts) of + Result -> Result + after + ok = file:close(RawFile) + end; + {error, _} = Error -> + Error + end; +sendfile(Socket, RawFile, Offset, Bytes, Opts) -> + Opts2 = case Opts of + [] -> [{chunk_size, 16#1FFF}]; + _ -> Opts + end, + try file:sendfile(RawFile, Socket, Offset, Bytes, Opts2) of Result -> Result catch error:{badmatch, {error, enotconn}} -> - %% file:sendfile/2 might fail by throwing a {badmatch, {error, enotconn}} + %% file:sendfile/5 might fail by throwing a {badmatch, {error, enotconn}} %% this is because its internal implementation fails with a badmatch in %% prim_file:sendfile/10 if the socket is not connected. {error, closed} -- cgit v1.2.3