moved daemon/sbin to daemon/scripts

This commit is contained in:
Blake J. Harnden 2018-03-15 11:30:11 -07:00
parent ac81c049ee
commit 09cf406187
7 changed files with 4 additions and 11 deletions

64
daemon/scripts/core-cleanup Executable file
View file

@ -0,0 +1,64 @@
#!/bin/sh
if [ "z$1" = "z-h" -o "z$1" = "z--help" ]; then
echo "usage: $0 [-d [-l]]"
echo -n " Clean up all CORE namespaces processes, bridges, interfaces, "
echo "and session\n directories. Options:"
echo " -h show this help message and exit"
echo " -d also kill the Python daemon"
echo " -l remove the core-daemon.log file"
exit 0
fi
if [ `id -u` != 0 ]; then
echo "Permission denied. Re-run this script as root."
exit 1
fi
PATH="/sbin:/bin:/usr/sbin:/usr/bin"
export PATH
if [ "z$1" = "z-d" ]; then
pypids=`pidof python python2`
for p in $pypids; do
grep -q core-daemon /proc/$p/cmdline
if [ $? = 0 ]; then
echo "cleaning up core-daemon process: $p"
kill -9 $p
fi
done
fi
if [ "z$2" = "z-l" ]; then
rm -f /var/log/core-daemon.log
fi
vnodedpids=`pidof vnoded`
if [ "z$vnodedpids" != "z" ]; then
echo "cleaning up old vnoded processes: $vnodedpids"
killall -v -KILL vnoded
# pause for 1 second for interfaces to disappear
sleep 1
fi
killall -q emane
killall -q emanetransportd
killall -q emaneeventservice
if [ -d /sys/class/net ]; then
ifcommand="ls -1 /sys/class/net"
else
ifcommand="ip -o link show | sed -r -e 's/[0-9]+: ([^[:space:]]+): .*/\1/'"
fi
eval "$ifcommand" | awk '
/^veth[0-9]+\./ {print "removing interface " $1; system("ip link del " $1);}
/tmp\./ {print "removing interface " $1; system("ip link del " $1);}
/gt\./ {print "removing interface " $1; system("ip link del " $1);}
/b\./ {print "removing bridge " $1; system("ip link set " $1 " down; brctl delbr " $1);}
'
ebtables -L FORWARD | awk '
/^-.*b\./ {print "removing ebtables " $0; system("ebtables -D FORWARD " $0); print "removing ebtables chain " $4; system("ebtables -X " $4);}
'
rm -rf /tmp/pycore*

316
daemon/scripts/core-daemon Executable file
View file

@ -0,0 +1,316 @@
#!/usr/bin/env python
"""
core-daemon: the CORE daemon is a server process that receives CORE API
messages and instantiates emulated nodes and networks within the kernel. Various
message handlers are defined and some support for sending messages.
"""
import ConfigParser
import atexit
import optparse
import os
import signal
import socket
import sys
import threading
import time
from core import constants
from core import corehandlers
from core import coreserver
from core import enumerations
from core import logger
from core import services
from core.api import coreapi
from core.corehandlers import CoreDatagramRequestHandler
from core.enumerations import MessageFlags
from core.enumerations import RegisterTlvs
from core.misc import nodeutils
from core.misc.utils import close_onexec
from core.misc.utils import daemonize
from core.service import ServiceManager
DEFAULT_MAXFD = 1024
def startudp(core_server, server_address):
"""
Start a thread running a UDP server on the same host,port for connectionless requests.
:param core.coreserver.CoreServer core_server: core server instance
:param tuple[str, int] server_address: server address
:return: created core udp server
:rtype: core.coreserver.CoreUdpServer
"""
core_server.udpserver = coreserver.CoreUdpServer(server_address, CoreDatagramRequestHandler, core_server)
core_server.udpthread = threading.Thread(target=core_server.udpserver.start)
core_server.udpthread.daemon = True
core_server.udpthread.start()
return core_server.udpserver
def banner():
"""
Output the program banner printed to the terminal or log file.
:return: nothing
"""
logger.info("CORE daemon v.%s started %s\n" % (constants.COREDPY_VERSION, time.ctime()))
def cored(cfg=None):
"""
Start the CoreServer object and enter the server loop.
:param dict cfg: core configuration
:return: nothing
"""
host = cfg["listenaddr"]
port = int(cfg["port"])
if host == "" or host is None:
host = "localhost"
try:
server = coreserver.CoreServer((host, port), corehandlers.CoreRequestHandler, cfg)
except:
logger.exception("error starting main server on: %s:%s", host, port)
sys.exit(1)
close_onexec(server.fileno())
logger.info("main server started, listening on: %s:%s\n" % (host, port))
udpserver = startudp(server, (host, port))
close_onexec(udpserver.fileno())
server.serve_forever()
# TODO: should sessions and the main core daemon both catch at exist to shutdown independently?
def cleanup():
"""
Runs server shutdown and cleanup when catching an exit signal.
:return: nothing
"""
while coreserver.CoreServer.servers:
server = coreserver.CoreServer.servers.pop()
server.shutdown()
atexit.register(cleanup)
def sighandler(signum, stackframe):
"""
Signal handler when different signals are sent.
:param int signum: singal number sent
:param stackframe: stack frame sent
:return: nothing
"""
logger.error("terminated by signal: %s", signum)
sys.exit(signum)
signal.signal(signal.SIGHUP, sighandler)
signal.signal(signal.SIGINT, sighandler)
signal.signal(signal.SIGTERM, sighandler)
signal.signal(signal.SIGUSR1, sighandler)
signal.signal(signal.SIGUSR2, sighandler)
def logrotate(stdout, stderr, stdoutmode=0644, stderrmode=0644):
"""
Log rotation method.
:param stdout: stdout
:param stderr: stderr
:param int stdoutmode: stdout mode
:param int stderrmode: stderr mode
:return:
"""
def reopen(fileno, filename, mode):
err = 0
fd = -1
try:
fd = os.open(filename,
os.O_WRONLY | os.O_CREAT | os.O_APPEND, mode)
os.dup2(fd, fileno)
except OSError as e:
err = e.errno
finally:
if fd >= 0:
os.close(fd)
return err
if stdout:
err = reopen(1, stdout, stdoutmode)
if stderr:
if stderr == stdout and not err:
try:
os.dup2(1, 2)
except OSError as e:
pass
else:
reopen(2, stderr, stderrmode)
def get_merged_config(filename):
"""
Return a configuration after merging config file and command-line arguments.
:param str filename: file name to merge configuration settings with
:return: merged configuration
:rtype: dict
"""
# these are the defaults used in the config file
defaults = {"port": "%d" % enumerations.CORE_API_PORT,
"listenaddr": "localhost",
"pidfile": "%s/run/core-daemon.pid" % constants.CORE_STATE_DIR,
"logfile": "%s/log/core-daemon.log" % constants.CORE_STATE_DIR,
"xmlfilever": "1.0",
"numthreads": "1",
"verbose": "False",
"daemonize": "False",
"debug": "False",
"execfile": None,
}
usagestr = "usage: %prog [-h] [options] [args]\n\n" + \
"CORE daemon v.%s instantiates Linux network namespace " \
"nodes." % constants.COREDPY_VERSION
parser = optparse.OptionParser(usage=usagestr)
parser.add_option("-f", "--configfile", dest="configfile",
type="string",
help="read config from specified file; default = %s" %
filename)
parser.add_option("-d", "--daemonize", dest="daemonize",
action="store_true",
help="run in background as daemon; default=%s" % \
defaults["daemonize"])
parser.add_option("-e", "--execute", dest="execfile", type="string",
help="execute a Python/XML-based session")
parser.add_option("-l", "--logfile", dest="logfile", type="string",
help="log output to specified file; default = %s" %
defaults["logfile"])
parser.add_option("-p", "--port", dest="port", type=int,
help="port number to listen on; default = %s" % \
defaults["port"])
parser.add_option("-i", "--pidfile", dest="pidfile",
help="filename to write pid to; default = %s" % \
defaults["pidfile"])
parser.add_option("-t", "--numthreads", dest="numthreads", type=int,
help="number of server threads; default = %s" % \
defaults["numthreads"])
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
help="enable verbose logging; default = %s" % \
defaults["verbose"])
parser.add_option("-g", "--debug", dest="debug", action="store_true",
help="enable debug logging; default = %s" % \
defaults["debug"])
# parse command line options
options, args = parser.parse_args()
# read the config file
if options.configfile is not None:
filename = options.configfile
del options.configfile
cfg = ConfigParser.SafeConfigParser(defaults)
cfg.read(filename)
section = "core-daemon"
if not cfg.has_section(section):
cfg.add_section(section)
# gracefully support legacy configs (cored.py/cored now core-daemon)
if cfg.has_section("cored.py"):
for name, val in cfg.items("cored.py"):
if name == "pidfile" or name == "logfile":
bn = os.path.basename(val).replace("coredpy", "core-daemon")
val = os.path.join(os.path.dirname(val), bn)
cfg.set(section, name, val)
if cfg.has_section("cored"):
for name, val in cfg.items("cored"):
if name == "pidfile" or name == "logfile":
bn = os.path.basename(val).replace("cored", "core-daemon")
val = os.path.join(os.path.dirname(val), bn)
cfg.set(section, name, val)
# merge command line with config file
for opt in options.__dict__:
val = options.__dict__[opt]
if val is not None:
cfg.set(section, opt, val.__str__())
return dict(cfg.items(section)), args
def exec_file(cfg):
"""
Send a Register Message to execute a new session based on XML or Python script file.
:param dict cfg: configuration settings
:return: 0
"""
filename = cfg["execfile"]
logger.info("Telling daemon to execute file: %s...", filename)
tlvdata = coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, filename)
msg = coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlvdata)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# TODO: connect address option
sock.connect(("localhost", int(cfg["port"])))
sock.sendall(msg)
return 0
def main():
"""
Main program startup.
:return: nothing
"""
# get a configuration merged from config file and command-line arguments
cfg, args = get_merged_config("%s/core.conf" % constants.CORE_CONF_DIR)
for a in args:
logger.error("ignoring command line argument: %s", a)
# attempt load custom services
service_paths = cfg.get("custom_services_dir")
logger.debug("custom service paths: %s", service_paths)
if service_paths:
for service_path in service_paths.split(','):
service_path = service_path.strip()
ServiceManager.add_services(service_path)
if cfg["daemonize"] == "True":
daemonize(rootdir=None, umask=0, close_fds=False,
stdin=os.devnull,
stdout=cfg["logfile"], stderr=cfg["logfile"],
pidfilename=cfg["pidfile"],
defaultmaxfd=DEFAULT_MAXFD)
signal.signal(signal.SIGUSR1, lambda signum, stackframe:
logrotate(stdout=cfg["logfile"], stderr=cfg["logfile"]))
banner()
if cfg["execfile"]:
cfg["execfile"] = os.path.abspath(cfg["execfile"])
sys.exit(exec_file(cfg))
try:
cored(cfg)
except KeyboardInterrupt:
logger.info("keyboard interrupt, stopping core daemon")
sys.exit(0)
if __name__ == "__main__":
# configure nodes to use
if len(sys.argv) == 2 and sys.argv[1] == "ovs":
from core.netns.openvswitch import OVS_NODES
nodeutils.update_node_map(OVS_NODES)
# load default services
services.load()
main()

248
daemon/scripts/core-manage Executable file
View file

@ -0,0 +1,248 @@
#!/usr/bin/env python
"""
core-manage: Helper tool to add, remove, or check for services, models, and
node types in a CORE installation.
"""
import ast
import optparse
import os
import re
import sys
from core import services
from core.constants import CORE_CONF_DIR
class FileUpdater(object):
"""
Helper class for changing configuration files.
"""
actions = ("add", "remove", "check")
targets = ("service", "model", "nodetype")
def __init__(self, action, target, data, options):
"""
"""
self.action = action
self.target = target
self.data = data
self.options = options
self.verbose = options.verbose
self.search, self.filename = self.get_filename(target)
def process(self):
""" Invoke update_file() using a helper method depending on target.
"""
if self.verbose:
txt = "Updating"
if self.action == "check":
txt = "Checking"
sys.stdout.write("%s file: %s\n" % (txt, self.filename))
if self.target == "service":
r = self.update_file(fn=self.update_services)
elif self.target == "model":
r = self.update_file(fn=self.update_emane_models)
elif self.target == "nodetype":
r = self.update_nodes_conf()
if self.verbose:
txt = ""
if not r:
txt = "NOT "
if self.action == "check":
sys.stdout.write("String %sfound.\n" % txt)
else:
sys.stdout.write("File %supdated.\n" % txt)
return r
def update_services(self, line):
""" Modify the __init__.py file having this format:
__all__ = ["quagga", "nrl", "xorp", "bird", ]
Returns True or False when "check" is the action, a modified line
otherwise.
"""
line = line.strip("\n")
key, valstr = line.split("= ")
vals = ast.literal_eval(valstr)
r = self.update_keyvals(key, vals)
if self.action == "check":
return r
valstr = "%s" % r
return "= ".join([key, valstr]) + "\n"
def update_emane_models(self, line):
""" Modify the core.conf file having this format:
emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass
Returns True or False when "check" is the action, a modified line
otherwise.
"""
line = line.strip("\n")
key, valstr = line.split("= ")
vals = valstr.split(", ")
r = self.update_keyvals(key, vals)
if self.action == "check":
return r
valstr = ", ".join(r)
return "= ".join([key, valstr]) + "\n"
def update_keyvals(self, key, vals):
""" Perform self.action on (key, vals).
Returns True or False when "check" is the action, a modified line
otherwise.
"""
if self.action == "check":
if self.data in vals:
return True
else:
return False
elif self.action == "add":
if self.data not in vals:
vals.append(self.data)
elif self.action == "remove":
try:
vals.remove(self.data)
except ValueError:
pass
return vals
def get_filename(self, target):
""" Return search string and filename based on target.
"""
if target == "service":
filename = os.path.abspath(services.__file__)
search = "__all__ ="
elif target == "model":
filename = os.path.join(CORE_CONF_DIR, "core.conf")
search = "emane_models ="
elif target == "nodetype":
if self.options.userpath is None:
raise ValueError, "missing user path"
filename = os.path.join(self.options.userpath, "nodes.conf")
search = self.data
else:
raise ValueError, "unknown target"
if not os.path.exists(filename):
raise ValueError, "file %s does not exist" % filename
return search, filename
def update_file(self, fn=None):
""" Open a file and search for self.search, invoking the supplied
function on the matching line. Write file changes if necessary.
Returns True if the file has changed (or action is "check" and the
search string is found), False otherwise.
"""
changed = False
output = "" # this accumulates output, assumes input is small
with open(self.filename, "r") as f:
for line in f:
if line[:len(self.search)] == self.search:
r = fn(line) # line may be modified by fn() here
if self.action == "check":
return r
else:
if line != r:
changed = True
line = r
output += line
if changed:
with open(self.filename, "w") as f:
f.write(output)
return changed
def update_nodes_conf(self):
""" Add/remove/check entries from nodes.conf. This file
contains a Tcl-formatted array of node types. The array index must be
properly set for new entries. Uses self.{action, filename, search,
data} variables as input and returns the same value as update_file().
"""
changed = False
output = "" # this accumulates output, assumes input is small
with open(self.filename, "r") as f:
for line in f:
# make sure data is not added twice
if line.find(self.search) >= 0:
if self.action == "check":
return True
elif self.action == "add":
return False
elif self.action == "remove":
changed = True
continue
else:
output += line
if self.action == "add":
index = int(re.match("^\d+", line).group(0))
output += str(index + 1) + " " + self.data + "\n"
changed = True
if changed:
with open(self.filename, "w") as f:
f.write(output)
return changed
def main():
usagestr = "usage: %prog [-h] [options] <action> <target> <string>\n"
usagestr += "\nHelper tool to add, remove, or check for "
usagestr += "services, models, and node types\nin a CORE installation.\n"
usagestr += "\nExamples:\n %prog add service newrouting"
usagestr += "\n %prog -v check model RfPipe"
usagestr += "\n %prog --userpath=\"$HOME/.core\" add nodetype \"{ftp ftp.gif ftp.gif {DefaultRoute FTP} netns {FTP server} }\" \n"
usagestr += "\nArguments:\n <action> should be one of: %s" % \
", ".join(FileUpdater.actions)
usagestr += "\n <target> should be one of: %s" % \
", ".join(FileUpdater.targets)
usagestr += "\n <string> is the text to %s" % \
", ".join(FileUpdater.actions)
parser = optparse.OptionParser(usage=usagestr)
parser.set_defaults(userpath=None, verbose=False, )
parser.add_option("--userpath", dest="userpath", type="string",
help="use the specified user path (e.g. \"$HOME/.core" \
"\") to access nodes.conf")
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
help="be verbose when performing action")
def usage(msg=None, err=0):
sys.stdout.write("\n")
if msg:
sys.stdout.write(msg + "\n\n")
parser.print_help()
sys.exit(err)
(options, args) = parser.parse_args()
if len(args) != 3:
usage("Missing required arguments!", 1)
action = args[0]
if action not in FileUpdater.actions:
usage("invalid action %s" % action, 1)
target = args[1]
if target not in FileUpdater.targets:
usage("invalid target %s" % target, 1)
if target == "nodetype" and not options.userpath:
usage("user path option required for this target (%s)" % target)
data = args[2]
try:
up = FileUpdater(action, target, data, options)
r = up.process()
except Exception, e:
sys.stderr.write("Exception: %s\n" % e)
sys.exit(1)
if not r:
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
main()

275
daemon/scripts/coresendmsg Executable file
View file

@ -0,0 +1,275 @@
#!/usr/bin/env python
"""
coresendmsg: utility for generating CORE messages
"""
import optparse
import os
import socket
import sys
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 print_available_tlvs(t, tlv_class):
"""
Print a TLV list.
"""
print "TLVs available for %s message:" % t
for tlv in sorted([tlv for tlv in tlv_class.tlv_type_map], 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 %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.
"""
try:
# large receive buffer used for UDP sockets, instead of just receiving
# the 4-byte header
data = sock.recv(4096)
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.unpack_header(msghdr)
if msglen:
msgdata = data[coreapi.CoreMessage.header_len:]
try:
msgcls = coreapi.CLASS_MAP[msgtype]
except KeyError:
msg = coreapi.CoreMessage(msgflags, msghdr, msgdata)
msg.message_type = msgtype
print "unimplemented CORE message type: %s" % msg.type_str()
return msg
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.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.
"""
# request the session list
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.get_tlv(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("|")
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:
session = requested
else:
print "requested session not found!"
return False
print "joining session %s..." % session
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.
"""
print "waiting for response..."
msg = receive_message(sock)
if msg is None:
print "disconnected from %s:%s" % (opt.address, opt.port)
sys.exit(0)
print "received message:", msg
def main():
"""
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=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.")
def usage(msg=None, err=0):
sys.stdout.write("\n")
if msg:
sys.stdout.write(msg + "\n\n")
parser.print_help()
sys.exit(err)
# parse command line opt
opt, args = parser.parse_args()
if opt.examples:
print_examples(os.path.basename(sys.argv[0]))
sys.exit(0)
if len(args) == 0:
usage("Please specify a message type to send.")
# given a message type t, determine the message and TLV classes
t = args.pop(0)
if t not in types:
usage("Unknown message type requested: %s" % t)
message_type = MessageTypes[t]
msg_cls = coreapi.CLASS_MAP[message_type.value]
tlv_cls = msg_cls.tlv_class
# 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
flagstr = ""
tlvdata = ""
for a in args:
typevalue = a.split("=")
if len(typevalue) < 2:
usage("Use \"type=value\" syntax instead of \"%s\"." % a)
tlv_typestr = typevalue[0]
tlv_valstr = "=".join(typevalue[1:])
if tlv_typestr == "flags":
flagstr = tlv_valstr
continue
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 == "":
continue
try:
flag_enum = MessageFlags[f]
n = flag_enum.value
flags |= n
except KeyError:
usage("Invalid flag \"%s\"." % f)
msg = msg_cls.pack(flags, tlvdata)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setblocking(True)
try:
sock.connect((opt.address, opt.port))
except Exception as e:
print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e)
sys.exit(1)
if not connect_to_session(sock, opt.session):
print "warning: continuing without joining a session!"
sock.sendall(msg)
if opt.listen:
receive_response(sock, opt)
if opt.tcp:
sock.shutdown(socket.SHUT_RDWR)
sock.close()
sys.exit(0)
if __name__ == "__main__":
main()