# ExSTUN
[![Hex.pm](https://img.shields.io/hexpm/v/ex_stun.svg)](https://hex.pm/packages/ex_stun)
[![API Docs](https://img.shields.io/badge/api-docs-yellow.svg?style=flat)](https://hexdocs.pm/ex_stun)
[![CI](https://img.shields.io/github/actions/workflow/status/elixir-webrtc/ex_stun/ci.yml?logo=github&label=CI)](https://github.com/elixir-webrtc/ex_stun/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/elixir-webrtc/ex_stun/branch/master/graph/badge.svg?token=7FJ64MDD0J)](https://codecov.io/gh/elixir-webrtc/ex_stun)
Implementation of the STUN protocol in Elixir - [RFC 8489](https://datatracker.ietf.org/doc/html/rfc8489)
## Installation
```elixir
def deps do
[
{:ex_stun, "~> 0.2.0"}
]
end
```
## Usage
```elixir
alias ExSTUN.Message
alias ExSTUN.Message.Type
alias ExSTUN.Message.Attribute.XORMappedAddress
{:ok, socket} = :gen_udp.open(0, [{:active, false}, :binary])
req =
%Type{class: :request, method: :binding}
|> Message.new()
|> Message.encode()
:ok = :gen_udp.send(socket, 'stun.l.google.com', 19302, req)
{:ok, {_, _, resp}} = :gen_udp.recv(socket, 0)
{:ok, msg} = Message.decode(resp)
Message.get_attribute(msg, XORMappedAddress)
```
## Benchmarks
```
Operating System: Linux
CPU Information: Intel(R) Core(TM) i5-9600K CPU @ 3.70GHz
Number of Available Cores: 6
Available memory: 15.55 GB
Elixir 1.16.0
Erlang 26.2.1
JIT enabled: true
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 2 s
reduction time: 2 s
parallel: 1
inputs: none specified
Estimated total run time: 3 min 29 s
Benchmarking binding_request.decode ...
Benchmarking binding_request.encode ...
Benchmarking binding_response.decode ...
Benchmarking binding_response.encode ...
Benchmarking error_code.from_raw ...
Benchmarking error_code.to_raw ...
Benchmarking message_full.authenticate (long-term) ...
Benchmarking message_full.authenticate (short-term) ...
Benchmarking message_full.check_fingerprint ...
Benchmarking message_full.decode ...
Benchmarking message_full.encode ...
Benchmarking new_transaction_id ...
Benchmarking raw_attr.encode ...
Benchmarking software.from_raw ...
Benchmarking software.to_raw ...
Benchmarking type.from_value ...
Benchmarking type.to_value ...
Benchmarking xor_mapped_address.from_raw ...
Benchmarking xor_mapped_address.to_raw ...
Calculating statistics...
Formatting results...
Name ips average deviation median 99th %
error_code.to_raw 36.93 M 27.08 ns ±7981.76% 26 ns 39 ns
software.to_raw 17.55 M 56.99 ns ±58293.86% 32 ns 47 ns
type.to_value 13.21 M 75.68 ns ±53851.08% 47 ns 60 ns
software.from_raw 12.70 M 78.76 ns ±48756.65% 39 ns 53 ns
raw_attr.encode 6.76 M 147.84 ns ±35284.68% 84 ns 99 ns
error_code.from_raw 6.68 M 149.72 ns ±31869.06% 68 ns 308 ns
xor_mapped_address.from_raw 6.53 M 153.04 ns ±24195.15% 90 ns 317 ns
type.from_value 5.93 M 168.77 ns ±29536.32% 89 ns 169 ns
xor_mapped_address.to_raw 4.83 M 206.94 ns ±18672.29% 154 ns 204 ns
binding_request.decode 3.88 M 257.52 ns ±18794.26% 164 ns 405 ns
binding_response.decode 2.58 M 387.01 ns ±12289.08% 258 ns 598 ns
message_full.check_fingerprint 1.96 M 509.65 ns ±8520.92% 410 ns 631 ns
binding_response.encode 1.75 M 572.69 ns ±7262.63% 463 ns 800 ns
message_full.decode 1.18 M 848.38 ns ±3970.03% 719 ns 1054 ns
new_transaction_id 0.98 M 1024.22 ns ±1116.74% 1010 ns 1049 ns
binding_request.encode 0.76 M 1321.81 ns ±1477.79% 1272 ns 1540 ns
message_full.authenticate (short-term) 0.35 M 2845.65 ns ±876.74% 2516 ns 3779 ns
message_full.authenticate (long-term) 0.26 M 3873.42 ns ±532.72% 3423 ns 5354 ns
message_full.encode 0.21 M 4870.66 ns ±604.07% 4115 ns 8119 ns
Extended statistics:
Name minimum maximum sample size mode
error_code.to_raw 23 ns 7959548 ns 13.57 M 26 ns
software.to_raw 28 ns 113335333 ns 12.84 M 32 ns
type.to_value 42 ns 103387309 ns 12.87 M 46 ns
software.from_raw 35 ns 115844653 ns 12.51 M 39 ns
raw_attr.encode 79 ns 112984566 ns 11.40 M 84 ns
error_code.from_raw 63 ns 112746828 ns 11.17 M 68 ns
xor_mapped_address.from_raw 84 ns 83446950 ns 10.82 M 90 ns
type.from_value 81 ns 99367969 ns 10.89 M 89 ns
xor_mapped_address.to_raw 146 ns 80528411 ns 9.65 M 153 ns
binding_request.decode 153 ns 94202921 ns 9.29 M 162 ns
binding_response.decode 240 ns 68201852 ns 7.57 M 250 ns
message_full.check_fingerprint 390 ns 59291887 ns 6.27 M 409 ns
binding_response.encode 448 ns 59683037 ns 5.73 M 463 ns
message_full.decode 681 ns 44644869 ns 4.46 M 704 ns
new_transaction_id 975 ns 20779566 ns 3.65 M 1013 ns
binding_request.encode 1225 ns 23295785 ns 2.94 M 1271 ns
message_full.authenticate (short-term) 2401 ns 14778234 ns 1.58 M 2500 ns
message_full.authenticate (long-term) 3243 ns 9581577 ns 1.18 M 3368 ns
message_full.encode 3880 ns 19112426 ns 948.71 K 4085 ns
Memory usage statistics:
Name Memory usage
error_code.to_raw 0 B
software.to_raw 48 B - ∞ x memory usage +48 B
type.to_value 0 B - 1.00x memory usage +0 B
software.from_raw 64 B - ∞ x memory usage +64 B
raw_attr.encode 32 B - ∞ x memory usage +32 B
error_code.from_raw 144 B - ∞ x memory usage +144 B
xor_mapped_address.from_raw 264 B - ∞ x memory usage +264 B
type.from_value 384 B - ∞ x memory usage +384 B
xor_mapped_address.to_raw 232 B - ∞ x memory usage +232 B
binding_request.decode 648 B - ∞ x memory usage +648 B
binding_response.decode 1024 B - ∞ x memory usage +1024 B
message_full.check_fingerprint 232 B - ∞ x memory usage +232 B
binding_response.encode 688 B - ∞ x memory usage +688 B
message_full.decode 2928 B - ∞ x memory usage +2928 B
new_transaction_id 72 B - ∞ x memory usage +72 B
binding_request.encode 360 B - ∞ x memory usage +360 B
message_full.authenticate (short-term) 664 B - ∞ x memory usage +664 B
message_full.authenticate (long-term) 808 B - ∞ x memory usage +808 B
message_full.encode 2344 B - ∞ x memory usage +2344 B
**All measurements for memory usage were the same**
Reduction count statistics:
Name Reduction count
error_code.to_raw 0
software.to_raw 2 - ∞ x reduction count +2
type.to_value 5 - ∞ x reduction count +5
software.from_raw 3 - ∞ x reduction count +3
raw_attr.encode 1 - ∞ x reduction count +1
error_code.from_raw 3 - ∞ x reduction count +3
xor_mapped_address.from_raw 13 - ∞ x reduction count +13
type.from_value 6 - ∞ x reduction count +6
xor_mapped_address.to_raw 10 - ∞ x reduction count +10
binding_request.decode 11 - ∞ x reduction count +11
binding_response.decode 17 - ∞ x reduction count +17
message_full.check_fingerprint 43 - ∞ x reduction count +43
binding_response.encode 40 - ∞ x reduction count +40
message_full.decode 53 - ∞ x reduction count +53
new_transaction_id 3 - ∞ x reduction count +3
binding_request.encode 22 - ∞ x reduction count +22
message_full.authenticate (short-term) 49 - ∞ x reduction count +49
message_full.authenticate (long-term) 84 - ∞ x reduction count +84
message_full.encode 99 - ∞ x reduction count +99
**All measurements for reduction count were the same**
```