2019-09-18 12:53:04 +08:00
|
|
|
package strategy
|
2018-08-10 19:03:30 +08:00
|
|
|
|
|
|
|
import (
|
2018-08-12 12:37:25 +08:00
|
|
|
"net"
|
|
|
|
"net/url"
|
|
|
|
"strconv"
|
2018-08-10 19:03:30 +08:00
|
|
|
"strings"
|
2018-08-12 12:37:25 +08:00
|
|
|
"sync/atomic"
|
2018-08-13 00:42:59 +08:00
|
|
|
|
|
|
|
"github.com/nadoo/glider/common/log"
|
2019-09-18 12:53:04 +08:00
|
|
|
"github.com/nadoo/glider/proxy"
|
2018-08-10 19:03:30 +08:00
|
|
|
)
|
|
|
|
|
2018-08-26 01:25:22 +08:00
|
|
|
// StatusHandler function will be called when the forwarder's status changed
|
|
|
|
type StatusHandler func(*Forwarder)
|
2018-08-25 23:56:18 +08:00
|
|
|
|
2018-08-10 19:03:30 +08:00
|
|
|
// Forwarder is a forwarder
|
|
|
|
type Forwarder struct {
|
2019-09-18 12:53:04 +08:00
|
|
|
proxy.Dialer
|
2018-08-23 00:01:31 +08:00
|
|
|
addr string
|
|
|
|
priority uint32
|
|
|
|
maxFailures uint32 // maxfailures to set to Disabled
|
|
|
|
disabled uint32
|
|
|
|
failures uint32
|
|
|
|
latency int64
|
|
|
|
intface string // local interface or ip address
|
2018-08-26 01:25:22 +08:00
|
|
|
handlers []StatusHandler
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
2018-08-14 19:33:18 +08:00
|
|
|
// ForwarderFromURL parses `forward=` command value and returns a new forwarder
|
2018-08-20 22:23:00 +08:00
|
|
|
func ForwarderFromURL(s, intface string) (f *Forwarder, err error) {
|
2018-08-15 00:54:17 +08:00
|
|
|
f = &Forwarder{}
|
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
ss := strings.Split(s, "#")
|
2018-08-15 00:54:17 +08:00
|
|
|
if len(ss) > 1 {
|
|
|
|
err = f.parseOption(ss[1])
|
|
|
|
}
|
|
|
|
|
2018-08-20 22:23:00 +08:00
|
|
|
iface := intface
|
|
|
|
if f.intface != "" && f.intface != intface {
|
|
|
|
iface = f.intface
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:53:04 +08:00
|
|
|
var d proxy.Dialer
|
|
|
|
d, err = proxy.NewDirect(iface)
|
2018-08-19 01:49:52 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
for _, url := range strings.Split(ss[0], ",") {
|
2019-09-18 12:53:04 +08:00
|
|
|
d, err = proxy.DialerFromURL(url, d)
|
2018-08-10 19:03:30 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-15 00:54:17 +08:00
|
|
|
f.Dialer = d
|
|
|
|
f.addr = d.Addr()
|
2018-08-12 12:37:25 +08:00
|
|
|
|
2018-12-19 23:33:58 +08:00
|
|
|
// set forwarder to disabled by default
|
|
|
|
f.Disable()
|
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
return f, err
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
2019-09-18 12:53:04 +08:00
|
|
|
// DirectForwarder returns a direct forwarder
|
|
|
|
func DirectForwarder(intface string) *Forwarder {
|
|
|
|
d, err := proxy.NewDirect(intface)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Forwarder{Dialer: d, addr: d.Addr()}
|
|
|
|
}
|
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
func (f *Forwarder) parseOption(option string) error {
|
|
|
|
query, err := url.ParseQuery(option)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var priority uint64
|
|
|
|
p := query.Get("priority")
|
|
|
|
if p != "" {
|
|
|
|
priority, err = strconv.ParseUint(p, 10, 32)
|
|
|
|
}
|
2018-08-23 00:01:31 +08:00
|
|
|
f.SetPriority(uint32(priority))
|
2018-08-12 12:37:25 +08:00
|
|
|
|
2018-08-18 23:59:21 +08:00
|
|
|
f.intface = query.Get("interface")
|
2018-08-15 00:54:17 +08:00
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:03:30 +08:00
|
|
|
// Addr .
|
|
|
|
func (f *Forwarder) Addr() string {
|
|
|
|
return f.addr
|
|
|
|
}
|
|
|
|
|
2018-08-12 12:37:25 +08:00
|
|
|
// Dial .
|
2019-09-18 19:40:14 +08:00
|
|
|
func (f *Forwarder) Dial(network, addr string) (c net.Conn, err error) {
|
|
|
|
c, err = f.Dialer.Dial(network, addr)
|
2018-08-12 12:37:25 +08:00
|
|
|
if err != nil {
|
2018-08-23 00:01:31 +08:00
|
|
|
f.IncFailures()
|
2018-08-12 12:37:25 +08:00
|
|
|
}
|
|
|
|
|
2019-09-18 19:40:14 +08:00
|
|
|
return c, err
|
2018-08-12 12:37:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Failures returns the failuer count of forwarder
|
|
|
|
func (f *Forwarder) Failures() uint32 {
|
|
|
|
return atomic.LoadUint32(&f.failures)
|
|
|
|
}
|
|
|
|
|
2018-08-23 00:01:31 +08:00
|
|
|
// IncFailures increase the failuer count by 1
|
|
|
|
func (f *Forwarder) IncFailures() {
|
2020-04-28 15:18:19 +08:00
|
|
|
failures := atomic.AddUint32(&f.failures, 1)
|
|
|
|
log.F("[forwarder] %s recorded %d failures", f.addr, failures)
|
2020-05-01 20:54:23 +08:00
|
|
|
|
2020-04-28 15:18:19 +08:00
|
|
|
if failures >= f.MaxFailures() && f.Enabled() {
|
|
|
|
log.F("[forwarder] %s reaches maxfailures.", f.addr)
|
|
|
|
f.Disable()
|
|
|
|
}
|
2018-08-23 00:01:31 +08:00
|
|
|
}
|
|
|
|
|
2018-08-25 23:56:18 +08:00
|
|
|
// AddHandler adds a custom handler to handle the status change event
|
2018-08-26 01:25:22 +08:00
|
|
|
func (f *Forwarder) AddHandler(h StatusHandler) {
|
2018-08-25 23:56:18 +08:00
|
|
|
f.handlers = append(f.handlers, h)
|
|
|
|
}
|
|
|
|
|
2018-08-12 22:00:12 +08:00
|
|
|
// Enable the forwarder
|
2018-08-12 12:37:25 +08:00
|
|
|
func (f *Forwarder) Enable() {
|
2018-08-25 23:56:18 +08:00
|
|
|
if atomic.CompareAndSwapUint32(&f.disabled, 1, 0) {
|
|
|
|
for _, h := range f.handlers {
|
|
|
|
h(f)
|
|
|
|
}
|
|
|
|
}
|
2018-08-12 21:40:22 +08:00
|
|
|
atomic.StoreUint32(&f.failures, 0)
|
2018-08-12 12:37:25 +08:00
|
|
|
}
|
|
|
|
|
2018-08-12 22:00:12 +08:00
|
|
|
// Disable the forwarder
|
2018-08-12 12:37:25 +08:00
|
|
|
func (f *Forwarder) Disable() {
|
2018-08-25 23:56:18 +08:00
|
|
|
if atomic.CompareAndSwapUint32(&f.disabled, 0, 1) {
|
|
|
|
for _, h := range f.handlers {
|
|
|
|
h(f)
|
|
|
|
}
|
|
|
|
}
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
2018-08-12 22:00:12 +08:00
|
|
|
// Enabled returns the status of forwarder
|
2018-08-10 19:03:30 +08:00
|
|
|
func (f *Forwarder) Enabled() bool {
|
2018-08-12 12:37:25 +08:00
|
|
|
return !isTrue(atomic.LoadUint32(&f.disabled))
|
|
|
|
}
|
|
|
|
|
|
|
|
func isTrue(n uint32) bool {
|
|
|
|
return n&1 == 1
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
2018-08-14 19:33:18 +08:00
|
|
|
|
2018-08-23 00:01:31 +08:00
|
|
|
// Priority returns the priority of forwarder
|
|
|
|
func (f *Forwarder) Priority() uint32 {
|
|
|
|
return atomic.LoadUint32(&f.priority)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPriority sets the priority of forwarder
|
|
|
|
func (f *Forwarder) SetPriority(l uint32) {
|
|
|
|
atomic.StoreUint32(&f.priority, l)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxFailures returns the maxFailures of forwarder
|
|
|
|
func (f *Forwarder) MaxFailures() uint32 {
|
|
|
|
return atomic.LoadUint32(&f.maxFailures)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetMaxFailures sets the maxFailures of forwarder
|
|
|
|
func (f *Forwarder) SetMaxFailures(l uint32) {
|
|
|
|
atomic.StoreUint32(&f.maxFailures, l)
|
|
|
|
}
|
|
|
|
|
2018-08-14 19:33:18 +08:00
|
|
|
// Latency returns the latency of forwarder
|
|
|
|
func (f *Forwarder) Latency() int64 {
|
|
|
|
return atomic.LoadInt64(&f.latency)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetLatency sets the latency of forwarder
|
|
|
|
func (f *Forwarder) SetLatency(l int64) {
|
|
|
|
atomic.StoreInt64(&f.latency, l)
|
|
|
|
}
|