summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--patches/libusb-add-zlp-flag.patch24
-rw-r--r--patches/valgrind-usbdevfs.patch133
-rw-r--r--python-client/tcprelay.py146
-rw-r--r--python-client/usbmux.py240
4 files changed, 543 insertions, 0 deletions
diff --git a/patches/libusb-add-zlp-flag.patch b/patches/libusb-add-zlp-flag.patch
new file mode 100644
index 0000000..add9f97
--- /dev/null
+++ b/patches/libusb-add-zlp-flag.patch
@@ -0,0 +1,24 @@
1diff -ur libusb-1.0.0/libusb/os/linux_usbfs.c libusb-1.0.0-mod/libusb/os/linux_usbfs.c
2--- libusb-1.0.0/libusb/os/linux_usbfs.c 2008-12-13 20:43:20.000000000 +0100
3+++ libusb-1.0.0-mod/libusb/os/linux_usbfs.c 2009-04-30 04:25:12.000000000 +0200
4@@ -1295,7 +1295,8 @@
5 urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH;
6 else
7 urb->buffer_length = MAX_BULK_BUFFER_LENGTH;
8-
9+ if ((!(transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK)) && (i == num_urbs - 1))
10+ urb->flags = USBFS_URB_ZLP;
11 r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
12 if (r < 0) {
13 int j;
14diff -ur libusb-1.0.0/libusb/os/linux_usbfs.h libusb-1.0.0-mod/libusb/os/linux_usbfs.h
15--- libusb-1.0.0/libusb/os/linux_usbfs.h 2008-07-16 16:17:57.000000000 +0200
16+++ libusb-1.0.0-mod/libusb/os/linux_usbfs.h 2009-04-30 04:08:27.000000000 +0200
17@@ -63,6 +63,7 @@
18 #define USBFS_URB_DISABLE_SPD 1
19 #define USBFS_URB_ISO_ASAP 2
20 #define USBFS_URB_QUEUE_BULK 0x10
21+#define USBFS_URB_ZLP 0x40
22
23 enum usbfs_urb_type {
24 USBFS_URB_TYPE_ISO = 0,
diff --git a/patches/valgrind-usbdevfs.patch b/patches/valgrind-usbdevfs.patch
new file mode 100644
index 0000000..9287573
--- /dev/null
+++ b/patches/valgrind-usbdevfs.patch
@@ -0,0 +1,133 @@
1diff -ur -x '*~' valgrind-3.4.1/coregrind/m_syswrap/syswrap-generic.c valgrind-3.4.1-mod/coregrind/m_syswrap/syswrap-generic.c
2--- valgrind-3.4.1/coregrind/m_syswrap/syswrap-generic.c 2009-03-01 23:01:09.000000000 +0100
3+++ valgrind-3.4.1-mod/coregrind/m_syswrap/syswrap-generic.c 2009-04-29 15:44:08.000000000 +0200
4@@ -4160,23 +4160,56 @@
5 struct vki_usbdevfs_urb *vkuu = (struct vki_usbdevfs_urb *)ARG3;
6
7 /* Not the whole struct needs to be initialized */
8- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).ep", (Addr)&vkuu->endpoint, sizeof(vkuu->endpoint));
9+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).endpoint", (Addr)&vkuu->endpoint, sizeof(vkuu->endpoint));
10 PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).type", (Addr)&vkuu->type, sizeof(vkuu->type));
11 PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).flags", (Addr)&vkuu->flags, sizeof(vkuu->flags));
12 PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)&vkuu->buffer, sizeof(vkuu->buffer));
13- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
14- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).usercontext", (Addr)&vkuu->usercontext, sizeof(vkuu->usercontext));
15- if (vkuu->endpoint & 0x80)
16- PRE_MEM_WRITE( "ioctl(USBDEVFS_URB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
17- else
18- PRE_MEM_READ( "ioctl(USBDEVFS_URB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
19- /* FIXME: Does not handle all cases this ioctl can do, ISOs are missing. */
20+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).signr", (Addr)&vkuu->signr, sizeof(vkuu->signr));
21+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).status", (Addr)&vkuu->status, sizeof(vkuu->status));
22+ if (vkuu->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
23+ struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)vkuu->buffer;
24+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
25+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.setup_packet", (Addr)vkusp, sizeof(*vkusp));
26+ if (vkusp->bRequestType & 0x80)
27+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
28+ else
29+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
30+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
31+ } else if (vkuu->type == VKI_USBDEVFS_URB_TYPE_ISO) {
32+ int total_length = 0;
33+ int i;
34+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).number_of_packets", (Addr)&vkuu->number_of_packets, sizeof(vkuu->number_of_packets));
35+ for(i=0; i<vkuu->number_of_packets; i++) {
36+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].length", (Addr)&vkuu->iso_frame_desc[i].length, sizeof(vkuu->iso_frame_desc[i].length));
37+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].actual_length", (Addr)&vkuu->iso_frame_desc[i].actual_length, sizeof(vkuu->iso_frame_desc[i].actual_length));
38+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].status", (Addr)&vkuu->iso_frame_desc[i].status, sizeof(vkuu->iso_frame_desc[i].status));
39+ total_length += vkuu->iso_frame_desc[i].length;
40+ }
41+ if (vkuu->endpoint & 0x80)
42+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
43+ else
44+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
45+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).error_count", (Addr)&vkuu->error_count, sizeof(vkuu->error_count));
46+ } else {
47+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
48+ if (vkuu->endpoint & 0x80)
49+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
50+ else
51+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
52+ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
53+ }
54 break;
55 }
56+ case VKI_USBDEVFS_DISCARDURB:
57+ break;
58 case VKI_USBDEVFS_REAPURB:
59+ if ( ARG3 ) {
60+ PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURB)", ARG3, sizeof(struct vki_usbdevfs_urb **));
61+ break;
62+ }
63 case VKI_USBDEVFS_REAPURBNDELAY:
64 if ( ARG3 ) {
65- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB)", ARG3, sizeof(struct vki_usbdevfs_urb *));
66+ PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURBNDELAY)", ARG3, sizeof(struct vki_usbdevfs_urb **));
67 break;
68 }
69 case VKI_USBDEVFS_CONNECTINFO:
70@@ -4986,11 +5019,31 @@
71 case VKI_USBDEVFS_REAPURBNDELAY:
72 if ( ARG3 ) {
73 struct vki_usbdevfs_urb **vkuu = (struct vki_usbdevfs_urb**)ARG3;
74+ POST_MEM_WRITE((Addr)vkuu, sizeof(*vkuu));
75 if (!*vkuu)
76 break;
77 POST_MEM_WRITE((Addr) &((*vkuu)->status),sizeof((*vkuu)->status));
78- if ((*vkuu)->endpoint & 0x80)
79- POST_MEM_WRITE((Addr)(*vkuu)->buffer, (*vkuu)->actual_length);
80+ if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
81+ struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)(*vkuu)->buffer;
82+ if (vkusp->bRequestType & 0x80)
83+ POST_MEM_WRITE((Addr)(vkusp+1), (*vkuu)->buffer_length - sizeof(*vkusp));
84+ POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
85+ } else if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_ISO) {
86+ char *bp = (*vkuu)->buffer;
87+ int i;
88+ for(i=0; i<(*vkuu)->number_of_packets; i++) {
89+ POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].actual_length, sizeof((*vkuu)->iso_frame_desc[i].actual_length));
90+ POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].status, sizeof((*vkuu)->iso_frame_desc[i].status));
91+ if ((*vkuu)->endpoint & 0x80)
92+ POST_MEM_WRITE((Addr)bp, (*vkuu)->iso_frame_desc[i].actual_length);
93+ bp += (*vkuu)->iso_frame_desc[i].length; // FIXME: or actual_length??
94+ }
95+ POST_MEM_WRITE((Addr)&(*vkuu)->error_count, sizeof((*vkuu)->error_count));
96+ } else {
97+ if ((*vkuu)->endpoint & 0x80)
98+ POST_MEM_WRITE((Addr)(*vkuu)->buffer, (*vkuu)->actual_length);
99+ POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
100+ }
101 break;
102 }
103 case VKI_USBDEVFS_CONNECTINFO:
104diff -ur -x '*~' valgrind-3.4.1/include/vki/vki-linux.h valgrind-3.4.1-mod/include/vki/vki-linux.h
105--- valgrind-3.4.1/include/vki/vki-linux.h 2009-03-01 22:46:45.000000000 +0100
106+++ valgrind-3.4.1-mod/include/vki/vki-linux.h 2009-04-29 15:42:05.000000000 +0200
107@@ -2325,11 +2325,26 @@
108 #define VKI_USBDEVFS_BULK _VKI_IOWR('U', 2, struct vki_usbdevfs_bulktransfer)
109 #define VKI_USBDEVFS_GETDRIVER _VKI_IOW('U', 8, struct vki_usbdevfs_getdriver)
110 #define VKI_USBDEVFS_SUBMITURB _VKI_IOR('U', 10, struct vki_usbdevfs_urb)
111+#define VKI_USBDEVFS_DISCARDURB _VKI_IO('U', 11)
112 #define VKI_USBDEVFS_REAPURB _VKI_IOW('U', 12, void *)
113 #define VKI_USBDEVFS_REAPURBNDELAY _VKI_IOW('U', 13, void *)
114 #define VKI_USBDEVFS_CONNECTINFO _VKI_IOW('U', 17, struct vki_usbdevfs_connectinfo)
115 #define VKI_USBDEVFS_IOCTL _VKI_IOWR('U', 18, struct vki_usbdevfs_ioctl)
116
117+#define VKI_USBDEVFS_URB_TYPE_ISO 0
118+#define VKI_USBDEVFS_URB_TYPE_INTERRUPT 1
119+#define VKI_USBDEVFS_URB_TYPE_CONTROL 2
120+#define VKI_USBDEVFS_URB_TYPE_BULK 3
121+
122+// this is missing in usbdevice_fs.h
123+struct vki_usbdevfs_setuppacket {
124+ __vki_u8 bRequestType;
125+ __vki_u8 bRequest;
126+ __vki_u16 wValue;
127+ __vki_u16 wIndex;
128+ __vki_u16 wLength;
129+};
130+
131 //----------------------------------------------------------------------
132 // From linux-2.6.20.1/include/linux/i2c.h
133 //----------------------------------------------------------------------
diff --git a/python-client/tcprelay.py b/python-client/tcprelay.py
new file mode 100644
index 0000000..3075fcb
--- /dev/null
+++ b/python-client/tcprelay.py
@@ -0,0 +1,146 @@
1#!/usr/bin/python
2#
3# tcprelay.py - TCP connection relay for usbmuxd
4#
5# Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 2 or version 3.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20import usbmux
21import SocketServer
22import select
23from optparse import OptionParser
24import sys
25import threading
26
27class SocketRelay(object):
28 def __init__(self, a, b, maxbuf=65535):
29 self.a = a
30 self.b = b
31 self.atob = ""
32 self.btoa = ""
33 self.maxbuf = maxbuf
34 def handle(self):
35 while True:
36 rlist = []
37 wlist = []
38 xlist = [self.a, self.b]
39 if self.atob:
40 wlist.append(self.b)
41 if self.btoa:
42 wlist.append(self.a)
43 if len(self.atob) < self.maxbuf:
44 rlist.append(self.a)
45 if len(self.btoa) < self.maxbuf:
46 rlist.append(self.b)
47 rlo, wlo, xlo = select.select(rlist, wlist, xlist)
48 if xlo:
49 return
50 if self.a in wlo:
51 n = self.a.send(self.btoa)
52 self.btoa = self.btoa[n:]
53 if self.b in wlo:
54 n = self.b.send(self.atob)
55 self.atob = self.atob[n:]
56 if self.a in rlo:
57 s = self.a.recv(self.maxbuf - len(self.atob))
58 if not s:
59 return
60 self.atob += s
61 if self.b in rlo:
62 s = self.b.recv(self.maxbuf - len(self.btoa))
63 if not s:
64 return
65 self.btoa += s
66 #print "Relay iter: %8d atob, %8d btoa, lists: %r %r %r"%(len(self.atob), len(self.btoa), rlo, wlo, xlo)
67
68class TCPRelay(SocketServer.BaseRequestHandler):
69 def handle(self):
70 print "Incoming connection to %d"%self.server.server_address[1]
71 mux = usbmux.USBMux("/tmp/usbmuxd")
72 print "Waiting for devices..."
73 if not mux.devices:
74 mux.process(1.0)
75 if not mux.devices:
76 print "No device found"
77 self.request.close()
78 return
79 dev = mux.devices[0]
80 print "Connecting to device %s"%str(dev)
81 dsock = mux.connect(dev, self.server.rport)
82 lsock = self.request
83 print "Connection established, relaying data"
84 try:
85 fwd = SocketRelay(dsock, lsock, self.server.bufsize * 1024)
86 fwd.handle()
87 finally:
88 dsock.close()
89 lsock.close()
90 print "Connection closed"
91
92class TCPServer(SocketServer.TCPServer):
93 allow_reuse_address = True
94
95class ThreadedTCPServer(SocketServer.ThreadingMixIn, TCPServer):
96 pass
97
98HOST = "localhost"
99
100parser = OptionParser(usage="usage: %prog [OPTIONS] RemotePort[:LocalPort] [RemotePort[:LocalPort]]...")
101parser.add_option("-t", "--threaded", dest='threaded', action='store_true', default=False, help="use threading to handle multiple connections at once")
102parser.add_option("-b", "--bufsize", dest='bufsize', action='store', metavar='KILOBYTES', type='int', default=128, help="specify buffer size for socket forwarding")
103
104options, args = parser.parse_args()
105
106serverclass = TCPServer
107if options.threaded:
108 serverclass = ThreadedTCPServer
109
110if len(args) == 0:
111 parser.print_help()
112 sys.exit(1)
113
114ports = []
115
116for arg in args:
117 try:
118 if ':' in arg:
119 rport, lport = arg.split(":")
120 rport = int(rport)
121 lport = int(lport)
122 ports.append((rport, lport))
123 else:
124 ports.append((int(arg), int(arg)))
125 except:
126 parser.print_help()
127 sys.exit(1)
128
129servers=[]
130
131for rport, lport in ports:
132 print "Forwarding local port %d to remote port %d"%(lport, rport)
133 server = serverclass((HOST, lport), TCPRelay)
134 server.rport = rport
135 server.bufsize = options.bufsize
136 servers.append(server)
137
138alive = True
139
140while alive:
141 try:
142 rl, wl, xl = select.select(servers, [], [])
143 for server in rl:
144 server.handle_request()
145 except:
146 alive = False
diff --git a/python-client/usbmux.py b/python-client/usbmux.py
new file mode 100644
index 0000000..172f326
--- /dev/null
+++ b/python-client/usbmux.py
@@ -0,0 +1,240 @@
1#!/usr/bin/python
2#
3# usbmux.py - usbmux client library for Python
4#
5# Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 2 or version 3.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20import socket, struct, select, sys
21
22try:
23 import plistlib
24 haveplist = True
25except:
26 haveplist = False
27
28class MuxError(Exception):
29 pass
30
31class MuxVersionError(MuxError):
32 pass
33
34class SafeStreamSocket:
35 def __init__(self, address, family):
36 self.sock = socket.socket(family, socket.SOCK_STREAM)
37 self.sock.connect(address)
38 def send(self, msg):
39 totalsent = 0
40 while totalsent < len(msg):
41 sent = self.sock.send(msg[totalsent:])
42 if sent == 0:
43 raise MuxError("socket connection broken")
44 totalsent = totalsent + sent
45 def recv(self, size):
46 msg = ''
47 while len(msg) < size:
48 chunk = self.sock.recv(size-len(msg))
49 if chunk == '':
50 raise MuxError("socket connection broken")
51 msg = msg + chunk
52 return msg
53
54class MuxDevice(object):
55 def __init__(self, devid, usbprod, serial, location):
56 self.devid = devid
57 self.usbprod = usbprod
58 self.serial = serial
59 self.location = location
60 def __str__(self):
61 return "<MuxDevice: ID %d ProdID 0x%04x Serial '%s' Location 0x%x>"%(self.devid, self.usbprod, self.serial, self.location)
62
63class BinaryProtocol(object):
64 TYPE_RESULT = 1
65 TYPE_CONNECT = 2
66 TYPE_LISTEN = 3
67 TYPE_DEVICE_ADD = 4
68 TYPE_DEVICE_REMOVE = 5
69 VERSION = 0
70 def __init__(self, socket):
71 self.socket = socket
72 self.connected = False
73
74 def _pack(self, req, payload):
75 if req == self.TYPE_CONNECT:
76 return struct.pack("IH", payload['DeviceID'], payload['PortNumber']) + "\x00\x00"
77 elif req == self.TYPE_LISTEN:
78 return ""
79 else:
80 raise ValueError("Invalid outgoing request type %d"%req)
81
82 def _unpack(self, resp, payload):
83 if resp == self.TYPE_RESULT:
84 return {'Number':struct.unpack("I", payload)[0]}
85 elif resp == self.TYPE_DEVICE_ADD:
86 devid, usbpid, serial, pad, location = struct.unpack("IH256sHI", payload)
87 serial = serial.split("\0")[0]
88 return {'DeviceID': devid, 'Properties': {'LocationID': location, 'SerialNumber': serial, 'ProductID': usbpid}}
89 elif resp == self.TYPE_DEVICE_REMOVE:
90 devid = struct.unpack("I", payload)[0]
91 return {'DeviceID': devid}
92 else:
93 raise MuxError("Invalid incoming request type %d"%req)
94
95 def sendpacket(self, req, tag, payload={}):
96 payload = self._pack(req, payload)
97 if self.connected:
98 raise MuxError("Mux is connected, cannot issue control packets")
99 length = 16 + len(payload)
100 data = struct.pack("IIII", length, self.VERSION, req, tag) + payload
101 self.socket.send(data)
102 def getpacket(self):
103 if self.connected:
104 raise MuxError("Mux is connected, cannot issue control packets")
105 dlen = self.socket.recv(4)
106 dlen = struct.unpack("I", dlen)[0]
107 body = self.socket.recv(dlen - 4)
108 version, resp, tag = struct.unpack("III",body[:0xc])
109 if version != self.VERSION:
110 raise MuxVersionError("Version mismatch: expected %d, got %d"%(self.VERSION,version))
111 payload = self._unpack(resp, body[0xc:])
112 return (resp, tag, payload)
113
114class PlistProtocol(BinaryProtocol):
115 TYPE_RESULT = "Result"
116 TYPE_CONNECT = "Connect"
117 TYPE_LISTEN = "Listen"
118 TYPE_DEVICE_ADD = "Attached"
119 TYPE_DEVICE_REMOVE = "Detached" #???
120 TYPE_PLIST = 8
121 VERSION = 1
122 def __init__(self, socket):
123 if not haveplist:
124 raise Exception("You need the plistlib module")
125 BinaryProtocol.__init__(self, socket)
126
127 def _pack(self, req, payload):
128 return payload
129
130 def _unpack(self, resp, payload):
131 return payload
132
133 def sendpacket(self, req, tag, payload={}):
134 payload['ClientVersionString'] = 'usbmux.py by marcan'
135 if isinstance(req, int):
136 req = [self.TYPE_CONNECT, self.TYPE_LISTEN][req-2]
137 payload['MessageType'] = req
138 payload['ProgName'] = 'tcprelay'
139 BinaryProtocol.sendpacket(self, self.TYPE_PLIST, tag, plistlib.writePlistToString(payload))
140 def getpacket(self):
141 resp, tag, payload = BinaryProtocol.getpacket(self)
142 if resp != self.TYPE_PLIST:
143 raise MuxError("Received non-plist type %d"%resp)
144 payload = plistlib.readPlistFromString(payload)
145 return payload['MessageType'], tag, payload
146
147class MuxConnection(object):
148 def __init__(self, socketpath, protoclass):
149 self.socketpath = socketpath
150 if sys.platform in ['win32', 'cygwin']:
151 family = socket.AF_INET
152 address = ('127.0.0.1', 27015)
153 else:
154 family = socket.AF_UNIX
155 address = self.socketpath
156 self.socket = SafeStreamSocket(address, family)
157 self.proto = protoclass(self.socket)
158 self.pkttag = 1
159 self.devices = []
160
161 def _getreply(self):
162 while True:
163 resp, tag, data = self.proto.getpacket()
164 if resp == self.proto.TYPE_RESULT:
165 return tag, data
166 else:
167 raise MuxError("Invalid packet type received: %d"%resp)
168 def _processpacket(self):
169 resp, tag, data = self.proto.getpacket()
170 if resp == self.proto.TYPE_DEVICE_ADD:
171 self.devices.append(MuxDevice(data['DeviceID'], data['Properties']['ProductID'], data['Properties']['SerialNumber'], data['Properties']['LocationID']))
172 elif resp == self.proto.TYPE_DEVICE_REMOVE:
173 for dev in self.devices:
174 if dev.devid == data['DeviceID']:
175 self.devices.remove(dev)
176 elif resp == self.proto.TYPE_RESULT:
177 raise MuxError("Unexpected result: %d"%resp)
178 else:
179 raise MuxError("Invalid packet type received: %d"%resp)
180 def _exchange(self, req, payload={}):
181 mytag = self.pkttag
182 self.pkttag += 1
183 self.proto.sendpacket(req, mytag, payload)
184 recvtag, data = self._getreply()
185 if recvtag != mytag:
186 raise MuxError("Reply tag mismatch: expected %d, got %d"%(mytag, recvtag))
187 return data['Number']
188
189 def listen(self):
190 ret = self._exchange(self.proto.TYPE_LISTEN)
191 if ret != 0:
192 raise MuxError("Listen failed: error %d"%ret)
193 def process(self, timeout=None):
194 if self.proto.connected:
195 raise MuxError("Socket is connected, cannot process listener events")
196 rlo, wlo, xlo = select.select([self.socket.sock], [], [self.socket.sock], timeout)
197 if xlo:
198 self.socket.sock.close()
199 raise MuxError("Exception in listener socket")
200 if rlo:
201 self._processpacket()
202 def connect(self, device, port):
203 ret = self._exchange(self.proto.TYPE_CONNECT, {'DeviceID':device.devid, 'PortNumber':((port<<8) & 0xFF00) | (port>>8)})
204 if ret != 0:
205 raise MuxError("Connect failed: error %d"%ret)
206 self.proto.connected = True
207 return self.socket.sock
208 def close(self):
209 self.socket.sock.close()
210
211class USBMux(object):
212 def __init__(self, socketpath="/tmp/usbmuxd"):
213 self.socketpath = socketpath
214 self.listener = MuxConnection(socketpath, BinaryProtocol)
215 try:
216 self.listener.listen()
217 self.version = 0
218 self.protoclass = BinaryProtocol
219 except MuxVersionError:
220 self.listener = MuxConnection(socketpath, PlistProtocol)
221 self.listener.listen()
222 self.protoclass = PlistProtocol
223 self.version = 1
224 self.devices = self.listener.devices
225 def process(self, timeout=None):
226 self.listener.process(timeout)
227 def connect(self, device, port):
228 connector = MuxConnection(self.socketpath, self.protoclass)
229 return connector.connect(device, port)
230
231if __name__ == "__main__":
232 mux = USBMux()
233 print "Waiting for devices..."
234 if not mux.devices:
235 mux.process(0.1)
236 while True:
237 print "Devices:"
238 for dev in mux.devices:
239 print dev
240 mux.process()