forked from danielpaulus/go-ios
-
Notifications
You must be signed in to change notification settings - Fork 0
/
forward.go
132 lines (112 loc) · 3.27 KB
/
forward.go
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
package forward
import (
"context"
"fmt"
"io"
"net"
"sync"
"github.com/greficsmurf/go-ios/ios"
log "github.com/sirupsen/logrus"
)
type iosproxy struct {
tcpConn net.Conn
deviceConn ios.DeviceConnectionInterface
}
type ConnListener struct {
listener net.Listener
quit chan interface{}
}
// Forward forwards every connection made to the hostPort to whatever service runs inside an app on the device on phonePort.
func Forward(device ios.DeviceEntry, hostPort uint16, phonePort uint16) (*ConnListener, error) {
log.Infof("Start listening on port %d forwarding to port %d on device", hostPort, phonePort)
l, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", hostPort))
if err != nil {
return nil, fmt.Errorf("forward: failed listener with err: %w", err)
}
cl := &ConnListener{
listener: l,
quit: make(chan interface{}),
}
go connectionAccept(cl, device.DeviceID, phonePort)
return cl, nil
}
// Close stops listening on the host port for the forwarded connection
func (cl *ConnListener) Close() error {
close(cl.quit)
err := cl.listener.Close()
if err != nil {
return fmt.Errorf("forward: failed closing listener with err: %w", err)
}
return nil
}
func connectionAccept(cl *ConnListener, deviceID int, phonePort uint16) {
for {
select {
case <-cl.quit:
log.WithFields(log.Fields{"phonePort": phonePort}).Info("closed listener successfully")
return
default:
clientConn, err := cl.listener.Accept()
if err != nil {
log.Errorf("Error accepting new connection %v", err)
continue
}
log.WithFields(log.Fields{"conn": fmt.Sprintf("%#v", cl)}).Info("new client connected")
go StartNewProxyConnection(context.TODO(), clientConn, deviceID, phonePort)
}
}
}
func StartNewProxyConnection(ctx context.Context, clientConn io.ReadWriteCloser, deviceID int, phonePort uint16) error {
usbmuxConn, err := ios.NewUsbMuxConnectionSimple()
if err != nil {
log.Errorf("could not connect to usbmuxd: %+v", err)
clientConn.Close()
return fmt.Errorf("could not connect to usbmuxd: %v", err)
}
muxError := usbmuxConn.Connect(deviceID, phonePort)
if muxError != nil {
log.WithFields(log.Fields{"conn": fmt.Sprintf("%#v", clientConn), "err": muxError, "phonePort": phonePort}).Infof("could not connect to phone")
clientConn.Close()
return fmt.Errorf("could not connect to port:%d on iOS: %v", phonePort, err)
}
log.WithFields(log.Fields{"conn": fmt.Sprintf("%#v", clientConn), "phonePort": phonePort}).Infof("Connected to port")
deviceConn := usbmuxConn.ReleaseDeviceConnection()
// proxyConn := iosproxy{clientConn, deviceConn}
ctx2, cancel := context.WithCancel(ctx)
var wg sync.WaitGroup
wg.Add(1)
closed := false
go func() {
io.Copy(clientConn, deviceConn.Reader())
if ctx2.Err() == nil {
cancel()
clientConn.Close()
deviceConn.Close()
closed = true
}
log.Errorf("forward: close clientConn <-- deviceConn")
wg.Done()
}()
wg.Add(1)
go func() {
io.Copy(deviceConn.Writer(), clientConn)
if ctx2.Err() == nil {
cancel()
clientConn.Close()
deviceConn.Close()
closed = true
}
log.Errorf("forward: close clientConn --> deviceConn")
wg.Done()
}()
<-ctx2.Done()
if !closed {
clientConn.Close()
deviceConn.Close()
}
wg.Wait()
return nil
}
func (proxyConn *iosproxy) Close() {
proxyConn.tcpConn.Close()
}