aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkg/ipstack/ipstack.go86
-rw-r--r--pkg/ipstack/ipstack_test.go45
2 files changed, 101 insertions, 30 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index fb18161..7b67d08 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -20,7 +20,7 @@ type Interface struct {
Name string
IpPrefix netip.Prefix
- RecvSocket net.Conn
+ RecvSocket net.UDPConn
SocketChannel chan bool
State bool
}
@@ -29,7 +29,7 @@ type Neighbor struct {
VipAddr netip.Addr
UdpAddr netip.AddrPort
- SendSocket net.Conn
+ SendSocket net.UDPConn
SocketChannel chan bool
}
@@ -63,7 +63,7 @@ var protocolHandlers = make(map[uint16]HandlerFunc)
var routingTable = make(map[netip.Prefix]Hop)
// reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go
-func createUDPConn(UdpAddr netip.AddrPort, conn *net.Conn) error {
+func createUDPConn(UdpAddr netip.AddrPort, conn *net.UDPConn) error {
listenString := UdpAddr.String()
listenAddr, err := net.ResolveUDPAddr("udp4", listenString)
if err != nil {
@@ -73,7 +73,7 @@ func createUDPConn(UdpAddr netip.AddrPort, conn *net.Conn) error {
if err != nil {
return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString)
}
- *conn = tmpConn
+ *conn = *tmpConn
return nil
}
@@ -98,14 +98,16 @@ func Initialize(lnxFilePath string) error {
i := &Interface{
Name: iface.Name,
IpPrefix: prefix,
- RecvSocket: nil,
- SocketChannel: nil,
+ RecvSocket: net.UDPConn{},
+ SocketChannel: make(chan bool),
State: false,
}
+
err := createUDPConn(iface.UDPAddr, &i.RecvSocket)
if err != nil {
return errors.WithMessage(err, "Error creating UDP socket for interface->\t"+iface.Name)
}
+ go InterfaceListenerRoutine(i.RecvSocket, i.SocketChannel)
myInterfaces = append(myInterfaces, i)
// TODO: (FOR HOSTS ONLY)
@@ -120,14 +122,18 @@ func Initialize(lnxFilePath string) error {
// 2) initialize the neighbors connected to the node and into the routing table
for _, neighbor := range lnxConfig.Neighbors {
n := &Neighbor{
- VipAddr: neighbor.DestAddr,
- UdpAddr: neighbor.UDPAddr,
- SendSocket: nil,
+ VipAddr: neighbor.DestAddr,
+ UdpAddr: neighbor.UDPAddr,
+ SendSocket: net.UDPConn{},
+ SocketChannel: make(chan bool),
}
+
err := createUDPConn(neighbor.UDPAddr, &n.SendSocket)
if err != nil {
return errors.WithMessage(err, "Error creating UDP socket for neighbor->\t"+neighbor.DestAddr.String())
}
+ go InterfaceListenerRoutine(n.SendSocket, n.SocketChannel)
+
myNeighbors[neighbor.InterfaceName] = append(myNeighbors[neighbor.InterfaceName], n)
// add to routing table
@@ -138,41 +144,63 @@ func Initialize(lnxFilePath string) error {
return nil
}
-func InterfaceListenerRoutine(iface Interface, signal <-chan bool) {
- isDown := false
+//func InitInterfaceListener(iface *Interface) {
+// // TODO: cleanup syntax
+// iface.State = false
+// go func() {
+// InterfaceListenerRoutine(iface.RecvSocket, iface.SocketChannel)
+// }()
+//}
+
+// TODO: differentiate between SEND AND RECV
+func InterfaceListenerRoutine(socket net.UDPConn, signal <-chan bool) {
+ isUp := false
+ closed := false
+
+ // go routine that hangs on the recv
+ fmt.Println("MAKING GO ROUTINE TO LISTEN:\t", socket.LocalAddr().String())
+ go func() {
+ defer func() { // on close, set isUp to false
+ fmt.Println("exiting go routine that listens on ", socket.LocalAddr().String())
+ }()
+
+ for {
+ if closed { // stop this go routine if channel is closed
+ return
+ }
+ if !isUp { // don't call the listeners if interface is down
+ continue
+ }
+
+ fmt.Println("no activity, actively listening on ", socket.LocalAddr().String())
+ // TODO: remove these training wheels, call the listener function
+ time.Sleep(1 * time.Millisecond)
+ }
+ }()
+
for {
select {
case open, sig := <-signal:
if !open {
fmt.Println("channel closed, exiting")
+ closed = true
return
}
- fmt.Println("received SIGNAL with value", sig)
- if sig {
- isDown = <-signal
- }
+ fmt.Println("received isUP SIGNAL with value", sig)
+ isUp = sig
default:
- if isDown {
- continue
- }
- fmt.Println("no activity, actively listening on", iface.Name)
- // TODO: remove these training wheels
- time.Sleep(1 * time.Millisecond)
}
}
}
// When an interface goes up, we need to start it's go routine that listens
func InterfaceUp(iface *Interface) {
- iface.SocketChannel = make(chan bool)
iface.State = true
- go func() {
- InterfaceListenerRoutine(*iface, iface.SocketChannel)
- }()
+ iface.SocketChannel <- true
}
func InterfaceDown(iface *Interface) {
- iface.SocketChannel <- true
+ iface.SocketChannel <- false
iface.State = false
}
@@ -335,7 +363,7 @@ func SprintRoutingTable() string {
func DebugNeighbors() {
for ifaceName, neighbor := range myNeighbors {
for _, n := range neighbor {
- fmt.Printf("%s\t%s\t%s\t%s\n", ifaceName, n.UdpAddr.String(), n.VipAddr.String(), n.SendSocket)
+ fmt.Printf("%s\t%s\t%s\n", ifaceName, n.UdpAddr.String(), n.VipAddr.String())
}
}
}
@@ -344,9 +372,7 @@ func CleanUp() {
fmt.Print("Cleaning up...\n")
// go through the interfaces, pop thread & close the UDP FDs
for _, iface := range myInterfaces {
- if iface.SocketChannel != nil {
- close(iface.SocketChannel)
- }
+ close(iface.SocketChannel)
iface.RecvSocket.Close()
}
diff --git a/pkg/ipstack/ipstack_test.go b/pkg/ipstack/ipstack_test.go
index d5b755a..97c4947 100644
--- a/pkg/ipstack/ipstack_test.go
+++ b/pkg/ipstack/ipstack_test.go
@@ -53,3 +53,48 @@ func TestInterfaceUpThenDown(t *testing.T) {
fmt.Println("TestInterfaceUpThenDown successful")
t.Cleanup(func() { CleanUp() })
}
+
+func TestInterfaceUpThenDownTwice(t *testing.T) {
+ lnxFilePath := "../../doc-example/r2.lnx"
+ err := Initialize(lnxFilePath)
+ if err != nil {
+ t.Error(err)
+ }
+
+ iface, err := GetInterfaceByName("if0")
+ if err != nil {
+ t.Error(err)
+ }
+
+ InterfaceUp(iface)
+ if iface.State == false {
+ t.Error("iface state should be true")
+ }
+
+ fmt.Printf("Interfaces:\n%s\n", SprintInterfaces())
+
+ time.Sleep(5 * time.Millisecond) // allow time to print
+
+ InterfaceDown(iface)
+ if iface.State == true {
+ t.Error("iface state should be false")
+ }
+
+ InterfaceUp(iface)
+ if iface.State == false {
+ t.Error("iface state should be true")
+ }
+ time.Sleep(3 * time.Millisecond) // allow time to print
+
+ InterfaceDown(iface)
+ if iface.State == true {
+ t.Error("iface state should be false")
+ }
+
+ time.Sleep(5 * time.Millisecond) // allow time to print
+
+ fmt.Printf("Interfaces:\n%s\n", SprintInterfaces())
+
+ fmt.Println("TestInterfaceUpThenDownTwice successful")
+ t.Cleanup(func() { CleanUp() })
+}