Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start mDNS only once per app #22

Merged
merged 4 commits into from
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,17 @@ Basically this library works similarly to [libnice].

`ExLibnice` can work both as CNode and as NIF.
By default `CNode` implementation is used however, user can change it by passing proper option while starting `ExLibnice` (see below) or by `config.exs`:

```elixir
config :ex_libnice, impl: :NIF
```

User can also choose whether to resolve mDNS addresses or not:

```elixir
config :ex_libnice, mdns: false
```

Example flow can look in the following way (this is not complete i.e. runnable example).

Listed functions must be invoked on both peers.
Expand Down Expand Up @@ -88,6 +95,7 @@ For more complete examples please refer to
[membrane_ice_plugin](https://github.com/membraneframework/membrane_ice_plugin) where we use
`ex_libnice` or our integration test.


## Copyright and License

Copyright 2020, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane_ice)
Expand Down
62 changes: 34 additions & 28 deletions lib/ex_libnice.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule ExLibnice do
stream_components: %{stream_id: integer(), n_components: integer()},
mdns_queries: %{
query: String.t(),
candidate: {sdp :: String.t(), stream_id :: integer(), component_id :: integer()}
candidates: [{sdp :: String.t(), stream_id :: integer(), component_id :: integer()}]
}
}

Expand Down Expand Up @@ -282,11 +282,6 @@ defmodule ExLibnice do
{:ok, state} =
call(impl, :init, [stun_servers, opts[:controlling_mode], min_port, max_port], state)

Logger.debug("Initializing mDNS lookup process")
Mdns.Client.start()
Logger.debug("Registering for mDNS events")
Mdns.EventManager.register()

{:ok, state}
end

Expand Down Expand Up @@ -436,10 +431,23 @@ defmodule ExLibnice do
withl candidate_check: 6 <- length(candidate_sp),
do: address = Enum.at(candidate_sp, 4),
mdns_check: true <- String.ends_with?(address, ".local") do
Logger.debug("Sending query to resolve mDNS address #{inspect(address)}")
Mdns.Client.query(address)
state = put_in(state, [:mdns_queries, address], {candidate, stream_id, component_id})
{:reply, :ok, state}
if Application.get_env(:ex_libnice, :mdns, true) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a word of docs about this would be useful

state =
update_in(state, [:mdns_queries, address], fn
# if we haven't query this address yet
nil ->
ExLibnice.Mdns.query(address)
[{candidate, stream_id, component_id}]

candidates ->
[{candidate, stream_id, component_id} | candidates]
end)

{:reply, :ok, state}
else
Logger.debug("Got mdns address but mdns client is turned off. Ignoring.")
{:reply, :ok, state}
end
else
candidate_check: _ -> {:reply, {:error, :failed_to_parse_sdp_string}, state}
mdns_check: _ -> do_set_remote_candidate(candidate, stream_id, component_id, state)
Expand Down Expand Up @@ -553,25 +561,16 @@ defmodule ExLibnice do
end

@impl true
def handle_info({_namespace, %Mdns.Client.Device{} = dev} = msg, state) do
Logger.debug("mDNS address resolved #{inspect(msg)}")
def handle_info({:mdns_response, address, ip}, state) do
{candidates, state} = pop_in(state, [:mdns_queries, address])

{query, state} = pop_in(state, [:mdns_queries, dev.domain])
for {candidate, stream_id, component_id} <- candidates do
candidate_parts =
String.split(candidate, " ", parts: 6)
|> List.replace_at(4, :inet.ntoa(ip))

case query do
nil ->
Logger.debug("""
mDNS response for non existing candidate.
We have probably already resolved address #{inspect(dev.domain)}
""")

{candidate, stream_id, component_id} ->
candidate_parts =
String.split(candidate, " ", parts: 6)
|> List.replace_at(4, :inet.ntoa(dev.ip))

candidate = Enum.join(candidate_parts, " ")
do_set_remote_candidate(candidate, stream_id, component_id, state)
candidate = Enum.join(candidate_parts, " ")
do_set_remote_candidate(candidate, stream_id, component_id, state)
end

{:noreply, state}
Expand Down Expand Up @@ -656,6 +655,13 @@ defmodule ExLibnice do
) do
{:ok, state}
else
{:error, :failed_to_lookup_addr} = err ->
Logger.warn("""
Couldn't lookup TURN server address #{inspect(server_addr)}
""")

{err, state}

{{:error, cause}, _state} = ret ->
Logger.warn("""
Couldn't set TURN server #{inspect(server_addr)} #{inspect(server_port)} \
Expand Down Expand Up @@ -703,7 +709,7 @@ defmodule ExLibnice do
Bunch.Enum.try_map(stun_servers, fn %{server_addr: addr, server_port: port} ->
case lookup_addr(addr) do
{:ok, ip} -> {:ok, "#{:inet.ntoa(ip)}:#{port}"}
{:error, _cause} = error -> error
{:error, cause} -> {:error, cause, addr}
end
end)
end
Expand Down
16 changes: 16 additions & 0 deletions lib/ex_libnice/app.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
defmodule ExLibnice.App do
@moduledoc false
use Application

@impl true
def start(_start_type, _start_args) do
children =
if Application.get_env(:ex_libnice, :mdns, true) do
[ExLibnice.Mdns]
else
[]
end

Supervisor.start_link(children, strategy: :one_for_one)
end
end
63 changes: 63 additions & 0 deletions lib/ex_libnice/mdns.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
defmodule ExLibnice.Mdns do
@moduledoc """
Module responsible for executing mDNS queries.

It can be turned off by `config :ex_libnice, mdns: false`.
"""
use GenServer
require Logger

@spec start_link(any()) :: GenServer.on_start()
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end

@spec query(String.t()) :: :ok
def query(address) do
send(__MODULE__, {:query, self(), address})
end

@impl true
def init(_opts) do
Logger.debug("Initializing mDNS lookup process")
:ok = Mdns.Client.start()
Logger.debug("Registering for mDNS events")
Mdns.EventManager.register()
{:ok, %{queries: %{}}}
end

@impl true
def handle_info({:query, from, address}, state) do
state =
update_in(state, [:queries, address], fn
# first query for this address
nil ->
Logger.debug("Sending query to resolve mDNS address #{inspect(address)}")
Mdns.Client.query(address)
[from]

pids ->
[from | pids]
end)

{:noreply, state}
end

@impl true
def handle_info({_namespace, %Mdns.Client.Device{} = dev} = msg, state) do
Logger.debug("mDNS address resolved #{inspect(msg)}")

{pids, state} = pop_in(state, [:queries, dev.domain])

if pids do
for pid <- pids, do: send(pid, {:mdns_response, dev.domain, dev.ip})
else
Logger.debug("""
mDNS response for non existing query.
We have probably already resolved address #{inspect(dev.domain)}
""")
end

{:noreply, state}
end
end
File renamed without changes.
1 change: 1 addition & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ defmodule ExLibnice.MixProject do

def application do
[
mod: {ExLibnice.App, []},
extra_applications: [:logger]
]
end
Expand Down