Upload files to ''

This commit is contained in:
Torma Kristóf 2021-04-23 18:06:09 +02:00
parent 45bc87dfe8
commit 4566f16293
5 changed files with 367 additions and 0 deletions

77
docs.md Normal file
View File

@ -0,0 +1,77 @@
Purpose
-------
The purpose of this network simulation package is to provide a simplified network interface abstraction for Python programs implementing cryptographic protocols and thus to help focusing on the crypto stuff instead of worrying about complicated networking issues.
The network interface abstraction
---------------------------------
Programs can instantiate the network_interface class (provided in the netinterface.py module) to create and use a network interface for communications. The network_interface class provides message sending and receiving abstractions via two functions: send_msg() and receive_msg().
The function send_msg(dst, msg) sends out message msg to destination dst, where msg must be a byte string and dst must be a string of valid destination addresses.
Network addresses are capital letters A, B, C, ... Z. Destination dst may contain a single address (e.g., 'A', 'B', ...) or multiple addresses (e.g., 'ABC' means sending the message to A, B, and C). The special broadcast address is +, so dst = '+' will result in sending the message to all addresses.
The function receive_msg(blocking) returns a status flag (Boolean) and a received message (byte string). It can be called in blocking or in non-blocking mode. Blocking mode (calling with blocking=True) means that the function will return only when a new message is available, and in this case, status=True and the received message will be returned. Non-blocking mode (calling with blocking=False) means that the function returns immediately, and if a message was available then status=True and the message will be returned, otherwise status=False and an empty byte string will be returned.
An example for calling receive_msg() in blocking mode is the following:
from netinterface import network_interface
netif = network_interface(NET_PATH, OWN_ADDR) # create network interface netif
status, msg = netif.receive_msg(blocking=True) # when returns, status is True and msg contains a message
print(msg)
An example for calling receive_msg() in non-blocking mode is the following:
from netinterface import network_interface
netif = network_interface(NET_PATH, OWN_ADDR) # create network interface netif
status, msg = netif.receive_msg(blocking=False)
if status: print(msg) # if status is True, then a message was returned in msg, and we can print it
else: ... # otherwise do something else, e.g., wait and try again
Creating a new network interface is done with the constructor of the network_interface class. The constructor takes two input parameters:
- a path where the messages sent to the various addresses are saved in files (e.g., './' or 'C:/network/')
- the address of the new interface being created (e.g., 'A', 'B', ... or 'Z').
The newtork module
------------------
The network is simulated by running the network.py program. This will copy files representing messages from the outgoing folder of the source to the incoming folders of the destinations. The network.py program should be started before any other program relying on the network_interface abstraction described above.
The network.py program is a command line application that can recieve the following parameters as inputs:
- a path where the messages sent to the various addresses are saved in files (e.g., './' or 'C:/network/'); this is provided with command line option -p or --path
- a string containing the valid addresses (e.g., 'ABCDE'); this is provided with command line option -a or --addrspace
If the path is not given as input, it will take deafult value './'. If the address space is not given as input, it will take default value 'ABC'.
The network.py program can also take an optional command line option -c or --clean. When calling with this option, it will delete all previous messages from the incoming and outgoing folders belonging to the network addresses on the given network path.
Examples:
python3 network.py
running the network simulation with default path './' and default address space 'ABC' (i.e., addresses A, B, and C);
no clean-up, so messages from a previous run remain in the folders of path './'
python3 network.py -p './network/' -a 'ABCDE'
running the network simulation such that it looks for files representing messages on path './network/'
and allowing five addresses to be used A, B, C, D, and E;
no clean-up, so messages from a previous run remain in the folders of path './network/'
python3 network.py -p './network/' -a 'ABCDE' --clean
same as above but cleaning-up all folders on path './network/'
Note: Programs using the network_interface class should provide the same network path to the constructor of network_interface as the network path used to start the network simulation program network.py. Also, programs should create network interfaces with addresses that are contained in the address space provided as input to the network simulation program network.py.
More examples
-------------
An example sender and an example receiver applications are provided too (sender.py and receiver.py). Here's how to use them:
python3 network.py -p './network/' -a 'ABCDE' --clean
python3 sender.py -p './network/' -a A
python3 receiver.py -p './network/' -a B
Now, A can send messages to B (given that network.py is running)...

60
netinterface.py Normal file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env python3
#netinterface.py
import os, time
class network_interface:
timeout = 0.800 # 800 millisec
addr_space = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
own_addr = ''
net_path = ''
last_read = -1
def __init__(self, path, addr):
self.net_path = path
self.own_addr = addr
addr_dir = self.net_path + self.own_addr
if not os.path.exists(addr_dir):
os.mkdir(addr_dir)
os.mkdir(addr_dir + '/IN')
os.mkdir(addr_dir + '/OUT')
in_dir = addr_dir + '/IN'
msgs = sorted(os.listdir(in_dir))
self.last_read = len(msgs) - 1
def send_msg(self, dst, msg):
out_dir = self.net_path + self.own_addr + '/OUT'
msgs = sorted(os.listdir(out_dir))
if len(msgs) > 0:
last_msg = msgs[-1].split('--')[0]
next_msg = (int.from_bytes(bytes.fromhex(last_msg), byteorder='big') + 1).to_bytes(2, byteorder='big').hex()
else:
next_msg = '0000'
next_msg += '--' + dst
with open(out_dir + '/' + next_msg, 'wb') as f: f.write(msg)
return True
def receive_msg(self, blocking=False):
in_dir = self.net_path + self.own_addr + '/IN'
status = False
msg = b''
while True:
msgs = sorted(os.listdir(in_dir))
if len(msgs) - 1 > self.last_read:
with open(in_dir + '/' + msgs[self.last_read + 1], 'rb') as f: msg = f.read()
status = True
self.last_read += 1
if not blocking or status: return status, msg
else: time.sleep(self.timeout)

127
network.py Normal file
View File

@ -0,0 +1,127 @@
#!/usr/bin/env python3
#network.py
import os, sys, getopt, time
NET_PATH = './'
ADDR_SPACE = 'ABC'
CLEAN = False
TIMEOUT = 0.500 # 500 millisec
def read_msg(src):
global last_read
out_dir = NET_PATH + src + '/OUT'
msgs = sorted(os.listdir(out_dir))
if len(msgs) - 1 <= last_read[src]: return '', ''
next_msg = msgs[last_read[src] + 1]
dsts = next_msg.split('--')[1]
with open(out_dir + '/' + next_msg, 'rb') as f: msg = f.read()
last_read[src] += 1
return msg, dsts
def write_msg(dst, msg):
in_dir = NET_PATH + dst + '/IN'
msgs = sorted(os.listdir(in_dir))
if len(msgs) > 0:
last_msg = msgs[-1]
next_msg = (int.from_bytes(bytes.fromhex(last_msg), byteorder='big') + 1).to_bytes(2, byteorder='big').hex()
else:
next_msg = '0000'
with open(in_dir + '/' + next_msg, 'wb') as f: f.write(msg)
return
# ------------
# main program
# ------------
try:
opts, args = getopt.getopt(sys.argv[1:], shortopts='hp:a:c', longopts=['help', 'path=', 'addrspace=', 'clean'])
except getopt.GetoptError:
print('Usage: python network.py -p <network path> -a <address space> [--clean]')
sys.exit(1)
#if len(opts) == 0:
# print('Usage: python network.py -p <network path> -a <address space> [--clean]')
# sys.exit(1)
for opt, arg in opts:
if opt == '-h' or opt == '--help':
print('Usage: python network.py -p <network path> -a <address space> [--clean]')
sys.exit(0)
elif opt == '-p' or opt == '--path':
NET_PATH = arg
elif opt == '-a' or opt == '--addrspace':
ADDR_SPACE = arg
elif opt == '-c' or opt == '--clean':
CLEAN = True
ADDR_SPACE = ''.join(sorted(set(ADDR_SPACE)))
if len(ADDR_SPACE) < 2:
print('Error: Address space must contain at least 2 addresses.')
sys.exit(1)
for addr in ADDR_SPACE:
if addr not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
print('Error: Addresses must be capital letters from the 26-element English alphabet.')
sys.exit(1)
if (NET_PATH[-1] != '/') and (NET_PATH[-1] != '\\'): NET_PATH += '/'
if not os.access(NET_PATH, os.F_OK):
print('Error: Cannot access path ' + NET_PATH)
sys.exit(1)
print('--------------------------------------------')
print('Network is running with the following input:')
print(' Network path: ' + NET_PATH)
print(' Address space: ' + ADDR_SPACE)
print(' Clean-up requested: ', CLEAN)
print('--------------------------------------------')
# create folders for addresses if needed
for addr in ADDR_SPACE:
addr_dir = NET_PATH + addr
if not os.path.exists(addr_dir):
print('Folder for address ' + addr + ' does not exist. Trying to create it... ', end='')
os.mkdir(addr_dir)
os.mkdir(addr_dir + '/IN')
os.mkdir(addr_dir + '/OUT')
print('Done.')
# if program was called with --clean, perform clean-up here
# go through the addr folders and delete messages
if CLEAN:
for addr in ADDR_SPACE:
in_dir = NET_PATH + addr + '/IN'
for f in os.listdir(in_dir): os.remove(in_dir + '/' + f)
out_dir = NET_PATH + addr + '/OUT'
for f in os.listdir(out_dir): os.remove(out_dir + '/' + f)
# initialize state (needed for tracking last read messages from OUT dirs)
last_read = {}
for addr in ADDR_SPACE:
out_dir = NET_PATH + addr + '/OUT'
msgs = sorted(os.listdir(out_dir))
last_read[addr] = len(msgs) - 1
# main loop
print('Main loop started, quit with pressing CTRL-C...')
while True:
time.sleep(TIMEOUT)
for src in ADDR_SPACE:
msg, dsts = read_msg(src) # read outgoing message
if dsts != '': # if read returned a message...
if dsts == '+': dsts = ADDR_SPACE # handle broadcast address +
for dst in dsts: # for all destinations of the message...
if dst in ADDR_SPACE: # destination must be a valid address
write_msg(dst, msg) # write incoming message

53
receiver.py Normal file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
#receiver.py
import os, sys, getopt, time
from netinterface import network_interface
NET_PATH = './'
OWN_ADDR = 'B'
# ------------
# main program
# ------------
try:
opts, args = getopt.getopt(sys.argv[1:], shortopts='hp:a:', longopts=['help', 'path=', 'addr='])
except getopt.GetoptError:
print('Usage: python receiver.py -p <network path> -a <own addr>')
sys.exit(1)
for opt, arg in opts:
if opt == '-h' or opt == '--help':
print('Usage: python receiver.py -p <network path> -a <own addr>')
sys.exit(0)
elif opt == '-p' or opt == '--path':
NET_PATH = arg
elif opt == '-a' or opt == '--addr':
OWN_ADDR = arg
if (NET_PATH[-1] != '/') and (NET_PATH[-1] != '\\'): NET_PATH += '/'
if not os.access(NET_PATH, os.F_OK):
print('Error: Cannot access path ' + NET_PATH)
sys.exit(1)
if len(OWN_ADDR) > 1: OWN_ADDR = OWN_ADDR[0]
if OWN_ADDR not in network_interface.addr_space:
print('Error: Invalid address ' + OWN_ADDR)
sys.exit(1)
# main loop
netif = network_interface(NET_PATH, OWN_ADDR)
print('Main loop started...')
while True:
# Calling receive_msg() in non-blocking mode ...
# status, msg = netif.receive_msg(blocking=False)
# if status: print(msg) # if status is True, then a message was returned in msg
# else: time.sleep(2) # otherwise msg is empty
# Calling receive_msg() in blocking mode ...
status, msg = netif.receive_msg(blocking=True) # when returns, status is True and msg contains a message
print(msg.decode('utf-8'))

50
sender.py Normal file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env python3
#sender.py
import os, sys, getopt, time
from netinterface import network_interface
NET_PATH = './'
OWN_ADDR = 'A'
# ------------
# main program
# ------------
try:
opts, args = getopt.getopt(sys.argv[1:], shortopts='hp:a:', longopts=['help', 'path=', 'addr='])
except getopt.GetoptError:
print('Usage: python sender.py -p <network path> -a <own addr>')
sys.exit(1)
for opt, arg in opts:
if opt == '-h' or opt == '--help':
print('Usage: python sender.py -p <network path> -a <own addr>')
sys.exit(0)
elif opt == '-p' or opt == '--path':
NET_PATH = arg
elif opt == '-a' or opt == '--addr':
OWN_ADDR = arg
if (NET_PATH[-1] != '/') and (NET_PATH[-1] != '\\'): NET_PATH += '/'
if not os.access(NET_PATH, os.F_OK):
print('Error: Cannot access path ' + NET_PATH)
sys.exit(1)
if len(OWN_ADDR) > 1: OWN_ADDR = OWN_ADDR[0]
if OWN_ADDR not in network_interface.addr_space:
print('Error: Invalid address ' + OWN_ADDR)
sys.exit(1)
# main loop
netif = network_interface(NET_PATH, OWN_ADDR)
print('Main loop started...')
while True:
msg = input('Type a message: ')
dst = input('Type a destination address: ')
netif.send_msg(dst, msg.encode('utf-8'))
if input('Continue? (y/n): ') == 'n': break