source: rtems-tools/tester/rt/tftp.py @ 4b76b8e

Last change on this file since 4b76b8e was 4b76b8e, checked in by Chris Johns <chrisj@…>, on Oct 11, 2017 at 11:49:17 AM

testing: Generate console message on a second TFTP exe request.

  • Property mode set to 100644
File size: 6.3 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2013-2017 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# 1. Redistributions of source code must retain the above copyright notice,
12# this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above copyright notice,
15# this list of conditions and the following disclaimer in the documentation
16# and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28# POSSIBILITY OF SUCH DAMAGE.
29#
30
31#
32# RTEMS Testing TFTP Interface
33#
34
35from __future__ import print_function
36
37import errno
38import logging
39import threading
40import time
41import sys
42
43from rtemstoolkit import error
44from rtemstoolkit import reraise
45
46#
47# Support to handle use in a package and as a unit test.
48# If there is a better way to let us know.
49#
50try:
51    from . import tftpy
52except (ValueError, SystemError):
53    import tftpy
54
55class tftp(object):
56    '''RTEMS Testing TFTP base.'''
57
58    def __init__(self, bsp_arch, bsp, trace = False):
59        self.trace = trace
60        self.lock_trace = False
61        self.lock = threading.RLock()
62        self.bsp = bsp
63        self.bsp_arch = bsp_arch
64        self._init()
65
66    def __del__(self):
67        self.kill()
68
69    def _init(self):
70        self.output_length = None
71        self.console = None
72        self.server = None
73        self.port = 0
74        self.exe = None
75        self.timeout = None
76        self.timer = None
77        self.running = False
78        self.finished = False
79        self.caught = None
80
81    def _lock(self, msg):
82        if self.lock_trace:
83            print('|[   LOCK:%s ]|' % (msg))
84        self.lock.acquire()
85
86    def _unlock(self, msg):
87        if self.lock_trace:
88            print('|] UNLOCK:%s [|' % (msg))
89        self.lock.release()
90
91    def _finished(self):
92        self.server = None
93        self.exe = None
94
95    def _stop(self):
96        try:
97            if self.server:
98                self.server.stop(now = True)
99        except:
100            pass
101
102    def _kill(self):
103        self._stop()
104        while self.running or not self.finished:
105            self._unlock('_kill')
106            time.sleep(0.1)
107            self._lock('_kill')
108
109    def _timeout(self):
110        self._stop()
111        if self.timeout is not None:
112            self.timeout()
113
114    def _exe_handle(self, req_file, raddress, rport):
115        self._lock('_exe_handle')
116        exe = self.exe
117        self.exe = None
118        self._unlock('_exe_handle')
119        if exe is not None:
120            if self.console:
121                self.console('tftp: %s' % (exe))
122            return open(exe, "rb")
123        if self.console:
124            self.console('tftp: re-requesting exe; target must have reset')
125        self._stop()
126        return None
127
128    def _listener(self):
129        tftpy.log.setLevel(100)
130        try:
131            self.server = tftpy.TftpServer(tftproot = '.',
132                                           dyn_file_func = self._exe_handle)
133        except tftpy.TftpException as te:
134            raise error.general('tftp: %s' % (str(te)))
135        if self.server is not None:
136            try:
137                self.server.listen('0.0.0.0', self.port, 0.5)
138            except tftpy.TftpException as te:
139                raise error.general('tftp: %s' % (str(te)))
140            except IOError as ie:
141                if ie.errno == errno.EACCES:
142                    raise error.general('tftp: permissions error: check tftp server port')
143                raise error.general('tftp: io error: %s' % (str(ie)))
144
145    def _runner(self):
146        self._lock('_runner')
147        self.running = True
148        self._unlock('_runner')
149        caught = None
150        try:
151            self._listener()
152        except:
153            caught = sys.exc_info()
154        self._lock('_runner')
155        self._init()
156        self.running = False
157        self.finished = True
158        self.caught = caught
159        self._unlock('_runner')
160
161    def open(self, executable, port, output_length, console, timeout):
162        self._lock('_open')
163        if self.exe is not None:
164            self._unlock('_open')
165            raise error.general('tftp: already running')
166        self._init()
167        self.output_length = output_length
168        self.console = console
169        self.port = port
170        self.exe = executable
171        self.timeout = timeout[1]
172        self.listener = threading.Thread(target = self._runner,
173                                         name = 'tftp-listener')
174        self.listener.start()
175        step = 0.5
176        period = timeout[0]
177        output_len = self.output_length()
178        while not self.finished and period > 0:
179            current_length = self.output_length()
180            if output_length != current_length:
181                period = timeout[0]
182            output_length = current_length
183            if period < step:
184                period = 0
185            else:
186                period -= step
187            self._unlock('_open')
188            time.sleep(step)
189            self._lock('_open')
190        if not self.finished and period == 0:
191            self._timeout()
192        caught = self.caught
193        self.caught = None
194        self._unlock('_open')
195        if caught is not None:
196            reraise.reraise(*caught)
197
198    def kill(self):
199        self._lock('kill')
200        self._kill()
201        self._unlock('kill')
202
203if __name__ == "__main__":
204    import sys
205    if len(sys.argv) > 1:
206        executable = sys.argv[1]
207    else:
208        executable = None
209    t = tftp('arm', 'beagleboneblack')
210    t.open(executable)
Note: See TracBrowser for help on using the repository browser.