diff options
| author | 2009-05-05 01:40:22 +0200 | |
|---|---|---|
| committer | 2009-05-05 01:40:22 +0200 | |
| commit | dce2546afadd9185b7e65f1db6b127d6293b178c (patch) | |
| tree | 956f7d1adbba68ca2db4ce7d8740e10be8f5f53b | |
| parent | 78577f36b4fd92b052300e0b4d3b369d45b40e67 (diff) | |
| download | usbmuxd-dce2546afadd9185b7e65f1db6b127d6293b178c.tar.gz usbmuxd-dce2546afadd9185b7e65f1db6b127d6293b178c.tar.bz2 | |
Add python stuff and patches
| -rw-r--r-- | patches/libusb-add-zlp-flag.patch | 24 | ||||
| -rw-r--r-- | patches/valgrind-usbdevfs.patch | 133 | ||||
| -rw-r--r-- | python-client/tcprelay.py | 146 | ||||
| -rw-r--r-- | python-client/usbmux.py | 240 | 
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() | 
