VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/tests/usb/usbgadget2.py@ 60548

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

ValdiationKit/usb: Return bus and device ID for the created gadget to make it usable for device filters

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.6 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: usbgadget2.py 60548 2016-04-18 17:33:15Z 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: 60548 $"
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(u8):
169 """Encodes the u8 value as a little endian byte (B) array."""
170 return array.array('B', (u8 % 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):
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 == 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' % (sCommand, sOpcode, getSZ(abPayload, 16, sOpcode)));
667 return None;
668
669 def sendMsg(self, sOpcode, aoPayload = (), cMsTimeout = None):
670 """
671 Wrapper for TransportBase.sendMsg that inserts the correct timeout.
672 """
673 if cMsTimeout == None:
674 cMsTimeout = self.getMsLeft(500);
675 return self.oTransport.sendMsg(sOpcode, cMsTimeout, aoPayload);
676
677 def asyncToSync(self, fnAsync, *aArgs):
678 """
679 Wraps an asynchronous task into a synchronous operation.
680
681 Returns False on failure, task return status on success.
682 """
683 rc = fnAsync(*aArgs);
684 if rc is False:
685 reporter.log2('asyncToSync(%s): returns False (#1)' % (fnAsync));
686 return rc;
687
688 rc = self.waitForTask(self.cMsTimeout + 5000);
689 if rc is False:
690 reporter.maybeErrXcpt(self.fErr, 'asyncToSync: waitForTask failed...');
691 self.cancelTask();
692 #reporter.log2('asyncToSync(%s): returns False (#2)' % (fnAsync, rc));
693 return False;
694
695 rc = self.getResult();
696 #reporter.log2('asyncToSync(%s): returns %s' % (fnAsync, rc));
697 return rc;
698
699 #
700 # Connection tasks.
701 #
702
703 def taskConnect(self, cMsIdleFudge):
704 """Tries to connect to the UTS"""
705 while not self.isCancelled():
706 reporter.log2('taskConnect: connecting ...');
707 rc = self.oTransport.connect(self.getMsLeft(500));
708 if rc is True:
709 reporter.log('taskConnect: succeeded');
710 return self.taskGreet(cMsIdleFudge);
711 if rc is None:
712 reporter.log2('taskConnect: unable to connect');
713 return None;
714 if self.hasTimedOut():
715 reporter.log2('taskConnect: timed out');
716 if not self.fTryConnect:
717 reporter.maybeErr(self.fErr, 'taskConnect: timed out');
718 return False;
719 time.sleep(self.getMsLeft(1, 1000) / 1000.0);
720 if not self.fTryConnect:
721 reporter.maybeErr(self.fErr, 'taskConnect: cancelled');
722 return False;
723
724 def taskGreet(self, cMsIdleFudge):
725 """Greets the UTS"""
726 sHostname = socket.gethostname().lower();
727 cbFill = 68 - len(sHostname) - 1;
728 rc = self.sendMsg("HOWDY", ((1 << 16) | 0, 0x1, len(sHostname), sHostname, zeroByteArray(cbFill)));
729 if rc is True:
730 rc = self.recvAckLogged("HOWDY", self.fTryConnect);
731 if rc is True:
732 while cMsIdleFudge > 0:
733 cMsIdleFudge -= 1000;
734 time.sleep(1);
735 else:
736 self.oTransport.disconnect(self.fTryConnect);
737 return rc;
738
739 def taskBye(self):
740 """Says goodbye to the UTS"""
741 rc = self.sendMsg("BYE");
742 if rc is True:
743 rc = self.recvAckLogged("BYE");
744 self.oTransport.disconnect();
745 return rc;
746
747 #
748 # Gadget tasks.
749 #
750
751 def taskGadgetCreate(self, iGadgetType, iGadgetAccess):
752 """Creates a new gadget on UTS"""
753 fRc = self.sendMsg("GDGTCRT", (iGadgetType, iGadgetAccess, 0, 0));
754 if fRc is True:
755 fRc = self.recvAckLogged("GDGTCRT");
756 return fRc;
757
758 def taskGadgetDestroy(self, iGadgetId):
759 """Destroys the given gadget handle on UTS"""
760 fRc = self.sendMsg("GDGTDTOR", (iGadgetId, zeroByteArray(12)));
761 if fRc is True:
762 fRc = self.recvAckLogged("GDGTDTOR");
763 return fRc;
764
765 def taskGadgetConnect(self, iGadgetId):
766 """Connects the given gadget handle on UTS"""
767 fRc = self.sendMsg("GDGTCNCT", (iGadgetId, zeroByteArray(12)));
768 if fRc is True:
769 fRc = self.recvAckLogged("GDGTCNCT");
770 return fRc;
771
772 def taskGadgetDisconnect(self, iGadgetId):
773 """Disconnects the given gadget handle from UTS"""
774 fRc = self.sendMsg("GDGTDCNT", (iGadgetId, zeroByteArray(12)));
775 if fRc is True:
776 fRc = self.recvAckLogged("GDGTDCNT");
777 return fRc;
778
779 #
780 # Public methods - generic task queries
781 #
782
783 def isSuccess(self):
784 """Returns True if the task completed successfully, otherwise False."""
785 self.lockTask();
786 sStatus = self.sStatus;
787 oTaskRc = self.oTaskRc;
788 self.unlockTask();
789 if sStatus != "":
790 return False;
791 if oTaskRc is False or oTaskRc is None:
792 return False;
793 return True;
794
795 def getResult(self):
796 """
797 Returns the result of a completed task.
798 Returns None if not completed yet or no previous task.
799 """
800 self.lockTask();
801 sStatus = self.sStatus;
802 oTaskRc = self.oTaskRc;
803 self.unlockTask();
804 if sStatus != "":
805 return None;
806 return oTaskRc;
807
808 def getLastReply(self):
809 """
810 Returns the last reply three-tuple: cbMsg, sOpcode, abPayload.
811 Returns a None, None, None three-tuple if there was no last reply.
812 """
813 self.lockTask();
814 t3oReply = self.t3oReply;
815 self.unlockTask();
816 return t3oReply;
817
818 #
819 # Public methods - connection.
820 #
821
822 def asyncDisconnect(self, cMsTimeout = 30000, fIgnoreErrors = False):
823 """
824 Initiates a disconnect task.
825
826 Returns True on success, False on failure (logged).
827
828 The task returns True on success and False on failure.
829 """
830 return self.startTask(cMsTimeout, fIgnoreErrors, "bye", self.taskBye);
831
832 def syncDisconnect(self, cMsTimeout = 30000, fIgnoreErrors = False):
833 """Synchronous version."""
834 return self.asyncToSync(self.asyncDisconnect, cMsTimeout, fIgnoreErrors);
835
836 #
837 # Public methods - gadget API
838 #
839
840 def asyncGadgetCreate(self, iGadgetType, iGadgetAccess, cMsTimeout = 30000, fIgnoreErrors = False):
841 """
842 Initiates a gadget create task.
843
844 Returns True on success, False on failure (logged).
845
846 The task returns True on success and False on failure.
847 """
848 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetCreate", self.taskGadgetCreate, \
849 (iGadgetType, iGadgetAccess));
850
851 def syncGadgetCreate(self, iGadgetType, iGadgetAccess, cMsTimeout = 30000, fIgnoreErrors = False):
852 """Synchronous version."""
853 return self.asyncToSync(self.asyncGadgetCreate, iGadgetType, iGadgetAccess, cMsTimeout, fIgnoreErrors);
854
855 def asyncGadgetDestroy(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
856 """
857 Initiates a gadget destroy task.
858
859 Returns True on success, False on failure (logged).
860
861 The task returns True on success and False on failure.
862 """
863 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetDestroy", self.taskGadgetDestroy, \
864 (iGadgetId, ));
865
866 def syncGadgetDestroy(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
867 """Synchronous version."""
868 return self.asyncToSync(self.asyncGadgetDestroy, iGadgetId, cMsTimeout, fIgnoreErrors);
869
870 def asyncGadgetConnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
871 """
872 Initiates a gadget connect task.
873
874 Returns True on success, False on failure (logged).
875
876 The task returns True on success and False on failure.
877 """
878 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetConnect", self.taskGadgetConnect, \
879 (iGadgetId, ));
880
881 def syncGadgetConnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
882 """Synchronous version."""
883 return self.asyncToSync(self.asyncGadgetConnect, iGadgetId, cMsTimeout, fIgnoreErrors);
884
885 def asyncGadgetDisconnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
886 """
887 Initiates a gadget disconnect task.
888
889 Returns True on success, False on failure (logged).
890
891 The task returns True on success and False on failure.
892 """
893 return self.startTask(cMsTimeout, fIgnoreErrors, "GadgetDisconnect", self.taskGadgetDisconnect, \
894 (iGadgetId, ));
895
896 def syncGadgetDisconnect(self, iGadgetId, cMsTimeout = 30000, fIgnoreErrors = False):
897 """Synchronous version."""
898 return self.asyncToSync(self.asyncGadgetDisconnect, iGadgetId, cMsTimeout, fIgnoreErrors);
899
900
901class TransportTcp(TransportBase):
902 """
903 TCP transport layer for the UTS client session class.
904 """
905
906 def __init__(self, sHostname, uPort):
907 """
908 Save the parameters. The session will call us back to make the
909 connection later on its worker thread.
910 """
911 TransportBase.__init__(self, utils.getCallerName());
912 self.sHostname = sHostname;
913 self.uPort = uPort if uPort is not None else 6042;
914 self.oSocket = None;
915 self.oWakeupW = None;
916 self.oWakeupR = None;
917 self.fConnectCanceled = False;
918 self.fIsConnecting = False;
919 self.oCv = threading.Condition();
920 self.abReadAhead = array.array('B');
921
922 def toString(self):
923 return '<%s sHostname=%s, uPort=%s, oSocket=%s,'\
924 ' fConnectCanceled=%s, fIsConnecting=%s, oCv=%s, abReadAhead=%s>' \
925 % (TransportBase.toString(self), self.sHostname, self.uPort, self.oSocket,
926 self.fConnectCanceled, self.fIsConnecting, self.oCv, self.abReadAhead);
927
928 def __isInProgressXcpt(self, oXcpt):
929 """ In progress exception? """
930 try:
931 if isinstance(oXcpt, socket.error):
932 try:
933 if oXcpt[0] == errno.EINPROGRESS:
934 return True;
935 except: pass;
936 # Windows?
937 try:
938 if oXcpt[0] == errno.EWOULDBLOCK:
939 return True;
940 except: pass;
941 except:
942 pass;
943 return False;
944
945 def __isWouldBlockXcpt(self, oXcpt):
946 """ Would block exception? """
947 try:
948 if isinstance(oXcpt, socket.error):
949 try:
950 if oXcpt[0] == errno.EWOULDBLOCK:
951 return True;
952 except: pass;
953 try:
954 if oXcpt[0] == errno.EAGAIN:
955 return True;
956 except: pass;
957 except:
958 pass;
959 return False;
960
961 def __isConnectionReset(self, oXcpt):
962 """ Connection reset by Peer or others. """
963 try:
964 if isinstance(oXcpt, socket.error):
965 try:
966 if oXcpt[0] == errno.ECONNRESET:
967 return True;
968 except: pass;
969 try:
970 if oXcpt[0] == errno.ENETRESET:
971 return True;
972 except: pass;
973 except:
974 pass;
975 return False;
976
977 def _closeWakeupSockets(self):
978 """ Closes the wakup sockets. Caller should own the CV. """
979 oWakeupR = self.oWakeupR;
980 self.oWakeupR = None;
981 if oWakeupR is not None:
982 oWakeupR.close();
983
984 oWakeupW = self.oWakeupW;
985 self.oWakeupW = None;
986 if oWakeupW is not None:
987 oWakeupW.close();
988
989 return None;
990
991 def cancelConnect(self):
992 # This is bad stuff.
993 self.oCv.acquire();
994 reporter.log2('TransportTcp::cancelConnect: fIsConnecting=%s oSocket=%s' % (self.fIsConnecting, self.oSocket));
995 self.fConnectCanceled = True;
996 if self.fIsConnecting:
997 oSocket = self.oSocket;
998 self.oSocket = None;
999 if oSocket is not None:
1000 reporter.log2('TransportTcp::cancelConnect: closing the socket');
1001 oSocket.close();
1002
1003 oWakeupW = self.oWakeupW;
1004 self.oWakeupW = None;
1005 if oWakeupW is not None:
1006 reporter.log2('TransportTcp::cancelConnect: wakeup call');
1007 try: oWakeupW.send('cancelled!\n');
1008 except: reporter.logXcpt();
1009 try: oWakeupW.shutdown(socket.SHUT_WR);
1010 except: reporter.logXcpt();
1011 oWakeupW.close();
1012 self.oCv.release();
1013
1014 def _connectAsClient(self, oSocket, oWakeupR, cMsTimeout):
1015 """ Connects to the UTS server as client. """
1016
1017 # Connect w/ timeouts.
1018 rc = None;
1019 try:
1020 oSocket.connect((self.sHostname, self.uPort));
1021 rc = True;
1022 except socket.error, e:
1023 iRc = e[0];
1024 if self.__isInProgressXcpt(e):
1025 # Do the actual waiting.
1026 reporter.log2('TransportTcp::connect: operation in progress (%s)...' % (e,));
1027 try:
1028 ttRc = select.select([oWakeupR], [oSocket], [oSocket, oWakeupR], cMsTimeout / 1000.0);
1029 if len(ttRc[1]) + len(ttRc[2]) == 0:
1030 raise socket.error(errno.ETIMEDOUT, 'select timed out');
1031 iRc = oSocket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR);
1032 rc = iRc == 0;
1033 except socket.error, e:
1034 iRc = e[0];
1035 except:
1036 iRc = -42;
1037 reporter.fatalXcpt('socket.select() on connect failed');
1038
1039 if rc is True:
1040 pass;
1041 elif iRc == errno.ECONNREFUSED \
1042 or iRc == errno.EHOSTUNREACH \
1043 or iRc == errno.EINTR \
1044 or iRc == errno.ENETDOWN \
1045 or iRc == errno.ENETUNREACH \
1046 or iRc == errno.ETIMEDOUT:
1047 rc = False; # try again.
1048 else:
1049 if iRc != errno.EBADF or not self.fConnectCanceled:
1050 reporter.fatalXcpt('socket.connect((%s,%s)) failed; iRc=%s' % (self.sHostname, self.uPort, iRc));
1051 reporter.log2('TransportTcp::connect: rc=%s iRc=%s' % (rc, iRc));
1052 except:
1053 reporter.fatalXcpt('socket.connect((%s,%s)) failed' % (self.sHostname, self.uPort));
1054 return rc;
1055
1056
1057 def connect(self, cMsTimeout):
1058 # Create a non-blocking socket.
1059 reporter.log2('TransportTcp::connect: cMsTimeout=%s sHostname=%s uPort=%s' % (cMsTimeout, self.sHostname, self.uPort));
1060 try:
1061 oSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0);
1062 except:
1063 reporter.fatalXcpt('socket.socket() failed');
1064 return None;
1065 try:
1066 oSocket.setblocking(0);
1067 except:
1068 oSocket.close();
1069 reporter.fatalXcpt('socket.socket() failed');
1070 return None;
1071
1072 # Create wakeup socket pair for unix (select doesn't wake up on socket close on Linux).
1073 oWakeupR = None;
1074 oWakeupW = None;
1075 if hasattr(socket, 'socketpair'):
1076 try: (oWakeupR, oWakeupW) = socket.socketpair(); # pylint: disable=E1101
1077 except: reporter.logXcpt('socket.socketpair() failed');
1078
1079 # Update the state.
1080 self.oCv.acquire();
1081 rc = None;
1082 if not self.fConnectCanceled:
1083 self.oSocket = oSocket;
1084 self.oWakeupW = oWakeupW;
1085 self.oWakeupR = oWakeupR;
1086 self.fIsConnecting = True;
1087 self.oCv.release();
1088
1089 # Try connect.
1090 if oWakeupR is None:
1091 oWakeupR = oSocket; # Avoid select failure.
1092 rc = self._connectAsClient(oSocket, oWakeupR, cMsTimeout);
1093 oSocket = None;
1094
1095 # Update the state and cleanup on failure/cancel.
1096 self.oCv.acquire();
1097 if rc is True and self.fConnectCanceled:
1098 rc = False;
1099 self.fIsConnecting = False;
1100
1101 if rc is not True:
1102 if self.oSocket is not None:
1103 self.oSocket.close();
1104 self.oSocket = None;
1105 self._closeWakeupSockets();
1106 self.oCv.release();
1107
1108 reporter.log2('TransportTcp::connect: returning %s' % (rc,));
1109 return rc;
1110
1111 def disconnect(self, fQuiet = False):
1112 if self.oSocket is not None:
1113 self.abReadAhead = array.array('B');
1114
1115 # Try a shutting down the socket gracefully (draining it).
1116 try:
1117 self.oSocket.shutdown(socket.SHUT_WR);
1118 except:
1119 if not fQuiet:
1120 reporter.error('shutdown(SHUT_WR)');
1121 try:
1122 self.oSocket.setblocking(0); # just in case it's not set.
1123 sData = "1";
1124 while len(sData) > 0:
1125 sData = self.oSocket.recv(16384);
1126 except:
1127 pass;
1128
1129 # Close it.
1130 self.oCv.acquire();
1131 try: self.oSocket.setblocking(1);
1132 except: pass;
1133 self.oSocket.close();
1134 self.oSocket = None;
1135 else:
1136 self.oCv.acquire();
1137 self._closeWakeupSockets();
1138 self.oCv.release();
1139
1140 def sendBytes(self, abMsg, cMsTimeout):
1141 if self.oSocket is None:
1142 reporter.error('TransportTcp.sendBytes: No connection.');
1143 return False;
1144
1145 # Try send it all.
1146 try:
1147 cbSent = self.oSocket.send(abMsg);
1148 if cbSent == len(abMsg):
1149 return True;
1150 except Exception, oXcpt:
1151 if not self.__isWouldBlockXcpt(oXcpt):
1152 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1153 return False;
1154 cbSent = 0;
1155
1156 # Do a timed send.
1157 msStart = base.timestampMilli();
1158 while True:
1159 cMsElapsed = base.timestampMilli() - msStart;
1160 if cMsElapsed > cMsTimeout:
1161 reporter.error('TranportTcp.sendBytes: %s bytes timed out (1)' % (len(abMsg)));
1162 break;
1163
1164 # wait.
1165 try:
1166 ttRc = select.select([], [self.oSocket], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1167 if len(ttRc[2]) > 0 and len(ttRc[1]) == 0:
1168 reporter.error('TranportTcp.sendBytes: select returned with exception');
1169 break;
1170 if len(ttRc[1]) == 0:
1171 reporter.error('TranportTcp.sendBytes: %s bytes timed out (2)' % (len(abMsg)));
1172 break;
1173 except:
1174 reporter.errorXcpt('TranportTcp.sendBytes: select failed');
1175 break;
1176
1177 # Try send more.
1178 try:
1179 cbSent += self.oSocket.send(abMsg[cbSent:]);
1180 if cbSent == len(abMsg):
1181 return True;
1182 except Exception, oXcpt:
1183 if not self.__isWouldBlockXcpt(oXcpt):
1184 reporter.errorXcpt('TranportTcp.sendBytes: %s bytes' % (len(abMsg)));
1185 break;
1186
1187 return False;
1188
1189 def __returnReadAheadBytes(self, cb):
1190 """ Internal worker for recvBytes. """
1191 assert(len(self.abReadAhead) >= cb);
1192 abRet = self.abReadAhead[:cb];
1193 self.abReadAhead = self.abReadAhead[cb:];
1194 return abRet;
1195
1196 def recvBytes(self, cb, cMsTimeout, fNoDataOk):
1197 if self.oSocket is None:
1198 reporter.error('TransportTcp.recvBytes(%s,%s): No connection.' % (cb, cMsTimeout));
1199 return None;
1200
1201 # Try read in some more data without bothering with timeout handling first.
1202 if len(self.abReadAhead) < cb:
1203 try:
1204 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1205 if len(abBuf) > 0:
1206 self.abReadAhead.extend(array.array('B', abBuf));
1207 except Exception, oXcpt:
1208 if not self.__isWouldBlockXcpt(oXcpt):
1209 reporter.errorXcpt('TranportTcp.recvBytes: 0/%s bytes' % (cb,));
1210 return None;
1211
1212 if len(self.abReadAhead) >= cb:
1213 return self.__returnReadAheadBytes(cb);
1214
1215 # Timeout loop.
1216 msStart = base.timestampMilli();
1217 while True:
1218 cMsElapsed = base.timestampMilli() - msStart;
1219 if cMsElapsed > cMsTimeout:
1220 if not fNoDataOk or len(self.abReadAhead) > 0:
1221 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (1)' % (len(self.abReadAhead), cb));
1222 break;
1223
1224 # Wait.
1225 try:
1226 ttRc = select.select([self.oSocket], [], [self.oSocket], (cMsTimeout - cMsElapsed) / 1000.0);
1227 if len(ttRc[2]) > 0 and len(ttRc[0]) == 0:
1228 reporter.error('TranportTcp.recvBytes: select returned with exception');
1229 break;
1230 if len(ttRc[0]) == 0:
1231 if not fNoDataOk or len(self.abReadAhead) > 0:
1232 reporter.error('TranportTcp.recvBytes: %s/%s bytes timed out (2) fNoDataOk=%s'
1233 % (len(self.abReadAhead), cb, fNoDataOk));
1234 break;
1235 except:
1236 reporter.errorXcpt('TranportTcp.recvBytes: select failed');
1237 break;
1238
1239 # Try read more.
1240 try:
1241 abBuf = self.oSocket.recv(cb - len(self.abReadAhead));
1242 if len(abBuf) == 0:
1243 reporter.error('TranportTcp.recvBytes: %s/%s bytes (%s) - connection has been shut down'
1244 % (len(self.abReadAhead), cb, fNoDataOk));
1245 self.disconnect();
1246 return None;
1247
1248 self.abReadAhead.extend(array.array('B', abBuf));
1249
1250 except Exception, oXcpt:
1251 reporter.log('recv => exception %s' % (oXcpt,));
1252 if not self.__isWouldBlockXcpt(oXcpt):
1253 if not fNoDataOk or not self.__isConnectionReset(oXcpt) or len(self.abReadAhead) > 0:
1254 reporter.errorXcpt('TranportTcp.recvBytes: %s/%s bytes (%s)' % (len(self.abReadAhead), cb, fNoDataOk));
1255 break;
1256
1257 # Done?
1258 if len(self.abReadAhead) >= cb:
1259 return self.__returnReadAheadBytes(cb);
1260
1261 #reporter.log('recv => None len(self.abReadAhead) -> %d' % (len(self.abReadAhead), ));
1262 return None;
1263
1264 def isConnectionOk(self):
1265 if self.oSocket is None:
1266 return False;
1267 try:
1268 ttRc = select.select([], [], [self.oSocket], 0.0);
1269 if len(ttRc[2]) > 0:
1270 return False;
1271
1272 self.oSocket.send(array.array('B')); # send zero bytes.
1273 except:
1274 return False;
1275 return True;
1276
1277 def isRecvPending(self, cMsTimeout = 0):
1278 try:
1279 ttRc = select.select([self.oSocket], [], [], cMsTimeout / 1000.0);
1280 if len(ttRc[0]) == 0:
1281 return False;
1282 except:
1283 pass;
1284 return True;
1285
1286
1287class UsbGadget(object):
1288 """
1289 USB Gadget control class using the USBT Test Service to talk to the external
1290 board behaving like a USB device.
1291 """
1292
1293 def __init__(self):
1294 self.oUtsSession = None;
1295 self.sImpersonation = g_ksGadgetImpersonationInvalid;
1296 self.idGadget = None;
1297 self.iBusId = None;
1298 self.iDevId = None;
1299 self.iUsbIpPort = None;
1300
1301 def clearImpersonation(self):
1302 """
1303 Removes the current impersonation of the gadget.
1304 """
1305 fRc = True;
1306
1307 if self.idGadget is not None:
1308 fRc = self.oUtsSession.syncGadgetDestroy(self.idGadget);
1309 self.idGadget = None;
1310 self.iBusId = None;
1311 self.iDevId = None;
1312
1313 return fRc;
1314
1315 def disconnectUsb(self):
1316 """
1317 Disconnects the USB gadget from the host. (USB connection not network
1318 connection used for control)
1319 """
1320 return self.oUtsSession.syncGadgetDisconnect(self.idGadget);
1321
1322 def connectUsb(self):
1323 """
1324 Connect the USB gadget to the host.
1325 """
1326 return self.oUtsSession.syncGadgetConnect(self.idGadget);
1327
1328 def impersonate(self, sImpersonation):
1329 """
1330 Impersonate a given device.
1331 """
1332
1333 # Clear any previous impersonation
1334 self.clearImpersonation();
1335 self.sImpersonation = sImpersonation;
1336
1337 fRc = False;
1338 if sImpersonation == g_ksGadgetImpersonationTest:
1339 fDone = self.oUtsSession.syncGadgetCreate(g_kiGadgetTypeTest, g_kiGadgetAccessUsbIp);
1340 if fDone is True and self.oUtsSession.isSuccess():
1341 # Get the gadget ID.
1342 _, _, abPayload = self.oUtsSession.getLastReply();
1343
1344 fRc = True;
1345 self.idGadget = getU32(abPayload, 16);
1346 self.iBusId = getU32(abPayload, 20);
1347 self.iDevId = getU32(abPayload, 24);
1348 else:
1349 reporter.log('Invalid or unsupported impersonation');
1350
1351 return fRc;
1352
1353 def getUsbIpPort(self):
1354 """
1355 Returns the port the USB/IP server is listening on if requested,
1356 None if USB/IP is not supported.
1357 """
1358 return self.iUsbIpPort;
1359
1360 def getGadgetBusAndDevId(self):
1361 """
1362 Returns the bus ad device ID of the gadget as a tuple.
1363 """
1364 return (self.iBusId, self.iDevId);
1365
1366 def connectTo(self, cMsTimeout, sHostname, uPort = None, fUsbIpSupport = True, cMsIdleFudge = 0):
1367 """
1368 Connects to the specified target device.
1369 Returns True on Success.
1370 Returns False otherwise.
1371 """
1372 fRc = True;
1373
1374 reporter.log2('openTcpSession(%s, %s, %s, %s)' % \
1375 (cMsTimeout, sHostname, uPort, cMsIdleFudge));
1376 try:
1377 oTransport = TransportTcp(sHostname, uPort);
1378 self.oUtsSession = Session(oTransport, cMsTimeout, cMsIdleFudge);
1379
1380 if self.oUtsSession is not None:
1381 fDone = self.oUtsSession.waitForTask(30*1000);
1382 print 'connect: waitForTask -> %s, result %s' % (fDone, self.oUtsSession.getResult());
1383 if fDone is True and self.oUtsSession.isSuccess():
1384 # Parse the reply.
1385 _, _, abPayload = self.oUtsSession.getLastReply();
1386
1387 if getU32(abPayload, 20) is g_kiGadgetAccessUsbIp:
1388 fRc = True;
1389 self.iUsbIpPort = getU32(abPayload, 24);
1390 else:
1391 reporter.log('Gadget doesn\'t support access over USB/IP despite being requested');
1392 fRc = False;
1393 else:
1394 fRc = False;
1395 else:
1396 fRc = False;
1397 except:
1398 reporter.errorXcpt(None, 15);
1399 return False;
1400
1401 return fRc;
1402
1403 def disconnectFrom(self):
1404 """
1405 Disconnects from the target device.
1406 """
1407 fRc = True;
1408
1409 self.clearImpersonation();
1410 if self.oUtsSession is not None:
1411 fRc = self.oUtsSession.syncDisconnect();
1412
1413 return fRc;
1414
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