aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2012-12-01 10:24:07 +0100
committerLoïc Hoguin <[email protected]>2012-12-01 10:24:07 +0100
commitfb7ed3807620f7534c617789e7347192838a419a (patch)
tree4feb6f6ede8548a889a2e33fdab304b95e071ed0
parent0d18f4f93054d9df6a0496a2b9fe8c09f336906e (diff)
downloadranch-fb7ed3807620f7534c617789e7347192838a419a.tar.gz
ranch-fb7ed3807620f7534c617789e7347192838a419a.tar.bz2
ranch-fb7ed3807620f7534c617789e7347192838a419a.zip
Add Transport:sendfile/2 support
Uses file:sendfile/2 for TCP, a fallback function for SSL.
-rw-r--r--src/ranch_ssl.erl29
-rw-r--r--src/ranch_tcp.erl13
2 files changed, 42 insertions, 0 deletions
diff --git a/src/ranch_ssl.erl b/src/ranch_ssl.erl
index 4bbc3ce..734de21 100644
--- a/src/ranch_ssl.erl
+++ b/src/ranch_ssl.erl
@@ -32,6 +32,7 @@
-export([connect/3]).
-export([recv/3]).
-export([send/2]).
+-export([sendfile/2]).
-export([setopts/2]).
-export([controlling_process/2]).
-export([peername/1]).
@@ -138,6 +139,34 @@ recv(Socket, Length, Timeout) ->
send(Socket, Packet) ->
ssl:send(Socket, Packet).
+%% @doc Send a file on a socket.
+%%
+%% Unlike with TCP, no syscall can be used here, so sending files
+%% through SSL will be much slower in comparison.
+%%
+%% @see file:sendfile/2
+-spec sendfile(ssl:sslsocket(), file:name())
+ -> {ok, non_neg_integer()} | {error, atom()}.
+sendfile(Socket, Filepath) ->
+ {ok, IoDevice} = file:open(Filepath, [read, binary, raw]),
+ sendfile(Socket, IoDevice, 0).
+
+-spec sendfile(ssl:sslsocket(), file:io_device(), non_neg_integer())
+ -> {ok, non_neg_integer()} | {error, atom()}.
+sendfile(Socket, IoDevice, Sent) ->
+ case file:read(IoDevice, 16#1FFF) of
+ eof ->
+ ok = file:close(IoDevice),
+ {ok, Sent};
+ {ok, Bin} ->
+ case send(Socket, Bin) of
+ ok ->
+ sendfile(Socket, IoDevice, Sent + byte_size(Bin));
+ {error, Reason} ->
+ {error, Reason}
+ end
+ end.
+
%% @doc Set options on the given socket.
%% @see ssl:setopts/2
%% @todo Probably filter Opts?
diff --git a/src/ranch_tcp.erl b/src/ranch_tcp.erl
index d68972d..b113186 100644
--- a/src/ranch_tcp.erl
+++ b/src/ranch_tcp.erl
@@ -27,6 +27,7 @@
-export([connect/3]).
-export([recv/3]).
-export([send/2]).
+-export([sendfile/2]).
-export([setopts/2]).
-export([controlling_process/2]).
-export([peername/1]).
@@ -103,6 +104,18 @@ recv(Socket, Length, Timeout) ->
send(Socket, Packet) ->
gen_tcp:send(Socket, Packet).
+%% @doc Send 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.
+%%
+%% @see file:sendfile/2
+-spec sendfile(inet:socket(), file:name())
+ -> {ok, non_neg_integer()} | {error, atom()}.
+sendfile(Socket, Filename) ->
+ file:sendfile(Filename, Socket).
+
%% @doc Set options on the given socket.
%% @see inet:setopts/2
%% @todo Probably filter Opts?