SmolNet.Loopback (smolnet v0.7.1)

Copy Markdown View Source

A link process that feeds a stack's outbound packets back into itself.

SmolNet stacks are transport-neutral: a stack emits complete IPv4 or IPv6 packets to a link process, which carries them to wherever the other end of the wire is. A loopback link is the degenerate case of that contract, where the other end of the wire is the same stack. It lets one stack reach its own addresses with no peer, no external transport, and no privileges, which makes it the simplest way to exercise the library in an example, a doctest, or a test case.

{:ok, link, stack} =
  SmolNet.Loopback.start_link(
    addresses: [{{0, 0, 0, 0, 0, 0, 0, 1}, 128}, {{127, 0, 0, 1}, 8}]
  )

The link owns the stack it loops. start_link/1 accepts the same options as SmolNet.start_stack/1 apart from :egress, which the link supplies, and returns once the stack is running. Stopping the link stops the stack through the stack's own :link_down policy. The link watches its stack with SmolNet.monitor/1, so stopping the stack with SmolNet.stop_stack/1, or a stack crash, stops the link.

Because the loop is an ordinary link process, packets re-enter through the public SmolNet.ingress/2 and are validated exactly like packets arriving from a real transport. A packet the stack refuses, which in practice means a packet offered while the stack is already busy with another feeder, is dropped as a real link would drop it.

Given :egress_credit, the link grants back each batch once it has fed it in, as a link with a bounded queue would; see SmolNet.grant_egress/3.

Reaching a loopback address

A loopback link carries packets; it does not invent addresses. A stack answers on the addresses it was configured with, so give it whichever addresses the example needs. Conventional localhost addresses work, and so does any other address the stack holds:

{:ok, _link, stack} =
  SmolNet.Loopback.start_link(addresses: [{{192, 0, 2, 1}, 24}])

{:ok, listener} = SmolNet.open(:inet, :stream, :tcp, stack: stack)
:ok = SmolNet.bind(listener, %{family: :inet, addr: {192, 0, 2, 1}, port: 8080})
:ok = SmolNet.listen(listener, 1)

A connection to 192.0.2.1:8080 on that stack now completes against its own listener.

Summary

Functions

Returns a specification to start this module under a supervisor.

Returns the stack for an already-running loopback link.

Starts a loopback link and the stack it loops.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

stack(link)

Returns the stack for an already-running loopback link.

start_link(options)

@spec start_link(keyword()) ::
  {:ok, pid(), SmolNet.Stack.Ref.t()} | :ignore | {:error, term()}

Starts a loopback link and the stack it loops.

Options are the SmolNet.start_stack/1 options, plus an optional :name for the link process itself. Supplying :egress is an error, because the link is the stack's egress. Returns the link process and the stack reference as {:ok, link, stack}.