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