mirror of https://github.com/deavmi/twine
Compare commits
9 Commits
1c629681a2
...
15b13b6e58
Author | SHA1 | Date |
---|---|---|
Tristan B. Velloza Kildaire | 15b13b6e58 | |
Tristan B. Velloza Kildaire | ec8e155eb7 | |
Tristan B. Velloza Kildaire | d64677895d | |
Tristan B. Velloza Kildaire | ada91b2355 | |
Tristan B. Velloza Kildaire | 2e1108ea31 | |
Tristan B. Velloza Kildaire | da114e1793 | |
Tristan B. Velloza Kildaire | 29940a90b0 | |
Tristan B. Velloza Kildaire | 8bb3801548 | |
Tristan B. Velloza Kildaire | deb4d52a80 |
|
@ -0,0 +1,105 @@
|
|||
Links and Receivers
|
||||
===================
|
||||
|
||||
So-called _links_ are _receivers_ are terms referred to throughout the documentation
|
||||
and understanding what they are and how they relate to each other is important for what
|
||||
is to follow.
|
||||
|
||||
## The `Receiver`
|
||||
|
||||
A _receiver_ is a relatively simple type, the interface is defined as follows:
|
||||
|
||||
```{.numberLines .d}
|
||||
/**
|
||||
* A subscriber could be a router that wants
|
||||
* to subscribe to data coming in from this
|
||||
* interface
|
||||
*/
|
||||
public interface Receiver
|
||||
{
|
||||
/**
|
||||
* On reception of the provided data from
|
||||
* the given link-layer address over
|
||||
* the given `Link`
|
||||
*
|
||||
* Params:
|
||||
* source = the source `Link`
|
||||
* recv = the received data
|
||||
* srcAddr = the source link-layer address
|
||||
*/
|
||||
public void onReceive(Link source, byte[] recv, string srcAddr);
|
||||
}
|
||||
```
|
||||
|
||||
As you can probably understand from the just of it, it is basically a handler for _ingress_
|
||||
traffic whereby the first argument is the data itself and the second must be the link-layer
|
||||
address the traffic is sourced from. Any class which implements the `Receiver` interface may
|
||||
be (as you will see later) attached to a `Link` such that it can have data passed to it.
|
||||
|
||||
## The `Link`
|
||||
|
||||
A _Link_ is provides us with a method to send data to a destination link-layer address
|
||||
and be notified when we receive packets from link-layer addressed hosts over said link.
|
||||
|
||||
A _link_ is composed out of a few things:
|
||||
|
||||
1. A list of _receivers_
|
||||
* These are the currently attached receivers which is to be called
|
||||
serially (one after the other) whenever a data packet arrives over
|
||||
this link.
|
||||
* Given a link with two `Receiver`(s) attached, then in an example
|
||||
whereby the bytes `[66, 65, 65, 66]` arrive over the link then that
|
||||
that byte array would be copied to the attached
|
||||
2. A _source address_
|
||||
* We must have a way to determine the source address of the link
|
||||
such that it can be used for various procedures such as ARP
|
||||
3. A _transmission_ and _broadcast_ mechanism
|
||||
* We need a way to send unicast (traffic directed to a singular _given_
|
||||
host) and also to broadcast to all those attached to the link
|
||||
|
||||
### Concrete methods
|
||||
|
||||
There are a few methods which relate to the `Receiver`(s). These are shown below and essentially are for adding,
|
||||
removing and enumerating receivers for this link:
|
||||
|
||||
| Method name | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `attachReceiver(Receiver receiver)` | This attaches the given receiver to this `Link`, meaning packets will be copied to it |
|
||||
| `removeReceiver(Receiver receiver)` | Removes the given receiver from this `Link` meaning that packets will no longer be copied to it |
|
||||
| `auto getRecvCnt()` | Returns the number of receivers attached to this `Link` |
|
||||
|
||||
#### Implementing your driver
|
||||
|
||||
As part of implementing your driver, i.e. by method of extending/sub-classing the `Link` class, you will implement the mechanism (however
|
||||
you go about it) by which will extract data from your link-layer and extract the network-layer part (the twine data payload of your
|
||||
link-layer packet)
|
||||
|
||||
> and then what do you do with it?
|
||||
|
||||
Well, you will want to make this data available to any of the `Receiver`(s) which are attached currently. you want to _pass it up_ to the handlers. This can be safely done by calling the `receive(...)` method as shown below:
|
||||
|
||||
| Method name | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `receive(byte[] recv, string srcAddr)` | This is to be called when the `Link` sub-class (implementation) has network-layer traffic to provide |
|
||||
|
||||
Calling this method iterates over every attached `Receiver` and calls their respective `onReceive(...)` methods.
|
||||
|
||||
Note: that the `srcAddr` must contain the link-layer source address.
|
||||
|
||||
### Abstract methods
|
||||
|
||||
There are a few more methods to take note of, these are not available as an already-implemented set of methods in
|
||||
the `Link` class, and hence must be overriden.
|
||||
|
||||
#### Implementing your driver... _again_
|
||||
|
||||
Whilst the usage of the aforementioned `receive(byte[], string)` method had to do with processing _ingress_ traffic, these methods require
|
||||
an implementation for handling _egress_ traffic.
|
||||
|
||||
| Method name | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `void transmit(byte[] xmit, string addr)`| Link-implementation specific for driver to send data to a specific destination address |
|
||||
| `void broadcast(byte[] xmit)` | Link-implementation specific for driver to broadcast to all hosts on its broadcast domain |
|
||||
| `string getAddress()` | Link-implementation specific for driver to report its address |
|
||||
|
||||
Note: The last method, `getAddress()`, must return the `Link`'s link-layer address.
|
|
@ -111,4 +111,6 @@ public struct Route
|
|||
return isSameRoute(this, rhs);
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
##
|
BIN
doc/texput.pdf
BIN
doc/texput.pdf
Binary file not shown.
|
@ -42,6 +42,12 @@ void main(string[] args)
|
|||
import core.thread;
|
||||
while(true)
|
||||
{
|
||||
if(identity == "laptop")
|
||||
{
|
||||
import std.datetime.systime : Clock;
|
||||
import std.conv : to;
|
||||
r.sendData(cast(byte[])("The time currently is "~to!(string)(Clock.currTime())), "desktop");
|
||||
}
|
||||
r.dumpRoutes();
|
||||
Thread.sleep(dur!("seconds")(5));
|
||||
}
|
||||
|
|
|
@ -12,14 +12,23 @@ public abstract class Link
|
|||
private SList!(Receiver) receivers;
|
||||
private Mutex receiverLock;
|
||||
|
||||
/**
|
||||
* Constructs a new `Link`
|
||||
*/
|
||||
this()
|
||||
{
|
||||
this.receiverLock = new Mutex();
|
||||
}
|
||||
|
||||
// A link driver must call this when it
|
||||
// has new data
|
||||
public final void receive(byte[] recv, string srcAddr) // todo, src addr?
|
||||
/**
|
||||
* A link driver must call this when it
|
||||
* has new data
|
||||
*
|
||||
* Params:
|
||||
* recv = the received bytes
|
||||
* srcAddr = the link-layer source address
|
||||
*/
|
||||
public final void receive(byte[] recv, string srcAddr)
|
||||
{
|
||||
// To avoid potential design issues
|
||||
// lock, copy, unlock and then emit
|
||||
|
@ -53,6 +62,12 @@ public abstract class Link
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of attaches
|
||||
* receivers
|
||||
*
|
||||
* Returns: the count
|
||||
*/
|
||||
public final auto getRecvCnt()
|
||||
{
|
||||
this.receiverLock.lock();
|
||||
|
@ -65,6 +80,16 @@ public abstract class Link
|
|||
return walkLength(this.receivers[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the given receiver.
|
||||
*
|
||||
* Will not attach it if
|
||||
* already attached
|
||||
*
|
||||
* Params:
|
||||
* receiver = the `Receiver`
|
||||
* to attach
|
||||
*/
|
||||
public final void attachReceiver(Receiver receiver)
|
||||
{
|
||||
this.receiverLock.lock();
|
||||
|
@ -86,6 +111,13 @@ public abstract class Link
|
|||
this.receivers.insertAfter(this.receivers[], receiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given receiver.
|
||||
*
|
||||
* Params:
|
||||
* receiver = the `Receiver`
|
||||
* to remove
|
||||
*/
|
||||
public final void removeReceiver(Receiver receiver)
|
||||
{
|
||||
this.receiverLock.lock();
|
||||
|
@ -98,18 +130,38 @@ public abstract class Link
|
|||
this.receivers.linearRemoveElement(receiver);
|
||||
}
|
||||
|
||||
// Link-implementation specific for driver to send data
|
||||
// to a specific destination address
|
||||
/**
|
||||
* Link-implementation specific for driver to send data
|
||||
* to a specific destination address
|
||||
*
|
||||
* Params:
|
||||
* xmit = the data to transmit
|
||||
* addr = the link-layer destination address
|
||||
*/
|
||||
public abstract void transmit(byte[] xmit, string addr);
|
||||
|
||||
// Link-implementation spefici for driver to broadcast
|
||||
// to all hosts on its broadcast domain
|
||||
/**
|
||||
* Link-implementation spefici for driver to broadcast
|
||||
* to all hosts on its broadcast domain
|
||||
*
|
||||
* Params:
|
||||
* xmit = the data to broadcast
|
||||
*/
|
||||
public abstract void broadcast(byte[] xmit);
|
||||
|
||||
// Link-implementation specific for driver to report its address
|
||||
/**
|
||||
* Link-implementation specific for driver to report its address
|
||||
*
|
||||
* Returns: the link-layer address
|
||||
*/
|
||||
public abstract string getAddress();
|
||||
|
||||
// shows the memory address, type and the number of attached receivers
|
||||
/**
|
||||
* Shows the memory address, type and the number of
|
||||
* attached receivers
|
||||
*
|
||||
* Returns: the string
|
||||
*/
|
||||
public override string toString()
|
||||
{
|
||||
// fixme, calling this has shown to cause deadlocks, and I know one case where
|
||||
|
@ -124,11 +176,23 @@ public abstract class Link
|
|||
}
|
||||
}
|
||||
|
||||
// A subscriber could be a router that wants
|
||||
// to subscribe to data coming in from this
|
||||
// interface
|
||||
/**
|
||||
* A subscriber could be a router that wants
|
||||
* to subscribe to data coming in from this
|
||||
* interface
|
||||
*/
|
||||
public interface Receiver
|
||||
{
|
||||
/**
|
||||
* On reception of the provided data from
|
||||
* the given link-layer address over
|
||||
* the given `Link`
|
||||
*
|
||||
* Params:
|
||||
* source = the source `Link`
|
||||
* recv = the received data
|
||||
* srcAddr = the source link-layer address
|
||||
*/
|
||||
public void onReceive(Link source, byte[] recv, string srcAddr);
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,19 @@ public class LLInterface : Link
|
|||
|
||||
public override string getAddress()
|
||||
{
|
||||
return if_.getAddress().toAddrString();
|
||||
import std.stdio;
|
||||
writeln("HHHA");
|
||||
writeln("HHHA");
|
||||
writeln("HHHA");
|
||||
writeln("HHHA");
|
||||
// we need the bound port (not the 0 from init)
|
||||
string port = this.peerSock.localAddress().toPortString();
|
||||
string ret = if_.getAddress().toAddrString()~":"~port;
|
||||
writeln("ret: ", ret);
|
||||
writeln("ret: ", ret);
|
||||
writeln("ret: ", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override string toString()
|
||||
|
@ -91,15 +103,42 @@ public class LLInterface : Link
|
|||
return "LLInterface [name: "~if_.getName()~", address: "~if_.getAddress().toAddrString()~", recvs: "~to!(string)(getRecvCnt())~"]";
|
||||
}
|
||||
|
||||
private static Address getAddress_fromStringWithKak(string addr)
|
||||
{
|
||||
import std.string : split, lastIndexOf, strip;
|
||||
string[] cmps = addr.split(":");
|
||||
import std.conv : to;
|
||||
writeln(cmps);
|
||||
string host = strip(strip(addr[0..lastIndexOf(addr, ":")], "["), "]");
|
||||
writeln("host: ", host);
|
||||
ushort port = to!(ushort)(addr[lastIndexOf(addr, ":")+1..$]);
|
||||
writeln("port: ", port);
|
||||
|
||||
return parseAddress(host, port);
|
||||
}
|
||||
|
||||
public override void transmit(byte[] xmit, string addr)
|
||||
{
|
||||
// we could send via any socket probably, just destination address is iportant
|
||||
this.peerSock.sendTo(xmit, parseAddress(addr));
|
||||
import std.socket : SocketException;
|
||||
try
|
||||
{
|
||||
// we could send via any socket probably, just destination address is iportant
|
||||
writeln("transmit LLInterface to: "~addr);
|
||||
writeln("transmit LLInterface to (Address object): ", getAddress_fromStringWithKak(addr));
|
||||
auto i=this.peerSock.sendTo(xmit, getAddress_fromStringWithKak(addr));
|
||||
writeln("transmit LLInterface to: "~addr~" with return-no: ", i);
|
||||
}
|
||||
catch(SocketException e)
|
||||
{
|
||||
writeln("transmit failure: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void broadcast(byte[] xmit)
|
||||
{
|
||||
this.peerSock.sendTo(xmit, cast(Address)this.mcastAddress);
|
||||
writeln("heyo: broadcasting");
|
||||
auto i = this.peerSock.sendTo(xmit, cast(Address)this.mcastAddress);
|
||||
writeln("broadcast result: ", i);
|
||||
}
|
||||
|
||||
private void mcastLoop()
|
||||
|
@ -122,14 +161,14 @@ public class LLInterface : Link
|
|||
// Now dequeue the correct number of bytes
|
||||
else
|
||||
{
|
||||
Address fromAddr; // todo, do we need this?
|
||||
Address fromAddr;
|
||||
|
||||
buffer.length = cnt;
|
||||
this.mcastSock.receiveFrom(buffer, fromAddr);
|
||||
writeln("from: ", fromAddr, "bytes: ", buffer);
|
||||
|
||||
// Pass received data on upwards
|
||||
receive(buffer, fromAddr.toString()); // todo, pass in fromAddr
|
||||
receive(buffer, fromAddr.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,18 +177,37 @@ public class LLInterface : Link
|
|||
{
|
||||
while(this.running) // todo flag
|
||||
{
|
||||
byte[] buffer;
|
||||
byte[] buffer = [1];
|
||||
|
||||
// this.socket.receiveFrom(buffer, SocketFlags.PEEK|)
|
||||
Thread.sleep(dur!("seconds")(100));
|
||||
// + Return the length of datagram, not successfully read bytes
|
||||
// + Don't dequeue the datagram from the kernel's internal buffer
|
||||
SocketFlags firstReadFlags = cast(SocketFlags)(MSG_TRUNC|MSG_PEEK);
|
||||
ptrdiff_t cnt = this.peerSock.receiveFrom(buffer, firstReadFlags);
|
||||
|
||||
// todo, implement dis
|
||||
if(cnt <= 0)
|
||||
{
|
||||
// todo handle errors
|
||||
// 0 would not happen no dc
|
||||
// anything less maybe?
|
||||
}
|
||||
// Now dequeue the correct number of bytes
|
||||
else
|
||||
{
|
||||
Address fromAddr;
|
||||
|
||||
buffer.length = cnt;
|
||||
this.peerSock.receiveFrom(buffer, fromAddr);
|
||||
writeln("from: ", fromAddr, "bytes: ", buffer);
|
||||
|
||||
// Pass received data on upwards
|
||||
receive(buffer, fromAddr.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
|
||||
// todo, interrupt the thread here - I want to be able to do that
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue