Compare commits

...

9 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 15b13b6e58 App
- Broadcast to `"desktop"` (as a test) if identity is `"laptop"`
2024-01-23 21:40:03 +02:00
Tristan B. Velloza Kildaire ec8e155eb7 LLInterface
- `getAddress()` no longer returns the `InterfaceInfo`'s address and no port, no we want the finally-bound address hence we derive this from the `peerSock` and APPEND that to the `InterfaceInfo`'s address (this also means we get the port then)
- Implemented `getAddress_fromStringWithKak(string addr)`
- `transmit(byte[] xmit, string addr)` now fixed when transmitting as we needed to remove the `[]` from the addresses and then extract the port and return an `Address`
- `broadcast(byte[] xmit)` we send using the `peerSock` to the broadcast address (although it's probably fine to use either)
- `mcastLoop()` now passes all received broadcasts up to the attached `Receiver`(s)
- `peerLoop()` now handles incoming peer-destined data and passes it up to the attached `Receiver`(s)
2024-01-23 21:39:46 +02:00
Tristan B. Velloza Kildaire d64677895d Docs
- Updated
2024-01-23 21:32:20 +02:00
Tristan B. Velloza Kildaire ada91b2355 Link
- Documented methods
2024-01-23 19:38:19 +02:00
Tristan B. Velloza Kildaire 2e1108ea31 Docs
- Fixed typo
2024-01-23 19:33:52 +02:00
Tristan B. Velloza Kildaire da114e1793 Receiver
- Documented interface
2024-01-23 19:29:41 +02:00
Tristan B. Velloza Kildaire 29940a90b0 Docs
- Added information on the `Receiver` interface
2024-01-23 19:29:24 +02:00
Tristan B. Velloza Kildaire 8bb3801548 Docs
- Updated PDF
2024-01-23 19:20:42 +02:00
Tristan B. Velloza Kildaire deb4d52a80 Docs
- Added information on links and driver implementation
2024-01-23 19:20:31 +02:00
6 changed files with 259 additions and 24 deletions

105
doc/links.md Normal file
View File

@ -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.

View File

@ -111,4 +111,6 @@ public struct Route
return isSameRoute(this, rhs);
}
}
```
```
##

Binary file not shown.

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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
}
}