core/chain/transport.go
2024-06-25 20:37:08 +08:00

146 lines
3.3 KiB
Go

package chain
import (
"context"
"net"
net_dialer "github.com/go-gost/core/common/net/dialer"
"github.com/go-gost/core/connector"
"github.com/go-gost/core/dialer"
)
type TransportOptions struct {
Addr string
IfceName string
Netns string
SockOpts *SockOpts
Route Route
}
type TransportOption func(*TransportOptions)
func AddrTransportOption(addr string) TransportOption {
return func(o *TransportOptions) {
o.Addr = addr
}
}
func InterfaceTransportOption(ifceName string) TransportOption {
return func(o *TransportOptions) {
o.IfceName = ifceName
}
}
func NetnsTransportOption(netns string) TransportOption {
return func(o *TransportOptions) {
o.Netns = netns
}
}
func SockOptsTransportOption(so *SockOpts) TransportOption {
return func(o *TransportOptions) {
o.SockOpts = so
}
}
func RouteTransportOption(route Route) TransportOption {
return func(o *TransportOptions) {
o.Route = route
}
}
type Transport struct {
dialer dialer.Dialer
connector connector.Connector
options TransportOptions
}
func NewTransport(d dialer.Dialer, c connector.Connector, opts ...TransportOption) *Transport {
tr := &Transport{
dialer: d,
connector: c,
}
for _, opt := range opts {
if opt != nil {
opt(&tr.options)
}
}
return tr
}
func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) {
netd := &net_dialer.NetDialer{
Interface: tr.options.IfceName,
Netns: tr.options.Netns,
}
if tr.options.SockOpts != nil {
netd.Mark = tr.options.SockOpts.Mark
}
if tr.options.Route != nil && len(tr.options.Route.Nodes()) > 0 {
netd.DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error) {
return tr.options.Route.Dial(ctx, network, addr)
}
}
opts := []dialer.DialOption{
dialer.HostDialOption(tr.options.Addr),
dialer.NetDialerDialOption(netd),
}
return tr.dialer.Dial(ctx, addr, opts...)
}
func (tr *Transport) Handshake(ctx context.Context, conn net.Conn) (net.Conn, error) {
var err error
if hs, ok := tr.dialer.(dialer.Handshaker); ok {
conn, err = hs.Handshake(ctx, conn,
dialer.AddrHandshakeOption(tr.options.Addr))
if err != nil {
return nil, err
}
}
if hs, ok := tr.connector.(connector.Handshaker); ok {
return hs.Handshake(ctx, conn)
}
return conn, nil
}
func (tr *Transport) Connect(ctx context.Context, conn net.Conn, network, address string) (net.Conn, error) {
netd := &net_dialer.NetDialer{
Interface: tr.options.IfceName,
Netns: tr.options.Netns,
}
if tr.options.SockOpts != nil {
netd.Mark = tr.options.SockOpts.Mark
}
return tr.connector.Connect(ctx, conn, network, address,
connector.NetDialerConnectOption(netd),
)
}
func (tr *Transport) Bind(ctx context.Context, conn net.Conn, network, address string, opts ...connector.BindOption) (net.Listener, error) {
if binder, ok := tr.connector.(connector.Binder); ok {
return binder.Bind(ctx, conn, network, address, opts...)
}
return nil, connector.ErrBindUnsupported
}
func (tr *Transport) Multiplex() bool {
if mux, ok := tr.dialer.(dialer.Multiplexer); ok {
return mux.Multiplex()
}
return false
}
func (tr *Transport) Options() *TransportOptions {
if tr != nil {
return &tr.options
}
return nil
}
func (tr *Transport) Copy() *Transport {
tr2 := &Transport{}
*tr2 = *tr
return tr
}