78
vendor/sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/client.go
generated
vendored
78
vendor/sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/client.go
generated
vendored
@@ -19,6 +19,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
|
||||
)
|
||||
|
||||
@@ -49,11 +50,23 @@ type grpcTunnel struct {
|
||||
conns map[int64]*conn
|
||||
pendingDialLock sync.RWMutex
|
||||
connsLock sync.RWMutex
|
||||
|
||||
// The tunnel will be closed if the caller fails to read via conn.Read()
|
||||
// more than readTimeoutSeconds after a packet has been received.
|
||||
readTimeoutSeconds int
|
||||
}
|
||||
|
||||
// CreateGrpcTunnel creates a Tunnel to dial to a remote server through a
|
||||
type clientConn interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
var _ clientConn = &grpc.ClientConn{}
|
||||
|
||||
// CreateSingleUseGrpcTunnel creates a Tunnel to dial to a remote server through a
|
||||
// gRPC based proxy service.
|
||||
func CreateGrpcTunnel(address string, opts ...grpc.DialOption) (Tunnel, error) {
|
||||
// Currently, a single tunnel supports a single connection, and the tunnel is closed when the connection is terminated
|
||||
// The Dial() method of the returned tunnel should only be called once
|
||||
func CreateSingleUseGrpcTunnel(address string, opts ...grpc.DialOption) (Tunnel, error) {
|
||||
c, err := grpc.Dial(address, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -67,28 +80,31 @@ func CreateGrpcTunnel(address string, opts ...grpc.DialOption) (Tunnel, error) {
|
||||
}
|
||||
|
||||
tunnel := &grpcTunnel{
|
||||
stream: stream,
|
||||
pendingDial: make(map[int64]chan<- dialResult),
|
||||
conns: make(map[int64]*conn),
|
||||
stream: stream,
|
||||
pendingDial: make(map[int64]chan<- dialResult),
|
||||
conns: make(map[int64]*conn),
|
||||
readTimeoutSeconds: 10,
|
||||
}
|
||||
|
||||
go tunnel.serve()
|
||||
go tunnel.serve(c)
|
||||
|
||||
return tunnel, nil
|
||||
}
|
||||
|
||||
func (t *grpcTunnel) serve() {
|
||||
func (t *grpcTunnel) serve(c clientConn) {
|
||||
defer c.Close()
|
||||
|
||||
for {
|
||||
pkt, err := t.stream.Recv()
|
||||
if err == io.EOF {
|
||||
return
|
||||
}
|
||||
if err != nil || pkt == nil {
|
||||
klog.Warningf("stream read error: %v", err)
|
||||
klog.ErrorS(err, "stream read failure")
|
||||
return
|
||||
}
|
||||
|
||||
klog.V(6).Infof("[tracing] recv packet, type: %s", pkt.Type)
|
||||
klog.V(5).InfoS("[tracing] recv packet", "type", pkt.Type)
|
||||
|
||||
switch pkt.Type {
|
||||
case client.PacketType_DIAL_RSP:
|
||||
@@ -98,13 +114,26 @@ func (t *grpcTunnel) serve() {
|
||||
t.pendingDialLock.RUnlock()
|
||||
|
||||
if !ok {
|
||||
klog.Warning("DialResp not recognized; dropped")
|
||||
klog.V(1).Infoln("DialResp not recognized; dropped")
|
||||
} else {
|
||||
ch <- dialResult{
|
||||
result := dialResult{
|
||||
err: resp.Error,
|
||||
connid: resp.ConnectID,
|
||||
}
|
||||
select {
|
||||
case ch <- result:
|
||||
default:
|
||||
klog.ErrorS(fmt.Errorf("blocked pending channel"), "Received second dial response for connection request", "connectionID", resp.ConnectID, "dialID", resp.Random)
|
||||
// On multiple dial responses, avoid leaking serve goroutine.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Error != "" {
|
||||
// On dial error, avoid leaking serve goroutine.
|
||||
return
|
||||
}
|
||||
|
||||
case client.PacketType_DATA:
|
||||
resp := pkt.GetData()
|
||||
// TODO: flow control
|
||||
@@ -113,9 +142,16 @@ func (t *grpcTunnel) serve() {
|
||||
t.connsLock.RUnlock()
|
||||
|
||||
if ok {
|
||||
conn.readCh <- resp.Data
|
||||
timer := time.NewTimer((time.Duration)(t.readTimeoutSeconds) * time.Second)
|
||||
select {
|
||||
case conn.readCh <- resp.Data:
|
||||
timer.Stop()
|
||||
case <-timer.C:
|
||||
klog.ErrorS(fmt.Errorf("timeout"), "readTimeout has been reached, the grpc connection to the proxy server will be closed", "connectionID", conn.connID, "readTimeoutSeconds", t.readTimeoutSeconds)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
klog.Warningf("connection id %d not recognized", resp.ConnectID)
|
||||
klog.V(1).InfoS("connection not recognized", "connectionID", resp.ConnectID)
|
||||
}
|
||||
case client.PacketType_CLOSE_RSP:
|
||||
resp := pkt.GetCloseResponse()
|
||||
@@ -130,9 +166,9 @@ func (t *grpcTunnel) serve() {
|
||||
t.connsLock.Lock()
|
||||
delete(t.conns, resp.ConnectID)
|
||||
t.connsLock.Unlock()
|
||||
} else {
|
||||
klog.Warningf("connection id %d not recognized", resp.ConnectID)
|
||||
return
|
||||
}
|
||||
klog.V(1).InfoS("connection not recognized", "connectionID", resp.ConnectID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,8 +180,8 @@ func (t *grpcTunnel) Dial(protocol, address string) (net.Conn, error) {
|
||||
return nil, errors.New("protocol not supported")
|
||||
}
|
||||
|
||||
random := rand.Int63()
|
||||
resCh := make(chan dialResult)
|
||||
random := rand.Int63() /* #nosec G404 */
|
||||
resCh := make(chan dialResult, 1)
|
||||
t.pendingDialLock.Lock()
|
||||
t.pendingDial[random] = resCh
|
||||
t.pendingDialLock.Unlock()
|
||||
@@ -165,14 +201,14 @@ func (t *grpcTunnel) Dial(protocol, address string) (net.Conn, error) {
|
||||
},
|
||||
},
|
||||
}
|
||||
klog.V(6).Infof("[tracing] send packet, type: %s", req.Type)
|
||||
klog.V(5).InfoS("[tracing] send packet", "type", req.Type)
|
||||
|
||||
err := t.stream.Send(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
klog.Info("DIAL_REQ sent to proxy server")
|
||||
klog.V(5).Infoln("DIAL_REQ sent to proxy server")
|
||||
|
||||
c := &conn{stream: t.stream}
|
||||
|
||||
@@ -183,7 +219,7 @@ func (t *grpcTunnel) Dial(protocol, address string) (net.Conn, error) {
|
||||
}
|
||||
c.connID = res.connid
|
||||
c.readCh = make(chan []byte, 10)
|
||||
c.closeCh = make(chan string)
|
||||
c.closeCh = make(chan string, 1)
|
||||
t.connsLock.Lock()
|
||||
t.conns[res.connid] = c
|
||||
t.connsLock.Unlock()
|
||||
|
||||
8
vendor/sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/conn.go
generated
vendored
8
vendor/sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/conn.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog"
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client"
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ func (c *conn) Write(data []byte) (n int, err error) {
|
||||
},
|
||||
}
|
||||
|
||||
klog.V(6).Infof("[tracing] send req, type: %s", req.Type)
|
||||
klog.V(5).InfoS("[tracing] send req", "type", req.Type)
|
||||
|
||||
err = c.stream.Send(req)
|
||||
if err != nil {
|
||||
@@ -112,7 +112,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
|
||||
// Close closes the connection. It also sends CLOSE_REQ packet over
|
||||
// proxy service to notify remote to drop the connection.
|
||||
func (c *conn) Close() error {
|
||||
klog.Info("conn.Close()")
|
||||
klog.V(4).Infoln("closing connection")
|
||||
req := &client.Packet{
|
||||
Type: client.PacketType_CLOSE_REQ,
|
||||
Payload: &client.Packet_CloseRequest{
|
||||
@@ -122,7 +122,7 @@ func (c *conn) Close() error {
|
||||
},
|
||||
}
|
||||
|
||||
klog.V(6).Infof("[tracing] send req, type: %s", req.Type)
|
||||
klog.V(5).InfoS("[tracing] send req", "type", req.Type)
|
||||
|
||||
if err := c.stream.Send(req); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user