VirtualBox

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

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

ValidationKit/usb: Move usbgadget2 to usbgadget and rmeove the old version, smaller fixes for pylint

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: usbgadget.py 60567 2016-04-19 11:15:23Z 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: 60567 $"
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 # pylint: disable=R0916
1041 if rc is True:
1042 pass;
1043 elif iRc == errno.ECONNREFUSED \
1044 or iRc == errno.EHOSTUNREACH \
1045 or iRc == errno.EINTR \
1046 or iRc == errno.ENETDOWN \
1047 or iRc == errno.ENETUNREACH \
1048 or iRc == errno.ETIMEDOUT:
1049 rc = False; # try again.
1050 else:
1051 if iRc != errno.EBADF or not self.fConnectCanceled:
1052 reporter.fatalXcpt('socket.connect((%s,%s)) failed; iRc=%s' % (self.sHostname, self.uPort, iRc));
1053 reporter.log2('TransportTcp::connect: rc=%s iRc=%s' % (rc, iRc));
1054 # pylint: enable=R0916
1055 except:
1056 reporter.fatalXcpt('socket.connect((%s,%s)) failed' % (self.sHostname, self.uPort));
1057 return rc;
1058
1059
1060 def connect(self, cMsTimeout):
1061 # Create a non-blocking socket.
1062 reporter.log2('TransportTcp::connect: cMsTimeout=%s sHostname=%s uPort=%s' % (cMsTimeout, self.sHostname, self.uPort));
1063 try:
1064 oSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
1065 except:
1066 reporter.fatalXcpt('socket.socket() failed');
1067 return None;
1068 try:
1069 oSocket.setblocking(0);
1070 except:
1071 oSocket.close();
1072 reporter.fatalXcpt('socket.socket() failed');
1073 return None;
1074
1075 # Create wakeup socket pair for unix (select doesn't wake up on socket close on Linux).
1076 oWakeupR = None;
1077 oWakeupW = None;
1078 if hasattr(socket, 'socketpair'):
1079 try: (oWakeupR, oWakeupW) = socket.socketpair(); # pylint: disable=E1101
1080 except: reporter.logXcpt('socket.socketpair() failed');
1081
1082 # Update the state.
1083 self.oCv.acquire();
1084 rc = None;
1085 if not self.fConnectCanceled:
1086 self.oSocket = oSocket;
1087 self.oWakeupW = oWakeupW;
1088 self.oWakeupR = oWakeupR;
1089 self.fIsConnecting = True;
1090 self.oCv.release();
1091
1092 # Try connect.
1093 if oWakeupR is None:
1094 oWakeupR = oSocket; # Avoid select failure.
1095 rc = self._connectAsClient(oSocket, oWakeupR, cMsTimeout);
1096 oSocket = None;
1097
1098 # Update the state and cleanup on failure/cancel.
1099 self.oCv.acquire();
1100 if rc is True and self.fConnectCanceled:
1101 rc = False;
1102 self.fIsConnecting = False;
1103
1104 if rc is not True:
1105 if self.oSocket is not None:
1106 self.oSocket.close();
1107 self.oSocket = None;
1108 self._closeWakeupSockets();
1109 self.oCv.release();
1110
1111 reporter.log2('TransportTcp::connect: returning %s' % (rc,));
1112 return rc;
1113
1114 def disconnect(self, fQuiet = False):
1115 if self.oSocket is not None:
1116 self.abReadAhead = array.array('B');
1117
1118 # Try a shutting down the socket gracefully (draining it).
1119 try:
1120 self.oSocket.shutdown(socket.SHUT_WR);
1121 except:
1122 if not fQuiet:
1123 reporter.error('shutdown(SHUT_WR)');
1124 try:
1125 self.oSocket.setblocking(0); # just in case it's not set.
1126 sData = "1";
1127 while len(sData) > 0:
1128 sData = self.oSocket.recv(16384);
1129 except:
1130 pass;
1131
1132 # Close it.
1133 self.oCv.acquire();
1134 try: self.oSocket.setblocking(1);
1135 except: pass;
1136 self.oSocket.close();
1137 self.oSocket = None;
1138 else:
1139 self.oCv.acquire();
1140 self._closeWakeupSockets();
1141 self.oCv.release();
1142
1143 def sendBytes(self, abMsg, cMsTimeout):
1144 if self.oSocket is None:
1145 reporter.error('TransportTcp.sendBytes: No connection.');
1146 return False;
1147
1148 # Try send it all.
1149 try:
1150 cbSent = self.oSocket.send(abMsg);
1151 if cbSent == len(abMsg):
1152 return True;
1153 except Exception, oXcpt:
1154 if not self.__isWouldBlockXcpt(oXcpt):
1155 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1156 return False;
1157 cbSent = 0;
1158
1159 # Do a timed send.
1160 msStart = base.timestampMilli();
1161 while True:
1162 cMsElapsed = base.timestampMilli() - msStart;
1163 if cMsElapsed > cMsTimeout:
1164 reporter.error('TranportTcp.sendBytes: %s bytes timed out (1)' % (len(abMsg)));
1165 break;
1166
1167 # wait.
1168 try:
1169 ttRc = select.select([], [self.oSocket], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1170 if len(ttRc[2]) > 0 and len(ttRc[1]) == 0:
1171 reporter.error('TranportTcp.sendBytes: select returned with exception');
1172 break;
1173 if len(ttRc[1]) == 0:
1174 reporter.error('TranportTcp.sendBytes: %s bytes timed out (2)' % (len(abMsg)));
1175 break;
1176 except:
1177 reporter.errorXcpt('TranportTcp.sendBytes: select failed');
1178 break;
1179
1180 # Try send more.
1181 try:
1182 cbSent += self.oSocket.send(abMsg[cbSent:]);
1183 if cbSent == len(abMsg):
1184 return True;
1185 except Exception, oXcpt:
1186 if not self.__isWouldBlockXcpt(oXcpt):
1187 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1188 break;
1189
1190 return False;
1191
1192 def __returnReadAheadBytes(self, cb):
1193 """ Internal worker for recvBytes. """
1194 assert(len(self.abReadAhead) >= cb);
1195 abRet = self.abReadAhead[:cb];
1196 self.abReadAhead = self.abReadAhead[cb:];
1197 return abRet;
1198
1199 def recvBytes(self, cb, cMsTimeout, fNoDataOk):
1200 if self.oSocket is None:
1201 reporter.error('TransportTcp.recvBytes(%s,%s): No connection.' % (cb, cMsTimeout));
1202 return None;
1203
1204 # Try read in some more data without bothering with timeout handling first.
1205 if len(self.abReadAhead) < cb:
1206 try:
1207 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1208 if len(abBuf) > 0:
1209 self.abReadAhead.extend(array.array('B', abBuf));
1210 except Exception, oXcpt:
1211 if not self.__isWouldBlockXcpt(oXcpt):
1212 reporter.errorXcpt('TranportTcp.recvBytes: 0/%s bytes' % (cb,));
1213 return None;
1214
1215 if len(self.abReadAhead) >= cb:
1216 return self.__returnReadAheadBytes(cb);
1217
1218 # Timeout loop.
1219 msStart = base.timestampMilli();
1220 while True:
1221 cMsElapsed = base.timestampMilli() - msStart;
1222 if cMsElapsed > cMsTimeout:
1223 if not fNoDataOk or len(self.abReadAhead) > 0:
1224 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (1)' % (len(self.abReadAhead), cb));
1225 break;
1226
1227 # Wait.
1228 try:
1229 ttRc = select.select([self.oSocket], [], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1230 if len(ttRc[2]) > 0 and len(ttRc[0]) == 0:
1231 reporter.error('TranportTcp.recvBytes: select returned with exception');
1232 break;
1233 if len(ttRc[0]) == 0:
1234 if not fNoDataOk or len(self.abReadAhead) > 0:
1235 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (2) fNoDataOk=%s'
1236 % (len(self.abReadAhead), cb, fNoDataOk));
1237 break;
1238 except:
1239 reporter.errorXcpt('TranportTcp.recvBytes: select failed');
1240 break;
1241
1242 # Try read more.
1243 try:
1244 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1245 if len(abBuf) == 0:
1246 reporter.error('TranportTcp.recvBytes: %s/%s bytes (%s) - connection has been shut down'
1247 % (len(self.abReadAhead), cb, fNoDataOk));
1248 self.disconnect();
1249 return None;
1250
1251 self.abReadAhead.extend(array.array('B', abBuf));
1252
1253 except Exception, oXcpt:
1254 reporter.log('recv => exception %s' % (oXcpt,));
1255 if not self.__isWouldBlockXcpt(oXcpt):
1256 if not fNoDataOk or not self.__isConnectionReset(oXcpt) or len(self.abReadAhead) > 0:
1257 reporter.errorXcpt('TranportTcp.recvBytes: %s/%s bytes (%s)' % (len(self.abReadAhead), cb, fNoDataOk));
1258 break;
1259
1260 # Done?
1261 if len(self.abReadAhead) >= cb:
1262 return self.__returnReadAheadBytes(cb);
1263
1264 #reporter.log('recv => None len(self.abReadAhead) -> %d' % (len(self.abReadAhead), ));
1265 return None;
1266
1267 def isConnectionOk(self):
1268 if self.oSocket is None:
1269 return False;
1270 try:
1271 ttRc = select.select([], [], [self.oSocket], 0.0);
1272 if len(ttRc[2]) > 0:
1273 return False;
1274
1275 self.oSocket.send(array.array('B')); # send zero bytes.
1276 except:
1277 return False;
1278 return True;
1279
1280 def isRecvPending(self, cMsTimeout = 0):
1281 try:
1282 ttRc = select.select([self.oSocket], [], [], cMsTimeout / 1000.0);
1283 if len(ttRc[0]) == 0:
1284 return False;
1285 except:
1286 pass;
1287 return True;
1288
1289
1290class UsbGadget(object):
1291 """
1292 USB Gadget control class using the USBT Test Service to talk to the external
1293 board behaving like a USB device.
1294 """
1295
1296 def __init__(self):
1297 self.oUtsSession = None;
1298 self.sImpersonation = g_ksGadgetImpersonationInvalid;
1299 self.idGadget = None;
1300 self.iBusId = None;
1301 self.iDevId = None;
1302 self.iUsbIpPort = None;
1303
1304 def clearImpersonation(self):
1305 """
1306 Removes the current impersonation of the gadget.
1307 """
1308 fRc = True;
1309
1310 if self.idGadget is not None:
1311 fRc = self.oUtsSession.syncGadgetDestroy(self.idGadget);
1312 self.idGadget = None;
1313 self.iBusId = None;
1314 self.iDevId = None;
1315
1316 return fRc;
1317
1318 def disconnectUsb(self):
1319 """
1320 Disconnects the USB gadget from the host. (USB connection not network
1321 connection used for control)
1322 """
1323 return self.oUtsSession.syncGadgetDisconnect(self.idGadget);
1324
1325 def connectUsb(self):
1326 """
1327 Connect the USB gadget to the host.
1328 """
1329 return self.oUtsSession.syncGadgetConnect(self.idGadget);
1330
1331 def impersonate(self, sImpersonation):
1332 """
1333 Impersonate a given device.
1334 """
1335
1336 # Clear any previous impersonation
1337 self.clearImpersonation();
1338 self.sImpersonation = sImpersonation;
1339
1340 fRc = False;
1341 if sImpersonation == g_ksGadgetImpersonationTest:
1342 fDone = self.oUtsSession.syncGadgetCreate(g_kiGadgetTypeTest, g_kiGadgetAccessUsbIp);
1343 if fDone is True and self.oUtsSession.isSuccess():
1344 # Get the gadget ID.
1345 _, _, abPayload = self.oUtsSession.getLastReply();
1346
1347 fRc = True;
1348 self.idGadget = getU32(abPayload, 16);
1349 self.iBusId = getU32(abPayload, 20);
1350 self.iDevId = getU32(abPayload, 24);
1351 else:
1352 reporter.log('Invalid or unsupported impersonation');
1353
1354 return fRc;
1355
1356 def getUsbIpPort(self):
1357 """
1358 Returns the port the USB/IP server is listening on if requested,
1359 None if USB/IP is not supported.
1360 """
1361 return self.iUsbIpPort;
1362
1363 def getGadgetBusAndDevId(self):
1364 """
1365 Returns the bus ad device ID of the gadget as a tuple.
1366 """
1367 return (self.iBusId, self.iDevId);
1368
1369 def connectTo(self, cMsTimeout, sHostname, uPort = None, fUsbIpSupport = True, cMsIdleFudge = 0):
1370 """
1371 Connects to the specified target device.
1372 Returns True on Success.
1373 Returns False otherwise.
1374 """
1375 fRc = True;
1376
1377 # @todo
1378 if fUsbIpSupport is False:
1379 return False;
1380
1381 reporter.log2('openTcpSession(%s, %s, %s, %s)' % \
1382 (cMsTimeout, sHostname, uPort, cMsIdleFudge));
1383 try:
1384 oTransport = TransportTcp(sHostname, uPort);
1385 self.oUtsSession = Session(oTransport, cMsTimeout, cMsIdleFudge);
1386
1387 if self.oUtsSession is not None:
1388 fDone = self.oUtsSession.waitForTask(30*1000);
1389 print 'connect: waitForTask -> %s, result %s' % (fDone, self.oUtsSession.getResult());
1390 if fDone is True and self.oUtsSession.isSuccess():
1391 # Parse the reply.
1392 _, _, abPayload = self.oUtsSession.getLastReply();
1393
1394 if getU32(abPayload, 20) is g_kiGadgetAccessUsbIp:
1395 fRc = True;
1396 self.iUsbIpPort = getU32(abPayload, 24);
1397 else:
1398 reporter.log('Gadget doesn\'t support access over USB/IP despite being requested');
1399 fRc = False;
1400 else:
1401 fRc = False;
1402 else:
1403 fRc = False;
1404 except:
1405 reporter.errorXcpt(None, 15);
1406 return False;
1407
1408 return fRc;
1409
1410 def disconnectFrom(self):
1411 """
1412 Disconnects from the target device.
1413 """
1414 fRc = True;
1415
1416 self.clearImpersonation();
1417 if self.oUtsSession is not None:
1418 fRc = self.oUtsSession.syncDisconnect();
1419
1420 return fRc;
1421
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