From b239b906bd06377749927558064832d17449369d Mon Sep 17 00:00:00 2001 From: Rod A Santiago Date: Wed, 14 Sep 2016 17:15:16 -0700 Subject: [PATCH] Cleaned up for checking in to NRL repo --- daemon/core/coreserver.py | 172 ++++++++++++++++++++++++++++++++++---- daemon/data/core.conf | 2 +- daemon/sbin/core-daemon | 13 +-- 3 files changed, 162 insertions(+), 25 deletions(-) diff --git a/daemon/core/coreserver.py b/daemon/core/coreserver.py index 64e05f32..7849d069 100644 --- a/daemon/core/coreserver.py +++ b/daemon/core/coreserver.py @@ -11,7 +11,7 @@ import SocketServer, sys, threading, time, traceback -import os, gc +import os, gc, shlex, shutil from core import pycore from core.api import coreapi from core.misc.utils import hexdump, cmdresult, mutedetach, closeonexec @@ -19,12 +19,13 @@ from core.misc.xmlsession import opensessionxml, savesessionxml ''' -Defines server classes and request handlers for TCP and UDP. Also defined here is a TCP based - +Defines server classes and request handlers for TCP and UDP. Also defined here is a TCP based auxiliary server class for supporting externally defined handlers. ''' + + class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): - ''' The main server - a TCP server class, manages sessions and spawns request handlers for + ''' TCP server class, manages sessions and spawns request handlers for incoming connections. ''' daemon_threads = True @@ -218,14 +219,11 @@ class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): break finally: self._sessionslock.release() - return found - - class CoreUdpServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): - ''' A UDP server class, manages sessions and spawns request handlers for + ''' UDP server class, manages sessions and spawns request handlers for incoming connections. ''' daemon_threads = True @@ -235,7 +233,7 @@ class CoreUdpServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): ''' Server class initialization takes configuration data and calls the SocketServer constructor ''' - self.mainserver = mainserver # tcpserver is the main server + self.mainserver = mainserver SocketServer.UDPServer.__init__(self, server_address, RequestHandlerClass) @@ -246,6 +244,7 @@ class CoreUdpServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): + class CoreAuxServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): ''' An auxiliary TCP server. ''' @@ -275,7 +274,6 @@ class CoreAuxServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): - class CoreRequestHandler(SocketServer.BaseRequestHandler): ''' The SocketServer class uses the RequestHandler class for servicing requests, mainly through the handle() method. The CoreRequestHandler @@ -494,17 +492,17 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): try: replies = msghandler(msg) - self.dispatchreplies(replies) + self.dispatchreplies(replies,msg) except Exception, e: self.warn("%s: exception while handling msg:\n%s\n%s" % (threading.currentThread().getName(), msg, traceback.format_exc())) - - # Added to allow the API2 handler to define a different behavior when replying + # Added to allow the auxiliary handlers to define a different behavior when replying # to messages from clients - def dispatchreplies(self, replies): - ''' Dispatch replies to a handled message. + def dispatchreplies(self, replies, msg): + ''' + Dispatch replies by CORE to message msg previously received from the client. ''' for reply in replies: if self.debug: @@ -525,6 +523,7 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): except Exception, e: self.warn("Error sending reply data: %s" % e) + def handle(self): ''' Handle a new connection request from a client. Dispatch to the recvmsg() method for receiving data into CORE API messages, and @@ -1139,10 +1138,10 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler): if ex: try: self.info("executing '%s'" % ex) - if isinstance(self.server, CoreUdpServer): - server = self.server.mainserver - elif isinstance(self.server, CoreApi2Server): + if not isinstance(self.server, CoreServer): # CoreUdpServer): server = self.server.mainserver + # elif isinstance(self.server, CoreAuxServer): + # server = self.server.mainserver else: server = self.server if msg.flags & coreapi.CORE_API_STR_FLAG: @@ -1575,3 +1574,140 @@ class CoreDatagramRequestHandler(CoreRequestHandler): ''' Use sendto() on the connectionless UDP socket. ''' self.request[1].sendto(data, self.client_address) + + + + +class BaseAuxRequestHandler(CoreRequestHandler): + ''' + This is the superclass for auxiliary handlers in CORE. A concrete auxiliary handler class + must, at a minimum, define the recvmsg(), sendall(), and dispatchreplies() methods. + See SockerServer.BaseRequestHandler for parameter details. + ''' + + def __init__(self, request, client_address, server): + self.msghandler = { + coreapi.CORE_API_NODE_MSG: self.handlenodemsg, + coreapi.CORE_API_LINK_MSG: self.handlelinkmsg, + coreapi.CORE_API_EXEC_MSG: self.handleexecmsg, + coreapi.CORE_API_REG_MSG: self.handleregmsg, + coreapi.CORE_API_CONF_MSG: self.handleconfmsg, + coreapi.CORE_API_FILE_MSG: self.handlefilemsg, + coreapi.CORE_API_IFACE_MSG: self.handleifacemsg, + coreapi.CORE_API_EVENT_MSG: self.handleeventmsg, + coreapi.CORE_API_SESS_MSG: self.handlesessionmsg, + } + self.handlerthreads = [] + self.nodestatusreq = {} + self.master = False + self.session = None + self.verbose = bool(server.mainserver.cfg['verbose'].lower() == "true") + self.debug = bool(server.mainserver.cfg['debug'].lower() == "true") + SocketServer.BaseRequestHandler.__init__(self, request, + client_address, server) + + def setup(self): + ''' New client has connected to the auxiliary server. + ''' + if self.verbose: + self.info("new auxiliary server client: %s:%s" % self.client_address) + + def handle(self): + ''' + The handler main loop + ''' + port = self.request.getpeername()[1] + self.session = self.server.mainserver.getsession(sessionid = port, + useexisting = False) + self.session.connect(self) + while True: + try: + msgs = self.recvmsg() + if msgs: + for msg in msgs: + self.session.broadcast(self, msg) + self.handlemsg(msg) + except EOFError: + break; + except IOError, e: + self.warn("IOError in CoreAuxRequestHandler: %s" % e) + break; + + def finish(self): + ''' + Disconnect the client + ''' + if self.session: + self.session.disconnect(self) + return SocketServer.BaseRequestHandler.finish(self) + + ''' + ======================================================================= + Concrete AuxRequestHandler classes must redefine the following methods + ======================================================================= + ''' + + + def recvmsg(self): + ''' + Receive data from the client in the supported format. Parse, transform to CORE API format and + return transformed messages. + + EXAMPLE: + return self.handler.request.recv(siz) + + ''' + pass + return None + + def dispatchreplies(self, replies, msg): + ''' + Dispatch CORE 'replies' to a previously received message 'msg' from a client. + Replies passed to this method follow the CORE API. This method allows transformation to + the form supported by the auxiliary handler and within the context of 'msg'. + Add transformation and transmission code here. + + EXAMPLE: + transformed_replies = stateful_transform (replies, msg) # stateful_transform method needs to be defined + if transformed_replies: + for reply in transformed_replies: + try: + self.request.sendall(reply) + except Exception, e: + if self.debug: + self.info("-"*60) + traceback.print_exc(file=sys.stdout) + self.info("-"*60) + raise e + + ''' + pass + + + def sendall(self, data): + ''' + CORE calls this method when data needs to be asynchronously sent to a client. The data is + in CORE API format. This method allows transformation to the required format supported by this + handler prior to transmission. + + EXAMPLE: + msgs = self.transform(data) # transform method needs to be defined + if msgs: + for msg in msgs: + try: + self.request.sendall(reply) + except Exception, e: + if self.debug: + self.info("-"*60) + traceback.print_exc(file=sys.stdout) + self.info("-"*60) + raise e + ''' + pass + + + + + + + diff --git a/daemon/data/core.conf b/daemon/data/core.conf index ea30b380..fd927298 100644 --- a/daemon/data/core.conf +++ b/daemon/data/core.conf @@ -62,4 +62,4 @@ emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass #emane_log_level = 2 emane_realtime = True -aux_request_handler = core.addons.api2.CoreApi2RequestHandler:12222 \ No newline at end of file +aux_request_handler = core.addons.api2handler.CoreApi2RequestHandler:12222 \ No newline at end of file diff --git a/daemon/sbin/core-daemon b/daemon/sbin/core-daemon index bda6b9df..f9126b16 100755 --- a/daemon/sbin/core-daemon +++ b/daemon/sbin/core-daemon @@ -67,9 +67,9 @@ coreapi.add_node_class("CORE_NODE_TUNNEL", coreapi.add_node_class("CORE_NODE_EMANE", coreapi.CORE_NODE_EMANE, pycore.nodes.EmaneNode) - - - +# +# UDP server startup +# def startudp(mainserver, server_address): ''' Start a thread running a UDP server on the same host,port for connectionless requests. @@ -121,13 +121,14 @@ def cored(cfg = None): try: server = CoreServer((host, port), CoreRequestHandler, cfg) except Exception, e: - sys.stderr.write("error starting server on: %s:%s\n\t%s\n" % \ + sys.stderr.write("error starting main server on: %s:%s\n\t%s\n" % \ (host, port, e)) sys.stderr.flush() sys.exit(1) closeonexec(server.fileno()) sys.stdout.write("main server started, listening on: %s:%s\n" % (host, port)) sys.stdout.flush() + udpserver = startudp(server, (host,port)) closeonexec(udpserver.fileno()) @@ -200,8 +201,8 @@ def getMergedConfig(filename): 'daemonize' : 'False', 'debug' : 'False', 'execfile' : None, - 'aux_request_handler' : None - } + 'aux_request_handler' : None, + } usagestr = "usage: %prog [-h] [options] [args]\n\n" + \ "CORE daemon v.%s instantiates Linux network namespace " \