Skip to content

Commit cace937

Browse files
committed
Add proxy package
This package includes the proxy which translates the unix socket to the vsock. This proxy could be dropped in the future if podman will support natively the vsock protocol. Signed-off-by: Alice Frosi <[email protected]>
1 parent 6fa974d commit cace937

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

pkg/vsock/proxy.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package proxy
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net"
8+
"os"
9+
10+
"github.com/sirupsen/logrus"
11+
"golang.org/x/sys/unix"
12+
)
13+
14+
const podmanVMProxyDefault = "/tmp/podman-bootc-proxy.sock"
15+
16+
type Proxy struct {
17+
cid uint
18+
port uint
19+
socket string
20+
done chan struct{}
21+
}
22+
23+
func NewProxy(cid, port uint, socket string) *Proxy {
24+
if socket == "" {
25+
socket = podmanVMProxyDefault
26+
}
27+
return &Proxy{
28+
cid: cid,
29+
port: port,
30+
socket: socket,
31+
done: make(chan struct{}),
32+
}
33+
}
34+
35+
func (proxy *Proxy) GetSocket() string {
36+
return proxy.socket
37+
}
38+
39+
func (proxy *Proxy) Stop() {
40+
select {
41+
case <-proxy.done:
42+
// already closed
43+
default:
44+
close(proxy.done)
45+
}
46+
os.Remove(proxy.socket)
47+
logrus.Debugf("Stopped proxy")
48+
}
49+
50+
func (proxy *Proxy) Start() error {
51+
_ = os.Remove(proxy.socket)
52+
53+
unixListener, err := net.Listen("unix", proxy.socket)
54+
if err != nil {
55+
return fmt.Errorf("Failed to listen on unix socket: %v", err)
56+
}
57+
go func() {
58+
defer unixListener.Close()
59+
60+
for {
61+
select {
62+
case <-proxy.done:
63+
return
64+
default:
65+
unixConn, err := unixListener.Accept()
66+
if err != nil {
67+
logrus.Warnf("Accept error: %v", err)
68+
continue
69+
}
70+
71+
go proxy.handleConnection(unixConn)
72+
}
73+
}
74+
}()
75+
76+
logrus.Debugf("Started proxy at: %s", proxy.socket)
77+
78+
return nil
79+
}
80+
81+
func (proxy *Proxy) handleConnection(unixConn net.Conn) {
82+
defer unixConn.Close()
83+
84+
fd, err := unix.Socket(unix.AF_VSOCK, unix.SOCK_STREAM, 0)
85+
if err != nil {
86+
logrus.Errorf("vsock socket error: %v", err)
87+
return
88+
}
89+
90+
sa := &unix.SockaddrVM{CID: uint32(proxy.cid), Port: uint32(proxy.port)}
91+
if err := unix.Connect(fd, sa); err != nil {
92+
logrus.Debugf("Failed to connect error: %v", err)
93+
return
94+
}
95+
96+
vconnFile := os.NewFile(uintptr(fd), "vsock")
97+
if vconnFile == nil {
98+
logrus.Error("Failed to create os.File from fd")
99+
unix.Close(fd)
100+
return
101+
}
102+
defer vconnFile.Close()
103+
104+
ctx, cancel := context.WithCancel(context.Background())
105+
defer cancel()
106+
107+
errCh := make(chan error, 2)
108+
go proxy.proxyFileToConn(ctx, vconnFile, unixConn, errCh)
109+
go proxy.proxyConnToFile(ctx, unixConn, vconnFile, errCh)
110+
111+
// Wait for the first error or cancellation
112+
select {
113+
case <-proxy.done:
114+
case err := <-errCh:
115+
if err != nil && err != io.EOF {
116+
logrus.Errorf("proxy error: %v", err)
117+
}
118+
}
119+
}
120+
121+
func (proxy *Proxy) proxyFileToConn(ctx context.Context, file *os.File, conn net.Conn, errCh chan error) {
122+
go func() {
123+
_, err := io.Copy(conn, file)
124+
errCh <- err
125+
}()
126+
select {
127+
case <-ctx.Done():
128+
case <-proxy.done:
129+
case <-errCh:
130+
}
131+
}
132+
133+
func (proxy *Proxy) proxyConnToFile(ctx context.Context, conn net.Conn, file *os.File, errCh chan error) {
134+
go func() {
135+
_, err := io.Copy(file, conn)
136+
errCh <- err
137+
}()
138+
select {
139+
case <-ctx.Done():
140+
case <-proxy.done:
141+
case <-errCh:
142+
}
143+
}

0 commit comments

Comments
 (0)