1
2 '''
3 State Machine Engine
4
5 Will try and run a state machine.
6
7 @author: Michael Eddington
8 @version: $Id: state.py 1099 2008-07-29 05:40:17Z meddingt $
9 '''
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 import sys, re, types, time
39 import traceback
40
41 import Ft.Xml.Domlette
42 from Ft.Xml.Domlette import Print, PrettyPrint
43
44 from Peach.Engine.dom import *
45 from Peach.Engine.parser import *
46 from Peach.Engine.incoming import *
47 from Peach.Engine.common import *
48 import Peach
49
53
55 print "peachPrint: ", msg
56
58 '''
59 Runs a StateMachine instance.
60 '''
61
62 - def __init__(self, engine, stateMachine, publisher):
63 '''
64 engine - Engine
65 stateMachien - StateMachine to use
66 publisher - Publisher to use
67 '''
68
69 self.engine = engine
70 self.stateMachine = stateMachine
71 self.publisher = publisher
72 self.f = peachPrint
73
74 - def run(self, mutator):
112
114 '''
115 Locate a State object by name in the StateMachine.
116 '''
117
118 for child in self.stateMachine:
119 if child.elementType == 'state' and child.name == stateName:
120 return child
121
122
123
124
125 return None
126
128 '''
129 Runs a specific State from a StateMachine.
130 '''
131
132 Debug(1, "StateEngine._runState: %s" % state.name)
133
134
135
136
137 for action in state:
138 if not isinstance(action, Action):
139 continue
140
141 if action.template == None:
142 for c in action:
143 if c.elementType == 'actionparam' or c.elementType == 'actionresult':
144
145 if not hasattr(c, 'origionalTemplate'):
146 c.origionalTemplate = c.template
147
148
149 c.__delitem__(c.template.name)
150 c.template = c.origionalTemplate.copy(c)
151 c.append(c.template)
152
153 continue
154
155
156 if not hasattr(action, 'origionalTemplate'):
157 action.origionalTemplate = action.template
158
159
160 action.__delitem__(action.template.name)
161 action.template = action.origionalTemplate.copy(action)
162 action.append(action.template)
163
164
165
166 self.actionValues.append( [ state.name, 'state' ] )
167 mutator.onStateStart(state)
168
169
170 if state.onEnter != None:
171 environment = {
172 'Peach' : self.engine.peach,
173 'State' : state,
174 'StateModel' : state.parent,
175 'peachPrint' : self.f,
176 'Mutator' : mutator,
177 'sleep' : time.sleep
178 }
179
180 evalEvent(state.onEnter, environment)
181
182 try:
183
184 try:
185
186 for action in state:
187 if action.elementType != 'action':
188 continue
189
190 self._runAction(action, mutator)
191
192 except SoftException:
193
194 pass
195
196
197 if state.onExit != None:
198 environment = {
199 'Peach' : self.engine.peach,
200 'State' : state,
201 'StateModel' : state.parent,
202 'peachPrint' : self.f,
203 'Mutator' : mutator,
204 'sleep' : time.sleep
205 }
206
207 evalEvent(state.onExit, environment)
208
209 mutator.onStateComplete(state)
210
211 except StateChangeStateException, e:
212
213
214 if state.onExit != None:
215 environment = {
216 'Peach' : self.engine.peach,
217 'State' : state,
218 'StateModel' : state.parent,
219 'peachPrint' : self.f,
220 'Mutator' : mutator,
221 'sleep' : time.sleep
222 }
223
224 evalEvent(state.onExit, environment)
225
226 mutator.onStateComplete(state)
227
228 self._runState(e.state, mutator)
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
249
250 Debug(1, "StateEngine._runAction: %s" % action.name)
251
252 mutator.onActionStart(action)
253
254
255 if action.when != None:
256 environment = {
257 'Peach' : self.engine.peach,
258 'Action' : action,
259 'State' : action.parent,
260 'StateModel' : action.parent.parent,
261 'Mutator' : mutator,
262 'peachPrint' : self.f,
263 'sleep' : time.sleep
264 }
265
266
267
268
269
270 if not evalEvent(action.when, environment):
271 return
272
273
274 if action.onStart != None:
275 environment = {
276 'Peach' : self.engine.peach,
277 'Action' : action,
278 'State' : action.parent,
279 'StateModel' : action.parent.parent,
280 'Mutator' : mutator,
281 'peachPrint' : self.f,
282 'sleep' : time.sleep
283 }
284
285 evalEvent(action.onStart, environment)
286
287 if action.type == 'input':
288 action.value = None
289
290 if self.publisher.hasBeenStarted == False:
291 self.publisher.start()
292 self.publisher.hasBeenStarted = True
293 if not self.publisher.hasBeenConnected:
294 self.publisher.connect()
295 self.publisher.hasBeenConnected = True
296
297
298 cracker = DataCracker(self.engine.peach)
299 size = cracker.getInitialReadSize(action.template)
300 Debug(1, "StateEngine._runAction(input): Found initial read size of %s" % size)
301
302 data = ""
303 timeout = False
304 haveAllData = False
305
306 while True:
307 try:
308 Debug(2, ">> STATE IS CALLING RECEIVE FOR %d BYTES" % size)
309
310
311 if size == -1:
312 try:
313
314 haveAllData = True
315 data += self.publisher.receive()
316
317 except Peach.publisher.Timeout, e:
318
319 pass
320
321
322 else:
323 try:
324 data += self.publisher.receive(size)
325 timeout = False
326
327 except Peach.publisher.Timeout, e:
328
329
330 if timeout:
331 raise
332
333 timeout = True
334 haveAllData = True
335
336
337 action.__delitem__(action.template.name)
338 action.template = action.origionalTemplate.copy(action)
339 action.append(action.template)
340
341
342 Debug(1, "\n\n\n\n### cracker.crackData(%d) ##############################################" % len(data))
343 if haveAllData:
344 Debug(1, "### HAVE ALL DATA!!!!!! ##############################################")
345
346 cracker = DataCracker(self.engine.peach)
347 cracker.haveAllData = haveAllData
348 (rating, pos) = cracker.crackData(action.template, data)
349 if rating > 2:
350 raise SoftException("Was unble to crack incoming data into %s data model." % action.template.name)
351
352
353 break
354
355 except NeedMoreData, e:
356 size = e.amount
357 Debug(2, ">> Going back for: %d" % size)
358 Debug(2, ">> Tab Level: %d" % DataCracker._tabLevel)
359 if DataCracker._tabLevel > 0:
360 size = 0
361
362
363
364
365
366
367 action.value = action.template.getValue()
368
369
370
371
372
373 if Peach.Engine.engine.Engine.debug:
374 dict = {}
375 doc = Ft.Xml.Domlette.NonvalidatingReader.parseString("<Peach/>")
376
377 stateMachine = action.parent.parent
378 stateMachineNode = stateMachine.toXmlDom(doc.rootNode.firstChild, dict)
379
380 print "*****POST INPUT*************"
381 PrettyPrint(doc, asHtml=1)
382 print "******************"
383
384 elif action.type == 'output':
385
386 if not self.publisher.hasBeenStarted:
387 self.publisher.start()
388 self.publisher.hasBeenStarted = True
389 if not self.publisher.hasBeenConnected:
390 self.publisher.connect()
391 self.publisher.hasBeenConnected = True
392
393 action.value = mutator.getActionValue(action)
394
395 Debug(1, "Actiong output sending %d bytes" % len(action.value))
396 self.publisher.send(action.value)
397 self.actionValues.append( [ action.name, 'output', action.value ] )
398
399 obj = Element(action.name, None)
400 obj.elementType = 'dom'
401 obj.defaultValue = action.value
402 action.value = obj
403
404 elif action.type == 'call':
405 action.value = None
406
407 actionParams = []
408
409 if not self.publisher.hasBeenStarted:
410 self.publisher.start()
411 self.publisher.hasBeenStarted = True
412
413
414 method = action.method
415 if method == None:
416 raise PeachException("StateEngine: Action of type \"call\" does not have method name!")
417
418 params = []
419 for c in action:
420 if c.elementType == 'actionparam':
421 params.append(c)
422
423 argValues = []
424 for p in params:
425 if p.type == 'out' or p.type == 'inout':
426 raise PeachException("StateEngine: Action of type \"call\" does not yet support out or inout parameters (bug in comtypes)!")
427
428 p.value = mutator.getActionParamValue(p)
429 argValues.append(p.value)
430
431 actionParams.append([p.name, 'param', p.value])
432
433 ret = self.publisher.call(method, argValues)
434
435
436 for c in action:
437 if c.elementType == 'actionresult':
438 cracker = DataCracker(self.engine.peach)
439 cracker.haveAllData = True
440 (rating, pos) = cracker.crackData(action.template, ret)
441 if rating > 2:
442 raise SoftException("Was unble to crack result data into %s data model." % action.template.name)
443
444 self.actionValues.append( [ action.name, 'call', method, actionParams ] )
445
446 elif action.type == 'getprop':
447 action.value = None
448
449 if not self.publisher.hasBeenStarted:
450 self.publisher.start()
451 self.publisher.hasBeenStarted = True
452
453
454 property = action.property
455 if property == None:
456 raise Exception("StateEngine._runAction(): getprop type does not have property name!")
457
458 data = self.publisher.property(property)
459
460 self.actionValues.append( [ action.name, 'getprop', property, data ] )
461
462 cracker = DataCracker(self.engine.peach)
463 cracker.haveAllData = True
464 (rating, pos) = cracker.crackData(action.template, data)
465 if rating > 2:
466 raise SoftException("Was unble to crack getprop data into %s data model." % action.template.name)
467
468
469
470 action.value = action.template.getValue()
471
472 if Peach.Engine.engine.Engine.debug:
473
474 dict = {}
475 doc = Ft.Xml.Domlette.NonvalidatingReader.parseString("<Peach/>")
476
477 stateMachine = action.parent.parent
478 stateMachineNode = stateMachine.toXmlDom(doc.rootNode.firstChild, dict)
479
480 print "*******POST GETPROP***********"
481 PrettyPrint(doc, asHtml=1)
482 print "******************"
483
484 elif action.type == 'setprop':
485 action.value = None
486
487 if not self.publisher.hasBeenStarted:
488 self.publisher.start()
489 self.publisher.hasBeenStarted = True
490
491
492 property = action.property
493 if property == None:
494 raise Exception("StateEngine: setprop type does not have property name!")
495
496 value = None
497 for c in action:
498 if c.elementType == 'actionparam' and c.type == "in":
499 value = c.value = mutator.getActionParamValue(c)
500 break
501
502 self.publisher.property(property, value)
503 self.actionValues.append( [ action.name, 'setprop', property, value ] )
504
505 elif action.type == 'changeState':
506 action.value = None
507 mutator.onActionComplete(action)
508 raise StateChangeStateException(self._getStateByName(action.ref))
509
510 self.actionValues.append( [ action.name, 'changeState', action.ref ] )
511
512 elif action.type == 'slurp':
513 action.value = None
514
515 dict = {}
516 doc = Ft.Xml.Domlette.NonvalidatingReader.parseString("<Peach/>")
517
518 stateMachine = action.parent.parent
519 stateMachineNode = stateMachine.toXmlDom(doc.rootNode.firstChild, dict)
520
521 if Peach.Engine.engine.Engine.debug:
522 print "****** PRE SLURP ************"
523 PrettyPrint(doc, asHtml=1)
524 print "******************"
525
526 setNodes = doc.xpath(action.setXpath)
527 if len(setNodes) == 0:
528 raise Exception("StateEngine._runAction(xpath): setXpath did not return a node")
529
530 for node in setNodes:
531
532 if action.valueXpath != None:
533 valueNodes = doc.xpath(action.valueXpath)
534 if len(valueNodes) == 0:
535 raise Exception("StateEngine._runAction(xpath): valueXpath did not return a node")
536
537 valueNode = valueNodes[0]
538
539 if valueNode.hasAttributeNS(None, "currentValue"):
540 Debug(1, "Setting currentValue: [%s]" % str(valueNode.getAttributeNS(None, 'currentValue')))
541 node.setAttributeNS(None, 'currentValue', valueNode.getAttributeNS(None, 'currentValue'))
542
543 if valueNode.hasAttributeNS(None, 'currentValue-Encoded'):
544 node.setAttributeNS(None, 'currentValue-Encoded',
545 valueNode.getAttributeNS(None, 'currentValue-Encoded'))
546
547 elif valueNode.hasAttributeNS(None, 'value'):
548 Debug(1, "Setting value: [%s]" % str(valueNode.getAttributeNS(None, 'value')))
549 node.setAttributeNS(None, 'currentValue', valueNode.getAttributeNS(None, 'value'))
550
551 if valueNode.hasAttributeNS(None, 'value-Encoded'):
552 node.setAttributeNS(None, 'currentValue-Encoded',
553 valueNode.getAttributeNS(None, 'value-Encoded'))
554
555 else:
556 Debug(1, "Setting currentValue: [%s]" % str(action.valueLiteral))
557 try:
558 node.setAttributeNS(None, 'currentValue', action.valueLiteral)
559
560 except UnicodeDecodeError:
561 node.setAttributeNS(None, "currentValue-Encoded", "base64")
562 node.setAttributeNS(None, 'currentValue', base64.b64encode(action.valueLiteral))
563
564
565 if Peach.Engine.engine.Engine.debug:
566 print "****** POST SLURP ************"
567 PrettyPrint(doc, asHtml=1)
568 print "******************"
569
570 stateMachine.updateFromXmlDom(stateMachineNode, dict)
571 dict = None
572
573 elif action.type == 'connect':
574 if not self.publisher.hasBeenStarted:
575 self.publisher.start()
576 self.publisher.hasBeenStarted = True
577
578 self.publisher.connect()
579 self.publisher.hasBeenConnected = True
580
581 elif action.type == 'accept':
582 if not self.publisher.hasBeenStarted:
583 self.publisher.start()
584 self.publisher.hasBeenStarted = True
585
586 self.publisher.accept()
587 self.publisher.hasBeenConnected = True
588
589 elif action.type == 'close':
590 if not self.publisher.hasBeenConnected:
591
592
593 return
594
595 self.publisher.close()
596 self.publisher.hasBeenConnected = False
597
598 elif action.type == 'start':
599 self.publisher.start()
600 self.publisher.hasBeenStarted = True
601
602 elif action.type == 'stop':
603 if self.publisher.hasBeenStarted:
604 self.publisher.stop()
605 self.publisher.hasBeenStarted = False
606
607 elif action.type == 'wait':
608 time.sleep(float(action.valueLiteral))
609
610 else:
611 raise Exception("StateEngine._runAction(): Unknown action.type of [%s]" % str(action.type))
612
613
614 if action.onComplete != None:
615 environment = {
616 'Peach' : self.engine.peach,
617 'Action' : action,
618 'State' : action.parent,
619 'Mutator' : mutator,
620 'StateModel' : action.parent.parent,
621 'sleep' : time.sleep
622 }
623
624 evalEvent(action.onComplete, environment)
625
626 mutator.onActionComplete(action)
627
629 '''
630 Reset XML node tree starting at 'node'. We will remove
631 any attribute calleed:
632
633 value
634 currentValue
635 defaultValue
636 value-Encoded
637 currentValue-Encoded
638 defaultValue-Encoded
639
640 '''
641
642 att = ['value', 'currentValue', 'defaultValue',
643 'value-Encoded', 'currentValue-Encoded', 'defaultValue-Encoded']
644
645 for a in att:
646 if node.hasAttributeNS(None, a):
647 node.removeAttributeNS(None, a)
648
649 for child in node.childNodes:
650 self._resetXmlNodes(child)
651
655
657 return "Exception: StateChangeStateException"
658
665
666
667