Browse Source

this is a hellhole. my code is pure trash

tarfeef101 6 years ago
parent
commit
d5969df498
4 changed files with 399 additions and 0 deletions
  1. 80 0
      a2/packet.java
  2. 108 0
      a3/packets.py
  3. 20 0
      a3/router
  4. 191 0
      a3/router.py

+ 80 - 0
a2/packet.java

@@ -0,0 +1,80 @@
+// common packet class used by both SENDER and RECEIVER
+
+import java.nio.ByteBuffer;
+
+public class packet {
+	
+	// constants
+	private final int maxDataLength = 500;
+	private final int SeqNumModulo = 32;
+	
+	// data members
+	private int type;
+	private int seqnum;
+	private String data;
+	
+	//////////////////////// CONSTRUCTORS //////////////////////////////////////////
+	
+	// hidden constructor to prevent creation of invalid packets
+	private packet(int Type, int SeqNum, String strData) throws Exception {
+		// if data seqment larger than allowed, then throw exception
+		if (strData.length() > maxDataLength)
+			throw new Exception("data too large (max 500 chars)");
+			
+		type = Type;
+		seqnum = SeqNum % SeqNumModulo;
+		data = strData;
+	}
+	
+	// special packet constructors to be used in place of hidden constructor
+	public static packet createACK(int SeqNum) throws Exception {
+		return new packet(0, SeqNum, new String());
+	}
+	
+	public static packet createPacket(int SeqNum, String data) throws Exception {
+		return new packet(1, SeqNum, data);
+	}
+	
+	public static packet createEOT(int SeqNum) throws Exception {
+		return new packet(2, SeqNum, new String());
+	}
+	
+	///////////////////////// PACKET DATA //////////////////////////////////////////
+	
+	public int getType() {
+		return type;
+	}
+	
+	public int getSeqNum() {
+		return seqnum;
+	}
+	
+	public int getLength() {
+		return data.length();
+	}
+	
+	public byte[] getData() {
+		return data.getBytes();
+	}
+	
+	//////////////////////////// UDP HELPERS ///////////////////////////////////////
+	
+	public byte[] getUDPdata() {
+		ByteBuffer buffer = ByteBuffer.allocate(512);
+		buffer.putInt(type);
+        buffer.putInt(seqnum);
+        buffer.putInt(data.length());
+        buffer.put(data.getBytes(),0,data.length());
+		return buffer.array();
+	}
+	
+	public static packet parseUDPdata(byte[] UDPdata) throws Exception {
+		ByteBuffer buffer = ByteBuffer.wrap(UDPdata);
+		int type = buffer.getInt();
+		int seqnum = buffer.getInt();
+		int length = buffer.getInt();
+		byte data[] = new byte[length];
+		buffer.get(data, 0, length);
+		return new packet(type, seqnum, new String(data));
+	}
+}

+ 108 - 0
a3/packets.py

@@ -0,0 +1,108 @@
+import struct
+        
+# Init Packets
+class ipacket:
+    # creates an ipacket with routerid
+    def __init__(this, rid):
+        this.rid = rid
+        
+    # packs the packet into a packet (bytes)
+    def package(this):
+        return struct.pack("<I", this.rid)
+
+
+# Hello Packets
+class hpacket:
+    # creates an hpacket with routerid and linkid
+    def __init__(this, rid, lid):
+        this.rid = rid
+        this.lid = lid
+    
+    # packs the packet into a packet (bytes)
+    def package(this):
+        return struct.pack("<II", this.rid, this.lid)
+        
+        
+# LSPDU Packets
+class lpacket:
+    # creates an lpacket with senderid, routerid, linkid, link cost, and sender link id
+    def __init__(this, sid, rid, lid, cost, slid):
+        this.sid = sid
+        this.rid = rid
+        this.lid = lid
+        this.cost = cost
+        this.slid = slid
+        
+    # packs the packet into a packet (bytes)
+    def package(this):
+        return struct.pack("<IIIII", this.sid, this.rid, this.lid, this.cost, this.slid)
+        
+        
+# Link Class/struct
+class link:
+    # creates a link with id lid, cost cost
+    def __init__(this, lid, cost):
+        this.lid = lid
+        this.cost = cost
+        
+    # packs the link into bytes
+    def package(this):
+        return struct.pack("<II", this.lid, this.cost)
+        
+    # returns link id
+    def getlid(this):
+        return this.lid
+        
+    # returns link cost
+    def getcost(this):
+        return this.cost
+        
+
+# CircuitDB Packets
+class cpacket:
+    # creates a cpacket with # of links nlinks, list of links links
+    def __init__(this, nlinks, links):
+        this.nklinks = nlinks
+        this.links = links
+        
+    # packs the packet into a packet (bytes)
+    def package(this):
+        bytes = struct.pack("<I", this.nlinks)
+        for i in this.links:
+            bytes += i.package()
+            
+        return bytes
+        
+    # returns the number of links
+    def getnlinks(this):
+        return this.nlinks
+        
+    # returns the list of links
+    def getlink(this):
+        return this.links
+
+# unpacks a packet and returns a packet of the corresponding type
+def unpacket(bytes):
+    size = len(bytes)
+    
+    # init packet
+    if (size == 4):
+        stuff = struct.unpack("<I", bytes)
+        return (0, ipacket(stuff[0]))
+    # hello packet
+    elif (size == 8):
+        stuff = struct.unpack("<II", bytes)
+        return (1, hpacket(stuff[0], stuff[1]))
+    # LSPDU Packet
+    elif (size == 20):
+        stuff = struct.unpack("<IIIII", bytes)
+        return (2, lpacket(stuff[0], stuff[1], stuff[2], stuff[3], stuff[4]))
+    # circuitDB packet
+    else:
+        nlinks = struct.unpack("<I", bytes)
+        links = []
+        for i in range(0, nlinks):
+            stuff = struct.unpack("<II", bytes, i * 8 + 4)
+            links.append(link(stuff[0], stuff[1]))
+            
+        return (3, cpacket(nlinks, links))

+ 20 - 0
a3/router

@@ -0,0 +1,20 @@
+#!/bin/bash
+
+#Run script for router as part of
+#Assignment 3
+#Computer Networks (CS 456)
+#Number of parameters: 4
+#Parameter:
+#    $1: router_id = unique int identifier for the router
+#    $2: nse_host = host address of the network emulator
+#    $3: nse_port = the same, but the port number
+#    $4: router_port = the port for the router
+
+#For Python implementation
+if [ "$#" -ne 4 ];
+then
+  echo "Program takes 4 parameters, which are a router_id, emulator host addr, host port, and router port."
+  exit 1
+fi
+
+python3 router.py $1 $2 $3 $4

+ 191 - 0
a3/router.py

@@ -0,0 +1,191 @@
+from packets import *
+import socket, sys, os
+
+# save values needed to talk to host emulator
+rid = int(sys.argv[1]) # RouterID
+haddr = sys.argv[2] # emulator host addr
+hport = int(sys.argv[3]) # emulator host port
+rport = int(sys.argv[4]) # router's port
+
+# random consts/globals
+inf = 65535
+
+# logfile; at end call log.close()
+logname = "router" + str(rid)
+log = open(logname, "a")
+
+# create socket
+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+sock.bind(('', rport))
+
+# send init packet to the emulator
+init = ipacket(rid)
+sock.sendto(init.package(), (haddr, hport))
+
+# receive circuitDB packet from emulator
+pack, addr = sock.recvfrom(4096)
+circuit = unpacket(pack)[1]
+
+# send shit out to emulator
+for i in circuit.getlinks():
+    sock.sendto(hpacket(rid, i.getlid()).package(), (haddr, hport))
+
+# stores neighbours, topology db, and graph
+neighbours = []
+database = db(5) # change constant here to reflect network size
+graph = graph(5) # same as above
+
+# listen for network activity
+while (1):
+    pack, addr = sock.recvfrom(4096)
+    ptype, pack = unpacket(pack)
+    
+    # hello packet
+    if (ptype == 1):
+        # save hello in hellodb
+        neighbours.append((pack.rid, pack.lid))
+        # reply with the links from circuit sent individually as lspdus
+        send_links(pack.lid)
+        continue
+    # lspdu packet
+    elif (ptype == 2):
+        # add router ID (link source), linkid, cost to db (only if not a dupe)
+        conn = connection(pack.sid, pack.rid, None, pack.lid, pack.cost)
+        database.insert(conn)
+        # otherwise,send to all ppl that hello-d me (except who sent it) (but modify sid and slid)
+        continue
+    # undefined behaviour
+    else:
+        print("Recieved unexpected packet. Dropping.")
+        continue
+    
+print("Unexpected end of program.")
+    
+# sends out our circuit as lspdus over link
+def send_links(link):
+    for i in circuit.getlinks():
+        # make lspdu with link info, router as
+        sock.sendto(lpacket(rid, rid, i.getlid(), i.getcost(), link).package(), (haddr, hport))
+
+# notify neighbours of this new lspdu entry
+def notify(connection):
+    for i in neighbours:
+        # if this is the sender, continue
+        if (i[0] == connection.sender):
+            continue
+        else:
+            # lookup shortest path to i (the neighbour)
+            dlink = graph.lookup(i[0])
+            # send to neighbour using dlink
+            sock.sendto(lpacket(rid, connection.src, connection.link, connection.cost, dlink))
+
+
+class connection:
+    def __init__(this, sender, src, dest, link, cost):
+        this.sender = sender
+        this.src = src
+        this.dest = dest
+        this.link = link
+        this.cost = cost
+        
+    # infers what this connection's (link's) destination is
+    def infer(this, db):
+        # search all known paths for one with this link
+        for i in range(0, len(db.entries)):
+            # don't search the list with this as the source, that's pointless
+            if ((i + 1) == this.src):
+                continue
+            # check all entries for one w/ this link
+            for j in db.entries[i]:
+                # match! return
+                if (j.link == this.link):
+                    this.dest = j.src
+                    j.dest = this.src
+                    return True
+                    
+        return False
+        
+class db:
+    def __init__(this, routers):
+        this.entries = [ [] for i in range(routers) ]
+        
+    def insert(connection):
+        src = connection.src
+        # check each entry in the source's list within entries
+        # index is src - 1 since router #s start at 1
+        for i in this.entries[src - 1]:
+            # dupe entry
+            if (connection.link == i.link):
+                print("this should be a log")
+                return False
+        # not a dupe, insert
+        this.entries[src - 1].append(connection)
+        # update entries and connection to contain
+        got_dest = connection.infer(this)
+        # insert into graph if we have the endpoints for this edge
+        if (got_dest):
+            graph.insert(connection)
+            graph.rebuild()
+        # notify neighbours
+        notify(connection)
+        return True
+        
+
+class graph:
+    def __init__(this, routers):
+        # stores shortest paths
+        this.sssp = [inf] * routers
+        # stores adjacency list (Graph)
+        this.alist = [ [-1, -1, -1, -1, -1] for i in range(routers) ]
+        
+    def lookup(dest):
+        return this.sssp[dest - 1]
+        
+    def insert(connection):
+        src = connection.src
+        dest = connection.dest
+        weight = connection.cost
+        this.alist[src - 1][dest] = weight
+        this.alist[dest - 1][src] = weight
+            
+    def rebuild():
+        this.sssp = [inf * 5]
+        this.sssp[rid - 1] = 0
+        
+        curnode = rid - 1
+        unvisited = [1] * 5
+        
+        while(unvisited):
+            # iterate on routers adjacent to curnode
+            for i in range(0, 5):
+                # don't check curnode
+                if (i == curnode):
+                    continue
+                # not an edge/neighbour
+                if (this.alist[curnode][i] == -1):
+                    continue
+                # visited already
+                if (unvisited[i] == 0):
+                    continue
+                this.sssp[i] = min((this.sssp[curnode] + this.alist[curnode][i]), this.sssp[i])
+                
+            unvisited[curnode] = 0
+            # if we visited all, we're done
+            if (sum(unvisited) == 0):
+                break
+            
+            minsofar = inf
+            mindexsofar = curnode
+            # select next curnode
+            for i in range(0, 5):
+                # visited already
+                if (unvisited[i] == 0):
+                    continue
+                minsofar = min(minsofar, this.sssp[i])
+                mindexsofar = i
+            
+            # no change, we are disconnected. breka
+            if (mindexsofar == curnode):
+                break
+            
+        print("SSSP: this.sssp")