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-10 19:03:30 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// Forwarder is a forwarder
|
|
|
|
type Forwarder struct {
|
|
|
|
Dialer
|
2018-08-12 12:37:25 +08:00
|
|
|
Priority int
|
2018-08-10 19:03:30 +08:00
|
|
|
addr string
|
2018-08-12 12:37:25 +08:00
|
|
|
disabled uint32
|
|
|
|
failures uint32
|
2018-08-11 11:46:10 +08:00
|
|
|
latency int
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// ForwarderFromURL returns a new forwarder
|
2018-08-12 12:37:25 +08:00
|
|
|
func ForwarderFromURL(s string) (f *Forwarder, err error) {
|
|
|
|
ss := strings.Split(s, "#")
|
2018-08-10 19:03:30 +08:00
|
|
|
var d Dialer
|
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-12 12:37:25 +08:00
|
|
|
f = NewForwarder(d)
|
|
|
|
if len(ss) > 1 {
|
|
|
|
err = f.parseOption(ss[1])
|
|
|
|
}
|
|
|
|
|
|
|
|
return f, err
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewForwarder .
|
|
|
|
func NewForwarder(dialer Dialer) *Forwarder {
|
|
|
|
return &Forwarder{Dialer: dialer, addr: dialer.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)
|
|
|
|
}
|
|
|
|
f.Priority = int(priority)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
// TODO: proxy timeout, target timeout?
|
|
|
|
if err != nil {
|
|
|
|
atomic.AddUint32(&f.failures, 1)
|
|
|
|
// log.F("forward dial failed, %d", f.failures)
|
|
|
|
}
|
|
|
|
|
|
|
|
return c, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Failures returns the failuer count of forwarder
|
|
|
|
func (f *Forwarder) Failures() uint32 {
|
|
|
|
return atomic.LoadUint32(&f.failures)
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:03:30 +08:00
|
|
|
// Enable .
|
2018-08-12 12:37:25 +08:00
|
|
|
func (f *Forwarder) Enable() {
|
|
|
|
atomic.StoreUint32(&f.failures, 0)
|
|
|
|
atomic.StoreUint32(&f.failures, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable .
|
|
|
|
func (f *Forwarder) Disable() {
|
|
|
|
atomic.StoreUint32(&f.failures, 1)
|
2018-08-10 19:03:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enabled .
|
|
|
|
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
|
|
|
}
|