mirror of https://github.com/deavmi/twine
Compare commits
6 Commits
a431aaad60
...
0d8d2ec242
Author | SHA1 | Date |
---|---|---|
Tristan B. Velloza Kildaire | 0d8d2ec242 | |
Tristan B. Velloza Kildaire | 311f4d388f | |
Tristan B. Velloza Kildaire | ffef54d98f | |
Tristan B. Velloza Kildaire | 7c38b56384 | |
Tristan B. Velloza Kildaire | 3acc85093b | |
Tristan B. Velloza Kildaire | 5501d5f23b |
109
doc/arp.md
109
doc/arp.md
|
@ -244,6 +244,115 @@ to return _some_ `ArpEntry` because that is the signature of our method,
|
|||
one generated by `ArpEntry.empty()`, else we return the actual entry that
|
||||
we received.
|
||||
|
||||
#### Catching responses
|
||||
|
||||
I have mentioned that the thread which waits for a matching ARP response
|
||||
to come in (the one which calls the `wait(Duration)`) above. So then,
|
||||
the question is - which thread is the one calling `notify()` on the
|
||||
condition variable and under which scenarios?
|
||||
|
||||
---
|
||||
|
||||
Recall that we attached the `ArpManager` as a `Receiver` to the `Link`
|
||||
object which was passed into the `regen(Target)` method:
|
||||
|
||||
```{.d}
|
||||
// use this link
|
||||
Link link = target.getLink();
|
||||
|
||||
// address we want to resolve
|
||||
string addr = target.getAddr();
|
||||
|
||||
// attach as a receiver to this link
|
||||
link.attachReceiver(this);
|
||||
|
||||
logger.dbg("attach done");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Now the reason for this is that whenever traffic is received on a `Link`
|
||||
it will copy the `byte[]` containing the payload to each attached `Receiver`.
|
||||
|
||||
This means that the `ArpManager` will receive all packets from a given
|
||||
link, the question is - which ones to we react to? Well that's easy. Below
|
||||
I show you the `onReceive(Link src, byte[] data, string srcAddr)` method
|
||||
which the arp manager overrides. This is called every time a given link
|
||||
receives data:
|
||||
|
||||
```{.numberLines .d}
|
||||
/**
|
||||
* Called by the `Link` which received a packet which
|
||||
* may be of interest to us
|
||||
*
|
||||
* Params:
|
||||
* src = the `Link` from where the packet came from
|
||||
* data = the packet's data
|
||||
* srcAddr = the link-layer source address
|
||||
*/
|
||||
public override void onReceive(Link src, byte[] data, string srcAddr)
|
||||
{
|
||||
Message recvMesg;
|
||||
if(Message.decode(data, recvMesg))
|
||||
{
|
||||
// payload type
|
||||
if(recvMesg.getType() == MType.ARP)
|
||||
{
|
||||
Arp arpMesg;
|
||||
if(recvMesg.decodeAs(arpMesg))
|
||||
{
|
||||
logger.dbg("arpMesg, received: ", arpMesg, "from: ", srcAddr);
|
||||
ArpReply reply;
|
||||
if(arpMesg.getReply(reply))
|
||||
{
|
||||
logger.info("ArpReply: ", reply);
|
||||
|
||||
// place and wakeup waiters
|
||||
placeLLAddr(reply.networkAddr(), reply.llAddr());
|
||||
}
|
||||
|
||||
...
|
||||
...
|
||||
...
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
What we do here is we attempt to decode each incoming packet
|
||||
into our `Message` type, then further check if it is an ARP-typed
|
||||
message. If this is the case then we check if it is an ARP request
|
||||
(because as we have seen, ARP requests are **not** handled here).
|
||||
|
||||
```{.numberLines .d}
|
||||
/**
|
||||
* Called by the thread which has an ARP response
|
||||
* it would like to pass off to the thread waiting
|
||||
* on the condition variable
|
||||
*
|
||||
* Params:
|
||||
* l3Addr = the network layer address
|
||||
* llAddr = the link-layer address
|
||||
*/
|
||||
private void placeLLAddr(string l3Addr, string llAddr)
|
||||
{
|
||||
this.waitLock.lock();
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
this.waitLock.unlock();
|
||||
}
|
||||
|
||||
this.waitSig.notify(); // todo, more than one or never?
|
||||
|
||||
this.addrIncome[l3Addr] = llAddr;
|
||||
}
|
||||
```
|
||||
|
||||
If this is the case then we will place the link-layer address into
|
||||
a key-value map where the key is the network-layer address and the
|
||||
value is the link-layer address. After this we wake up the sleeping
|
||||
thread by calling `notify()`.
|
||||
|
||||
### Caching
|
||||
|
||||
I mentioned that there is caching involved. The involvement is that all
|
||||
|
|
BIN
doc/texput.pdf
BIN
doc/texput.pdf
Binary file not shown.
|
@ -4,6 +4,9 @@ import twine.links.link;
|
|||
import std.datetime.stopwatch : StopWatch, AutoStart;
|
||||
import std.datetime : Duration, dur;
|
||||
|
||||
/**
|
||||
* Represents a route
|
||||
*/
|
||||
public struct Route
|
||||
{
|
||||
private string dstKey; // destination
|
||||
|
@ -14,13 +17,38 @@ public struct Route
|
|||
private StopWatch lifetime;
|
||||
private Duration expirationTime;
|
||||
|
||||
// direct route (reachable over the given link)
|
||||
/**
|
||||
* Constructs a route to a destination
|
||||
* over a given link with a given metric.
|
||||
*
|
||||
* The destination of this route is
|
||||
* directly reachable over the link.
|
||||
*
|
||||
* Params:
|
||||
* dst = the destination network-layer
|
||||
* address
|
||||
* link = the `Link`
|
||||
* distance = the distance
|
||||
*/
|
||||
this(string dst, Link link, ubyte distance)
|
||||
{
|
||||
this(dst, link, dst, distance);
|
||||
}
|
||||
|
||||
// indirect route (reachable via the `via`)
|
||||
/**
|
||||
* Constructs a route to a destination
|
||||
* over a link with a given metric.
|
||||
*
|
||||
* This also let's you set the next-hop
|
||||
* gateway that should be used.
|
||||
*
|
||||
* Params:
|
||||
* dst = the destination network-layer
|
||||
* address
|
||||
* link = the `Link`
|
||||
* via = the next-hop gateway's address
|
||||
* distance = the distance
|
||||
*/
|
||||
this(string dst, Link link, string via, ubyte distance, Duration expirationTime = dur!("seconds")(60))
|
||||
{
|
||||
this.dstKey = dst;
|
||||
|
@ -32,50 +60,115 @@ public struct Route
|
|||
this.expirationTime = expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this route direct? As
|
||||
* in the destination is
|
||||
* directly reachable via
|
||||
* the gateway (i.e. the
|
||||
* destination matches the
|
||||
* gateway)
|
||||
*
|
||||
* Returns: `true` if so,
|
||||
* otherwise `false`
|
||||
*/
|
||||
public bool isDirect()
|
||||
{
|
||||
return this.dstKey == this.viaKey; // todo, should we ever use cmp?
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this route
|
||||
* has expired
|
||||
*
|
||||
* Returns: `true` if so,
|
||||
* `false` otherwise
|
||||
*/
|
||||
public bool hasExpired()
|
||||
{
|
||||
return this.lifetime.peek() > this.expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the expiration
|
||||
* timer for this route
|
||||
*/
|
||||
public void refresh()
|
||||
{
|
||||
this.lifetime.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this route's
|
||||
* destination address
|
||||
*
|
||||
* Returns: the address
|
||||
*/
|
||||
public string destination()
|
||||
{
|
||||
return this.dstKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves this route's
|
||||
* associated link
|
||||
*
|
||||
* Returns: a `Link`, or
|
||||
* `null` if this is a
|
||||
* self-route
|
||||
*/
|
||||
public Link link()
|
||||
{
|
||||
return this.ll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retirns whether or not
|
||||
* this route is a self-route
|
||||
* (i.e. the link set was
|
||||
* `null`)
|
||||
*
|
||||
* Returns: `true` if so,
|
||||
* otherwise `false`
|
||||
*/
|
||||
public bool isSelfRoute()
|
||||
{
|
||||
return this.ll is null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the gateway
|
||||
* of this route
|
||||
*
|
||||
* Returns: the gateway's
|
||||
* address
|
||||
*/
|
||||
public string gateway()
|
||||
{
|
||||
return this.viaKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the distance
|
||||
*
|
||||
* Returns: the distance
|
||||
* metric
|
||||
*/
|
||||
public ubyte distance()
|
||||
{
|
||||
return this.dst;
|
||||
}
|
||||
|
||||
// two routes are considered the same if they
|
||||
// are to the same destination using the same
|
||||
// gateway, distance and link
|
||||
public static isSameRoute(Route r1, Route r2)
|
||||
/**
|
||||
* Compares two routes with one
|
||||
* another
|
||||
*
|
||||
* Params:
|
||||
* r1 = first route
|
||||
* r2 = second route
|
||||
* Returns: `true` if the routes
|
||||
* match exactly, otherwise `false`
|
||||
*/
|
||||
public static bool isSameRoute(Route r1, Route r2)
|
||||
{
|
||||
|
||||
return r1.destination() == r2.destination() &&
|
||||
|
@ -84,6 +177,15 @@ public struct Route
|
|||
r1.link() == r2.link();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this `Route` with
|
||||
* another
|
||||
*
|
||||
* Params:
|
||||
* rhs = the other route
|
||||
* Returns: `true` if the routes
|
||||
* are identical, `false` otherwise
|
||||
*/
|
||||
public bool opEquals(Route rhs)
|
||||
{
|
||||
return isSameRoute(this, rhs);
|
||||
|
|
Loading…
Reference in New Issue