Skip to content

Instantly share code, notes, and snippets.

@alex-pat
Created December 22, 2016 08:27
Show Gist options
  • Save alex-pat/929d79caff8333995a48e5d5a56c88c3 to your computer and use it in GitHub Desktop.
Save alex-pat/929d79caff8333995a48e5d5a56c88c3 to your computer and use it in GitHub Desktop.
token ring
#!/usr/bin/env python3
import os
import sys
import random
import time
SD = b'S'
ED = b'E'
RING_SIZE = 5
MONITOR = False
NAME = None
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
sys.stderr.flush()
def read(*args, **kwargs):
data = os.read(*args, **kwargs)
if len(data) == 0:
raise Exception
# eprint(data)
return data
def write(*args, **kwargs):
# eprint("write", *args, ** kwargs)
ret = os.write(*args, **kwargs)
sys.stdout.flush()
return ret
def countdown():
for i in reversed(range(10)):
os.write(2, " Starting in {}\r".format(i).encode())
time.sleep(1)
eprint("Started \n")
write(1, SD + b'\x00' + ED)
def parity_bit(bytes):
i = int.from_bytes(bytes, byteorder='little')
i = i - ((i >> 1) & 0x55555555)
i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
i = (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24
return int(i % 2)
def try_create_data(data):
dest = None
if not (data or random.randint(0, 5)):
data = os.urandom(3)
dest = random.randint(1, RING_SIZE)
if dest == NAME[0]:
dest = (dest - 2) % RING_SIZE + 1
dest = bytes([dest])
eprint("I have new data to send")
return data, dest
def getopts():
global NAME, MONITOR
if len(sys.argv) >= 2:
NAME = bytes([int(sys.argv[1])])
if sys.argv[2] == "-m":
MONITOR = True
else:
eprint("Bad params")
sys.exit(1)
def main():
getopts()
os.write(2, "Name: {}, Monitor: {}\n".format(NAME, MONITOR).encode())
MONITOR and countdown()
data = None
while True:
time.sleep(1)
if not data:
data, dest = try_create_data(data)
start = read(0, 1)
while start != SD:
write(1, start)
start = read(0, 1)
AC = int.from_bytes(read(0, 1), byteorder='little')
frame = AC & 0x10
if MONITOR:
if AC & 0xE0:
AC = AC & 0xF7
if frame and AC & 0x08:
eprint("BAD ERROR! FRAME CYCLED!")
sys.exit(1)
if not frame and AC & 0x08:
AC = AC & 0xF7
if frame or AC & 0xE0:
AC = AC | 0x08
Pr = (AC & 0xE0) >> 5
Rr = AC & 0x07
Pf = NAME[0]
if not frame:
if read(0, 1) != ED:
eprint("BAD ERROR! ED IS NOT ED!")
sys.exit(1)
if not data:
write(1, SD + bytes([AC]) + ED)
continue
if Pf < Pr:
if Pf > Rr:
eprint("Can't reserve empty marker: Rr is too big")
write(1, SD + bytes([AC]) + ED)
continue
eprint("Reserving empty marker")
marker = SD + bytes([(Pr << 5) | (AC & 0x18) | Pf]) + ED
write(1, marker)
continue
res_frame = SD + bytes([(Pf << 5) | 0x10 | (AC & 0x08)])
res_frame += dest + NAME + data
res_frame += bytes([parity_bit(data)])
res_frame += ED
write(1, res_frame)
eprint("Sending 0x{data} to {dest} ...".format(
data=data.hex(),
dest=dest[0]
))
continue
frame_tail = read(0, 7)
r_DA = frame_tail[0]
r_SA = frame_tail[1]
r_DATA = frame_tail[2:5]
r_PB = frame_tail[5]
r_ED = frame_tail[6]
if bytes([r_ED]) != ED:
eprint("BAD ERROR! ED IS NOT ED!")
sys.exit(1)
if r_PB != parity_bit(r_DATA):
eprint("BAD ERROR! PARITY BIT WRONG!")
sys.exit(1)
if r_DA == NAME[0]:
eprint("Received message 0x{data} from {source}".format(
data=r_DATA.hex(),
source=r_SA
))
t_frame = (
SD +
bytes([AC, 0, r_SA]) +
r_DATA +
bytes([r_PB, r_ED])
)
write(1, t_frame)
data = None
continue
if r_SA == NAME[0]:
if r_DA:
eprint("Message not readed")
eprint("Releasing marker...")
t_marker = (
SD +
bytes([(Rr << 5) | (AC & 8)]) +
ED
)
write(1, t_marker)
data = None
continue
if data and Pf >= Pr:
eprint("Reserving marker")
AC = (AC & 0xF8) | Pf
t_frame = (
SD +
bytes([AC]) +
frame_tail
)
write(1, t_frame)
if __name__ == "__main__":
main()
#!/bin/bash
myncat() {
while ! ncat "$1" "$2" 2>/dev/null
do
sleep 0.1
done
}
if [ -z "$5" ]; then
echo "Usage: $0 LISTEN_IP LISTEN_PORT WRITE_IP WRITE_PORT NAME [-m]"
exit 1
fi
ncat -l "$1" "$2" | python3 ./main.py "$5" "$6" | myncat "$3" "$4"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment