diff --git a/daemon/sbin/coresendmsg b/daemon/sbin/coresendmsg index ebf56486..85679e9a 100755 --- a/daemon/sbin/coresendmsg +++ b/daemon/sbin/coresendmsg @@ -6,187 +6,207 @@ # # authors: Jeff Ahrenholz # -''' +""" coresendmsg: utility for generating CORE messages -''' +""" -import sys -import socket import optparse import os +import socket +import sys -try: - from core.constants import * -except ImportError: - # hack for Fedora autoconf that uses the following pythondir: - if "/usr/lib/python2.6/site-packages" in sys.path: - sys.path.append("/usr/local/lib/python2.6/site-packages") - if "/usr/lib64/python2.6/site-packages" in sys.path: - sys.path.append("/usr/local/lib64/python2.6/site-packages") - if "/usr/lib/python2.7/site-packages" in sys.path: - sys.path.append("/usr/local/lib/python2.7/site-packages") - if "/usr/lib64/python2.7/site-packages" in sys.path: - sys.path.append("/usr/local/lib64/python2.7/site-packages") - from core.constants import * from core.api import coreapi +from core.enumerations import CORE_API_PORT +from core.enumerations import MessageFlags +from core.enumerations import MessageTypes +from core.enumerations import SessionTlvs -def msgtypenum_to_str(num): - ''' Convert the message type number into a string, such as - 1 = 'CORE_API_NODE_MSG' = 'node' - ''' - fulltypestr = coreapi.message_types[num] - r = fulltypestr.split('_')[2] - return r.lower() +# def msgtypenum_to_str(num): +# """ +# Convert the message type number into a string, such as +# 1 = "CORE_API_NODE_MSG" = "node" +# """ +# fulltypestr = str(MessageTypes(num)) +# r = fulltypestr.split("_")[2] +# return r.lower() -def str_to_msgtypenum(s): - ''' Convert a shorthand string into a message type number. - ''' - fulltypestr = str_to_msgtypename(s) - for k, v in coreapi.message_types.iteritems(): - if v == fulltypestr: - return k - return None -def str_to_msgtypename(s): - ''' Convert a shorthand string into a message type name. - ''' - return "CORE_API_%s_MSG" % s.upper() +# def str_to_msgtypenum(message_string): +# """ +# Convert a shorthand string into a message type number. +# """ +# fulltypestr = str_to_msgtypename(message_string) +# for k, v in coreapi.message_types.iteritems(): +# if v == fulltypestr: +# return k +# return None -def msgflagnum_to_str(num): - ''' Convert the message flag number into a string, such as - 1 = 'CORE_API_ADD_FLAG' = add - ''' - fullflagstr = coreapi.message_flags[num] - r = fullflagstr.split('_')[2] - return r.lower() -def str_to_msgflagname(s): - ''' Convert a shorthand string into a message flag name. - ''' - return "CORE_API_%s_FLAG" % s.upper() +# def str_to_msgtypename(s): +# """ +# Convert a shorthand string into a message type name. +# """ +# return "CORE_API_%s_MSG" % s.upper() -def str_to_msgflagnum(s): - flagname = str_to_msgflagname(s) - for (k, v) in coreapi.message_flags.iteritems(): - if v == flagname: - return k - return None -def tlvname_to_str(name): - ''' Convert a TLV name such as CORE_TLV_CONF_NODE to a short sring 'node'. - ''' - items = name.split('_')[3:] - return '_'.join(items).lower() +# def msgflagnum_to_str(num): +# """ +# Convert the message flag number into a string, such as +# 1 = "CORE_API_ADD_FLAG" = add +# """ +# fullflagstr = coreapi.message_flags[num] +# r = fullflagstr.split("_")[2] +# return r.lower() -def tlvname_to_num(tlv_cls, name): - ''' Convert the given TLV Type class and TLV name to the TLV number. - ''' - for (k, v) in tlv_cls.tlvtypemap.iteritems(): - if v == name: - return k - return None -def str_to_tlvname(t, s): - ''' Convert the given TLV type t and string s to a TLV name. - ''' - return "CORE_TLV_%s_%s" % (t.upper(), s.upper()) +# def str_to_msgflagname(s): +# """ +# Convert a shorthand string into a message flag name. +# """ +# return "CORE_API_%s_FLAG" % s.upper() + + +# def str_to_msgflagnum(s): +# flagname = str_to_msgflagname(s) +# for (k, v) in coreapi.message_flags.iteritems(): +# if v == flagname: +# return k +# return None + + +# def tlvname_to_str(name): +# """ +# Convert a TLV name such as CORE_TLV_CONF_NODE to a short sring "node". +# """ +# items = name.split("_")[3:] +# return "_".join(items).lower() + + +# def tlvname_to_num(tlv_cls, name): +# """ +# Convert the given TLV Type class and TLV name to the TLV number. +# """ +# for k, v in tlv_cls.tlv_type_map.iteritems(): +# if v == name: +# return k +# return None + + +# def str_to_tlvname(t, s): +# """ +# Convert the given TLV type t and string s to a TLV name. +# """ +# return "CORE_TLV_%s_%s" % (t.upper(), s.upper()) def print_available_tlvs(t, tlv_cls): - ''' Print a TLV list. - ''' + """ + Print a TLV list. + """ print "TLVs available for %s message:" % t - for k in sorted(tlv_cls.tlvtypemap.keys()): - print "%d:%s" % (k, tlvname_to_str(tlv_cls.tlvtypemap[k])), + for tlv in sorted([tlv for tlv in tlv_cls], key=lambda x: x.name): + print "%s:%s" % (tlv.value, tlv.name) + def print_examples(name): - ''' Print example usage of this script. - ''' - examples = [ - ('link n1number=2 n2number=3 delay=15000', - 'set a 15ms delay on the link between n2 and n3'), - ('link n1number=2 n2number=3 guiattr=\'color=blue\'', - 'change the color of the link between n2 and n3'), - ('node number=3 xpos=125 ypos=525', - 'move node number 3 to x,y=(125,525)'), - ('node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif', - 'change node number 4\'s icon to red'), - ('node flags=add number=5 type=0 name=\'n5\' xpos=500 ypos=500', - 'add a new router node n5'), - ('link flags=add n1number=4 n2number=5 if1ip4=\'10.0.3.2\' ' \ - 'if1ip4mask=24 if2ip4=\'10.0.3.1\' if2ip4mask=24', - 'link node n5 with n4 using the given interface addresses'), - ('exec flags=str,txt node=1 num=1000 cmd=\'uname -a\' -l', - 'run a command on node 1 and wait for the result'), - ('exec node=2 num=1001 cmd=\'killall ospfd\'', - 'run a command on node 2 and ignore the result'), - ('file flags=add node=1 name=\'/var/log/test.log\' data=\'Hello World.\'', - 'write a test.log file on node 1 with the given contents'), - ('file flags=add node=2 name=\'test.log\' ' \ - 'srcname=\'./test.log\'', - 'move a test.log file from host to node 2'), - ] + """ + Print example usage of this script. + """ + examples = [ + ("link n1number=2 n2number=3 delay=15000", + "set a 15ms delay on the link between n2 and n3"), + ("link n1number=2 n2number=3 guiattr=\"color=blue\"", + "change the color of the link between n2 and n3"), + ("node number=3 xpos=125 ypos=525", + "move node number 3 to x,y=(125,525)"), + ("node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif", + "change node number 4\"s icon to red"), + ("node flags=add number=5 type=0 name=\"n5\" xpos=500 ypos=500", + "add a new router node n5"), + ("link flags=add n1number=4 n2number=5 if1ip4=\"10.0.3.2\" " \ + "if1ip4mask=24 if2ip4=\"10.0.3.1\" if2ip4mask=24", + "link node n5 with n4 using the given interface addresses"), + ("exec flags=str,txt node=1 num=1000 cmd=\"uname -a\" -l", + "run a command on node 1 and wait for the result"), + ("exec node=2 num=1001 cmd=\"killall ospfd\"", + "run a command on node 2 and ignore the result"), + ("file flags=add node=1 name=\"/var/log/test.log\" data=\"Hello World.\"", + "write a test.log file on node 1 with the given contents"), + ("file flags=add node=2 name=\"test.log\" " \ + "srcname=\"./test.log\"", + "move a test.log file from host to node 2"), + ] print "Example %s invocations:" % name for cmd, descr in examples: print " %s %s\n\t\t%s" % (name, cmd, descr) + def receive_message(sock): - ''' Retrieve a message from a socket and return the CoreMessage object or - None upon disconnect. Socket data beyond the first message is dropped. - ''' + """ + Retrieve a message from a socket and return the CoreMessage object or + None upon disconnect. Socket data beyond the first message is dropped. + """ try: # large receive buffer used for UDP sockets, instead of just receiving # the 4-byte header data = sock.recv(4096) - msghdr = data[:coreapi.CoreMessage.hdrsiz] + msghdr = data[:coreapi.CoreMessage.header_len] except KeyboardInterrupt: print "CTRL+C pressed" sys.exit(1) + if len(msghdr) == 0: return None + msgdata = None - msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) + msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr) + if msglen: - msgdata = data[coreapi.CoreMessage.hdrsiz:] + msgdata = data[coreapi.CoreMessage.header_len:] try: - msgcls = coreapi.msg_class(msgtype) + msgcls = coreapi.CLASS_MAP[msgtype] except KeyError: msg = coreapi.CoreMessage(msgflags, msghdr, msgdata) - msg.msgtype = msgtype - print "unimplemented CORE message type: %s" % msg.typestr() + msg.message_type = msgtype + print "unimplemented CORE message type: %s" % msg.type_str() return msg - if len(data) > msglen + coreapi.CoreMessage.hdrsiz: + if len(data) > msglen + coreapi.CoreMessage.header_len: print "received a message of type %d, dropping %d bytes of extra data" \ - % (msgtype, len(data) - (msglen + coreapi.CoreMessage.hdrsiz)) + % (msgtype, len(data) - (msglen + coreapi.CoreMessage.header_len)) return msgcls(msgflags, msghdr, msgdata) def connect_to_session(sock, requested): - ''' Use Session Messages to retrieve the current list of sessions and - connect to the first one. - ''' + """ + Use Session Messages to retrieve the current list of sessions and + connect to the first one. + """ # request the session list - tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, "0") - flags = coreapi.CORE_API_STR_FLAG + tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, "0") + flags = MessageFlags.STRING.value smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) sock.sendall(smsg) + print "waiting for session list..." smsgreply = receive_message(sock) if smsgreply is None: print "disconnected" return False - sessstr = smsgreply.gettlv(coreapi.CORE_TLV_SESS_NUMBER) + + sessstr = smsgreply.gettlv(SessionTlvs.NUMBER.value) if sessstr is None: print "missing session numbers" return False + # join the first session (that is not our own connection) - (tmp, localport) = sock.getsockname() - sessions = sessstr.split('|') + tmp, localport = sock.getsockname() + sessions = sessstr.split("|") sessions.remove(str(localport)) if len(sessions) == 0: print "no sessions to join" return False + if not requested: session = sessions[0] elif requested in sessions: @@ -194,17 +214,19 @@ def connect_to_session(sock, requested): else: print "requested session not found!" return False + print "joining session %s..." % session - tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, session) - flags = coreapi.CORE_API_ADD_FLAG + tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER, session) + flags = MessageFlags.ADD smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) sock.sendall(smsg) return True def receive_response(sock, opt): - ''' Receive and print a CORE message from the given socket. - ''' + """ + Receive and print a CORE message from the given socket. + """ print "waiting for response..." msg = receive_message(sock) if msg is None: @@ -214,44 +236,46 @@ def receive_response(sock, opt): def main(): - ''' Parse command-line arguments to build and send a CORE message. - ''' - types = map(msgtypenum_to_str, coreapi.message_types.keys()[:-1]) - flags = map(msgflagnum_to_str, sorted(coreapi.message_flags.keys())) + """ + Parse command-line arguments to build and send a CORE message. + """ + types = [message_type.name for message_type in MessageTypes] + flags = [flag.name for flag in MessageFlags] usagestr = "usage: %prog [-h|-H] [options] [message-type] [flags=flags] " usagestr += "[message-TLVs]\n\n" usagestr += "Supported message types:\n %s\n" % types usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags - parser = optparse.OptionParser(usage = usagestr) - parser.set_defaults(port = coreapi.CORE_API_PORT, - address = "localhost", - session = None, - listen = False, - examples = False, - tlvs = False, - tcp = False) + parser = optparse.OptionParser(usage=usagestr) + parser.set_defaults( + port=CORE_API_PORT, + address="localhost", + session=None, + listen=False, + examples=False, + tlvs=False, + tcp=False + ) - parser.add_option("-H", dest = "examples", action = "store_true", - help = "show example usage help message and exit") - parser.add_option("-p", "--port", dest = "port", type = int, - help = "TCP port to connect to, default: %d" % \ - parser.defaults['port']) - parser.add_option("-a", "--address", dest = "address", type = str, - help = "Address to connect to, default: %s" % \ - parser.defaults['address']) - parser.add_option("-s", "--session", dest = "session", type = str, - help = "Session to join, default: %s" % \ - parser.defaults['session']) - parser.add_option("-l", "--listen", dest = "listen", action = "store_true", - help = "Listen for a response message and print it.") - parser.add_option("-t", "--list-tlvs", dest = "tlvs", action = "store_true", - help = "List TLVs for the specified message type.") - parser.add_option("-T", "--tcp", dest = "tcp", action = "store_true", - help = "Use TCP instead of UDP and connect to a session" \ - ", default: %s" % parser.defaults['tcp']) + parser.add_option("-H", dest="examples", action="store_true", + help="show example usage help message and exit") + parser.add_option("-p", "--port", dest="port", type=int, + help="TCP port to connect to, default: %d" % \ + parser.defaults["port"]) + parser.add_option("-a", "--address", dest="address", type=str, + help="Address to connect to, default: %s" % \ + parser.defaults["address"]) + parser.add_option("-s", "--session", dest="session", type=str, + help="Session to join, default: %s" % \ + parser.defaults["session"]) + parser.add_option("-l", "--listen", dest="listen", action="store_true", + help="Listen for a response message and print it.") + parser.add_option("-t", "--list-tlvs", dest="tlvs", action="store_true", + help="List TLVs for the specified message type.") + parser.add_option("-T", "--tcp", dest="tcp", action="store_true", + help="Use TCP instead of UDP and connect to a session" \ + ", default: %s" % parser.defaults["tcp"]) - - def usage(msg = None, err = 0): + def usage(msg=None, err=0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") @@ -259,8 +283,8 @@ def main(): sys.exit(err) # parse command line opt - (opt, args) = parser.parse_args() - if (opt.examples): + opt, args = parser.parse_args() + if opt.examples: print_examples(os.path.basename(sys.argv[0])) sys.exit(0) if len(args) == 0: @@ -270,40 +294,47 @@ def main(): t = args.pop(0) if t not in types: usage("Unknown message type requested: %s" % t) - msg_cls = coreapi.msgclsmap[str_to_msgtypenum(t)] - tlv_cls = msg_cls.tlvcls + message_type = MessageTypes[t] + msg_cls = coreapi.CLASS_MAP[message_type.value] + tlv_cls = msg_cls.tlv_cls # list TLV types for this message type if opt.tlvs: print_available_tlvs(t, tlv_cls) sys.exit(0) - # build a message consisting of TLVs from 'type=value' arguments + # build a message consisting of TLVs from "type=value" arguments flagstr = "" tlvdata = "" for a in args: - typevalue = a.split('=') + typevalue = a.split("=") if len(typevalue) < 2: - usage("Use 'type=value' syntax instead of '%s'." % a) + usage("Use \"type=value\" syntax instead of \"%s\"." % a) tlv_typestr = typevalue[0] - tlv_valstr = '='.join(typevalue[1:]) + tlv_valstr = "=".join(typevalue[1:]) if tlv_typestr == "flags": flagstr = tlv_valstr continue - tlv_name = str_to_tlvname(t, tlv_typestr) - tlv_type = tlvname_to_num(tlv_cls, tlv_name) - if tlv_name not in tlv_cls.tlvtypemap.values(): - usage("Unknown TLV: '%s' / %s" % (tlv_typestr, tlv_name)) - tlvdata += tlv_cls.packstring(tlv_type, tlv_valstr) + + tlv_name = tlv_typestr + tlv_type = tlv_cls[tlv_name].value + try: + tlv_cls.tlv_type_map[tlv_name] + except KeyError: + usage("Unknown TLV: \"%s\"" % tlv_name) + tlvdata += tlv_cls.pack_string(tlv_type, tlv_valstr) flags = 0 for f in flagstr.split(","): - if f == '': + if f == "": continue - n = str_to_msgflagnum(f) - if n is None: - usage("Invalid flag '%s'." % f) - flags |= n + + try: + flag_enum = MessageFlags[f] + n = flag_enum.value + flags |= n + except KeyError: + usage("Invalid flag \"%s\"." % f) msg = msg_cls.pack(flags, tlvdata) @@ -312,11 +343,13 @@ def main(): protocol = socket.SOCK_STREAM else: protocol = socket.SOCK_DGRAM + sock = socket.socket(socket.AF_INET, protocol) sock.setblocking(True) + try: sock.connect((opt.address, opt.port)) - except Exception, e: + except Exception as e: print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e) sys.exit(1)