[spp] [PATCH 47/57] spp_vf: add spp_vf.py instead of spp.py
x-fn-spp at sl.ntt-tx.co.jp
x-fn-spp at sl.ntt-tx.co.jp
Thu Dec 28 05:55:54 CET 2017
From: Hiroyuki Nakamura <nakamura.hioryuki at po.ntt-tx.co.jp>
Add spp_vf.py as a modified version of spp.py.
Signed-off-by: Kentaro Watanabe <watanabe.kentaro.z01 at as.ntt-tx.co.jp>
Signed-off-by: Yasufum Ogawa <ogawa.yasufumi at lab.ntt.co.jp>
---
src/spp_vf.py | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 443 insertions(+)
create mode 100755 src/spp_vf.py
diff --git a/src/spp_vf.py b/src/spp_vf.py
new file mode 100755
index 0000000..40310db
--- /dev/null
+++ b/src/spp_vf.py
@@ -0,0 +1,443 @@
+#!/usr/bin/python
+"""Soft Patch Panel"""
+
+from __future__ import print_function
+from Queue import Queue
+from thread import start_new_thread
+from threading import Thread
+import cmd
+import getopt
+import select
+import socket
+import sys
+
+import json
+
+class GrowingList(list):
+ """GrowingList"""
+
+ def __setitem__(self, index, value):
+ if index >= len(self):
+ self.extend([None]*(index + 1 - len(self)))
+ list.__setitem__(self, index, value)
+
+MAX_SECONDARY = 16
+
+# init
+PRIMARY = ''
+SECONDARY_LIST = []
+SECONDARY_COUNT = 0
+
+#init primary comm channel
+MAIN2PRIMARY = Queue()
+PRIMARY2MAIN = Queue()
+
+#init secondary comm channel list
+MAIN2SEC = GrowingList()
+SEC2MAIN = GrowingList()
+
+def connectionthread(name, client_id, conn, m2s, s2m):
+ """Manage secondary process connections"""
+
+ cmd_str = 'hello'
+
+ #infinite loop so that function do not terminate and thread do not end.
+ while True:
+ try:
+ _, _, _ = select.select([conn,], [conn,], [], 5)
+ except select.error:
+ break
+
+ #Sending message to connected secondary
+ try:
+ cmd_str = m2s.get(True)
+ conn.send(cmd_str) #send only takes string
+ except KeyError:
+ break
+ except Exception, excep:
+ print (str(excep))
+ break
+
+ #Receiving from secondary
+ try:
+ data = conn.recv(1024) # 1024 stands for bytes of data to be received
+ if data:
+ s2m.put("recv:" + str(conn.fileno()) + ":" + "{" + data + "}")
+ else:
+ s2m.put("closing:" + str(conn))
+ break
+ except Exception, excep:
+ print (str(excep))
+ break
+
+ SECONDARY_LIST.remove(client_id)
+ conn.close()
+
+def getclientid(conn):
+ """Get client_id from client"""
+
+ try:
+ conn.send("_get_client_id")
+ #conn.send("{\"commands\":[{\"command\":\"process\"}]}")
+ except KeyError:
+ return -1
+
+ data = conn.recv(1024)
+ if data == None:
+ return -1
+
+ #client_id = int(data.strip('\0'))
+ json_dict = json.loads(data)
+ client_id = int(json_dict['client_id'])
+
+ if client_id < 0 or client_id > MAX_SECONDARY:
+ return -1
+
+ print ("secondary id %d" % client_id)
+ return client_id
+
+ found = 0
+ for i in SECONDARY_LIST:
+ if client_id == i:
+ found = 1
+ break
+
+ if found == 0:
+ return client_id
+
+ # client_id in use, find a free one
+ free_client_id = -1
+ for i in range(MAX_SECONDARY):
+ found = -1
+ for j in SECONDARY_LIST:
+ if i == j:
+ found = i
+ break
+ if found == -1:
+ free_client_id = i
+ break
+
+ if free_client_id < 0:
+ return -1
+
+ conn.send("_set_client_id %u" % free_client_id)
+ data = conn.recv(1024)
+
+ return free_client_id
+
+def acceptthread(sock, main2sec, sec2main):
+ """Listen for secondary processes"""
+
+ global SECONDARY_COUNT
+
+ try:
+ while True:
+ #Accepting incoming connections
+ conn, _ = sock.accept()
+
+ client_id = getclientid(conn)
+ if client_id < 0:
+ break
+
+ #Creating new thread.
+ #Calling secondarythread function for this function and passing
+ #conn as argument.
+
+ SECONDARY_LIST.append(client_id)
+ main2sec[client_id] = Queue()
+ sec2main[client_id] = Queue()
+ start_new_thread(connectionthread,
+ ('secondary', client_id, conn,
+ main2sec[client_id],
+ sec2main[client_id], ))
+ SECONDARY_COUNT += 1
+ except Exception, excep:
+ print (str(excep))
+ sock.close()
+
+def command_primary(command):
+ """Send command to primary process"""
+
+ if PRIMARY:
+ MAIN2PRIMARY.put(command)
+ print (PRIMARY2MAIN.get(True))
+ else:
+ print ("primary not started")
+
+def command_secondary(sec_id, command):
+ """Send command to secondary process with sec_id"""
+
+ if sec_id in SECONDARY_LIST:
+ MAIN2SEC[sec_id].put(command)
+ print (SEC2MAIN[sec_id].get(True))
+ else:
+ print ("secondary id %d not exist" % sec_id)
+
+def print_status():
+ """Display information about connected clients"""
+
+ print ("Soft Patch Panel Status :")
+ print ("primary: %d" % PRIMARY)
+ print ("secondary count: %d" % len(SECONDARY_LIST))
+ for i in SECONDARY_LIST:
+ print ("Connected secondary id: %d" % i)
+
+def primarythread(sock, main2primary, primary2main):
+ """Manage primary process connection"""
+
+ global PRIMARY
+ cmd_str = ''
+
+ while True:
+ #waiting for connection
+ PRIMARY = False
+ conn, addr = sock.accept()
+ PRIMARY = True
+
+ while conn:
+ try:
+ _, _, _ = select.select([conn,], [conn,], [], 5)
+ except select.error:
+ break
+
+ #Sending message to connected primary
+ try:
+ cmd_str = main2primary.get(True)
+ conn.send(cmd_str) #send only takes string
+ except KeyError:
+ break
+ except Exception, excep:
+ print (str(excep))
+ break
+
+ #Receiving from primary
+ try:
+ data = conn.recv(1024) # 1024 stands for bytes of data to be received
+ if data:
+ primary2main.put("recv:" + str(addr) + ":" + "{" + data + "}")
+ else:
+ primary2main.put("closing:" + str(addr))
+ conn.close()
+ break
+ except Exception, excep:
+ print (str(excep))
+ break
+
+ print ("primary communication thread end")
+
+def close_all_secondary():
+ """Exit all secondary processes"""
+
+ return;
+
+ global SECONDARY_COUNT
+
+ tmp_list = []
+ for i in SECONDARY_LIST:
+ tmp_list.append(i)
+ for i in tmp_list:
+ command_secondary(i, 'exit')
+ SECONDARY_COUNT = 0
+
+def check_sec_cmds(cmds):
+ """Validate secondary commands before sending"""
+
+ return 1
+
+ level1 = ['status', 'exit', 'forward', 'stop']
+ level2 = ['add', 'patch', 'del']
+ patch_args = ['reset']
+ add_del_args = ['ring', 'vhost']
+ cmdlist = cmds.split(' ')
+ valid = 0
+
+ length = len(cmdlist)
+ if length == 1:
+ if cmdlist[0] in level1:
+ valid = 1
+ elif length == 2:
+ if cmdlist[0] == 'patch':
+ if cmdlist[1] in patch_args:
+ valid = 1
+ elif length == 3:
+ if cmdlist[0] in level2:
+ if cmdlist[0] == 'add' or cmdlist[0] == 'del':
+ if cmdlist[1] in add_del_args:
+ if str.isdigit(cmdlist[2]):
+ valid = 1
+ elif cmdlist[0] == 'patch':
+ if str.isdigit(cmdlist[1]) and str.isdigit(cmdlist[2]):
+ valid = 1
+
+ return valid
+
+class Shell(cmd.Cmd):
+ """SPP command prompt"""
+
+ intro = 'Welcome to the spp. Type help or ? to list commands.\n'
+ prompt = 'spp > '
+ recorded_file = None
+
+ COMMANDS = ['status', 'add', 'patch', 'ring', 'vhost',
+ 'reset', 'exit', 'forward', 'stop', 'clear']
+
+ def complete_pri(self, text, line, begidx, endidx):
+ """Completion for primary process commands"""
+
+ if not text:
+ completions = self.COMMANDS[:]
+ else:
+ completions = [p
+ for p in self.COMMANDS
+ if p.startswith(text)
+ ]
+ return completions
+
+ def complete_sec(self, text, line, begidx, endidx):
+ """Completion for secondary process commands"""
+
+ if not text:
+ completions = self.COMMANDS[:]
+ else:
+ completions = [p
+ for p in self.COMMANDS
+ if p.startswith(text)
+ ]
+ return completions
+
+ def do_status(self, _):
+ """Display Soft Patch Panel Status"""
+
+ print_status()
+
+ def do_pri(self, command):
+ """Send command to primary process"""
+
+ if command and command in self.COMMANDS:
+ command_primary(command)
+ else:
+ print ("primary invalid command")
+
+ def do_sec(self, arg):
+ """Send command to secondary process"""
+
+ cmds = arg.split(';')
+ if len(cmds) < 2:
+ print ("error")
+ elif str.isdigit(cmds[0]):
+ sec_id = int(cmds[0])
+ if check_sec_cmds(cmds[1]):
+ command_secondary(sec_id, cmds[1])
+ else:
+ print ("invalid cmd")
+ else:
+ print (cmds[0])
+ print ("first %s" % cmds[1])
+
+ def do_record(self, arg):
+ """Save future commands to filename: RECORD filename.cmd"""
+
+ self.recorded_file = open(arg, 'w')
+
+ def do_playback(self, arg):
+ """Playback commands from a file: PLAYBACK filename.cmd"""
+
+ self.close()
+ try:
+ with open(arg) as recorded_file:
+ lines = []
+ for line in recorded_file:
+ if line.strip().startswith("#"):
+ continue
+ lines.append(line)
+ self.cmdqueue.extend(lines)
+ except IOError:
+ print ("Error: File does not exist.")
+
+ def precmd(self, line):
+ line = line.lower()
+ if self.recorded_file and 'playback' not in line:
+ print(line, file=self.recorded_file)
+ return line
+
+ def close(self):
+ """Close record file"""
+
+ if self.recorded_file:
+ print("closing file")
+ self.recorded_file.close()
+ self.recorded_file = None
+
+ def do_bye(self, arg):
+ """Stop recording, close SPP, and exit: BYE"""
+
+ cmds = arg.split(' ')
+ if cmds[0] == 'sec':
+ close_all_secondary()
+ elif cmds[0] == 'all':
+ close_all_secondary()
+ command_primary('exit')
+ elif cmds[0] == '':
+ print('Thank you for using Soft Patch Panel')
+ self.close()
+ return True
+
+def main(argv):
+ """main"""
+
+ # Defining server address and port
+ host = '' #'localhost' or '127.0.0.1' or '' are all same
+
+ try:
+ opts, _ = getopt.getopt(argv, "p:s:h", ["help", "primary = ", "secondary"])
+ except getopt.GetoptError:
+ print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+ sys.exit(2)
+ for opt, arg in opts:
+ if opt in ("-h", "--help"):
+ print ('spp.py -p <primary__port_number> -s <secondary_port_number>')
+ sys.exit()
+ elif opt in ("-p", "--primary"):
+ primary_port = int(arg)
+ print ("primary port : %d" % primary_port)
+ elif opt in ("-s", "--secondary"):
+ secondary_port = int(arg)
+ print ('secondary port : %d' % secondary_port)
+
+ #Creating primary socket object
+ primary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ #Binding primary socket to a address. bind() takes tuple of host and port.
+ primary_sock.bind((host, primary_port))
+
+ #Listening primary at the address
+ primary_sock.listen(1) #5 denotes the number of clients can queue
+
+ primary_thread = Thread(target=primarythread,
+ args=(primary_sock, MAIN2PRIMARY, PRIMARY2MAIN,))
+ primary_thread.daemon = True
+ primary_thread.start()
+
+ #Creating secondary socket object
+ secondary_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ #Binding secondary socket to a address. bind() takes tuple of host and port.
+ secondary_sock.bind((host, secondary_port))
+
+ #Listening secondary at the address
+ secondary_sock.listen(MAX_SECONDARY)
+
+ # secondary process handling thread
+ start_new_thread(acceptthread, (secondary_sock, MAIN2SEC, SEC2MAIN))
+
+ shell = Shell()
+ shell.cmdloop()
+ shell = None
+
+ primary_sock.shutdown(socket.SHUT_RDWR)
+ primary_sock.close()
+ secondary_sock.shutdown(socket.SHUT_RDWR)
+ secondary_sock.close()
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
--
1.9.1
More information about the spp
mailing list