VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/serial/loopback.py

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: loopback.py 106061 2024-09-16 14:03:52Z vboxsync $
3
4"""
5VirtualBox Validation Kit - Serial loopback module.
6"""
7
8__copyright__ = \
9"""
10Copyright (C) 2018-2024 Oracle and/or its affiliates.
11
12This file is part of VirtualBox base platform packages, as
13available from https://www.virtualbox.org.
14
15This program is free software; you can redistribute it and/or
16modify it under the terms of the GNU General Public License
17as published by the Free Software Foundation, in version 3 of the
18License.
19
20This program is distributed in the hope that it will be useful, but
21WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with this program; if not, see <https://www.gnu.org/licenses>.
27
28The contents of this file may alternatively be used under the terms
29of the Common Development and Distribution License Version 1.0
30(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
31in the VirtualBox distribution, in which case the provisions of the
32CDDL are applicable instead of those of the GPL.
33
34You may elect to license modified versions of this file under the
35terms and conditions of either the GPL or the CDDL or both.
36
37SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
38"""
39__version__ = "$Revision: 106061 $"
40
41# Standard Python imports.
42#import os;
43import socket;
44import threading;
45
46
47g_ksLoopbackTcpServ = 'TcpServ';
48g_ksLoopbackTcpClient = 'TcpClient';
49g_ksLoopbackNamedPipeServ = 'NamedPipeServ';
50g_ksLoopbackNamedPipeClient = 'NamedPipeClient';
51
52class SerialLoopbackTcpServ(object):
53 """
54 Handler for a server TCP style connection.
55 """
56 def __init__(self, sLocation, iTimeout):
57 sHost, sPort = sLocation.split(':');
58 self.oConn = None;
59 self.oSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
60 self.oSock.settimeout(iTimeout);
61 self.oSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1);
62 self.oSock.bind((sHost, int(sPort)));
63 self.oSock.listen(1);
64 self.iTimeout = iTimeout;
65
66 def __del__(self):
67 if self.oConn is not None:
68 self.oConn.close();
69 if self.oSock is not None:
70 self.oSock.close();
71 self.oSock = None;
72
73 def shutdown(self):
74 if self.oConn is not None:
75 self.oConn.close();
76 self.oConn = None;
77 self.oSock.close();
78 self.oSock = None;
79
80 def pumpIo(self):
81 """
82 Main I/O pumping routine.
83 """
84 try:
85 if self.oConn is None:
86 oConn, _ = self.oSock.accept();
87 self.oConn = oConn;
88 else:
89 abData = self.oConn.recv(1024); # pylint: disable=no-member
90 if abData is not None:
91 self.oConn.send(abData); # pylint: disable=no-member
92 except:
93 pass;
94
95class SerialLoopbackTcpClient(object):
96 """
97 Handler for a client TCP style connection.
98 """
99 def __init__(self, sLocation, iTimeout):
100 sHost, sPort = sLocation.split(':');
101 self.oConn = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
102 self.oConn.connect((sHost, int(sPort)));
103 self.oConn.settimeout(iTimeout);
104 self.iTimeout = iTimeout;
105
106 def __del__(self):
107 if self.oConn is not None:
108 self.oConn.close();
109
110 def shutdown(self):
111 if self.oConn is not None:
112 self.oConn.close();
113 self.oConn = None;
114
115 def pumpIo(self):
116 """
117 Main I/O pumping routine.
118 """
119 try:
120 abData = self.oConn.recv(1024);
121 if abData is not None:
122 self.oConn.send(abData);
123 except:
124 pass;
125
126class SerialLoopbackNamedPipeServ(object):
127 """
128 Handler for a named pipe server style connection.
129 """
130 def __init__(self, sLocation, iTimeout):
131 self.oConn = None;
132 self.oSock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); # pylint: disable=no-member
133 self.oSock.settimeout(iTimeout);
134 self.oSock.bind(sLocation);
135 self.oSock.listen(1);
136 self.iTimeout = iTimeout;
137
138 def __del__(self):
139 if self.oConn is not None:
140 self.oConn.close();
141 if self.oSock is not None:
142 self.oSock.close();
143 self.oSock = None;
144
145 def shutdown(self):
146 if self.oConn is not None:
147 self.oConn.close();
148 self.oConn = None;
149 self.oSock.close();
150 self.oSock = None;
151
152 def pumpIo(self):
153 """
154 Main I/O pumping routine.
155 """
156 try:
157 if self.oConn is None:
158 oConn, _ = self.oSock.accept();
159 self.oConn = oConn;
160 else:
161 abData = self.oConn.recv(1024); # pylint: disable=no-member
162 if abData is not None:
163 self.oConn.send(abData); # pylint: disable=no-member
164 except:
165 pass;
166
167class SerialLoopbackNamedPipeClient(object):
168 """
169 Handler for a named pipe client style connection.
170 """
171 def __init__(self, sLocation, iTimeout):
172 self.oConn = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM); # pylint: disable=no-member
173 self.oConn.connect(sLocation);
174 self.oConn.settimeout(iTimeout);
175 self.iTimeout = iTimeout;
176
177 def __del__(self):
178 if self.oConn is not None:
179 self.oConn.close();
180
181 def shutdown(self):
182 if self.oConn is not None:
183 self.oConn.close();
184 self.oConn = None;
185
186 def pumpIo(self):
187 """
188 Main I/O pumping routine.
189 """
190 try:
191 abData = self.oConn.recv(1024);
192 if abData is not None:
193 self.oConn.send(abData);
194 except:
195 pass;
196
197class SerialLoopback(object):
198 """
199 Serial port loopback module working with TCP and named pipes.
200 """
201
202 def __init__(self, sType, sLocation):
203 self.fShutdown = False;
204 self.sType = sType;
205 self.sLocation = sLocation;
206 self.oLock = threading.Lock();
207 self.oThread = threading.Thread(target=self.threadWorker, args=(), name='SerLoopback');
208
209 if sType == g_ksLoopbackTcpServ:
210 self.oIoPumper = SerialLoopbackTcpServ(sLocation, 0.5);
211 self.oThread.start();
212 elif sType == g_ksLoopbackNamedPipeServ:
213 self.oIoPumper = SerialLoopbackNamedPipeServ(sLocation, 0.5); # pylint: disable=redefined-variable-type
214 self.oThread.start();
215
216 def connect(self):
217 """
218 Connects to the server for a client type version.
219 """
220 fRc = True;
221 try:
222 if self.sType == g_ksLoopbackTcpClient:
223 self.oIoPumper = SerialLoopbackTcpClient(self.sLocation, 0.5);
224 elif self.sType == g_ksLoopbackNamedPipeClient:
225 self.oIoPumper = SerialLoopbackNamedPipeClient(self.sLocation, 0.5); # pylint: disable=redefined-variable-type
226 except:
227 fRc = False;
228 else:
229 self.oThread.start();
230 return fRc;
231
232 def shutdown(self):
233 """
234 Shutdown any connection and wait for it to become idle.
235 """
236 with self.oLock:
237 self.fShutdown = True;
238 self.oIoPumper.shutdown();
239
240 def isShutdown(self):
241 """
242 Returns whether the I/O pumping thread should shut down.
243 """
244 with self.oLock:
245 fShutdown = self.fShutdown;
246
247 return fShutdown;
248
249 def threadWorker(self):
250 """
251 The threaded worker.
252 """
253 while not self.isShutdown():
254 self.oIoPumper.pumpIo();
255
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette