Subversion Repositories HomeAutomation

Rev

Rev 739 | Blame | Last modification | View Log | SVN | RSS feed

  1. #!/bin/env python
  2.  
  3. import os
  4. import sys
  5. import logging as log
  6. import getopt
  7. import atexit
  8. import time
  9.  
  10. from CanPktHandlerBase import CanPktHandlerBase
  11. from CanPktHandler1 import CanPktHandler1
  12.  
  13. from NodeIfBase import NodeIfBase
  14. from NodeIfCanStim import NodeIfCanStim
  15. from NodeIfSerial import NodeIfSerial
  16.  
  17. from DaemonConfig import DaemonConfig
  18.  
  19. daemonApp = None
  20.  
  21. class CanDaemon():
  22.    
  23.     cfg = None
  24.     nodeIf = None
  25.     ifNotifier = None
  26.     terminated = False
  27.     command_list = []
  28.     command_map = {}
  29.     help_command_map = {}
  30.  
  31.     def __init__ (self):
  32.         self.command_list = [['help', self.helpCmd, 'display help'],
  33.                        ['log', self.logCmd, 'log control: \"help log\"'],
  34.                        ['exec', self.execCmd,  'run command listing <filename>\n'],
  35.                        ['filter', self.filterCmd, 'filter commands: \"help filter\"'],
  36.                        ['state', self.stateCmd, 'state commands: \"help state\"\n'],
  37.                        ['addif', self.ifAddCmd, 'add interface: \"help addif\"'],
  38.                        ['remif', self.ifRemCmd, 'remove interface <name>'],
  39.                        ['ifup', self.ifUpCmd, 'bring up interface <name>'],
  40.                        ['ifdown', self.ifDownCmd, 'bring down interface <name>\n'],
  41.                        ['addbrigde', self.addBridgeCmd, 'add bridge: \"help addbridge\"'],
  42.                        ['rembridge', self.remBridgeCmd, 'remove bridge <name>\n'],
  43.                        ['tcpd', self.tcpdCmd, 'tcpd server control: \"help tcpd\"'],
  44.                        ['tlsd', self.tlsdCmd, 'tlsd server control: \"help tlsd\"'],
  45.                        ['canctld', self.canCtldCmd, 'canctld server control: \"help canctld\"\n'],
  46.                        ['status', self.statusCmd, 'show daemon status'],
  47.                        ['stats', self.statsCmd, 'show statistics\n'],
  48.                        ['nodelist', self.nodesCmd, 'list can nodes'],
  49.                        ['filterlist', self.filterlistCmd, 'list active filters\n'],
  50.                        ['sim', self.simCmd, 'simulator commands: \"help sim\"']]
  51.        
  52.         index = 0
  53.         for cmd in self.command_list:
  54.             self.command_map[cmd[0]] = index
  55.             index += 1
  56.  
  57.         logHelp = 'not implemented'
  58.         stateHelp = 'not implemented'
  59.         addifHelp = 'not implemented'
  60.         addbridgeHelp = 'not implemented'
  61.         tcpdHelp = 'not implemented'
  62.         tlsdHelp = 'not implemented'
  63.         canctldHelp = 'not implemented'
  64.         simHelp = 'not implemented'
  65.         self.help_command_map = {'log' : logHelp,
  66.                                 'state' : stateHelp,
  67.                                 'addif' : addifHelp,
  68.                                 'addbridge' : addbridgeHelp,
  69.                                 'tcpd' : tcpdHelp,
  70.                                 'tlsd' : tlsdHelp,
  71.                                 'canctld' : canctldHelp,
  72.                                 'sim' : simHelp}
  73.  
  74.         self.cfg = DaemonConfig()
  75.    
  76.     class IfNotifier():
  77.         """ Used by if threads to send messages to the main program thread """
  78.         UNDEFINED = 0
  79.         TERMINATE = 1
  80.    
  81.         def notify(self, msg):
  82.             if msg == self.TERMINATE:
  83.                 print 'Main terminate notify'
  84.                 self.terminated = True
  85.             else:
  86.                 print 'UNDEFINED NOTIFY'
  87.        
  88.    
  89.     def __rightAdjust(self, refstr, str):
  90.         spcstr = ''
  91.         endpos = 20-len(refstr)
  92.         for i in range(1,endpos):
  93.             if i == endpos-5:
  94.                 spcstr += ':'
  95.             else:
  96.                 spcstr += ' '
  97.         return (spcstr+str)
  98.    
  99.     def helpCmd(self, *args):
  100.         args = args[0]
  101.         if len(args) < 1:
  102.             quitStr = 'quit, exit'
  103.             print quitStr, self.__rightAdjust(quitStr, 'shutdown pyCanDaemon')
  104.             for cmd in self.command_list:
  105.                 print cmd[0], self.__rightAdjust(cmd[0], cmd[2])
  106.         elif len(args) < 2:
  107.             subCmd = args[0]
  108.             if self.help_command_map.has_key(subCmd):
  109.                 print self.help_command_map[subCmd]
  110.             else:
  111.                 print 'no help for ' + subCmd
  112.         else:
  113.             print 'usage: help [topic]'
  114.  
  115.     def filterCmd(self, *args):
  116.         cmd = args[0]
  117.         filterName = args[1]
  118.         # FIXME: verify
  119.         if cmd == 'add':
  120.             print 'Importing filter: ' + filterName
  121.             self.cfg.filterCfg.importFilter(filterName)
  122.         elif cmd == 'rem' or cmd == 'remove':
  123.             print 'Deleting filter: ' + filterName
  124.             # FIXME: actually delete
  125.    
  126.     def stateCmd(self, *args):
  127.         cmd = args[0]
  128.         spaceName = args[1]
  129.         if cmd == 'add':
  130.             print 'Importing state space: ' + spaceName
  131.             self.cfg.stateSpaceCfg.importSpace(spaceName)
  132.         elif cmd == 'rem' or cmd == 'remove':
  133.             print 'Deleting state space: ' + spaceName
  134.             # FIXME: actually delete statespace
  135.    
  136.     def ifAddCmd(self, *args):
  137.         print 'not implemented'
  138.    
  139.     def ifRemCmd(self, *args):
  140.         print 'not implemented'
  141.  
  142.     def ifUpCmd(self, *args):
  143.         print 'not implemented'
  144.  
  145.     def ifDownCmd(self, *args):
  146.         print 'not implemented'
  147.         pass
  148.    
  149.     def addBridgeCmd(self, *args):
  150.         print 'not implemented'
  151.  
  152.     def remBridgeCmd(self, *args):
  153.         print 'not implemented'
  154.    
  155.     def tcpdCmd(self, *args):
  156.         print 'not implemented'
  157.    
  158.     def tlsdCmd(self, *args):
  159.         print 'not implemented'
  160.    
  161.     def canCtldCmd(self, *args):
  162.         print 'not implemented'
  163.    
  164.     def statusCmd(self, *args):
  165.         print 'not implemented'
  166.    
  167.     def statsCmd(self, *args):
  168.         print 'not implemented'
  169.    
  170.     def nodesCmd(self, *args):
  171.         print 'not implemented'
  172.    
  173.     def filterlistCmd(self, *args):
  174.         print 'not implemented'
  175.    
  176.     def simCmd(self, *args):
  177.         print 'not implemented'
  178.    
  179.     def logCmd(self, *args):
  180.         print 'not implemented'
  181.  
  182.     def execCmd(self, *args):
  183.         pass
  184.    
  185.     def exitHelper(self):
  186.         if self.nodeIf is not None and self.nodeIf.running():
  187.             self.nodeIf.stop()
  188.            
  189.     def exceptHelper(self, type, value, tb):
  190.         import traceback
  191.         traceback.print_exception(type, value, tb)
  192.         print '\nException in main program, shutting down threads'
  193.         self.terminated = True
  194.         self.exitHelper()
  195.  #       sys.exit(-1)
  196.  
  197.     def run(self):
  198.         try:
  199.             demoPath = os.path.dirname(__file__)
  200.             os.chdir(demoPath)
  201.         except:
  202.             return
  203.        
  204.         print 'INIT: Start logging'
  205.         log.basicConfig(level=log.DEBUG)
  206.        
  207.         print 'INIT: Get config options from command line / config file'
  208.         try:
  209.             opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
  210.         except getopt.GetoptError:
  211.             print 'Invalid usage'
  212.             usage()
  213.             sys.exit(2)
  214.      #   output = None
  215.      #   verbose = False
  216.         for o, a in opts:
  217.             if o == "-v":
  218.                 pass
  219.      #           verbose = True
  220.             if o in ("-h", "--help"):
  221.                 usage()
  222.                 sys.exit()
  223.             if o in ("-o", "--output"):
  224.                 pass
  225.     #            output = a
  226.  
  227.         print 'INIT: Loading filters and spaces'
  228. #       self.cfg.filterCfg.importFilter('DefaultFilter')
  229. #       self.cfg.stateSpaceCfg.importSpace('DefaultStateSpace')
  230.         self.cfg.stateSpaceCfg.loadSpaces()
  231.         self.cfg.filterCfg.loadFilters()
  232.         self.cfg.setupFilterBindings()
  233.         self.cfg.setupFilterChain()
  234.  
  235.         print 'INIT: Starting selected can interface'
  236.         ''' nodeif thread launch '''
  237.         self.ifNotifier = self.IfNotifier()
  238.         pktHandler = CanPktHandler1(self.cfg)
  239.        
  240.         ifConfig = NodeIfCanStim.DEFAULT_CONFIG
  241.         self.nodeIf = NodeIfCanStim(ifConfig, pktHandler, self.ifNotifier)
  242.  #       ifConfig = NodeIfSerial.DEFAULT_CONFIG
  243.    
  244.         atexit.register(self.exitHelper)
  245.         sys.excepthook = self.exceptHelper
  246.  #       self.nodeIf = NodeIfSerial(pktHandler, ifConfig)
  247.        
  248.         if not self.nodeIf.start():
  249.             print 'FATAL: Failed to initialize node interface.'
  250.             print 'This may indicate that the interface is unavailable, ' \
  251.                   'or that you do not have permission to access it.'
  252.             sys.exit(-1)
  253.  
  254.         print 'Initialize/gather info on connected can nodes and load associated state'
  255.         print 'Start selected TCP and UDP server(s)'
  256.         # server threads launch
  257.        
  258.         print 'CanDaemon v1 ready'
  259.         print 'Enter command or type \"help\" for a list of commands'
  260.         while not self.terminated:
  261.             input = raw_input('> ').strip().lower()
  262.             cmd = input.split(' ')
  263.             if len(cmd[0]) < 2:
  264.                 continue
  265.             if cmd[0] == 'quit' or cmd[0] == 'exit':
  266.                 self.terminated = True
  267.             elif self.command_map.has_key(cmd[0]):
  268.                 self.command_list[self.command_map[cmd[0]]][1](cmd[1:])
  269.             else:
  270.                 print 'unknown command: ' + cmd[0]
  271.  
  272.         """ -- suggested commands -- p n = priority to implement (1 is highest)
  273.            base: (p 1)
  274.            filter add <name>
  275.            filter rem <name>
  276.            state add <name>
  277.            state rem <name>
  278.            state reset <name>
  279.            
  280.                 node interfaces:  (p 1)
  281.            addif <serial/sim/udp/telnet> <options> (help protocol gives options)
  282.            remif <name> - delete an interface
  283.            ifup <name> - bring up an interface
  284.            ifdown <name> - bring down an interface
  285.            
  286.                 bridging: (p 2)
  287.            addbridge <name> <ifname1> <ifname2> <ifname3> ... - create if bridge
  288.            rembridge <name>
  289.            
  290.                 servers:
  291.            tcpd start [port] - raw tcp (telnet, compat) server, all pkts  (p 1)
  292.            tcpd stop
  293.            tlsd start [port] - tcp+tls server, all pkts  (p 2)
  294.            tlsd stop
  295.            canctld start [port] - pyCanGUI server (tcp/tls)  (p 2)
  296.            canctld stop
  297.            
  298.            info commands: (p 3)
  299.            status - shows active settings, interfaces, servers
  300.            stats - shows some traffic statistics
  301.            nodes - shows active nodes
  302.            filters - shows active filters
  303.            state [name] - shows active states, opt specific state info\
  304.            log - log control (TBD)
  305.            
  306.            simulator commands: (p 2)
  307.            simrecord <file> - record incoming packets
  308.            simplay <file> [timescale] - play recorded stream, opt accel time:
  309.            simadd <nodeid> (nodetype)
  310.            simrem <nodeid>
  311.            simsave <config>
  312.            simload <config>
  313.        """
  314.  
  315.         """ -- other features --
  316.            startup.cfg - script to run at startup (command listing)
  317.            ie: ifup 0
  318.                tlsd start
  319.                canguid start
  320.            config.cfg - last daemon config (param override)
  321.            default.cfg - default daemon config (only read if config.cfg does not exist)
  322.        """
  323.  
  324.         print 'Shutdown'
  325.         if self.nodeIf.running():
  326.             print 'Stopping If thread'
  327.             self.nodeIf.stop()
  328.  
  329.         self.cfg.stateSpaceCfg.saveSpaces()
  330.         self.cfg.filterCfg.saveFilters()
  331.        
  332.         print 'Waiting 0.1..'
  333.         time.sleep(0.1) # wait for threads
  334.         print 'Terminating'
  335.         sys.exit(0) # will except if there are threads remaining
  336.  
  337. #---------------------------------------------------------------------------
  338.  
  339. def main():
  340.     daemonApp = CanDaemon()
  341. #    install_thread_excepthook()
  342.     daemonApp.run()
  343.  
  344. #---------------------------------------------------------------------------
  345.  
  346. if __name__ == '__main__':
  347.     __name__ = 'Main'
  348.     main()
  349.