summaryrefslogtreecommitdiffstats
path: root/python-client/tcprelay.py
diff options
context:
space:
mode:
Diffstat (limited to 'python-client/tcprelay.py')
-rw-r--r--python-client/tcprelay.py147
1 files changed, 147 insertions, 0 deletions
diff --git a/python-client/tcprelay.py b/python-client/tcprelay.py
new file mode 100644
index 0000000..2874ae1
--- /dev/null
+++ b/python-client/tcprelay.py
@@ -0,0 +1,147 @@
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(options.sockpath)
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")
103parser.add_option("-s", "--socket", dest='sockpath', action='store', metavar='PATH', type='str', default=None, help="specify the path of the usbmuxd socket")
104
105options, args = parser.parse_args()
106
107serverclass = TCPServer
108if options.threaded:
109 serverclass = ThreadedTCPServer
110
111if len(args) == 0:
112 parser.print_help()
113 sys.exit(1)
114
115ports = []
116
117for arg in args:
118 try:
119 if ':' in arg:
120 rport, lport = arg.split(":")
121 rport = int(rport)
122 lport = int(lport)
123 ports.append((rport, lport))
124 else:
125 ports.append((int(arg), int(arg)))
126 except:
127 parser.print_help()
128 sys.exit(1)
129
130servers=[]
131
132for rport, lport in ports:
133 print "Forwarding local port %d to remote port %d"%(lport, rport)
134 server = serverclass((HOST, lport), TCPRelay)
135 server.rport = rport
136 server.bufsize = options.bufsize
137 servers.append(server)
138
139alive = True
140
141while alive:
142 try:
143 rl, wl, xl = select.select(servers, [], [])
144 for server in rl:
145 server.handle_request()
146 except:
147 alive = False