Skip to content

Commit c2fcf38

Browse files
Ertan OnurErtan Onur
Ertan Onur
authored and
Ertan Onur
committed
Anonymous networks added
1 parent 8fd3894 commit c2fcf38

File tree

4 files changed

+487
-1
lines changed

4 files changed

+487
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Implementation of the "IEEE1394 (FireWire)" as described in the textbook
5+
"Fokkink, Wan. Distributed algorithms: an intuitive approach. MIT Press,
6+
2018.", first introduced in " IEEE 1394-1995 - IEEE Standard for a High
7+
Performance Serial Bus"
8+
"""
9+
10+
__author__ = "Yigit Sever"
11+
__contact__ = "[email protected]"
12+
__copyright__ = "Copyright 2021, WINSLAB"
13+
__credits__ = ["Yigit Sever"]
14+
__date__ = "2021-05-24"
15+
__deprecated__ = False
16+
__email__ = "[email protected]"
17+
__license__ = "GPLv3"
18+
__maintainer__ = "developer"
19+
__status__ = "Production"
20+
__version__ = "0.0.1"
21+
22+
import datetime
23+
import random
24+
from enum import Enum
25+
from time import sleep
26+
27+
from ...Experimentation.Topology import Topology
28+
from ...GenericModel import GenericModel, GenericMessageHeader, GenericMessagePayload, GenericMessage
29+
from ...Generics import *
30+
31+
class FireWirePacketType(Enum):
32+
"""Two types of FireWire requests:
33+
- Parent Request
34+
- Acknowledgement"""
35+
36+
PARENT_REQ = "PARENT_REQ"
37+
ACKNOWLEDGEMENT = "ACKNOWLEDGEMENT"
38+
START_TIMER = "START_TIMER"
39+
CHECK_TIMER = "CHECK_TIMER"
40+
TIMEOUT = "TIMEOUT"
41+
ROOT_CONTENTION = "ROOT_CONTENTION"
42+
43+
44+
class FireWireMessageHeader(GenericMessageHeader):
45+
def __init__(
46+
self,
47+
messagefrom,
48+
messageto,
49+
messagetype="FireWire Message",
50+
nexthop=float("inf"),
51+
interfaceid=float("inf"),
52+
sequencenumber=-1,
53+
):
54+
super().__init__(
55+
messagetype, messagefrom, messageto, nexthop, interfaceid, sequencenumber
56+
)
57+
58+
59+
class FireWireMessagePayload(GenericMessagePayload):
60+
def __init__(self):
61+
super().__init__(messagepayload="FireWire Message")
62+
63+
64+
class FireWireNode(GenericModel):
65+
66+
# For animation/plotting
67+
callback = None
68+
draw_delay = None
69+
70+
def __init__(self, componentname, componentinstancenumber, context=None, configurationparameters=None, num_worker_threads=1, topology=None):
71+
super().__init__(componentname, componentinstancenumber, context, configurationparameters, num_worker_threads, topology)
72+
self.eventhandlers[FireWirePacketType.START_TIMER] = self.on_timer_initialize
73+
self.eventhandlers[FireWirePacketType.CHECK_TIMER] = self.check_timer
74+
self.eventhandlers[FireWirePacketType.TIMEOUT] = self.timeout
75+
self.eventhandlers[FireWirePacketType.ROOT_CONTENTION] = self.root_contention
76+
77+
self.parent = None
78+
self.received = list()
79+
self.neighbours = set()
80+
self.is_leader = False
81+
self.in_root_contention = False
82+
self.is_waiting = False
83+
self.is_terminated = False
84+
85+
self.waiting_since = None
86+
self.timeout_duration = 2
87+
88+
def on_init(self, eventobj: Event):
89+
sleep(1)
90+
self.neighbours = set(self.topology.get_neighbors(self.componentinstancenumber))
91+
print(f"the neighbours of {self.componentinstancenumber} is {self.neighbours}")
92+
93+
self.send_parent_req()
94+
95+
def send_parent_req(self):
96+
"""Send a parent request to the only eligible neighbour node. The
97+
neighbour node should not have sent this node a parent request and the
98+
number of such neighbours of this node should be 1.
99+
"""
100+
# if there is *only* one possible parent then send them a parent request here
101+
102+
result = self.neighbours - set(self.received)
103+
104+
if len(result) == 1:
105+
par = result.pop()
106+
self.parent = par
107+
108+
print(
109+
f"🤖 {self.componentinstancenumber} picked {self.parent} as it's parent"
110+
)
111+
112+
next_hop_interface_id = f"{self.componentinstancenumber}-{self.parent}"
113+
114+
header = FireWireMessageHeader(
115+
messagefrom=self.componentinstancenumber,
116+
messageto=self.parent,
117+
nexthop=self.parent,
118+
messagetype=FireWirePacketType.PARENT_REQ,
119+
interfaceid=next_hop_interface_id
120+
)
121+
payload = FireWireMessagePayload()
122+
123+
message = GenericMessage(header, payload)
124+
self.send_down(Event(self, EventTypes.MFRT, message))
125+
else:
126+
# Cannot send a parent request, more than one possible parent
127+
return
128+
129+
def root_contention(self, eventobj: Event):
130+
if self.is_leader:
131+
return
132+
print(f"🤖 {self.componentinstancenumber} is in ROOT CONTENTION")
133+
decision = random.choice([True, False])
134+
135+
if decision:
136+
print(f"🤖 {self.componentinstancenumber} decides to YIELD")
137+
self.in_root_contention = True
138+
self.send_parent_req()
139+
self.is_waiting = False
140+
self.waiting_since = None
141+
else:
142+
print(f"🤖 {self.componentinstancenumber} decides to HOLD")
143+
self.is_waiting = True
144+
self.in_root_contention = False
145+
self.send_self(Event(self, FireWirePacketType.START_TIMER, "..."))
146+
147+
# self.callback.set()
148+
# self.draw_delay.wait()
149+
# self.draw_delay.clear()
150+
151+
def on_timer_initialize(self, eventobj: Event):
152+
start_time = eventobj.time
153+
self.waiting_since = start_time
154+
self.send_self(Event(self, FireWirePacketType.CHECK_TIMER, "..."))
155+
156+
def check_timer(self, eventobj: Event):
157+
current_time = datetime.datetime.now()
158+
delta = current_time - self.waiting_since
159+
if delta.seconds > self.timeout_duration:
160+
self.send_self(Event(self, FireWirePacketType.TIMEOUT, "..."))
161+
else:
162+
sleep(0.2)
163+
self.send_self(Event(self, FireWirePacketType.CHECK_TIMER, "..."))
164+
165+
def timeout(self, eventobj: Event):
166+
self.send_self(Event(self, FireWirePacketType.ROOT_CONTENTION, "..."))
167+
168+
def on_message_from_bottom(self, eventobj: Event):
169+
""" New message from the link layer """
170+
header: FireWireMessageHeader = eventobj.eventcontent.header
171+
# paylaod is not important for FireWire
172+
173+
if header.messagetype == FireWirePacketType.PARENT_REQ:
174+
if header.messagefrom is not self.parent:
175+
new_child = header.messagefrom
176+
177+
self.received.append(new_child)
178+
179+
next_hop_interface_id = f"{self.componentinstancenumber}-{new_child}"
180+
181+
header = FireWireMessageHeader(
182+
messagefrom=self.componentinstancenumber,
183+
messageto=new_child,
184+
nexthop=new_child,
185+
messagetype=FireWirePacketType.ACKNOWLEDGEMENT,
186+
interfaceid=next_hop_interface_id
187+
)
188+
payload = FireWireMessagePayload()
189+
190+
ack = GenericMessage(header, payload)
191+
self.send_down(Event(self, EventTypes.MFRT, ack))
192+
193+
self.send_parent_req()
194+
elif not self.is_waiting:
195+
self.send_self(Event(self, FireWirePacketType.ROOT_CONTENTION, "..."))
196+
else:
197+
print(f" 👑 {self.componentinstancenumber} is elected as the leader")
198+
self.is_leader = True
199+
self.is_terminated = True
200+
201+
elif (
202+
header.messagetype == FireWirePacketType.ACKNOWLEDGEMENT
203+
and header.messagefrom == self.parent
204+
):
205+
# This node's parent request got acknowledged, the process can
206+
# safely terminate
207+
print(
208+
f"🤖 {self.componentinstancenumber} received an ACK "
209+
f" from {header.messagefrom}, terminating"
210+
)
211+
self.is_terminated = True
212+
self.in_root_contention = False
213+
214+
self.callback.set()
215+
self.draw_delay.wait()
216+
self.draw_delay.clear()

0 commit comments

Comments
 (0)