router.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. from packets import *
  2. import socket, sys, os
  3. # save values needed to talk to host emulator
  4. rid = int(sys.argv[1]) # RouterID
  5. haddr = sys.argv[2] # emulator host addr
  6. hport = int(sys.argv[3]) # emulator host port
  7. rport = int(sys.argv[4]) # router's port
  8. # random consts/globals
  9. inf = 65535
  10. # logfile; at end call log.close()
  11. logname = "router" + str(rid)
  12. log = open(logname, "a")
  13. # create socket
  14. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  15. sock.bind(('', rport))
  16. # send init packet to the emulator
  17. init = ipacket(rid)
  18. sock.sendto(init.package(), (haddr, hport))
  19. # receive circuitDB packet from emulator
  20. pack, addr = sock.recvfrom(4096)
  21. circuit = unpacket(pack)[1]
  22. # send shit out to emulator
  23. for i in circuit.getlinks():
  24. sock.sendto(hpacket(rid, i.getlid()).package(), (haddr, hport))
  25. # stores neighbours, topology db, and graph
  26. neighbours = []
  27. database = db(5) # change constant here to reflect network size
  28. graph = graph(5) # same as above
  29. # listen for network activity
  30. while (1):
  31. pack, addr = sock.recvfrom(4096)
  32. ptype, pack = unpacket(pack)
  33. # hello packet
  34. if (ptype == 1):
  35. # save hello in hellodb
  36. neighbours.append((pack.rid, pack.lid))
  37. # reply with the links from circuit sent individually as lspdus
  38. send_links(pack.lid)
  39. continue
  40. # lspdu packet
  41. elif (ptype == 2):
  42. # add router ID (link source), linkid, cost to db (only if not a dupe)
  43. conn = connection(pack.sid, pack.rid, None, pack.lid, pack.cost)
  44. database.insert(conn)
  45. # otherwise,send to all ppl that hello-d me (except who sent it) (but modify sid and slid)
  46. continue
  47. # undefined behaviour
  48. else:
  49. print("Recieved unexpected packet. Dropping.")
  50. continue
  51. print("Unexpected end of program.")
  52. # sends out our circuit as lspdus over link
  53. def send_links(link):
  54. for i in circuit.getlinks():
  55. # make lspdu with link info, router as
  56. sock.sendto(lpacket(rid, rid, i.getlid(), i.getcost(), link).package(), (haddr, hport))
  57. # notify neighbours of this new lspdu entry
  58. def notify(connection):
  59. for i in neighbours:
  60. # if this is the sender, continue
  61. if (i[0] == connection.sender):
  62. continue
  63. else:
  64. # lookup shortest path to i (the neighbour)
  65. dlink = graph.lookup(i[0])
  66. # send to neighbour using dlink
  67. sock.sendto(lpacket(rid, connection.src, connection.link, connection.cost, dlink))
  68. class connection:
  69. def __init__(this, sender, src, dest, link, cost):
  70. this.sender = sender
  71. this.src = src
  72. this.dest = dest
  73. this.link = link
  74. this.cost = cost
  75. # infers what this connection's (link's) destination is
  76. def infer(this, db):
  77. # search all known paths for one with this link
  78. for i in range(0, len(db.entries)):
  79. # don't search the list with this as the source, that's pointless
  80. if ((i + 1) == this.src):
  81. continue
  82. # check all entries for one w/ this link
  83. for j in db.entries[i]:
  84. # match! return
  85. if (j.link == this.link):
  86. this.dest = j.src
  87. j.dest = this.src
  88. return True
  89. return False
  90. class db:
  91. def __init__(this, routers):
  92. this.entries = [ [] for i in range(routers) ]
  93. def insert(connection):
  94. src = connection.src
  95. # check each entry in the source's list within entries
  96. # index is src - 1 since router #s start at 1
  97. for i in this.entries[src - 1]:
  98. # dupe entry
  99. if (connection.link == i.link):
  100. print("this should be a log")
  101. return False
  102. # not a dupe, insert
  103. this.entries[src - 1].append(connection)
  104. # update entries and connection to contain
  105. got_dest = connection.infer(this)
  106. # insert into graph if we have the endpoints for this edge
  107. if (got_dest):
  108. graph.insert(connection)
  109. graph.rebuild()
  110. # notify neighbours
  111. notify(connection)
  112. return True
  113. class graph:
  114. def __init__(this, routers):
  115. # stores shortest paths
  116. this.sssp = [inf] * routers
  117. # stores adjacency list (Graph)
  118. this.alist = [ [-1, -1, -1, -1, -1] for i in range(routers) ]
  119. def lookup(dest):
  120. return this.sssp[dest - 1]
  121. def insert(connection):
  122. src = connection.src
  123. dest = connection.dest
  124. weight = connection.cost
  125. this.alist[src - 1][dest] = weight
  126. this.alist[dest - 1][src] = weight
  127. def rebuild():
  128. this.sssp = [inf * 5]
  129. this.sssp[rid - 1] = 0
  130. curnode = rid - 1
  131. unvisited = [1] * 5
  132. while(unvisited):
  133. # iterate on routers adjacent to curnode
  134. for i in range(0, 5):
  135. # don't check curnode
  136. if (i == curnode):
  137. continue
  138. # not an edge/neighbour
  139. if (this.alist[curnode][i] == -1):
  140. continue
  141. # visited already
  142. if (unvisited[i] == 0):
  143. continue
  144. this.sssp[i] = min((this.sssp[curnode] + this.alist[curnode][i]), this.sssp[i])
  145. unvisited[curnode] = 0
  146. # if we visited all, we're done
  147. if (sum(unvisited) == 0):
  148. break
  149. minsofar = inf
  150. mindexsofar = curnode
  151. # select next curnode
  152. for i in range(0, 5):
  153. # visited already
  154. if (unvisited[i] == 0):
  155. continue
  156. minsofar = min(minsofar, this.sssp[i])
  157. mindexsofar = i
  158. # no change, we are disconnected. breka
  159. if (mindexsofar == curnode):
  160. break
  161. print("SSSP: this.sssp")