source: rtems-tools/tester/rt/tftp.py @ 3ed65c0

5
Last change on this file since 3ed65c0 was 3ed65c0, checked in by Chris Johns <chrisj@…>, on 09/21/17 at 11:33:56

Lower the step size for the TFTP timeout.

  • Property mode set to 100644
File size: 6.2 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        self._stop()
124        return None
125
126    def _listener(self):
127        tftpy.log.setLevel(100)
128        try:
129            self.server = tftpy.TftpServer(tftproot = '.',
130                                           dyn_file_func = self._exe_handle)
131        except tftpy.TftpException as te:
132            raise error.general('tftp: %s' % (str(te)))
133        if self.server is not None:
134            try:
135                self.server.listen('0.0.0.0', self.port, 0.5)
136            except tftpy.TftpException as te:
137                raise error.general('tftp: %s' % (str(te)))
138            except IOError as ie:
139                if ie.errno == errno.EACCES:
140                    raise error.general('tftp: permissions error: check tftp server port')
141                raise error.general('tftp: io error: %s' % (str(ie)))
142
143    def _runner(self):
144        self._lock('_runner')
145        self.running = True
146        self._unlock('_runner')
147        caught = None
148        try:
149            self._listener()
150        except:
151            caught = sys.exc_info()
152        self._lock('_runner')
153        self._init()
154        self.running = False
155        self.finished = True
156        self.caught = caught
157        self._unlock('_runner')
158
159    def open(self, executable, port, output_length, console, timeout):
160        self._lock('_open')
161        if self.exe is not None:
162            self._unlock('_open')
163            raise error.general('tftp: already running')
164        self._init()
165        self.output_length = output_length
166        self.console = console
167        self.port = port
168        self.exe = executable
169        self.timeout = timeout[1]
170        self.listener = threading.Thread(target = self._runner,
171                                         name = 'tftp-listener')
172        self.listener.start()
173        step = 0.5
174        period = timeout[0]
175        output_len = self.output_length()
176        while not self.finished and period > 0:
177            current_length = self.output_length()
178            if output_length != current_length:
179                period = timeout[0]
180            output_length = current_length
181            if period < step:
182                period = 0
183            else:
184                period -= step
185            self._unlock('_open')
186            time.sleep(step)
187            self._lock('_open')
188        if not self.finished and period == 0:
189            self._timeout()
190        caught = self.caught
191        self.caught = None
192        self._unlock('_open')
193        if caught is not None:
194            reraise.reraise(*caught)
195
196    def kill(self):
197        self._lock('kill')
198        self._kill()
199        self._unlock('kill')
200
201if __name__ == "__main__":
202    import sys
203    if len(sys.argv) > 1:
204        executable = sys.argv[1]
205    else:
206        executable = None
207    t = tftp('arm', 'beagleboneblack')
208    t.open(executable)
Note: See TracBrowser for help on using the repository browser.