|
@@ -1,4 +1,4 @@
|
|
|
-%% Copyright (c) 2011-2012, Loïc Hoguin <essen@ninenines.eu>
|
|
|
+%% Copyright (c) 2011-2013, Loïc Hoguin <essen@ninenines.eu>
|
|
|
%%
|
|
|
%% Permission to use, copy, modify, and/or distribute this software for any
|
|
|
%% purpose with or without fee is hereby granted, provided that the above
|
|
@@ -12,17 +12,6 @@
|
|
|
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
-%% @doc SSL transport API.
|
|
|
-%%
|
|
|
-%% Wrapper around <em>ssl</em> implementing the Ranch transport API.
|
|
|
-%%
|
|
|
-%% This transport requires the <em>crypto</em>, <em>asn1</em>,
|
|
|
-%% <em>public_key</em> and <em>ssl</em> applications to be started.
|
|
|
-%% If they aren't started, it will try to start them itself before
|
|
|
-%% opening a port to listen. Applications aren't stopped when the
|
|
|
-%% listening socket is closed, though.
|
|
|
-%%
|
|
|
-%% @see ssl
|
|
|
-module(ranch_ssl).
|
|
|
-behaviour(ranch_transport).
|
|
|
|
|
@@ -71,77 +60,10 @@
|
|
|
| {verify_fun, {fun(), InitialUserState::term()}}].
|
|
|
-export_type([opts/0]).
|
|
|
|
|
|
-%% @doc Name of this transport, <em>ssl</em>.
|
|
|
name() -> ssl.
|
|
|
|
|
|
-%% @doc Atoms used to identify messages in {active, once | true} mode.
|
|
|
messages() -> {ssl, ssl_closed, ssl_error}.
|
|
|
|
|
|
-%% @doc Listen for connections on the given port number.
|
|
|
-%%
|
|
|
-%% Calling this function returns a listening socket that can then
|
|
|
-%% The available options are:
|
|
|
-%%
|
|
|
-%% <dl>
|
|
|
-%% <dt>backlog</dt><dd>Maximum length of the pending connections queue.
|
|
|
-%% Defaults to 1024.</dd>
|
|
|
-%% <dt>cacertfile</dt><dd>Optional. Path to file containing PEM encoded
|
|
|
-%% CA certificates (trusted certificates used for verifying a peer
|
|
|
-%% certificate).</dd>
|
|
|
-%% <dt>cert</dt><dd>Optional. The DER encoded users certificate. If this
|
|
|
-%% option is supplied it will override the certfile option.</dd>
|
|
|
-%% <dt>certfile</dt><dd>Mandatory. Path to a file containing the user's
|
|
|
-%% certificate.</dd>
|
|
|
-%% <dt>ciphers</dt><dd>Optional. The cipher suites that should be supported.
|
|
|
-%% The function ssl:cipher_suites/0 can be used to find all available
|
|
|
-%% ciphers.</dd>
|
|
|
-%% <dt>fail_if_no_peer_cert</dt><dd>Optional. Used together with {verify, verify_peer}.
|
|
|
-%% If set to true, the server will fail if the client does not have a certificate
|
|
|
-%% to send, i.e. sends a empty certificate, if set to false (that is by default)
|
|
|
-%% it will only fail if the client sends an invalid certificate (an empty
|
|
|
-%% certificate is considered valid).</dd>
|
|
|
-%% <dt>hibernate_after</dt><dd>When an integer-value is specified, the ssl_connection
|
|
|
-%% will go into hibernation after the specified number of milliseconds of inactivity,
|
|
|
-%% thus reducing its memory footprint. When undefined is specified (this is the
|
|
|
-%% default), the process will never go into hibernation.</dd>
|
|
|
-%% <dt>ip</dt><dd>Interface to listen on. Listen on all interfaces
|
|
|
-%% by default.</dd>
|
|
|
-%% <dt>key</dt><dd>Optional. The DER encoded users private key. If this option
|
|
|
-%% is supplied it will override the keyfile option.</dd>
|
|
|
-%% <dt>keyfile</dt><dd>Optional. Path to the file containing the user's
|
|
|
-%% private PEM encoded key.</dd>
|
|
|
-%% <dt>next_protocols_advertised</dt><dd>Optional. Erlang R16B+ required.
|
|
|
-%% List of protocols advertised by TLS Next Protocol Negotiation
|
|
|
-%% extension.</dd>
|
|
|
-%% <dt>nodelay</dt><dd>Optional. Enable TCP_NODELAY. Enabled by default.</dd>
|
|
|
-%% <dt>password</dt><dd>Optional. String containing the user's password.
|
|
|
-%% All private keyfiles must be password protected currently.</dd>
|
|
|
-%% <dt>port</dt><dd>TCP port number to open. Defaults to 0 (see below)</dd>
|
|
|
-%% <dt>reuse_session</dt><dd>Optional. Enables the ssl server to have a local
|
|
|
-%% policy for deciding if a session should be reused or not, only meaningful
|
|
|
-%% if reuse_sessions is set to true.</dd>
|
|
|
-%% <dt>reuse_sessions</dt><dd>Optional. Specifies if the server should agree
|
|
|
-%% to reuse sessions when the clients request to do so.</dd>
|
|
|
-%% <dt>secure_renegotiate</dt><dd>Optional. Specifies if to reject renegotiation
|
|
|
-%% attempt that does not live up to RFC 5746. By default secure_renegotiate is
|
|
|
-%% set to false i.e. secure renegotiation will be used if possible but it will
|
|
|
-%% fallback to unsecure renegotiation if the peer does not support RFC 5746.</dd>
|
|
|
-%% <dt>verify</dt><dd>Optional. If set to verify_peer, performs an x509-path
|
|
|
-%% validation and request the client for a certificate.</dd>
|
|
|
-%% <dt>verify_fun</dt><dd>Optional. The verify fun will be called during the
|
|
|
-%% X509-path validation when an error or an extension unknown to the ssl
|
|
|
-%% application is encountered. Additionally it will be called when a certificate
|
|
|
-%% is considered valid by the path validation to allow access to each certificate
|
|
|
-%% in the path to the user application.</dd>
|
|
|
-%% </dl>
|
|
|
-%%
|
|
|
-%% You can listen to a random port by setting the port option to 0.
|
|
|
-%% It is then possible to retrieve this port number by calling
|
|
|
-%% sockname/1 on the listening socket. If you are using Ranch's
|
|
|
-%% listener API, then this port number can obtained through
|
|
|
-%% ranch:get_port/1 instead.
|
|
|
-%%
|
|
|
-%% @see ssl:listen/2
|
|
|
-spec listen(opts()) -> {ok, ssl:sslsocket()} | {error, atom()}.
|
|
|
listen(Opts) ->
|
|
|
ranch:require([crypto, asn1, public_key, ssl]),
|
|
@@ -163,13 +85,6 @@ listen(Opts) ->
|
|
|
[binary, {active, false}, {packet, raw},
|
|
|
{reuseaddr, true}, {nodelay, true}])).
|
|
|
|
|
|
-%% @doc Accept connections with the given listening socket.
|
|
|
-%%
|
|
|
-%% Note that this function does both the transport accept and
|
|
|
-%% the SSL handshake. The returned socket is thus fully connected.
|
|
|
-%%
|
|
|
-%% @see ssl:transport_accept/2
|
|
|
-%% @see ssl:ssl_accept/2
|
|
|
-spec accept(ssl:sslsocket(), timeout())
|
|
|
-> {ok, ssl:sslsocket()} | {error, closed | timeout | atom()}.
|
|
|
accept(LSocket, Timeout) ->
|
|
@@ -185,8 +100,6 @@ accept_ack(CSocket, Timeout) ->
|
|
|
error(Reason)
|
|
|
end.
|
|
|
|
|
|
-%% @private Experimental. Open a connection to the given host and port number.
|
|
|
-%% @see ssl:connect/3
|
|
|
%% @todo Probably filter Opts?
|
|
|
-spec connect(inet:ip_address() | inet:hostname(),
|
|
|
inet:port_number(), any())
|
|
@@ -195,8 +108,6 @@ connect(Host, Port, Opts) when is_integer(Port) ->
|
|
|
ssl:connect(Host, Port,
|
|
|
Opts ++ [binary, {active, false}, {packet, raw}]).
|
|
|
|
|
|
-%% @private Experimental. Open a connection to the given host and port number.
|
|
|
-%% @see ssl:connect/4
|
|
|
%% @todo Probably filter Opts?
|
|
|
-spec connect(inet:ip_address() | inet:hostname(),
|
|
|
inet:port_number(), any(), timeout())
|
|
@@ -206,80 +117,55 @@ connect(Host, Port, Opts, Timeout) when is_integer(Port) ->
|
|
|
Opts ++ [binary, {active, false}, {packet, raw}],
|
|
|
Timeout).
|
|
|
|
|
|
-%% @doc Receive data from a socket in passive mode.
|
|
|
-%% @see ssl:recv/3
|
|
|
-spec recv(ssl:sslsocket(), non_neg_integer(), timeout())
|
|
|
-> {ok, any()} | {error, closed | atom()}.
|
|
|
recv(Socket, Length, Timeout) ->
|
|
|
ssl:recv(Socket, Length, Timeout).
|
|
|
|
|
|
-%% @doc Send data on a socket.
|
|
|
-%% @see ssl:send/2
|
|
|
-spec send(ssl:sslsocket(), iodata()) -> ok | {error, atom()}.
|
|
|
send(Socket, Packet) ->
|
|
|
ssl:send(Socket, Packet).
|
|
|
|
|
|
-%% @equiv sendfile(Socket, Filename, 0, 0, [])
|
|
|
-spec sendfile(ssl:sslsocket(), file:name_all() | file:fd())
|
|
|
-> {ok, non_neg_integer()} | {error, atom()}.
|
|
|
sendfile(Socket, Filename) ->
|
|
|
sendfile(Socket, Filename, 0, 0, []).
|
|
|
|
|
|
-%% @equiv sendfile(Socket, File, Offset, Bytes, [])
|
|
|
-spec sendfile(ssl:sslsocket(), 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.
|
|
|
-%%
|
|
|
%% Unlike with TCP, no syscall can be used here, so sending files
|
|
|
%% through SSL will be much slower in comparison. Note that unlike
|
|
|
%% file:sendfile/5 this function accepts either a file or a file name.
|
|
|
-%%
|
|
|
-%% @see ranch_transport:sendfile/6
|
|
|
-%% @see file:sendfile/5
|
|
|
-spec sendfile(ssl:sslsocket(), file:name_all() | file:fd(),
|
|
|
non_neg_integer(), non_neg_integer(), ranch_transport:sendfile_opts())
|
|
|
-> {ok, non_neg_integer()} | {error, atom()}.
|
|
|
sendfile(Socket, File, Offset, Bytes, Opts) ->
|
|
|
ranch_transport:sendfile(?MODULE, Socket, File, Offset, Bytes, Opts).
|
|
|
|
|
|
-%% @doc Set options on the given socket.
|
|
|
-%% @see ssl:setopts/2
|
|
|
%% @todo Probably filter Opts?
|
|
|
-spec setopts(ssl:sslsocket(), list()) -> ok | {error, atom()}.
|
|
|
setopts(Socket, Opts) ->
|
|
|
ssl:setopts(Socket, Opts).
|
|
|
|
|
|
-%% @doc Give control of the socket to a new process.
|
|
|
-%%
|
|
|
-%% Must be called from the process currently controlling the socket,
|
|
|
-%% otherwise an {error, not_owner} tuple will be returned.
|
|
|
-%%
|
|
|
-%% @see ssl:controlling_process/2
|
|
|
-spec controlling_process(ssl:sslsocket(), pid())
|
|
|
-> ok | {error, closed | not_owner | atom()}.
|
|
|
controlling_process(Socket, Pid) ->
|
|
|
ssl:controlling_process(Socket, Pid).
|
|
|
|
|
|
-%% @doc Return the remote address and port of the connection.
|
|
|
-%% @see ssl:peername/1
|
|
|
-spec peername(ssl:sslsocket())
|
|
|
-> {ok, {inet:ip_address(), inet:port_number()}} | {error, atom()}.
|
|
|
peername(Socket) ->
|
|
|
ssl:peername(Socket).
|
|
|
|
|
|
-%% @doc Return the local address and port of the connection.
|
|
|
-%% @see ssl:sockname/1
|
|
|
-spec sockname(ssl:sslsocket())
|
|
|
-> {ok, {inet:ip_address(), inet:port_number()}} | {error, atom()}.
|
|
|
sockname(Socket) ->
|
|
|
ssl:sockname(Socket).
|
|
|
|
|
|
-%% @doc Close the given socket.
|
|
|
-%% @see ssl:close/1
|
|
|
-spec close(ssl:sslsocket()) -> ok.
|
|
|
close(Socket) ->
|
|
|
ssl:close(Socket).
|