README.md

# etls

An alternative implementation of Erlang TCP/TLS layer.

*etls* is a NIF-based implementation of the whole TLS stack, built on top of
[Asio] and [BoringSSL]. It manages its own native threads to asynchronously
handle socket operations.

The main (and very important) benefit of using this project instead of Erlang's
built-in [`ssl`] is hardware acceleration. `etls` module achieves an order of
magnitude higher bandwidth when encoding/decoding data.

Currently only `TLSv1.2` is supported, and default [BoringSSL] cipher is used.

## Performance

Benchmark ran on OS X 10.11.5, 2,2 GHz Intel Core i7 (4 cores with HT). The
benchmark consisted of **10 concurrent connections**, each sending **10
messages**, each of **size 100 MB** for a total of **1 GB per connection**. The
bandwidth has been calculated using time measured between the first message sent
and the last message received.

| OTP version | transport | bandwidth |
|:------------|:----------|:----------|
| 18.3        | ssl       | 70 MB/s   |
| 19.0-rc1    | ssl       | 111 MB/s  |
| 19.0-rc1    | etls      | 833 MB/s  |

## Build

Dependencies:

* `cmake` >= 3.1.0
* `erlang` >= 17.0
* `g++` >= 4.9.0 (or `clang`)
* `git`
* `perl`
* `golang`
* `make`
* `ninja-build`
* `openssl`

To build the project, simply run `make` from its directory.

# User Guide

Add `etls` as a `rebar` dependency to your project:

```erlang
{deps, [
  {etls, "1.1.0", {git, "https://github.com/kzemek/etls.git", {tag, "1.1.0"}}}
}.
```

You can also take advantage of the [hex.pm package].

Now you can use `etls` module much like you would use `ssl`:

```erlang
% Server side
application:start(etls),

{ok, ListenSocket} =
  etls:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},
                     {reuseaddr, true}]),

{ok, Socket} = etls:accept(ListenSocket),
etls:handshake(Socket),
etls:setopts(Socket, [{active, once}]),

receive AMessage -> io:format("~p~n", [AMessage]) end.
```


```erlang
% Client side
application:start(etls),

{ok, Socket} = etls:connect("localhost", 9999,  [], infinity),
etls:send(Socket, "foo").
```

## Using with Ranch

`etls` can be easily used with [Ranch] by [starting a
listener](http://ninenines.eu/docs/en/ranch/1.2/guide/listeners/) with
`ranch_etls` as the transport module:

```erlang
{ok, _} = ranch:start_listener(tcp_echo, 100,
                               ranch_etls, [{port, 5555}, {certfile, CertPath}],
                               echo_protocol, []).
```

## APIs

API documentation can be found at [hexdocs.pm].

### Implemented `ssl` functions

The following `ssl`/[`inet`] functions are currently implemented:

* `connect/3`
* `connect/4`
* `send/2`
* `recv/2`
* `recv/3`
* `listen/2`
* `accept/1` (`ssl`: `transport_accept/1`)
* `accept/2` (`ssl`: `transport_accept/2`)
* `handshake/1` (`ssl`: `accept/1`)
* `handshake/2` (`ssl`: `accept/2`)
* `setopts/2`
* `controlling_process/2`
* `peername/1`
* `sockname/1`
* `close/1`
* `peercert/1`
* `certificate_chain/1` (not present in `ssl`)
* `shutdown/2`

### Implemented `ssl` options

The following `ssl`/`inet` options are currently supported:

* `{packet, raw | 0 | 1 | 2 | 4}`
* `{active, boolean() | once}`
* `{exit_on_close, boolean()}`
* `{verify_type, verify_none | verify_peer}`
* `{fail_if_no_peer_cert, boolean()}`
* `{verify_client_once, boolean()}`
* `{rfc2818_verification_hostname, str()}`
* `{cacerts, [pem_encoded()]}`
* `{crls, [pem_encoded()]}`
* `{certfile, str()}`
* `{keyfile, str()}`
* `{chain, [pem_encoded()]}`

[Asio]: http://think-async.com/
[BoringSSL]: https://boringssl.googlesource.com/boringssl/
[Ranch]: https://github.com/ninenines/ranch
[`ssl`]: http://erlang.org/doc/man/ssl.html
[`inet`]: http://erlang.org/doc/man/inet.html
[hex.pm package]: https://hex.pm/packages/etls/
[hexdocs.pm]: https://hexdocs.pm/etls/