2018-08-10 19:03:30 +08:00
|
|
|
package proxy
|
|
|
|
|
|
|
|
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"
|
2018-08-10 19:03:30 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Forwarder is a forwarder
|
|
|
|
type Forwarder struct {
|
|
|
|
Dialer
|
2018-08-12 21:40:22 +08:00
|
|
|
Priority int
|
|
|
|
addr string
|
|
|
|
disabled uint32
|
|
|
|
failures uint32
|
|
|
|
MaxFailures uint32 //maxfailures to set to Disabled
|
2018-08-14 19:33:18 +08:00
|
|
|
latency int64
|
2018-08-15 00:54:17 +08:00
|
|
|
localip string // local ip address
|
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-12 12:37:25 +08:00
|
|
|
func ForwarderFromURL(s 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])
|
|
|
|
}
|
|
|
|
|
|
|
|
var d Dialer = NewDirect(f.localip)
|
2018-08-12 12:37:25 +08:00
|
|
|
for _, url := range strings.Split(ss[0], ",") {
|
2018-08-10 19:03:30 +08:00
|
|
|
d, err = DialerFromURL(url, d)
|
|
|
|
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
|
|
|
|
|
|
|
return f, err
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
f.Priority = int(priority)
|
|
|
|
|
2018-08-15 00:54:17 +08:00
|
|
|
f.localip = query.Get("localip")
|
|
|
|
|
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 .
|
|
|
|
func (f *Forwarder) Dial(network, addr string) (c net.Conn, err error) {
|
|
|
|
c, err = f.Dialer.Dial(network, addr)
|
|
|
|
if err != nil {
|
|
|
|
atomic.AddUint32(&f.failures, 1)
|
2018-08-13 00:42:59 +08:00
|
|
|
if f.Failures() >= f.MaxFailures {
|
|
|
|
f.Disable()
|
|
|
|
log.F("[forwarder] %s reaches maxfailures, set to disabled", f.addr)
|
|
|
|
}
|
2018-08-12 12:37:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return c, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Failures returns the failuer count of forwarder
|
|
|
|
func (f *Forwarder) Failures() uint32 {
|
|
|
|
return atomic.LoadUint32(&f.failures)
|
|
|
|
}
|
|
|
|
|
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-12 18:50:44 +08:00
|
|
|
atomic.StoreUint32(&f.disabled, 0)
|
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-12 18:50:44 +08:00
|
|
|
atomic.StoreUint32(&f.disabled, 1)
|
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
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|