github.com/ipfans/trojan-go@v0.11.0/tunnel/websocket/client.go (about)

     1  package websocket
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"golang.org/x/net/websocket"
     8  
     9  	"github.com/ipfans/trojan-go/common"
    10  	"github.com/ipfans/trojan-go/config"
    11  	"github.com/ipfans/trojan-go/log"
    12  	"github.com/ipfans/trojan-go/tunnel"
    13  )
    14  
    15  type Client struct {
    16  	underlay tunnel.Client
    17  	hostname string
    18  	path     string
    19  }
    20  
    21  func (c *Client) DialConn(*tunnel.Address, tunnel.Tunnel) (tunnel.Conn, error) {
    22  	conn, err := c.underlay.DialConn(nil, &Tunnel{})
    23  	if err != nil {
    24  		return nil, common.NewError("websocket cannot dial with underlying client").Base(err)
    25  	}
    26  	url := "wss://" + c.hostname + c.path
    27  	origin := "https://" + c.hostname
    28  	wsConfig, err := websocket.NewConfig(url, origin)
    29  	if err != nil {
    30  		return nil, common.NewError("invalid websocket config").Base(err)
    31  	}
    32  	wsConn, err := websocket.NewClient(wsConfig, conn)
    33  	if err != nil {
    34  		return nil, common.NewError("websocket failed to handshake with server").Base(err)
    35  	}
    36  	return &OutboundConn{
    37  		Conn:    wsConn,
    38  		tcpConn: conn,
    39  	}, nil
    40  }
    41  
    42  func (c *Client) DialPacket(tunnel.Tunnel) (tunnel.PacketConn, error) {
    43  	return nil, common.NewError("not supported by websocket")
    44  }
    45  
    46  func (c *Client) Close() error {
    47  	return c.underlay.Close()
    48  }
    49  
    50  func NewClient(ctx context.Context, underlay tunnel.Client) (*Client, error) {
    51  	cfg := config.FromContext(ctx, Name).(*Config)
    52  	if !strings.HasPrefix(cfg.Websocket.Path, "/") {
    53  		return nil, common.NewError("websocket path must start with \"/\"")
    54  	}
    55  	if cfg.Websocket.Host == "" {
    56  		cfg.Websocket.Host = cfg.RemoteHost
    57  		log.Warn("empty websocket hostname")
    58  	}
    59  	log.Debug("websocket client created")
    60  	return &Client{
    61  		hostname: cfg.Websocket.Host,
    62  		path:     cfg.Websocket.Path,
    63  		underlay: underlay,
    64  	}, nil
    65  }