package connection import ( "context" "net" "time" "github.com/cloudflare/cloudflared/h2mux" "github.com/cloudflare/cloudflared/tunnelrpc" "github.com/cloudflare/cloudflared/tunnelrpc/pogs" tunnelpogs "github.com/cloudflare/cloudflared/tunnelrpc/pogs" "github.com/google/uuid" "github.com/pkg/errors" "github.com/sirupsen/logrus" rpc "zombiezen.com/go/capnproto2/rpc" ) const ( openStreamTimeout = 30 * time.Second ) type dialError struct { cause error } func (e dialError) Error() string { return e.cause.Error() } type Connection struct { id uuid.UUID muxer *h2mux.Muxer } func newConnection(muxer *h2mux.Muxer, edgeIP *net.TCPAddr) (*Connection, error) { id, err := uuid.NewRandom() if err != nil { return nil, err } return &Connection{ id: id, muxer: muxer, }, nil } func (c *Connection) Serve(ctx context.Context) error { // Serve doesn't return until h2mux is shutdown return c.muxer.Serve(ctx) } // Connect is used to establish connections with cloudflare's edge network func (c *Connection) Connect(ctx context.Context, parameters *tunnelpogs.ConnectParameters, logger *logrus.Entry) (pogs.ConnectResult, error) { openStreamCtx, cancel := context.WithTimeout(ctx, openStreamTimeout) defer cancel() rpcConn, err := c.newRPConn(openStreamCtx, logger) if err != nil { return nil, errors.Wrap(err, "cannot create new RPC connection") } defer rpcConn.Close() tsClient := tunnelpogs.TunnelServer_PogsClient{Client: rpcConn.Bootstrap(ctx)} return tsClient.Connect(ctx, parameters) } func (c *Connection) Shutdown() { c.muxer.Shutdown() } func (c *Connection) newRPConn(ctx context.Context, logger *logrus.Entry) (*rpc.Conn, error) { stream, err := c.muxer.OpenRPCStream(ctx) if err != nil { return nil, err } return rpc.NewConn( tunnelrpc.NewTransportLogger(logger.WithField("rpc", "connect"), rpc.StreamTransport(stream)), tunnelrpc.ConnLog(logger.WithField("rpc", "connect")), ), nil }