VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/usb/usbgadget.py@ 60686

Last change on this file since 60686 was 60571, checked in by vboxsync, 9 years ago

ValidationKit/usb: pylint fixes (unknown option for older pylint on the build boxes)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.7 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: usbgadget.py 60571 2016-04-19 12:00:51Z vboxsync $
3# pylint: disable=C0302
4
5"""
6UTS (USB Test Service) client.
7"""
8__copyright__ = \
9"""
10Copyright (C) 2010-2016 Oracle Corporation
11
12This file is part of VirtualBox Open Source Edition (OSE), as
13available from http://www.virtualbox.org. This file is free software;
14you can redistribute it and/or modify it under the terms of the GNU
15General Public License (GPL) as published by the Free Software
16Foundation, in version 2 as it comes in the "COPYING" file of the
17VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19
20The contents of this file may alternatively be used under the terms
21of the Common Development and Distribution License Version 1.0
22(CDDL) only, as it comes in the "COPYING.CDDL" file of the
23VirtualBox OSE distribution, in which case the provisions of the
24CDDL are applicable instead of those of the GPL.
25
26You may elect to license modified versions of this file under the
27terms and conditions of either the GPL or the CDDL or both.
28"""
29__version__ = "$Revision: 60571 $"
30
31# Standard Python imports.
32import array
33import errno
34import select
35import socket
36import threading
37import time
38import types
39import zlib
40
41# Validation Kit imports.
42from common import utils;
43from testdriver import base;
44from testdriver import reporter;
45from testdriver.base import TdTaskBase;
46
47## @name USB gadget impersonation string constants.
48## @{
49g_ksGadgetImpersonationInvalid = 'Invalid';
50g_ksGadgetImpersonationTest = 'Test';
51g_ksGadgetImpersonationMsd = 'Msd';
52g_ksGadgetImpersonationWebcam = 'Webcam';
53g_ksGadgetImpersonationEther = 'Ether';
54## @}
55
56## @name USB gadget type used in the UTS protocol.
57## @{
58g_kiGadgetTypeTest = 1;
59## @}
60
61## @name USB gadget access methods used in the UTS protocol.
62## @{
63g_kiGadgetAccessUsbIp = 1;
64## @}
65
66#
67# Helpers for decoding data received from the UTS.
68# These are used both the Session and Transport classes.
69#
70
71def getU64(abData, off):
72 """Get a U64 field."""
73 return abData[off] \
74 + abData[off + 1] * 256 \
75 + abData[off + 2] * 65536 \
76 + abData[off + 3] * 16777216 \
77 + abData[off + 4] * 4294967296 \
78 + abData[off + 5] * 1099511627776 \
79 + abData[off + 6] * 281474976710656 \
80 + abData[off + 7] * 72057594037927936;
81
82def getU32(abData, off):
83 """Get a U32 field."""
84 return abData[off] \
85 + abData[off + 1] * 256 \
86 + abData[off + 2] * 65536 \
87 + abData[off + 3] * 16777216;
88
89def getU16(abData, off):
90 """Get a U16 field."""
91 return abData[off] \
92 + abData[off + 1] * 256;
93
94def getU8(abData, off):
95 """Get a U8 field."""
96 return abData[off];
97
98def getSZ(abData, off, sDefault = None):
99 """
100 Get a zero-terminated string field.
101 Returns sDefault if the string is invalid.
102 """
103 cchStr = getSZLen(abData, off);
104 if cchStr >= 0:
105 abStr = abData[off:(off + cchStr)];
106 try:
107 return abStr.tostring().decode('utf_8');
108 except:
109 reporter.errorXcpt('getSZ(,%u)' % (off));
110 return sDefault;
111
112def getSZLen(abData, off):
113 """
114 Get the length of a zero-terminated string field, in bytes.
115 Returns -1 if off is beyond the data packet or not properly terminated.
116 """
117 cbData = len(abData);
118 if off >= cbData:
119 return -1;
120
121 offCur = off;
122 while abData[offCur] != 0:
123 offCur = offCur + 1;
124 if offCur >= cbData:
125 return -1;
126
127 return offCur - off;
128
129def isValidOpcodeEncoding(sOpcode):
130 """
131 Checks if the specified opcode is valid or not.
132 Returns True on success.
133 Returns False if it is invalid, details in the log.
134 """
135 sSet1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
136 sSet2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_ ";
137 if len(sOpcode) != 8:
138 reporter.error("invalid opcode length: %s" % (len(sOpcode)));
139 return False;
140 for i in range(0, 1):
141 if sSet1.find(sOpcode[i]) < 0:
142 reporter.error("invalid opcode char #%u: %s" % (i, sOpcode));
143 return False;
144 for i in range(2, 7):
145 if sSet2.find(sOpcode[i]) < 0:
146 reporter.error("invalid opcode char #%u: %s" % (i, sOpcode));
147 return False;
148 return True;
149
150#
151# Helper for encoding data sent to the UTS.
152#
153
154def u32ToByteArray(u32):
155 """Encodes the u32 value as a little endian byte (B) array."""
156 return array.array('B', \
157 ( u32 % 256, \
158 (u32 / 256) % 256, \
159 (u32 / 65536) % 256, \
160 (u32 / 16777216) % 256) );
161
162def u16ToByteArray(u16):
163 """Encodes the u16 value as a little endian byte (B) array."""
164 return array.array('B', \
165 ( u16 % 256, \
166 (u16 / 256) % 256) );
167
168def u8ToByteArray(uint8):
169 """Encodes the u8 value as a little endian byte (B) array."""
170 return array.array('B', (uint8 % 256));
171
172def zeroByteArray(cb):
173 """Returns an array with the given size containing 0."""
174 abArray = array.array('B', (0, ));
175 cb = cb - 1;
176 for i in range(cb): # pylint: disable=W0612
177 abArray.append(0);
178 return abArray;
179
180class TransportBase(object):
181 """
182 Base class for the transport layer.
183 """
184
185 def __init__(self, sCaller):
186 self.sDbgCreated = '%s: %s' % (utils.getTimePrefix(), sCaller);
187 self.fDummy = 0;
188 self.abReadAheadHdr = array.array('B');
189
190 def toString(self):
191 """
192 Stringify the instance for logging and debugging.
193 """
194 return '<%s: abReadAheadHdr=%s, sDbgCreated=%s>' % (type(self).__name__, self.abReadAheadHdr, self.sDbgCreated);
195
196 def __str__(self):
197 return self.toString();
198
199 def cancelConnect(self):
200 """
201 Cancels any pending connect() call.
202 Returns None;
203 """
204 return None;
205
206 def connect(self, cMsTimeout):
207 """
208 Quietly attempts to connect to the UTS.
209
210 Returns True on success.
211 Returns False on retryable errors (no logging).
212 Returns None on fatal errors with details in the log.
213
214 Override this method, don't call super.
215 """
216 _ = cMsTimeout;
217 return False;
218
219 def disconnect(self, fQuiet = False):
220 """
221 Disconnect from the UTS.
222
223 Returns True.
224
225 Override this method, don't call super.
226 """
227 _ = fQuiet;
228 return True;
229
230 def sendBytes(self, abBuf, cMsTimeout):
231 """
232 Sends the bytes in the buffer abBuf to the UTS.
233
234 Returns True on success.
235 Returns False on failure and error details in the log.
236
237 Override this method, don't call super.
238
239 Remarks: len(abBuf) is always a multiple of 16.
240 """
241 _ = abBuf; _ = cMsTimeout;
242 return False;
243
244 def recvBytes(self, cb, cMsTimeout, fNoDataOk):
245 """
246 Receive cb number of bytes from the UTS.
247
248 Returns the bytes (array('B')) on success.
249 Returns None on failure and error details in the log.
250
251 Override this method, don't call super.
252
253 Remarks: cb is always a multiple of 16.
254 """
255 _ = cb; _ = cMsTimeout; _ = fNoDataOk;
256 return False;
257
258 def isConnectionOk(self):
259 """
260 Checks if the connection is OK.
261
262 Returns True if it is.
263 Returns False if it isn't (caller should call diconnect).
264
265 Override this method, don't call super.
266 """
267 return True;
268
269 def isRecvPending(self, cMsTimeout = 0):
270 """
271 Checks if there is incoming bytes, optionally waiting cMsTimeout
272 milliseconds for something to arrive.
273
274 Returns True if there is, False if there isn't.
275
276 Override this method, don't call super.
277 """
278 _ = cMsTimeout;
279 return False;
280
281 def sendMsgInt(self, sOpcode, cMsTimeout, abPayload = array.array('B')):
282 """
283 Sends a message (opcode + encoded payload).
284
285 Returns True on success.
286 Returns False on failure and error details in the log.
287 """
288 # Fix + check the opcode.
289 if len(sOpcode) < 2:
290 reporter.fatal('sendMsgInt: invalid opcode length: %d (\"%s\")' % (len(sOpcode), sOpcode));
291 return False;
292 sOpcode = sOpcode.ljust(8);
293 if not isValidOpcodeEncoding(sOpcode):
294 reporter.fatal('sendMsgInt: invalid opcode encoding: \"%s\"' % (sOpcode));
295 return False;
296
297 # Start construct the message.
298 cbMsg = 16 + len(abPayload);
299 abMsg = array.array('B');
300 abMsg.extend(u32ToByteArray(cbMsg));
301 abMsg.extend((0, 0, 0, 0)); # uCrc32
302 try:
303 abMsg.extend(array.array('B', \
304 ( ord(sOpcode[0]), \
305 ord(sOpcode[1]), \
306 ord(sOpcode[2]), \
307 ord(sOpcode[3]), \
308 ord(sOpcode[4]), \
309 ord(sOpcode[5]), \
310 ord(sOpcode[6]), \
311 ord(sOpcode[7]) ) ) );
312 if len(abPayload) > 0:
313 abMsg.extend(abPayload);
314 except:
315 reporter.fatalXcpt('sendMsgInt: packing problem...');
316 return False;
317
318 # checksum it, padd it and send it off.
319 uCrc32 = zlib.crc32(abMsg[8:]);
320 abMsg[4:8] = u32ToByteArray(uCrc32);
321
322 while len(abMsg) % 16:
323 abMsg.append(0);
324
325 reporter.log2('sendMsgInt: op=%s len=%d to=%d' % (sOpcode, len(abMsg), cMsTimeout));
326 return self.sendBytes(abMsg, cMsTimeout);
327
328 def recvMsg(self, cMsTimeout, fNoDataOk = False):
329 """
330 Receives a message from the UTS.
331
332 Returns the message three-tuple: length, opcode, payload.
333 Returns (None, None, None) on failure and error details in the log.
334 """
335
336 # Read the header.
337 if len(self.abReadAheadHdr) > 0:
338 assert(len(self.abReadAheadHdr) == 16);
339 abHdr = self.abReadAheadHdr;
340 self.abReadAheadHdr = array.array('B');
341 else:
342 abHdr = self.recvBytes(16, cMsTimeout, fNoDataOk);
343 if abHdr is None:
344 return (None, None, None);
345 if len(abHdr) != 16:
346 reporter.fatal('recvBytes(16) returns %d bytes!' % (len(abHdr)));
347 return (None, None, None);
348
349 # Unpack and validate the header.
350 cbMsg = getU32(abHdr, 0);
351 uCrc32 = getU32(abHdr, 4);
352 sOpcode = abHdr[8:16].tostring().decode('ascii');
353
354 if cbMsg < 16:
355 reporter.fatal('recvMsg: message length is out of range: %s (min 16 bytes)' % (cbMsg));
356 return (None, None, None);
357 if cbMsg > 1024*1024:
358 reporter.fatal('recvMsg: message length is out of range: %s (max 1MB)' % (cbMsg));
359 return (None, None, None);
360 if not isValidOpcodeEncoding(sOpcode):
361 reporter.fatal('recvMsg: invalid opcode \"%s\"' % (sOpcode));
362 return (None, None, None);
363
364 # Get the payload (if any), dropping the padding.
365 abPayload = array.array('B');
366 if cbMsg > 16:
367 if cbMsg % 16:
368 cbPadding = 16 - (cbMsg % 16);
369 else:
370 cbPadding = 0;
371 abPayload = self.recvBytes(cbMsg - 16 + cbPadding, cMsTimeout, False);
372 if abPayload is None:
373 self.abReadAheadHdr = abHdr;
374 if not fNoDataOk :
375 reporter.log('recvMsg: failed to recv payload bytes!');
376 return (None, None, None);
377
378 while cbPadding > 0:
379 abPayload.pop();
380 cbPadding = cbPadding - 1;
381
382 # Check the CRC-32.
383 if uCrc32 != 0:
384 uActualCrc32 = zlib.crc32(abHdr[8:]);
385 if cbMsg > 16:
386 uActualCrc32 = zlib.crc32(abPayload, uActualCrc32);
387 uActualCrc32 = uActualCrc32 & 0xffffffff;
388 if uCrc32 != uActualCrc32:
389 reporter.fatal('recvMsg: crc error: expected %s, got %s' % (hex(uCrc32), hex(uActualCrc32)));
390 return (None, None, None);
391
392 reporter.log2('recvMsg: op=%s len=%d' % (sOpcode, len(abPayload)));
393 return (cbMsg, sOpcode, abPayload);
394
395 def sendMsg(self, sOpcode, cMsTimeout, aoPayload = ()):
396 """
397 Sends a message (opcode + payload tuple).
398
399 Returns True on success.
400 Returns False on failure and error details in the log.
401 Returns None if you pass the incorrectly typed parameters.
402 """
403 # Encode the payload.
404 abPayload = array.array('B');
405 for o in aoPayload:
406 try:
407 if isinstance(o, basestring):
408 # the primitive approach...
409 sUtf8 = o.encode('utf_8');
410 for i in range(0, len(sUtf8)):
411 abPayload.append(ord(sUtf8[i]))
412 abPayload.append(0);
413 elif isinstance(o, types.LongType):
414 if o < 0 or o > 0xffffffff:
415 reporter.fatal('sendMsg: uint32_t payload is out of range: %s' % (hex(o)));
416 return None;
417 abPayload.extend(u32ToByteArray(o));
418 elif isinstance(o, types.IntType):
419 if o < 0 or o > 0xffffffff:
420 reporter.fatal('sendMsg: uint32_t payload is out of range: %s' % (hex(o)));
421 return None;
422 abPayload.extend(u32ToByteArray(o));
423 elif isinstance(o, array.array):
424 abPayload.extend(o);
425 else:
426 reporter.fatal('sendMsg: unexpected payload type: %s (%s) (aoPayload=%s)' % (type(o), o, aoPayload));
427 return None;
428 except:
429 reporter.fatalXcpt('sendMsg: screwed up the encoding code...');
430 return None;
431 return self.sendMsgInt(sOpcode, cMsTimeout, abPayload);
432
433
434class Session(TdTaskBase):
435 """
436 A USB Test Service (UTS) client session.
437 """
438
439 def __init__(self, oTransport, cMsTimeout, cMsIdleFudge, fTryConnect = False):
440 """
441 Construct a UTS session.
442
443 This starts by connecting to the UTS and will enter the signalled state
444 when connected or the timeout has been reached.
445 """
446 TdTaskBase.__init__(self, utils.getCallerName());
447 self.oTransport = oTransport;
448 self.sStatus = "";
449 self.cMsTimeout = 0;
450 self.fErr = True; # Whether to report errors as error.
451 self.msStart = 0;
452 self.oThread = None;
453 self.fnTask = self.taskDummy;
454 self.aTaskArgs = None;
455 self.oTaskRc = None;
456 self.t3oReply = (None, None, None);
457 self.fScrewedUpMsgState = False;
458 self.fTryConnect = fTryConnect;
459
460 if not self.startTask(cMsTimeout, False, "connecting", self.taskConnect, (cMsIdleFudge,)):
461 raise base.GenError("startTask failed");
462
463 def __del__(self):
464 """Make sure to cancel the task when deleted."""
465 self.cancelTask();
466
467 def toString(self):
468 return '<%s fnTask=%s, aTaskArgs=%s, sStatus=%s, oTaskRc=%s, cMsTimeout=%s,' \
469 ' msStart=%s, fTryConnect=%s, fErr=%s, fScrewedUpMsgState=%s, t3oReply=%s oTransport=%s, oThread=%s>' \
470 % (TdTaskBase.toString(self), self.fnTask, self.aTaskArgs, self.sStatus, self.oTaskRc, self.cMsTimeout,
471 self.msStart, self.fTryConnect, self.fErr, self.fScrewedUpMsgState, self.t3oReply, self.oTransport, self.oThread);
472
473 def taskDummy(self):
474 """Place holder to catch broken state handling."""
475 raise Exception();
476
477 def startTask(self, cMsTimeout, fIgnoreErrors, sStatus, fnTask, aArgs = ()):
478 """
479 Kicks of a new task.
480
481 cMsTimeout: The task timeout in milliseconds. Values less than
482 500 ms will be adjusted to 500 ms. This means it is
483 OK to use negative value.
484 sStatus: The task status.
485 fnTask: The method that'll execute the task.
486 aArgs: Arguments to pass to fnTask.
487
488 Returns True on success, False + error in log on failure.
489 """
490 if not self.cancelTask():
491 reporter.maybeErr(not fIgnoreErrors, 'utsclient.Session.startTask: failed to cancel previous task.');
492 return False;
493
494 # Change status and make sure we're the
495 self.lockTask();
496 if self.sStatus != "":
497 self.unlockTask();
498 reporter.maybeErr(not fIgnoreErrors, 'utsclient.Session.startTask: race.');
499 return False;
500 self.sStatus = "setup";
501 self.oTaskRc = None;
502 self.t3oReply = (None, None, None);
503 self.resetTaskLocked();
504 self.unlockTask();
505
506 self.cMsTimeout = max(cMsTimeout, 500);
507 self.fErr = not fIgnoreErrors;
508 self.fnTask = fnTask;
509 self.aTaskArgs = aArgs;
510 self.oThread = threading.Thread(target=self.taskThread, args=(), name=('UTS-%s' % (sStatus)));
511 self.oThread.setDaemon(True);
512 self.msStart = base.timestampMilli();
513
514 self.lockTask();
515 self.sStatus = sStatus;
516 self.unlockTask();
517 self.oThread.start();
518
519 return True;
520
521 def cancelTask(self, fSync = True):
522 """
523 Attempts to cancel any pending tasks.
524 Returns success indicator (True/False).
525 """
526 self.lockTask();
527
528 if self.sStatus == "":
529 self.unlockTask();
530 return True;
531 if self.sStatus == "setup":
532 self.unlockTask();
533 return False;
534 if self.sStatus == "cancelled":
535 self.unlockTask();
536 return False;
537
538 reporter.log('utsclient: cancelling "%s"...' % (self.sStatus));
539 if self.sStatus == 'connecting':
540 self.oTransport.cancelConnect();
541
542 self.sStatus = "cancelled";
543 oThread = self.oThread;
544 self.unlockTask();
545
546 if not fSync:
547 return False;
548
549 oThread.join(61.0);
550 return oThread.isAlive();
551
552 def taskThread(self):
553 """
554 The task thread function.
555 This does some housekeeping activities around the real task method call.
556 """
557 if not self.isCancelled():
558 try:
559 fnTask = self.fnTask;
560 oTaskRc = fnTask(*self.aTaskArgs);
561 except:
562 reporter.fatalXcpt('taskThread', 15);
563 oTaskRc = None;
564 else:
565 reporter.log('taskThread: cancelled already');
566
567 self.lockTask();
568
569 reporter.log('taskThread: signalling task with status "%s", oTaskRc=%s' % (self.sStatus, oTaskRc));
570 self.oTaskRc = oTaskRc;
571 self.oThread = None;
572 self.sStatus = '';
573 self.signalTaskLocked();
574
575 self.unlockTask();
576 return None;
577
578 def isCancelled(self):
579 """Internal method for checking if the task has been cancelled."""
580 self.lockTask();
581 sStatus = self.sStatus;
582 self.unlockTask();
583 if sStatus == "cancelled":
584 return True;
585 return False;
586
587 def hasTimedOut(self):
588 """Internal method for checking if the task has timed out or not."""
589 cMsLeft = self.getMsLeft();
590 if cMsLeft <= 0:
591 return True;
592 return False;
593
594 def getMsLeft(self, cMsMin = 0, cMsMax = -1):
595 """Gets the time left until the timeout."""
596 cMsElapsed = base.timestampMilli() - self.msStart;
597 if cMsElapsed < 0:
598 return cMsMin;
599 cMsLeft = self.cMsTimeout - cMsElapsed;
600 if cMsLeft <= cMsMin:
601 return cMsMin;
602 if cMsLeft > cMsMax and cMsMax > 0:
603 return cMsMax
604 return cMsLeft;
605
606 def recvReply(self, cMsTimeout = None, fNoDataOk = False):
607 """
608 Wrapper for TransportBase.recvMsg that stashes the response away
609 so the client can inspect it later on.
610 """
611 if cMsTimeout is None:
612 cMsTimeout = self.getMsLeft(500);
613 cbMsg, sOpcode, abPayload = self.oTransport.recvMsg(cMsTimeout, fNoDataOk);
614 self.lockTask();
615 self.t3oReply = (cbMsg, sOpcode, abPayload);
616 self.unlockTask();
617 return (cbMsg, sOpcode, abPayload);
618
619 def recvAck(self, fNoDataOk = False):
620 """
621 Receives an ACK or error response from the UTS.
622
623 Returns True on success.
624 Returns False on timeout or transport error.
625 Returns (sOpcode, sDetails) tuple on failure. The opcode is stripped
626 and there are always details of some sort or another.
627 """
628 cbMsg, sOpcode, abPayload = self.recvReply(None, fNoDataOk);
629 if cbMsg is None:
630 return False;
631 sOpcode = sOpcode.strip()
632 if sOpcode == "ACK":
633 return True;
634 return (sOpcode, getSZ(abPayload, 16, sOpcode));
635
636 def recvAckLogged(self, sCommand, fNoDataOk = False):
637 """
638 Wrapper for recvAck and logging.
639 Returns True on success (ACK).
640 Returns False on time, transport error and errors signalled by UTS.
641 """
642 rc = self.recvAck(fNoDataOk);
643 if rc is not True and not fNoDataOk:
644 if rc is False:
645 reporter.maybeErr(self.fErr, 'recvAckLogged: %s transport error' % (sCommand));
646 else:
647 reporter.maybeErr(self.fErr, 'recvAckLogged: %s response was %s: %s' % (sCommand, rc[0], rc[1]));
648 rc = False;
649 return rc;
650
651 def recvTrueFalse(self, sCommand):
652 """
653 Receives a TRUE/FALSE response from the UTS.
654 Returns True on TRUE, False on FALSE and None on error/other (logged).
655 """
656 cbMsg, sOpcode, abPayload = self.recvReply();
657 if cbMsg is None:
658 reporter.maybeErr(self.fErr, 'recvAckLogged: %s transport error' % (sCommand));
659 return None;
660
661 sOpcode = sOpcode.strip()
662 if sOpcode == "TRUE":
663 return True;
664 if sOpcode == "FALSE":
665 return False;
666 reporter.maybeErr(self.fErr, 'recvAckLogged: %s response was %s: %s' % \
667 (sCommand, sOpcode, getSZ(abPayload, 16, sOpcode)));
668 return None;
669
670 def sendMsg(self, sOpcode, aoPayload = (), cMsTimeout = None):
671 """
672 Wrapper for TransportBase.sendMsg that inserts the correct timeout.
673 """
674 if cMsTimeout is None:
675 cMsTimeout = self.getMsLeft(500);
676 return self.oTransport.sendMsg(sOpcode, cMsTimeout, aoPayload);
677
678 def asyncToSync(self, fnAsync, *aArgs):
679 """
680 Wraps an asynchronous task into a synchronous operation.
681
682 Returns False on failure, task return status on success.
683 """
684 rc = fnAsync(*aArgs);
685 if rc is False:
686 reporter.log2('asyncToSync(%s): returns False (#1)' % (fnAsync));
687 return rc;
688
689 rc = self.waitForTask(self.cMsTimeout + 5000);
690 if rc is False:
691 reporter.maybeErrXcpt(self.fErr, 'asyncToSync: waitForTask failed...');
692 self.cancelTask();
693 #reporter.log2('asyncToSync(%s): returns False (#2)' % (fnAsync, rc));
694 return False;
695
696 rc = self.getResult();
697 #reporter.log2('asyncToSync(%s): returns %s' % (fnAsync, rc));
698 return rc;
699
700 #
701 # Connection tasks.
702 #
703
704 def taskConnect(self, cMsIdleFudge):
705 """Tries to connect to the UTS"""
706 while not self.isCancelled():
707 reporter.log2('taskConnect: connecting ...');
708 rc = self.oTransport.connect(self.getMsLeft(500));
709 if rc is True:
710 reporter.log('taskConnect: succeeded');
711 return self.taskGreet(cMsIdleFudge);
712 if rc is None:
713 reporter.log2('taskConnect: unable to connect');
714 return None;
715 if self.hasTimedOut():
716 reporter.log2('taskConnect: timed out');
717 if not self.fTryConnect:
718 reporter.maybeErr(self.fErr, 'taskConnect: timed out');
719 return False;
720 time.sleep(self.getMsLeft(1, 1000) / 1000.0);
721 if not self.fTryConnect:
722 reporter.maybeErr(self.fErr, 'taskConnect: cancelled');
723 return False;
724
725 def taskGreet(self, cMsIdleFudge):
726 """Greets the UTS"""
727 sHostname = socket.gethostname().lower();
728 cbFill = 68 - len(sHostname) - 1;
729 rc = self.sendMsg("HOWDY", ((1 << 16) | 0, 0x1, len(sHostname), sHostname, zeroByteArray(cbFill)));
730 if rc is True:
731 rc = self.recvAckLogged("HOWDY", self.fTryConnect);
732 if rc is True:
733 while cMsIdleFudge > 0:
734 cMsIdleFudge -= 1000;
735 time.sleep(1);
736 else:
737 self.oTransport.disconnect(self.fTryConnect);
738 return rc;
739
740 def taskBye(self):
741 """Says goodbye to the UTS"""
742 rc = self.sendMsg("BYE");
743 if rc is True:
744 rc = self.recvAckLogged("BYE");
745 self.oTransport.disconnect();
746 return rc;
747
748 #
749 # Gadget tasks.
750 #
751
752 def taskGadgetCreate(self, iGadgetType, iGadgetAccess):
753 """Creates a new gadget on UTS"""
754 fRc = self.sendMsg("GDGTCRT", (iGadgetType, iGadgetAccess, 0, 0));
755 if fRc is True:
756 fRc = self.recvAckLogged("GDGTCRT");
757 return fRc;
758
759 def taskGadgetDestroy(self, iGadgetId):
760 """Destroys the given gadget handle on UTS"""
761 fRc = self.sendMsg("GDGTDTOR", (iGadgetId, zeroByteArray(12)));
762 if fRc is True:
763 fRc = self.recvAckLogged("GDGTDTOR");
764 return fRc;
765
766 def taskGadgetConnect(self, iGadgetId):
767 """Connects the given gadget handle on UTS"""
768 fRc = self.sendMsg("GDGTCNCT", (iGadgetId, zeroByteArray(12)));
769 if fRc is True:
770 fRc = self.recvAckLogged("GDGTCNCT");
771 return fRc;
772
773 def taskGadgetDisconnect(self, iGadgetId):
774 """Disconnects the given gadget handle from UTS"""
775 fRc = self.sendMsg("GDGTDCNT", (iGadgetId, zeroByteArray(12)));
776 if fRc is True:
777 fRc = self.recvAckLogged("GDGTDCNT");
778 return fRc;
779
780 #
781 # Public methods - generic task queries
782 #
783
784 def isSuccess(self):
785 """Returns True if the task completed successfully, otherwise False."""
786 self.lockTask();
787 sStatus = self.sStatus;
788 oTaskRc = self.oTaskRc;
789 self.unlockTask();
790 if sStatus != "":
791 return False;
792 if oTaskRc is False or oTaskRc is None:
793 return False;
794 return True;
795
796 def getResult(self):
797 """
798 Returns the result of a completed task.
799 Returns None if not completed yet or no previous task.
800 """
801 self.lockTask();
802 sStatus = self.sStatus;
803 oTaskRc = self.oTaskRc;
804 self.unlockTask();
805 if sStatus != "":
806 return None;
807 return oTaskRc;
808
809 def getLastReply(self):
810 """
811 Returns the last reply three-tuple: cbMsg, sOpcode, abPayload.
812 Returns a None, None, None three-tuple if there was no last reply.
813 """
814 self.lockTask();
815 t3oReply = self.t3oReply;
816 self.unlockTask();
817 return t3oReply;
818
819 #
820 # Public methods - connection.
821 #
822
823 def asyncDisconnect(self, cMsTimeout = 30000, fIgnoreErrors = False):
824 """
825 Initiates a disconnect task.
826
827 Returns True on success, False on failure (logged).
828
829 The task returns True on success and False on failure.
830 """
831 return self.startTask(cMsTimeout, fIgnoreErrors, "bye", self.taskBye);
832
833 def syncDisconnect(self, cMsTimeout = 30000, fIgnoreErrors = False):
834 """Synchronous version."""
835 return self.asyncToSync(self.asyncDisconnect, cMsTimeout, fIgnoreErrors);
836
837 #
838 # Public methods - gadget API
839 #
840
841 def asyncGadgetCreate(self, iGadgetType, iGadgetAccess, cMsTimeout = 30000, fIgnoreErrors = False):
842 """
843 Initiates a gadget create task.
844
845 Returns True on success, False on failure (logged).
846
847 The task returns True on success and False on failure.
848 """
849 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetCreate", self.taskGadgetCreate, \
850 (iGadgetType, iGadgetAccess));
851
852 def syncGadgetCreate(self, iGadgetType, iGadgetAccess, cMsTimeout = 30000, fIgnoreErrors = False):
853 """Synchronous version."""
854 return self.asyncToSync(self.asyncGadgetCreate, iGadgetType, iGadgetAccess, cMsTimeout, fIgnoreErrors);
855
856 def asyncGadgetDestroy(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
857 """
858 Initiates a gadget destroy task.
859
860 Returns True on success, False on failure (logged).
861
862 The task returns True on success and False on failure.
863 """
864 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetDestroy", self.taskGadgetDestroy, \
865 (iGadgetId, ));
866
867 def syncGadgetDestroy(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
868 """Synchronous version."""
869 return self.asyncToSync(self.asyncGadgetDestroy, iGadgetId, cMsTimeout, fIgnoreErrors);
870
871 def asyncGadgetConnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
872 """
873 Initiates a gadget connect task.
874
875 Returns True on success, False on failure (logged).
876
877 The task returns True on success and False on failure.
878 """
879 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetConnect", self.taskGadgetConnect, \
880 (iGadgetId, ));
881
882 def syncGadgetConnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
883 """Synchronous version."""
884 return self.asyncToSync(self.asyncGadgetConnect, iGadgetId, cMsTimeout, fIgnoreErrors);
885
886 def asyncGadgetDisconnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
887 """
888 Initiates a gadget disconnect task.
889
890 Returns True on success, False on failure (logged).
891
892 The task returns True on success and False on failure.
893 """
894 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetDisconnect", self.taskGadgetDisconnect, \
895 (iGadgetId, ));
896
897 def syncGadgetDisconnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
898 """Synchronous version."""
899 return self.asyncToSync(self.asyncGadgetDisconnect, iGadgetId, cMsTimeout, fIgnoreErrors);
900
901
902class TransportTcp(TransportBase):
903 """
904 TCP transport layer for the UTS client session class.
905 """
906
907 def __init__(self, sHostname, uPort):
908 """
909 Save the parameters. The session will call us back to make the
910 connection later on its worker thread.
911 """
912 TransportBase.__init__(self, utils.getCallerName());
913 self.sHostname = sHostname;
914 self.uPort = uPort if uPort is not None else 6042;
915 self.oSocket = None;
916 self.oWakeupW = None;
917 self.oWakeupR = None;
918 self.fConnectCanceled = False;
919 self.fIsConnecting = False;
920 self.oCv = threading.Condition();
921 self.abReadAhead = array.array('B');
922
923 def toString(self):
924 return '<%s sHostname=%s, uPort=%s, oSocket=%s,'\
925 ' fConnectCanceled=%s, fIsConnecting=%s, oCv=%s, abReadAhead=%s>' \
926 % (TransportBase.toString(self), self.sHostname, self.uPort, self.oSocket,
927 self.fConnectCanceled, self.fIsConnecting, self.oCv, self.abReadAhead);
928
929 def __isInProgressXcpt(self, oXcpt):
930 """ In progress exception? """
931 try:
932 if isinstance(oXcpt, socket.error):
933 try:
934 if oXcpt[0] == errno.EINPROGRESS:
935 return True;
936 except: pass;
937 # Windows?
938 try:
939 if oXcpt[0] == errno.EWOULDBLOCK:
940 return True;
941 except: pass;
942 except:
943 pass;
944 return False;
945
946 def __isWouldBlockXcpt(self, oXcpt):
947 """ Would block exception? """
948 try:
949 if isinstance(oXcpt, socket.error):
950 try:
951 if oXcpt[0] == errno.EWOULDBLOCK:
952 return True;
953 except: pass;
954 try:
955 if oXcpt[0] == errno.EAGAIN:
956 return True;
957 except: pass;
958 except:
959 pass;
960 return False;
961
962 def __isConnectionReset(self, oXcpt):
963 """ Connection reset by Peer or others. """
964 try:
965 if isinstance(oXcpt, socket.error):
966 try:
967 if oXcpt[0] == errno.ECONNRESET:
968 return True;
969 except: pass;
970 try:
971 if oXcpt[0] == errno.ENETRESET:
972 return True;
973 except: pass;
974 except:
975 pass;
976 return False;
977
978 def _closeWakeupSockets(self):
979 """ Closes the wakup sockets. Caller should own the CV. """
980 oWakeupR = self.oWakeupR;
981 self.oWakeupR = None;
982 if oWakeupR is not None:
983 oWakeupR.close();
984
985 oWakeupW = self.oWakeupW;
986 self.oWakeupW = None;
987 if oWakeupW is not None:
988 oWakeupW.close();
989
990 return None;
991
992 def cancelConnect(self):
993 # This is bad stuff.
994 self.oCv.acquire();
995 reporter.log2('TransportTcp::cancelConnect: fIsConnecting=%s oSocket=%s' % (self.fIsConnecting, self.oSocket));
996 self.fConnectCanceled = True;
997 if self.fIsConnecting:
998 oSocket = self.oSocket;
999 self.oSocket = None;
1000 if oSocket is not None:
1001 reporter.log2('TransportTcp::cancelConnect: closing the socket');
1002 oSocket.close();
1003
1004 oWakeupW = self.oWakeupW;
1005 self.oWakeupW = None;
1006 if oWakeupW is not None:
1007 reporter.log2('TransportTcp::cancelConnect: wakeup call');
1008 try: oWakeupW.send('cancelled!\n');
1009 except: reporter.logXcpt();
1010 try: oWakeupW.shutdown(socket.SHUT_WR);
1011 except: reporter.logXcpt();
1012 oWakeupW.close();
1013 self.oCv.release();
1014
1015 def _connectAsClient(self, oSocket, oWakeupR, cMsTimeout):
1016 """ Connects to the UTS server as client. """
1017
1018 # Connect w/ timeouts.
1019 rc = None;
1020 try:
1021 oSocket.connect((self.sHostname, self.uPort));
1022 rc = True;
1023 except socket.error, e:
1024 iRc = e[0];
1025 if self.__isInProgressXcpt(e):
1026 # Do the actual waiting.
1027 reporter.log2('TransportTcp::connect: operation in progress (%s)...' % (e,));
1028 try:
1029 ttRc = select.select([oWakeupR], [oSocket], [oSocket, oWakeupR], cMsTimeout / 1000.0);
1030 if len(ttRc[1]) + len(ttRc[2]) == 0:
1031 raise socket.error(errno.ETIMEDOUT, 'select timed out');
1032 iRc = oSocket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR);
1033 rc = iRc == 0;
1034 except socket.error, e:
1035 iRc = e[0];
1036 except:
1037 iRc = -42;
1038 reporter.fatalXcpt('socket.select() on connect failed');
1039
1040 if rc is True:
1041 pass;
1042 elif iRc == errno.ECONNREFUSED \
1043 or iRc == errno.EHOSTUNREACH \
1044 or iRc == errno.EINTR \
1045 or iRc == errno.ENETDOWN \
1046 or iRc == errno.ENETUNREACH \
1047 or iRc == errno.ETIMEDOUT:
1048 rc = False; # try again.
1049 else:
1050 if iRc != errno.EBADF or not self.fConnectCanceled:
1051 reporter.fatalXcpt('socket.connect((%s,%s)) failed; iRc=%s' % (self.sHostname, self.uPort, iRc));
1052 reporter.log2('TransportTcp::connect: rc=%s iRc=%s' % (rc, iRc));
1053 except:
1054 reporter.fatalXcpt('socket.connect((%s,%s)) failed' % (self.sHostname, self.uPort));
1055 return rc;
1056
1057
1058 def connect(self, cMsTimeout):
1059 # Create a non-blocking socket.
1060 reporter.log2('TransportTcp::connect: cMsTimeout=%s sHostname=%s uPort=%s' % (cMsTimeout, self.sHostname, self.uPort));
1061 try:
1062 oSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
1063 except:
1064 reporter.fatalXcpt('socket.socket() failed');
1065 return None;
1066 try:
1067 oSocket.setblocking(0);
1068 except:
1069 oSocket.close();
1070 reporter.fatalXcpt('socket.socket() failed');
1071 return None;
1072
1073 # Create wakeup socket pair for unix (select doesn't wake up on socket close on Linux).
1074 oWakeupR = None;
1075 oWakeupW = None;
1076 if hasattr(socket, 'socketpair'):
1077 try: (oWakeupR, oWakeupW) = socket.socketpair(); # pylint: disable=E1101
1078 except: reporter.logXcpt('socket.socketpair() failed');
1079
1080 # Update the state.
1081 self.oCv.acquire();
1082 rc = None;
1083 if not self.fConnectCanceled:
1084 self.oSocket = oSocket;
1085 self.oWakeupW = oWakeupW;
1086 self.oWakeupR = oWakeupR;
1087 self.fIsConnecting = True;
1088 self.oCv.release();
1089
1090 # Try connect.
1091 if oWakeupR is None:
1092 oWakeupR = oSocket; # Avoid select failure.
1093 rc = self._connectAsClient(oSocket, oWakeupR, cMsTimeout);
1094 oSocket = None;
1095
1096 # Update the state and cleanup on failure/cancel.
1097 self.oCv.acquire();
1098 if rc is True and self.fConnectCanceled:
1099 rc = False;
1100 self.fIsConnecting = False;
1101
1102 if rc is not True:
1103 if self.oSocket is not None:
1104 self.oSocket.close();
1105 self.oSocket = None;
1106 self._closeWakeupSockets();
1107 self.oCv.release();
1108
1109 reporter.log2('TransportTcp::connect: returning %s' % (rc,));
1110 return rc;
1111
1112 def disconnect(self, fQuiet = False):
1113 if self.oSocket is not None:
1114 self.abReadAhead = array.array('B');
1115
1116 # Try a shutting down the socket gracefully (draining it).
1117 try:
1118 self.oSocket.shutdown(socket.SHUT_WR);
1119 except:
1120 if not fQuiet:
1121 reporter.error('shutdown(SHUT_WR)');
1122 try:
1123 self.oSocket.setblocking(0); # just in case it's not set.
1124 sData = "1";
1125 while len(sData) > 0:
1126 sData = self.oSocket.recv(16384);
1127 except:
1128 pass;
1129
1130 # Close it.
1131 self.oCv.acquire();
1132 try: self.oSocket.setblocking(1);
1133 except: pass;
1134 self.oSocket.close();
1135 self.oSocket = None;
1136 else:
1137 self.oCv.acquire();
1138 self._closeWakeupSockets();
1139 self.oCv.release();
1140
1141 def sendBytes(self, abMsg, cMsTimeout):
1142 if self.oSocket is None:
1143 reporter.error('TransportTcp.sendBytes: No connection.');
1144 return False;
1145
1146 # Try send it all.
1147 try:
1148 cbSent = self.oSocket.send(abMsg);
1149 if cbSent == len(abMsg):
1150 return True;
1151 except Exception, oXcpt:
1152 if not self.__isWouldBlockXcpt(oXcpt):
1153 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1154 return False;
1155 cbSent = 0;
1156
1157 # Do a timed send.
1158 msStart = base.timestampMilli();
1159 while True:
1160 cMsElapsed = base.timestampMilli() - msStart;
1161 if cMsElapsed > cMsTimeout:
1162 reporter.error('TranportTcp.sendBytes: %s bytes timed out (1)' % (len(abMsg)));
1163 break;
1164
1165 # wait.
1166 try:
1167 ttRc = select.select([], [self.oSocket], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1168 if len(ttRc[2]) > 0 and len(ttRc[1]) == 0:
1169 reporter.error('TranportTcp.sendBytes: select returned with exception');
1170 break;
1171 if len(ttRc[1]) == 0:
1172 reporter.error('TranportTcp.sendBytes: %s bytes timed out (2)' % (len(abMsg)));
1173 break;
1174 except:
1175 reporter.errorXcpt('TranportTcp.sendBytes: select failed');
1176 break;
1177
1178 # Try send more.
1179 try:
1180 cbSent += self.oSocket.send(abMsg[cbSent:]);
1181 if cbSent == len(abMsg):
1182 return True;
1183 except Exception, oXcpt:
1184 if not self.__isWouldBlockXcpt(oXcpt):
1185 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1186 break;
1187
1188 return False;
1189
1190 def __returnReadAheadBytes(self, cb):
1191 """ Internal worker for recvBytes. """
1192 assert(len(self.abReadAhead) >= cb);
1193 abRet = self.abReadAhead[:cb];
1194 self.abReadAhead = self.abReadAhead[cb:];
1195 return abRet;
1196
1197 def recvBytes(self, cb, cMsTimeout, fNoDataOk):
1198 if self.oSocket is None:
1199 reporter.error('TransportTcp.recvBytes(%s,%s): No connection.' % (cb, cMsTimeout));
1200 return None;
1201
1202 # Try read in some more data without bothering with timeout handling first.
1203 if len(self.abReadAhead) < cb:
1204 try:
1205 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1206 if len(abBuf) > 0:
1207 self.abReadAhead.extend(array.array('B', abBuf));
1208 except Exception, oXcpt:
1209 if not self.__isWouldBlockXcpt(oXcpt):
1210 reporter.errorXcpt('TranportTcp.recvBytes: 0/%s bytes' % (cb,));
1211 return None;
1212
1213 if len(self.abReadAhead) >= cb:
1214 return self.__returnReadAheadBytes(cb);
1215
1216 # Timeout loop.
1217 msStart = base.timestampMilli();
1218 while True:
1219 cMsElapsed = base.timestampMilli() - msStart;
1220 if cMsElapsed > cMsTimeout:
1221 if not fNoDataOk or len(self.abReadAhead) > 0:
1222 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (1)' % (len(self.abReadAhead), cb));
1223 break;
1224
1225 # Wait.
1226 try:
1227 ttRc = select.select([self.oSocket], [], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1228 if len(ttRc[2]) > 0 and len(ttRc[0]) == 0:
1229 reporter.error('TranportTcp.recvBytes: select returned with exception');
1230 break;
1231 if len(ttRc[0]) == 0:
1232 if not fNoDataOk or len(self.abReadAhead) > 0:
1233 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (2) fNoDataOk=%s'
1234 % (len(self.abReadAhead), cb, fNoDataOk));
1235 break;
1236 except:
1237 reporter.errorXcpt('TranportTcp.recvBytes: select failed');
1238 break;
1239
1240 # Try read more.
1241 try:
1242 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1243 if len(abBuf) == 0:
1244 reporter.error('TranportTcp.recvBytes: %s/%s bytes (%s) - connection has been shut down'
1245 % (len(self.abReadAhead), cb, fNoDataOk));
1246 self.disconnect();
1247 return None;
1248
1249 self.abReadAhead.extend(array.array('B', abBuf));
1250
1251 except Exception, oXcpt:
1252 reporter.log('recv => exception %s' % (oXcpt,));
1253 if not self.__isWouldBlockXcpt(oXcpt):
1254 if not fNoDataOk or not self.__isConnectionReset(oXcpt) or len(self.abReadAhead) > 0:
1255 reporter.errorXcpt('TranportTcp.recvBytes: %s/%s bytes (%s)' % (len(self.abReadAhead), cb, fNoDataOk));
1256 break;
1257
1258 # Done?
1259 if len(self.abReadAhead) >= cb:
1260 return self.__returnReadAheadBytes(cb);
1261
1262 #reporter.log('recv => None len(self.abReadAhead) -> %d' % (len(self.abReadAhead), ));
1263 return None;
1264
1265 def isConnectionOk(self):
1266 if self.oSocket is None:
1267 return False;
1268 try:
1269 ttRc = select.select([], [], [self.oSocket], 0.0);
1270 if len(ttRc[2]) > 0:
1271 return False;
1272
1273 self.oSocket.send(array.array('B')); # send zero bytes.
1274 except:
1275 return False;
1276 return True;
1277
1278 def isRecvPending(self, cMsTimeout = 0):
1279 try:
1280 ttRc = select.select([self.oSocket], [], [], cMsTimeout / 1000.0);
1281 if len(ttRc[0]) == 0:
1282 return False;
1283 except:
1284 pass;
1285 return True;
1286
1287
1288class UsbGadget(object):
1289 """
1290 USB Gadget control class using the USBT Test Service to talk to the external
1291 board behaving like a USB device.
1292 """
1293
1294 def __init__(self):
1295 self.oUtsSession = None;
1296 self.sImpersonation = g_ksGadgetImpersonationInvalid;
1297 self.idGadget = None;
1298 self.iBusId = None;
1299 self.iDevId = None;
1300 self.iUsbIpPort = None;
1301
1302 def clearImpersonation(self):
1303 """
1304 Removes the current impersonation of the gadget.
1305 """
1306 fRc = True;
1307
1308 if self.idGadget is not None:
1309 fRc = self.oUtsSession.syncGadgetDestroy(self.idGadget);
1310 self.idGadget = None;
1311 self.iBusId = None;
1312 self.iDevId = None;
1313
1314 return fRc;
1315
1316 def disconnectUsb(self):
1317 """
1318 Disconnects the USB gadget from the host. (USB connection not network
1319 connection used for control)
1320 """
1321 return self.oUtsSession.syncGadgetDisconnect(self.idGadget);
1322
1323 def connectUsb(self):
1324 """
1325 Connect the USB gadget to the host.
1326 """
1327 return self.oUtsSession.syncGadgetConnect(self.idGadget);
1328
1329 def impersonate(self, sImpersonation):
1330 """
1331 Impersonate a given device.
1332 """
1333
1334 # Clear any previous impersonation
1335 self.clearImpersonation();
1336 self.sImpersonation = sImpersonation;
1337
1338 fRc = False;
1339 if sImpersonation == g_ksGadgetImpersonationTest:
1340 fDone = self.oUtsSession.syncGadgetCreate(g_kiGadgetTypeTest, g_kiGadgetAccessUsbIp);
1341 if fDone is True and self.oUtsSession.isSuccess():
1342 # Get the gadget ID.
1343 _, _, abPayload = self.oUtsSession.getLastReply();
1344
1345 fRc = True;
1346 self.idGadget = getU32(abPayload, 16);
1347 self.iBusId = getU32(abPayload, 20);
1348 self.iDevId = getU32(abPayload, 24);
1349 else:
1350 reporter.log('Invalid or unsupported impersonation');
1351
1352 return fRc;
1353
1354 def getUsbIpPort(self):
1355 """
1356 Returns the port the USB/IP server is listening on if requested,
1357 None if USB/IP is not supported.
1358 """
1359 return self.iUsbIpPort;
1360
1361 def getGadgetBusAndDevId(self):
1362 """
1363 Returns the bus ad device ID of the gadget as a tuple.
1364 """
1365 return (self.iBusId, self.iDevId);
1366
1367 def connectTo(self, cMsTimeout, sHostname, uPort = None, fUsbIpSupport = True, cMsIdleFudge = 0):
1368 """
1369 Connects to the specified target device.
1370 Returns True on Success.
1371 Returns False otherwise.
1372 """
1373 fRc = True;
1374
1375 # @todo
1376 if fUsbIpSupport is False:
1377 return False;
1378
1379 reporter.log2('openTcpSession(%s, %s, %s, %s)' % \
1380 (cMsTimeout, sHostname, uPort, cMsIdleFudge));
1381 try:
1382 oTransport = TransportTcp(sHostname, uPort);
1383 self.oUtsSession = Session(oTransport, cMsTimeout, cMsIdleFudge);
1384
1385 if self.oUtsSession is not None:
1386 fDone = self.oUtsSession.waitForTask(30*1000);
1387 print 'connect: waitForTask -> %s, result %s' % (fDone, self.oUtsSession.getResult());
1388 if fDone is True and self.oUtsSession.isSuccess():
1389 # Parse the reply.
1390 _, _, abPayload = self.oUtsSession.getLastReply();
1391
1392 if getU32(abPayload, 20) is g_kiGadgetAccessUsbIp:
1393 fRc = True;
1394 self.iUsbIpPort = getU32(abPayload, 24);
1395 else:
1396 reporter.log('Gadget doesn\'t support access over USB/IP despite being requested');
1397 fRc = False;
1398 else:
1399 fRc = False;
1400 else:
1401 fRc = False;
1402 except:
1403 reporter.errorXcpt(None, 15);
1404 return False;
1405
1406 return fRc;
1407
1408 def disconnectFrom(self):
1409 """
1410 Disconnects from the target device.
1411 """
1412 fRc = True;
1413
1414 self.clearImpersonation();
1415 if self.oUtsSession is not None:
1416 fRc = self.oUtsSession.syncDisconnect();
1417
1418 return fRc;
1419
Note: See TracBrowser for help on using the repository browser.

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