summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Hector Martin2009-05-05 01:40:22 +0200
committerGravatar Hector Martin2009-05-05 01:40:22 +0200
commitdce2546afadd9185b7e65f1db6b127d6293b178c (patch)
tree956f7d1adbba68ca2db4ce7d8740e10be8f5f53b
parent78577f36b4fd92b052300e0b4d3b369d45b40e67 (diff)
downloadusbmuxd-dce2546afadd9185b7e65f1db6b127d6293b178c.tar.gz
usbmuxd-dce2546afadd9185b7e65f1db6b127d6293b178c.tar.bz2
Add python stuff and patches
-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 @@
+diff -ur libusb-1.0.0/libusb/os/linux_usbfs.c libusb-1.0.0-mod/libusb/os/linux_usbfs.c
+--- libusb-1.0.0/libusb/os/linux_usbfs.c 2008-12-13 20:43:20.000000000 +0100
++++ libusb-1.0.0-mod/libusb/os/linux_usbfs.c 2009-04-30 04:25:12.000000000 +0200
+@@ -1295,7 +1295,8 @@
+ urb->buffer_length = transfer->length % MAX_BULK_BUFFER_LENGTH;
+ else
+ urb->buffer_length = MAX_BULK_BUFFER_LENGTH;
+-
++ if ((!(transfer->endpoint & LIBUSB_ENDPOINT_DIR_MASK)) && (i == num_urbs - 1))
++ urb->flags = USBFS_URB_ZLP;
+ r = ioctl(dpriv->fd, IOCTL_USBFS_SUBMITURB, urb);
+ if (r < 0) {
+ int j;
+diff -ur libusb-1.0.0/libusb/os/linux_usbfs.h libusb-1.0.0-mod/libusb/os/linux_usbfs.h
+--- libusb-1.0.0/libusb/os/linux_usbfs.h 2008-07-16 16:17:57.000000000 +0200
++++ libusb-1.0.0-mod/libusb/os/linux_usbfs.h 2009-04-30 04:08:27.000000000 +0200
+@@ -63,6 +63,7 @@
+ #define USBFS_URB_DISABLE_SPD 1
+ #define USBFS_URB_ISO_ASAP 2
+ #define USBFS_URB_QUEUE_BULK 0x10
++#define USBFS_URB_ZLP 0x40
+
+ enum usbfs_urb_type {
+ 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 @@
+diff -ur -x '*~' valgrind-3.4.1/coregrind/m_syswrap/syswrap-generic.c valgrind-3.4.1-mod/coregrind/m_syswrap/syswrap-generic.c
+--- valgrind-3.4.1/coregrind/m_syswrap/syswrap-generic.c 2009-03-01 23:01:09.000000000 +0100
++++ valgrind-3.4.1-mod/coregrind/m_syswrap/syswrap-generic.c 2009-04-29 15:44:08.000000000 +0200
+@@ -4160,23 +4160,56 @@
+ struct vki_usbdevfs_urb *vkuu = (struct vki_usbdevfs_urb *)ARG3;
+
+ /* Not the whole struct needs to be initialized */
+- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).ep", (Addr)&vkuu->endpoint, sizeof(vkuu->endpoint));
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).endpoint", (Addr)&vkuu->endpoint, sizeof(vkuu->endpoint));
+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).type", (Addr)&vkuu->type, sizeof(vkuu->type));
+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).flags", (Addr)&vkuu->flags, sizeof(vkuu->flags));
+ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)&vkuu->buffer, sizeof(vkuu->buffer));
+- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
+- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).usercontext", (Addr)&vkuu->usercontext, sizeof(vkuu->usercontext));
+- if (vkuu->endpoint & 0x80)
+- PRE_MEM_WRITE( "ioctl(USBDEVFS_URB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
+- else
+- PRE_MEM_READ( "ioctl(USBDEVFS_URB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
+- /* FIXME: Does not handle all cases this ioctl can do, ISOs are missing. */
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).signr", (Addr)&vkuu->signr, sizeof(vkuu->signr));
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).status", (Addr)&vkuu->status, sizeof(vkuu->status));
++ if (vkuu->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
++ struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)vkuu->buffer;
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.setup_packet", (Addr)vkusp, sizeof(*vkusp));
++ if (vkusp->bRequestType & 0x80)
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
++ else
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer.data", (Addr)(vkusp+1), vkuu->buffer_length - sizeof(*vkusp));
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
++ } else if (vkuu->type == VKI_USBDEVFS_URB_TYPE_ISO) {
++ int total_length = 0;
++ int i;
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).number_of_packets", (Addr)&vkuu->number_of_packets, sizeof(vkuu->number_of_packets));
++ for(i=0; i<vkuu->number_of_packets; i++) {
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].length", (Addr)&vkuu->iso_frame_desc[i].length, sizeof(vkuu->iso_frame_desc[i].length));
++ 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));
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).iso_frame_desc[].status", (Addr)&vkuu->iso_frame_desc[i].status, sizeof(vkuu->iso_frame_desc[i].status));
++ total_length += vkuu->iso_frame_desc[i].length;
++ }
++ if (vkuu->endpoint & 0x80)
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
++ else
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, total_length);
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).error_count", (Addr)&vkuu->error_count, sizeof(vkuu->error_count));
++ } else {
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer_length", (Addr)&vkuu->buffer_length, sizeof(vkuu->buffer_length));
++ if (vkuu->endpoint & 0x80)
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
++ else
++ PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB).buffer", (Addr)vkuu->buffer, vkuu->buffer_length);
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_SUBMITURB).actual_length", (Addr)&vkuu->actual_length, sizeof(vkuu->actual_length));
++ }
+ break;
+ }
++ case VKI_USBDEVFS_DISCARDURB:
++ break;
+ case VKI_USBDEVFS_REAPURB:
++ if ( ARG3 ) {
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURB)", ARG3, sizeof(struct vki_usbdevfs_urb **));
++ break;
++ }
+ case VKI_USBDEVFS_REAPURBNDELAY:
+ if ( ARG3 ) {
+- PRE_MEM_READ( "ioctl(USBDEVFS_SUBMITURB)", ARG3, sizeof(struct vki_usbdevfs_urb *));
++ PRE_MEM_WRITE( "ioctl(USBDEVFS_REAPURBNDELAY)", ARG3, sizeof(struct vki_usbdevfs_urb **));
+ break;
+ }
+ case VKI_USBDEVFS_CONNECTINFO:
+@@ -4986,11 +5019,31 @@
+ case VKI_USBDEVFS_REAPURBNDELAY:
+ if ( ARG3 ) {
+ struct vki_usbdevfs_urb **vkuu = (struct vki_usbdevfs_urb**)ARG3;
++ POST_MEM_WRITE((Addr)vkuu, sizeof(*vkuu));
+ if (!*vkuu)
+ break;
+ POST_MEM_WRITE((Addr) &((*vkuu)->status),sizeof((*vkuu)->status));
+- if ((*vkuu)->endpoint & 0x80)
+- POST_MEM_WRITE((Addr)(*vkuu)->buffer, (*vkuu)->actual_length);
++ if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_CONTROL) {
++ struct vki_usbdevfs_setuppacket *vkusp = (struct vki_usbdevfs_setuppacket *)(*vkuu)->buffer;
++ if (vkusp->bRequestType & 0x80)
++ POST_MEM_WRITE((Addr)(vkusp+1), (*vkuu)->buffer_length - sizeof(*vkusp));
++ POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
++ } else if ((*vkuu)->type == VKI_USBDEVFS_URB_TYPE_ISO) {
++ char *bp = (*vkuu)->buffer;
++ int i;
++ for(i=0; i<(*vkuu)->number_of_packets; i++) {
++ POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].actual_length, sizeof((*vkuu)->iso_frame_desc[i].actual_length));
++ POST_MEM_WRITE((Addr)&(*vkuu)->iso_frame_desc[i].status, sizeof((*vkuu)->iso_frame_desc[i].status));
++ if ((*vkuu)->endpoint & 0x80)
++ POST_MEM_WRITE((Addr)bp, (*vkuu)->iso_frame_desc[i].actual_length);
++ bp += (*vkuu)->iso_frame_desc[i].length; // FIXME: or actual_length??
++ }
++ POST_MEM_WRITE((Addr)&(*vkuu)->error_count, sizeof((*vkuu)->error_count));
++ } else {
++ if ((*vkuu)->endpoint & 0x80)
++ POST_MEM_WRITE((Addr)(*vkuu)->buffer, (*vkuu)->actual_length);
++ POST_MEM_WRITE((Addr)&(*vkuu)->actual_length, sizeof((*vkuu)->actual_length));
++ }
+ break;
+ }
+ case VKI_USBDEVFS_CONNECTINFO:
+diff -ur -x '*~' valgrind-3.4.1/include/vki/vki-linux.h valgrind-3.4.1-mod/include/vki/vki-linux.h
+--- valgrind-3.4.1/include/vki/vki-linux.h 2009-03-01 22:46:45.000000000 +0100
++++ valgrind-3.4.1-mod/include/vki/vki-linux.h 2009-04-29 15:42:05.000000000 +0200
+@@ -2325,11 +2325,26 @@
+ #define VKI_USBDEVFS_BULK _VKI_IOWR('U', 2, struct vki_usbdevfs_bulktransfer)
+ #define VKI_USBDEVFS_GETDRIVER _VKI_IOW('U', 8, struct vki_usbdevfs_getdriver)
+ #define VKI_USBDEVFS_SUBMITURB _VKI_IOR('U', 10, struct vki_usbdevfs_urb)
++#define VKI_USBDEVFS_DISCARDURB _VKI_IO('U', 11)
+ #define VKI_USBDEVFS_REAPURB _VKI_IOW('U', 12, void *)
+ #define VKI_USBDEVFS_REAPURBNDELAY _VKI_IOW('U', 13, void *)
+ #define VKI_USBDEVFS_CONNECTINFO _VKI_IOW('U', 17, struct vki_usbdevfs_connectinfo)
+ #define VKI_USBDEVFS_IOCTL _VKI_IOWR('U', 18, struct vki_usbdevfs_ioctl)
+
++#define VKI_USBDEVFS_URB_TYPE_ISO 0
++#define VKI_USBDEVFS_URB_TYPE_INTERRUPT 1
++#define VKI_USBDEVFS_URB_TYPE_CONTROL 2
++#define VKI_USBDEVFS_URB_TYPE_BULK 3
++
++// this is missing in usbdevice_fs.h
++struct vki_usbdevfs_setuppacket {
++ __vki_u8 bRequestType;
++ __vki_u8 bRequest;
++ __vki_u16 wValue;
++ __vki_u16 wIndex;
++ __vki_u16 wLength;
++};
++
+ //----------------------------------------------------------------------
+ // From linux-2.6.20.1/include/linux/i2c.h
+ //----------------------------------------------------------------------
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 @@
+#!/usr/bin/python
+#
+# tcprelay.py - TCP connection relay for usbmuxd
+#
+# Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 or version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import usbmux
+import SocketServer
+import select
+from optparse import OptionParser
+import sys
+import threading
+
+class SocketRelay(object):
+ def __init__(self, a, b, maxbuf=65535):
+ self.a = a
+ self.b = b
+ self.atob = ""
+ self.btoa = ""
+ self.maxbuf = maxbuf
+ def handle(self):
+ while True:
+ rlist = []
+ wlist = []
+ xlist = [self.a, self.b]
+ if self.atob:
+ wlist.append(self.b)
+ if self.btoa:
+ wlist.append(self.a)
+ if len(self.atob) < self.maxbuf:
+ rlist.append(self.a)
+ if len(self.btoa) < self.maxbuf:
+ rlist.append(self.b)
+ rlo, wlo, xlo = select.select(rlist, wlist, xlist)
+ if xlo:
+ return
+ if self.a in wlo:
+ n = self.a.send(self.btoa)
+ self.btoa = self.btoa[n:]
+ if self.b in wlo:
+ n = self.b.send(self.atob)
+ self.atob = self.atob[n:]
+ if self.a in rlo:
+ s = self.a.recv(self.maxbuf - len(self.atob))
+ if not s:
+ return
+ self.atob += s
+ if self.b in rlo:
+ s = self.b.recv(self.maxbuf - len(self.btoa))
+ if not s:
+ return
+ self.btoa += s
+ #print "Relay iter: %8d atob, %8d btoa, lists: %r %r %r"%(len(self.atob), len(self.btoa), rlo, wlo, xlo)
+
+class TCPRelay(SocketServer.BaseRequestHandler):
+ def handle(self):
+ print "Incoming connection to %d"%self.server.server_address[1]
+ mux = usbmux.USBMux("/tmp/usbmuxd")
+ print "Waiting for devices..."
+ if not mux.devices:
+ mux.process(1.0)
+ if not mux.devices:
+ print "No device found"
+ self.request.close()
+ return
+ dev = mux.devices[0]
+ print "Connecting to device %s"%str(dev)
+ dsock = mux.connect(dev, self.server.rport)
+ lsock = self.request
+ print "Connection established, relaying data"
+ try:
+ fwd = SocketRelay(dsock, lsock, self.server.bufsize * 1024)
+ fwd.handle()
+ finally:
+ dsock.close()
+ lsock.close()
+ print "Connection closed"
+
+class TCPServer(SocketServer.TCPServer):
+ allow_reuse_address = True
+
+class ThreadedTCPServer(SocketServer.ThreadingMixIn, TCPServer):
+ pass
+
+HOST = "localhost"
+
+parser = OptionParser(usage="usage: %prog [OPTIONS] RemotePort[:LocalPort] [RemotePort[:LocalPort]]...")
+parser.add_option("-t", "--threaded", dest='threaded', action='store_true', default=False, help="use threading to handle multiple connections at once")
+parser.add_option("-b", "--bufsize", dest='bufsize', action='store', metavar='KILOBYTES', type='int', default=128, help="specify buffer size for socket forwarding")
+
+options, args = parser.parse_args()
+
+serverclass = TCPServer
+if options.threaded:
+ serverclass = ThreadedTCPServer
+
+if len(args) == 0:
+ parser.print_help()
+ sys.exit(1)
+
+ports = []
+
+for arg in args:
+ try:
+ if ':' in arg:
+ rport, lport = arg.split(":")
+ rport = int(rport)
+ lport = int(lport)
+ ports.append((rport, lport))
+ else:
+ ports.append((int(arg), int(arg)))
+ except:
+ parser.print_help()
+ sys.exit(1)
+
+servers=[]
+
+for rport, lport in ports:
+ print "Forwarding local port %d to remote port %d"%(lport, rport)
+ server = serverclass((HOST, lport), TCPRelay)
+ server.rport = rport
+ server.bufsize = options.bufsize
+ servers.append(server)
+
+alive = True
+
+while alive:
+ try:
+ rl, wl, xl = select.select(servers, [], [])
+ for server in rl:
+ server.handle_request()
+ except:
+ 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 @@
+#!/usr/bin/python
+#
+# usbmux.py - usbmux client library for Python
+#
+# Copyright (C) 2009 Hector Martin "marcan" <hector@marcansoft.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 or version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import socket, struct, select, sys
+
+try:
+ import plistlib
+ haveplist = True
+except:
+ haveplist = False
+
+class MuxError(Exception):
+ pass
+
+class MuxVersionError(MuxError):
+ pass
+
+class SafeStreamSocket:
+ def __init__(self, address, family):
+ self.sock = socket.socket(family, socket.SOCK_STREAM)
+ self.sock.connect(address)
+ def send(self, msg):
+ totalsent = 0
+ while totalsent < len(msg):
+ sent = self.sock.send(msg[totalsent:])
+ if sent == 0:
+ raise MuxError("socket connection broken")
+ totalsent = totalsent + sent
+ def recv(self, size):
+ msg = ''
+ while len(msg) < size:
+ chunk = self.sock.recv(size-len(msg))
+ if chunk == '':
+ raise MuxError("socket connection broken")
+ msg = msg + chunk
+ return msg
+
+class MuxDevice(object):
+ def __init__(self, devid, usbprod, serial, location):
+ self.devid = devid
+ self.usbprod = usbprod
+ self.serial = serial
+ self.location = location
+ def __str__(self):
+ return "<MuxDevice: ID %d ProdID 0x%04x Serial '%s' Location 0x%x>"%(self.devid, self.usbprod, self.serial, self.location)
+
+class BinaryProtocol(object):
+ TYPE_RESULT = 1
+ TYPE_CONNECT = 2
+ TYPE_LISTEN = 3
+ TYPE_DEVICE_ADD = 4
+ TYPE_DEVICE_REMOVE = 5
+ VERSION = 0
+ def __init__(self, socket):
+ self.socket = socket
+ self.connected = False
+
+ def _pack(self, req, payload):
+ if req == self.TYPE_CONNECT:
+ return struct.pack("IH", payload['DeviceID'], payload['PortNumber']) + "\x00\x00"
+ elif req == self.TYPE_LISTEN:
+ return ""
+ else:
+ raise ValueError("Invalid outgoing request type %d"%req)
+
+ def _unpack(self, resp, payload):
+ if resp == self.TYPE_RESULT:
+ return {'Number':struct.unpack("I", payload)[0]}
+ elif resp == self.TYPE_DEVICE_ADD:
+ devid, usbpid, serial, pad, location = struct.unpack("IH256sHI", payload)
+ serial = serial.split("\0")[0]
+ return {'DeviceID': devid, 'Properties': {'LocationID': location, 'SerialNumber': serial, 'ProductID': usbpid}}
+ elif resp == self.TYPE_DEVICE_REMOVE:
+ devid = struct.unpack("I", payload)[0]
+ return {'DeviceID': devid}
+ else:
+ raise MuxError("Invalid incoming request type %d"%req)
+
+ def sendpacket(self, req, tag, payload={}):
+ payload = self._pack(req, payload)
+ if self.connected:
+ raise MuxError("Mux is connected, cannot issue control packets")
+ length = 16 + len(payload)
+ data = struct.pack("IIII", length, self.VERSION, req, tag) + payload
+ self.socket.send(data)
+ def getpacket(self):
+ if self.connected:
+ raise MuxError("Mux is connected, cannot issue control packets")
+ dlen = self.socket.recv(4)
+ dlen = struct.unpack("I", dlen)[0]
+ body = self.socket.recv(dlen - 4)
+ version, resp, tag = struct.unpack("III",body[:0xc])
+ if version != self.VERSION:
+ raise MuxVersionError("Version mismatch: expected %d, got %d"%(self.VERSION,version))
+ payload = self._unpack(resp, body[0xc:])
+ return (resp, tag, payload)
+
+class PlistProtocol(BinaryProtocol):
+ TYPE_RESULT = "Result"
+ TYPE_CONNECT = "Connect"
+ TYPE_LISTEN = "Listen"
+ TYPE_DEVICE_ADD = "Attached"
+ TYPE_DEVICE_REMOVE = "Detached" #???
+ TYPE_PLIST = 8
+ VERSION = 1
+ def __init__(self, socket):
+ if not haveplist:
+ raise Exception("You need the plistlib module")
+ BinaryProtocol.__init__(self, socket)
+
+ def _pack(self, req, payload):
+ return payload
+
+ def _unpack(self, resp, payload):
+ return payload
+
+ def sendpacket(self, req, tag, payload={}):
+ payload['ClientVersionString'] = 'usbmux.py by marcan'
+ if isinstance(req, int):
+ req = [self.TYPE_CONNECT, self.TYPE_LISTEN][req-2]
+ payload['MessageType'] = req
+ payload['ProgName'] = 'tcprelay'
+ BinaryProtocol.sendpacket(self, self.TYPE_PLIST, tag, plistlib.writePlistToString(payload))
+ def getpacket(self):
+ resp, tag, payload = BinaryProtocol.getpacket(self)
+ if resp != self.TYPE_PLIST:
+ raise MuxError("Received non-plist type %d"%resp)
+ payload = plistlib.readPlistFromString(payload)
+ return payload['MessageType'], tag, payload
+
+class MuxConnection(object):
+ def __init__(self, socketpath, protoclass):
+ self.socketpath = socketpath
+ if sys.platform in ['win32', 'cygwin']:
+ family = socket.AF_INET
+ address = ('127.0.0.1', 27015)
+ else:
+ family = socket.AF_UNIX
+ address = self.socketpath
+ self.socket = SafeStreamSocket(address, family)
+ self.proto = protoclass(self.socket)
+ self.pkttag = 1
+ self.devices = []
+
+ def _getreply(self):
+ while True:
+ resp, tag, data = self.proto.getpacket()
+ if resp == self.proto.TYPE_RESULT:
+ return tag, data
+ else:
+ raise MuxError("Invalid packet type received: %d"%resp)
+ def _processpacket(self):
+ resp, tag, data = self.proto.getpacket()
+ if resp == self.proto.TYPE_DEVICE_ADD:
+ self.devices.append(MuxDevice(data['DeviceID'], data['Properties']['ProductID'], data['Properties']['SerialNumber'], data['Properties']['LocationID']))
+ elif resp == self.proto.TYPE_DEVICE_REMOVE:
+ for dev in self.devices:
+ if dev.devid == data['DeviceID']:
+ self.devices.remove(dev)
+ elif resp == self.proto.TYPE_RESULT:
+ raise MuxError("Unexpected result: %d"%resp)
+ else:
+ raise MuxError("Invalid packet type received: %d"%resp)
+ def _exchange(self, req, payload={}):
+ mytag = self.pkttag
+ self.pkttag += 1
+ self.proto.sendpacket(req, mytag, payload)
+ recvtag, data = self._getreply()
+ if recvtag != mytag:
+ raise MuxError("Reply tag mismatch: expected %d, got %d"%(mytag, recvtag))
+ return data['Number']
+
+ def listen(self):
+ ret = self._exchange(self.proto.TYPE_LISTEN)
+ if ret != 0:
+ raise MuxError("Listen failed: error %d"%ret)
+ def process(self, timeout=None):
+ if self.proto.connected:
+ raise MuxError("Socket is connected, cannot process listener events")
+ rlo, wlo, xlo = select.select([self.socket.sock], [], [self.socket.sock], timeout)
+ if xlo:
+ self.socket.sock.close()
+ raise MuxError("Exception in listener socket")
+ if rlo:
+ self._processpacket()
+ def connect(self, device, port):
+ ret = self._exchange(self.proto.TYPE_CONNECT, {'DeviceID':device.devid, 'PortNumber':((port<<8) & 0xFF00) | (port>>8)})
+ if ret != 0:
+ raise MuxError("Connect failed: error %d"%ret)
+ self.proto.connected = True
+ return self.socket.sock
+ def close(self):
+ self.socket.sock.close()
+
+class USBMux(object):
+ def __init__(self, socketpath="/tmp/usbmuxd"):
+ self.socketpath = socketpath
+ self.listener = MuxConnection(socketpath, BinaryProtocol)
+ try:
+ self.listener.listen()
+ self.version = 0
+ self.protoclass = BinaryProtocol
+ except MuxVersionError:
+ self.listener = MuxConnection(socketpath, PlistProtocol)
+ self.listener.listen()
+ self.protoclass = PlistProtocol
+ self.version = 1
+ self.devices = self.listener.devices
+ def process(self, timeout=None):
+ self.listener.process(timeout)
+ def connect(self, device, port):
+ connector = MuxConnection(self.socketpath, self.protoclass)
+ return connector.connect(device, port)
+
+if __name__ == "__main__":
+ mux = USBMux()
+ print "Waiting for devices..."
+ if not mux.devices:
+ mux.process(0.1)
+ while True:
+ print "Devices:"
+ for dev in mux.devices:
+ print dev
+ mux.process()