Packages

This is an implementation of Mark Qvist's Reticulum Network Stack, a 'cryptography-based networking stack for building local and wide-area networks with readily available hardware.'

Current section

Files

Jump to
reticulum lib rns packet_handler.ex
Raw

lib/rns/packet_handler.ex

defmodule RNS.PacketHandler do
@moduledoc """
Process that handles packets.
"""
require Logger
require RNS.Packet
@doc """
Create a new PacketHandler process.
This is the function an interface should run.
"""
def handle(data_fn) do
spawn(__MODULE__, :start, [data_fn])
end
@doc """
This is the actual handler.
It should NEVER BE RUN BY AN INTERFACE as it does not do it in another process.
"""
@spec start(fun(), RNS.Interface.t(), RNS.Config.transport()) :: :ok
def start(packet_fn, interface, transport) do
case packet_fn.() do
{:ok, raw} ->
packet = RNS.Packet.from_raw(raw)
packet_hash = RNS.Packet.hash(packet)
if not RNS.PacketHashStore.exists?(packet_hash) do
RNS.PacketHashStore.add(packet_hash)
handle(packet, interface, transport)
end
{:error, error} ->
Logger.warning(
"Failed to pre-handle packet on interface #{inspect(interface)}: #{inspect(error)}."
)
end
end
@spec handle(RNS.Packet.t(), RNS.Interface.t(), RNS.Config.transport()) :: :ok
def handle(packet, interface, transport) do
interface_id = RNS.Interface.id(interface)
packet_hops = RNS.Packet.hops(packet)
packet = RNS.Packet.packet(packet, hops: packet_hops + 1)
case RNS.Packet.packet_type(packet) do
:announce ->
RNS.Packet.Announce.handle(packet, interface_id)
_type ->
if RNS.Packet.propagation_type(packet) == :transport do
maybe_route(packet, transport, interface)
end
end
end
@spec maybe_route(RNS.Packet.t(), RNS.Config.transport(), RNS.Interface.t()) :: :ok
def maybe_route(packet, transport, source) do
case transport do
true ->
route(packet, source)
false ->
destination_hash = RNS.Packet.destination_hash(packet)
case RNS.DestinationStore.fetch(destination_hash) do
{:ok, destination} ->
if RNS.Destination.hops(destination) <= 0 do
route(packet, source, destination)
end
{:error, :not_found} ->
:ok
end
end
end
@spec route(RNS.Packet.t(), RNS.Interface.t()) :: :ok
def route(packet, source) do
destination_hash = RNS.Packet.destination_hash(packet)
case RNS.DestinationStore.fetch(destination_hash) do
{:ok, destination} ->
route(packet, source, destination)
end
end
@spec route(RNS.Packet.t(), RNS.Interface.t(), RNS.Destination.t()) :: :ok
def route(packet, source, destination) do
RNS.Interface.send(packet, RNS.Destination.interface(destination), source)
end
end