testing/marionette/transport/marionette_transport/transport.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import errno
michael@0 6 import json
michael@0 7 import socket
michael@0 8
michael@0 9
michael@0 10 class MarionetteTransport(object):
michael@0 11 """ The Marionette socket client. This speaks the same protocol
michael@0 12 as the remote debugger inside Gecko, in which messages are
michael@0 13 always preceded by the message length and a colon, e.g.,
michael@0 14
michael@0 15 20:{'command': 'test'}
michael@0 16 """
michael@0 17
michael@0 18 max_packet_length = 4096
michael@0 19 connection_lost_msg = "Connection to Marionette server is lost. Check gecko.log (desktop firefox) or logcat (b2g) for errors."
michael@0 20
michael@0 21 def __init__(self, addr, port):
michael@0 22 self.addr = addr
michael@0 23 self.port = port
michael@0 24 self.sock = None
michael@0 25 self.traits = None
michael@0 26 self.applicationType = None
michael@0 27 self.actor = 'root'
michael@0 28
michael@0 29 def _recv_n_bytes(self, n):
michael@0 30 """ Convenience method for receiving exactly n bytes from
michael@0 31 self.sock (assuming it's open and connected).
michael@0 32 """
michael@0 33 data = ''
michael@0 34 while len(data) < n:
michael@0 35 chunk = self.sock.recv(n - len(data))
michael@0 36 if chunk == '':
michael@0 37 break
michael@0 38 data += chunk
michael@0 39 return data
michael@0 40
michael@0 41 def receive(self):
michael@0 42 """ Receive the next complete response from the server, and return
michael@0 43 it as a dict. Each response from the server is prepended by
michael@0 44 len(message) + ':'.
michael@0 45 """
michael@0 46 assert(self.sock)
michael@0 47 response = self.sock.recv(10)
michael@0 48 sep = response.find(':')
michael@0 49 length = response[0:sep]
michael@0 50 if length != '':
michael@0 51 response = response[sep + 1:]
michael@0 52 response += self._recv_n_bytes(int(length) + 1 + len(length) - 10)
michael@0 53 return json.loads(response)
michael@0 54 else:
michael@0 55 raise IOError(self.connection_lost_msg)
michael@0 56
michael@0 57 def connect(self, timeout=360.0):
michael@0 58 """ Connect to the server and process the hello message we expect
michael@0 59 to receive in response.
michael@0 60 """
michael@0 61 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
michael@0 62 self.sock.settimeout(timeout)
michael@0 63 try:
michael@0 64 self.sock.connect((self.addr, self.port))
michael@0 65 except:
michael@0 66 # Unset self.sock so that the next attempt to send will cause
michael@0 67 # another connection attempt.
michael@0 68 self.sock = None
michael@0 69 raise
michael@0 70 hello = self.receive()
michael@0 71 self.traits = hello.get('traits')
michael@0 72 self.applicationType = hello.get('applicationType')
michael@0 73
michael@0 74 # get the marionette actor id
michael@0 75 response = self.send({'to': 'root', 'name': 'getMarionetteID'})
michael@0 76 self.actor = response['id']
michael@0 77
michael@0 78 def send(self, msg):
michael@0 79 """ Send a message on the socket, prepending it with len(msg) + ':'.
michael@0 80 """
michael@0 81 if not self.sock:
michael@0 82 self.connect()
michael@0 83 if 'to' not in msg:
michael@0 84 msg['to'] = self.actor
michael@0 85 data = json.dumps(msg)
michael@0 86 data = '%s:%s' % (len(data), data)
michael@0 87
michael@0 88 for packet in [data[i:i + self.max_packet_length] for i in
michael@0 89 range(0, len(data), self.max_packet_length)]:
michael@0 90 try:
michael@0 91 self.sock.send(packet)
michael@0 92 except IOError as e:
michael@0 93 if e.errno == errno.EPIPE:
michael@0 94 raise IOError("%s: %s" % (str(e)), self.connection_lost_msg)
michael@0 95 else:
michael@0 96 raise e
michael@0 97
michael@0 98 response = self.receive()
michael@0 99 return response
michael@0 100
michael@0 101 def close(self):
michael@0 102 """ Close the socket.
michael@0 103 """
michael@0 104 if self.sock:
michael@0 105 self.sock.close()
michael@0 106 self.sock = None

mercurial