-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdeviceconnection.py
162 lines (119 loc) · 3.85 KB
/
deviceconnection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import SocketServer
import logging
from multiprocessing import Process, Manager, Event, log_to_stderr
from python_client import SocketRelay, ThreadedTCPServer, USBMux, MuxError
_LOGGER = log_to_stderr()
_JOIN_TIMEOUT = 5
class DeviceTCPRelay(SocketServer.BaseRequestHandler):
def handle(self):
if self.server.stopped():
return
if not self.server.muxdev:
_LOGGER.error("Device invalid")
self.request.close()
return
_LOGGER.debug("Connecting to device %s" % str(self.server.muxdev))
dsock = None
try:
dsock = self.server.mux.connect(self.server.muxdev, self.server.rport)
except MuxError:
_LOGGER.warning("Connection to device %s died!" % str(self.server.muxdev))
if self.request:
self.request.close()
return
lsock = self.request
_LOGGER.debug("Connection established, relaying data")
try:
fwd = SocketRelay(dsock, lsock)
#, self.server.bufsize * 1024)
fwd.handle()
finally:
dsock.close()
lsock.close()
_LOGGER.debug("Connection closed")
class DeviceServer(ThreadedTCPServer, Process):
#causes handle_request to return
timeout = 1
def __init__(self, mux, muxdevice, server_address, RequestHandlerClass):
Process.__init__(self)
ThreadedTCPServer.__init__(self, server_address, RequestHandlerClass)
self.mux = mux
self.muxdev = muxdevice
self._stop = Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.is_set()
def run(self):
if self.stopped():
_LOGGER.warning("Thread already stopped")
while not self.stopped():
self.handle_request()
self.socket.close()
_LOGGER.debug("%s will exit now" % (str(self)))
class DeviceConnectionHandler(Process):
def __init__(self):
super(DeviceConnectionHandler, self).__init__()
self._stop = Event()
self.manager = Manager()
# devices: dont read that field after start() (will be empty)
self.devices = {}
# a managed dict to sync changes between threads
self.device_id_map = self.manager.dict()
self.mux = USBMux()
def handle(self):
""" Start device handling. Will not return until calling stop() """
if not self.mux.devices:
self.mux.process(1.0)
while not self.stopped():
muxdevs = self.mux.devices
# print muxdevs
#create new device handlers
for dev in muxdevs:
if dev not in self.devices:
_LOGGER.info("New Device: %s" % str(dev))
# create device connection tunnel via usbmux
server = DeviceServer(self.mux, dev, ('localhost', 0), DeviceTCPRelay)
server.rport = 8080
server.start()
self.devices[dev] = server
self.device_id_map[dev.serial] = server.server_address
_LOGGER.debug("Serving device %s via %s" % (str(dev), server.server_address))
#remove invalid devices
for dev in self.devices.keys():
if dev not in muxdevs:
_LOGGER.info("Device gone: %s" % str(dev))
_LOGGER.debug("Server: %s" % server)
server.stop()
server.join(_JOIN_TIMEOUT)
_LOGGER.debug("Server stopped: %s" % server)
self.devices.pop(dev)
self.device_id_map.pop(dev.serial)
#check for new devices, ...
self.mux.process(0.1)
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.is_set()
def run(self):
self.handle()
_LOGGER.debug("stopping device servers...")
for server in self.devices.itervalues():
server.stop()
server.join(_JOIN_TIMEOUT)
_LOGGER.debug("%s will exit now" % (str(self)))
def device_connection_info(self, deviceUUID):
'''Returns a tuple of ip and port'''
if deviceUUID in self.device_id_map:
return self.device_id_map[deviceUUID]
else:
return None
_SHARED_DEVICE_HANDLER = None
def shared_device_handler():
global _SHARED_DEVICE_HANDLER
if not _SHARED_DEVICE_HANDLER:
_SHARED_DEVICE_HANDLER = DeviceConnectionHandler()
_SHARED_DEVICE_HANDLER.start()
import time
time.sleep(1)
return _SHARED_DEVICE_HANDLER