Merge branch 'dev' into Alpha

This commit is contained in:
Skyxim 2022-06-26 21:53:03 +08:00
commit 10383e2701
9 changed files with 119 additions and 71 deletions

View file

@ -151,25 +151,32 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
} }
client := http.Client{ client := http.Client{
Timeout: 30 * time.Second,
Transport: transport, Transport: transport,
CheckRedirect: func(req *http.Request, via []*http.Request) error { CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse return http.ErrUseLastResponse
}, },
} }
defer client.CloseIdleConnections() defer client.CloseIdleConnections()
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return return
} }
_ = resp.Body.Close()
if unifiedDelay { if unifiedDelay {
start = time.Now() second := time.Now()
resp, err = client.Do(req) resp, err = client.Do(req)
if err != nil { if err == nil {
return _ = resp.Body.Close()
start = second
} }
} }
_ = resp.Body.Close()
t = uint16(time.Since(start) / time.Millisecond) t = uint16(time.Since(start) / time.Millisecond)
return return
} }

View file

@ -41,24 +41,32 @@ var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`)
type Hysteria struct { type Hysteria struct {
*Base *Base
client *core.Client client *core.Client
clientTransport *transport.ClientTransport
} }
func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), hyDialer(func() (net.PacketConn, error) { hdc := hyDialerWithContext{
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...) ctx: ctx,
})) hyDialer: func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
},
}
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), &hdc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewConn(tcpConn, h), nil return NewConn(tcpConn, h), nil
} }
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
udpConn, err := h.client.DialUDP(hyDialer(func() (net.PacketConn, error) { hdc := hyDialerWithContext{
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...) ctx: ctx,
})) hyDialer: func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
},
}
udpConn, err := h.client.DialUDP(&hdc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -93,7 +101,7 @@ func (c *HysteriaOption) Speed() (uint64, uint64, error) {
} }
down = stringToBps(c.Down) down = stringToBps(c.Down)
if up == 0 { if down == 0 {
return 0, 0, fmt.Errorf("invaild download speed: %s", c.Down) return 0, 0, fmt.Errorf("invaild download speed: %s", c.Down)
} }
@ -191,8 +199,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) {
iface: option.Interface, iface: option.Interface,
rmark: option.RoutingMark, rmark: option.RoutingMark,
}, },
client: client, client: client,
clientTransport: clientTransport,
}, nil }, nil
} }
@ -255,8 +262,15 @@ func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return return
} }
type hyDialer func() (net.PacketConn, error) type hyDialerWithContext struct {
hyDialer func() (net.PacketConn, error)
func (h hyDialer) ListenPacket() (net.PacketConn, error) { ctx context.Context
return h() }
func (h *hyDialerWithContext) ListenPacket() (net.PacketConn, error) {
return h.hyDialer()
}
func (h *hyDialerWithContext) Context() context.Context {
return h.ctx
} }

View file

@ -111,11 +111,11 @@ func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16
wg.Add(1) wg.Add(1)
go func() { go func() {
delay, err := proxy.URLTest(ctx, url) delay, err := proxy.URLTest(ctx, url)
lock.Lock()
if err == nil { if err == nil {
lock.Lock()
mp[proxy.Name()] = delay mp[proxy.Name()] = delay
lock.Unlock()
} }
lock.Unlock()
wg.Done() wg.Done()
}() }()

View file

@ -202,6 +202,7 @@ func newFetcher[V any](name string, interval time.Duration, vehicle types.Vehicl
parser: parser, parser: parser,
done: make(chan struct{}, 1), done: make(chan struct{}, 1),
onUpdate: onUpdate, onUpdate: onUpdate,
interval: interval,
} }
} }

View file

@ -2,6 +2,7 @@ package provider
import ( import (
"context" "context"
"github.com/Dreamacro/clash/common/singledo"
"time" "time"
"github.com/Dreamacro/clash/common/batch" "github.com/Dreamacro/clash/common/batch"
@ -26,6 +27,7 @@ type HealthCheck struct {
lazy bool lazy bool
lastTouch *atomic.Int64 lastTouch *atomic.Int64
done chan struct{} done chan struct{}
singleDo *singledo.Single[struct{}]
} }
func (hc *HealthCheck) process() { func (hc *HealthCheck) process() {
@ -63,17 +65,21 @@ func (hc *HealthCheck) touch() {
} }
func (hc *HealthCheck) check() { func (hc *HealthCheck) check() {
b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10)) _, _, _ = hc.singleDo.Do(func() (struct{}, error) {
for _, proxy := range hc.proxies { b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10))
p := proxy for _, proxy := range hc.proxies {
b.Go(p.Name(), func() (bool, error) { p := proxy
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) b.Go(p.Name(), func() (bool, error) {
defer cancel() ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
_, _ = p.URLTest(ctx, hc.url) defer cancel()
return false, nil _, _ = p.URLTest(ctx, hc.url)
}) return false, nil
} })
b.Wait() }
b.Wait()
return struct{}{}, nil
})
} }
func (hc *HealthCheck) close() { func (hc *HealthCheck) close() {
@ -88,5 +94,6 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *He
lazy: lazy, lazy: lazy,
lastTouch: atomic.NewInt64(0), lastTouch: atomic.NewInt64(0),
done: make(chan struct{}, 1), done: make(chan struct{}, 1),
singleDo: singledo.NewSingle[struct{}](time.Second),
} }
} }

View file

@ -4,11 +4,10 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/component/resolver"
"net" "net"
"net/netip" "net/netip"
"sync" "sync"
"github.com/Dreamacro/clash/component/resolver"
) )
var ( var (
@ -171,25 +170,31 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt
go startRacer(ctx, network+"4", host, opt.direct, false) go startRacer(ctx, network+"4", host, opt.direct, false)
go startRacer(ctx, network+"6", host, opt.direct, true) go startRacer(ctx, network+"6", host, opt.direct, true)
for res := range results { count := 2
if res.error == nil { for i := 0; i < count; i++ {
return res.Conn, nil select {
} case res := <-results:
if res.error == nil {
if !res.ipv6 { return res.Conn, nil
primary = res
} else {
fallback = res
}
if primary.done && fallback.done {
if primary.resolved {
return nil, primary.error
} else if fallback.resolved {
return nil, fallback.error
} else {
return nil, primary.error
} }
if !res.ipv6 {
primary = res
} else {
fallback = res
}
if primary.done && fallback.done {
if primary.resolved {
return nil, primary.error
} else if fallback.resolved {
return nil, fallback.error
} else {
return nil, primary.error
}
}
case <-ctx.Done():
break
} }
} }
@ -225,7 +230,6 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
} }
results := make(chan dialResult) results := make(chan dialResult)
tcpRacer := func(ctx context.Context, ip netip.Addr) { tcpRacer := func(ctx context.Context, ip netip.Addr) {
result := dialResult{ip: ip} result := dialResult{ip: ip}
@ -252,13 +256,13 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
} }
connCount := len(ips) connCount := len(ips)
for res := range results { for i := 0; i < connCount; i++ {
connCount-- select {
if res.error == nil { case res := <-results:
return res.Conn, nil if res.error == nil {
} return res.Conn, nil
}
if connCount == 0 { case <-ctx.Done():
break break
} }
} }

View file

@ -129,7 +129,7 @@ func (dc *quicClient) getSession(ctx context.Context) (quic.Connection, error) {
func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error) { func (dc *quicClient) openSession(ctx context.Context) (quic.Connection, error) {
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
InsecureSkipVerify: true, InsecureSkipVerify: false,
NextProtos: []string{ NextProtos: []string{
NextProtoDQ, NextProtoDQ,
}, },

View file

@ -152,17 +152,9 @@ func (wpc *wrapPacketConn) LocalAddr() net.Addr {
} }
func dialContextExtra(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) { func dialContextExtra(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) {
adapter, ok := tunnel.Proxies()[adapterName]
if !ok {
opts = append(opts, dialer.WithInterface(adapterName))
adapter, _ = tunnel.Proxies()[tunnel.Direct.String()]
}
networkType := C.TCP networkType := C.TCP
if network == "udp" { if network == "udp" {
if !adapter.SupportUDP() {
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", adapterName)
}
networkType = C.UDP networkType = C.UDP
} }
@ -179,6 +171,29 @@ func dialContextExtra(ctx context.Context, adapterName string, network string, d
DstPort: port, DstPort: port,
} }
adapter, ok := tunnel.Proxies()[adapterName]
if !ok {
opts = append(opts, dialer.WithInterface(adapterName))
if C.TCP == networkType {
return dialer.DialContext(ctx, network, dstIP.String()+":"+port, opts...)
} else {
packetConn, err := dialer.ListenPacket(ctx, network, dstIP.String()+":"+port, opts...)
if err != nil {
return nil, err
}
return &wrapPacketConn{
PacketConn: packetConn,
rAddr: metadata.UDPAddr(),
}, nil
}
}
if networkType == C.UDP && !adapter.SupportUDP() {
return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", adapterName)
}
if networkType == C.UDP { if networkType == C.UDP {
packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...) packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...)
if err != nil { if err != nil {

View file

@ -64,7 +64,7 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) {
return return
} }
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout)) ctx, cancel := context.WithTimeout(r.Context(), time.Millisecond*time.Duration(timeout))
defer cancel() defer cancel()
dm, err := group.URLTest(ctx, url) dm, err := group.URLTest(ctx, url)