diff --git a/cmd/stdiscosrv/apisrv.go b/cmd/stdiscosrv/apisrv.go
index a5428fa20..35475eca3 100644
--- a/cmd/stdiscosrv/apisrv.go
+++ b/cmd/stdiscosrv/apisrv.go
@@ -336,7 +336,7 @@ func fixupAddresses(remote net.IP, addresses []string) []string {
ip := net.ParseIP(host)
if host == "" || ip.IsUnspecified() {
// Do not use IPv6 remote address if requested scheme is ...4
- // (i.e., tcp4, kcp4, etc.)
+ // (i.e., tcp4, etc.)
if strings.HasSuffix(uri.Scheme, "4") && remote.To4() == nil {
continue
}
diff --git a/cmd/syncthing/usage_report.go b/cmd/syncthing/usage_report.go
index 2556d45fd..0c1da16cf 100644
--- a/cmd/syncthing/usage_report.go
+++ b/cmd/syncthing/usage_report.go
@@ -199,7 +199,6 @@ func reportData(cfg configIntf, m modelIntf, connectionsService connectionsIntf,
res["limitBandwidthInLan"] = opts.LimitBandwidthInLan
res["customReleaseURL"] = opts.ReleasesURL != "https://upgrades.syncthing.net/meta.json"
res["restartOnWakeup"] = opts.RestartOnWakeup
- res["customStunServers"] = len(opts.StunServers) == 0 || opts.StunServers[0] != "default" || len(opts.StunServers) > 1
folderUsesV3 := map[string]int{
"scanProgressDisabled": 0,
diff --git a/lib/config/config.go b/lib/config/config.go
index 5e26ef3aa..7546b92b7 100644
--- a/lib/config/config.go
+++ b/lib/config/config.go
@@ -39,8 +39,6 @@ const (
var (
// DefaultTCPPort defines default TCP port used if the URI does not specify one, for example tcp://0.0.0.0
DefaultTCPPort = 22000
- // DefaultKCPPort defines default KCP (UDP) port used if the URI does not specify one, for example kcp://0.0.0.0
- DefaultKCPPort = 22020
// DefaultListenAddresses should be substituted when the configuration
// contains default. This is done by the
// "consumer" of the configuration as we don't want these saved to the
@@ -48,7 +46,6 @@ var (
DefaultListenAddresses = []string{
util.Address("tcp", net.JoinHostPort("0.0.0.0", strconv.Itoa(DefaultTCPPort))),
"dynamic+https://relays.syncthing.net/endpoint",
- util.Address("kcp", net.JoinHostPort("0.0.0.0", strconv.Itoa(DefaultKCPPort))),
}
// DefaultDiscoveryServersV4 should be substituted when the configuration
// contains default-v4.
@@ -65,25 +62,6 @@ var (
// DefaultDiscoveryServers should be substituted when the configuration
// contains default.
DefaultDiscoveryServers = append(DefaultDiscoveryServersV4, DefaultDiscoveryServersV6...)
- // DefaultStunServers should be substituted when the configuration
- // contains default.
- DefaultStunServers = []string{
- "stun.callwithus.com:3478",
- "stun.counterpath.com:3478",
- "stun.counterpath.net:3478",
- "stun.ekiga.net:3478",
- "stun.ideasip.com:3478",
- "stun.internetcalls.com:3478",
- "stun.schlund.de:3478",
- "stun.sipgate.net:10000",
- "stun.sipgate.net:3478",
- "stun.voip.aebc.com:3478",
- "stun.voiparound.com:3478",
- "stun.voipbuster.com:3478",
- "stun.voipstunt.com:3478",
- "stun.voxgratia.org:3478",
- "stun.xten.com:3478",
- }
// DefaultTheme is the default and fallback theme for the web UI.
DefaultTheme = "default"
)
@@ -380,6 +358,16 @@ func (cfg *Configuration) clean() error {
}
cfg.IgnoredDevices = newIgnoredDevices
+ // Deprecated protocols are removed from the list of listeners and
+ // device addresses. So far just kcp*.
+ for _, prefix := range []string{"kcp"} {
+ cfg.Options.ListenAddresses = filterURLSchemePrefix(cfg.Options.ListenAddresses, prefix)
+ for i := range cfg.Devices {
+ dev := &cfg.Devices[i]
+ dev.Addresses = filterURLSchemePrefix(dev.Addresses, prefix)
+ }
+ }
+
return nil
}
@@ -768,3 +756,21 @@ func cleanSymlinks(filesystem fs.Filesystem, dir string) {
return nil
})
}
+
+// filterURLSchemePrefix returns the list of addresses after removing all
+// entries whose URL scheme matches the given prefix.
+func filterURLSchemePrefix(addrs []string, prefix string) []string {
+ for i := 0; i < len(addrs); i++ {
+ uri, err := url.Parse(addrs[i])
+ if err != nil {
+ continue
+ }
+ if strings.HasPrefix(uri.Scheme, prefix) {
+ // Remove this entry
+ copy(addrs[i:], addrs[i+1:])
+ addrs = addrs[:len(addrs)-1]
+ i--
+ }
+ }
+ return addrs
+}
diff --git a/lib/config/config_test.go b/lib/config/config_test.go
index b0db080d8..adb1a3157 100644
--- a/lib/config/config_test.go
+++ b/lib/config/config_test.go
@@ -68,13 +68,6 @@ func TestDefaultValues(t *testing.T) {
TempIndexMinBlocks: 10,
UnackedNotificationIDs: []string{},
WeakHashSelectionMethod: WeakHashAuto,
- StunKeepaliveS: 24,
- StunServers: []string{"default"},
- KCPCongestionControl: true,
- KCPReceiveWindowSize: 128,
- KCPSendWindowSize: 128,
- KCPUpdateIntervalMs: 25,
- KCPFastResend: false,
DefaultFolderPath: "~",
SetLowPriority: true,
}
@@ -217,13 +210,6 @@ func TestOverriddenValues(t *testing.T) {
"channelNotification", // added in 17->18 migration
},
WeakHashSelectionMethod: WeakHashNever,
- StunKeepaliveS: 10,
- StunServers: []string{"a.stun.com", "b.stun.com"},
- KCPCongestionControl: false,
- KCPReceiveWindowSize: 1280,
- KCPSendWindowSize: 1280,
- KCPUpdateIntervalMs: 1000,
- KCPFastResend: true,
DefaultFolderPath: "/media/syncthing",
SetLowPriority: false,
}
@@ -953,6 +939,32 @@ func TestInvalidFolderIDRejected(t *testing.T) {
}
}
+func TestFilterURLSchemePrefix(t *testing.T) {
+ cases := []struct {
+ before []string
+ prefix string
+ after []string
+ }{
+ {[]string{}, "kcp", []string{}},
+ {[]string{"tcp://foo"}, "kcp", []string{"tcp://foo"}},
+ {[]string{"kcp://foo"}, "kcp", []string{}},
+ {[]string{"tcp6://foo", "kcp6://foo"}, "kcp", []string{"tcp6://foo"}},
+ {[]string{"kcp6://foo", "tcp6://foo"}, "kcp", []string{"tcp6://foo"}},
+ {
+ []string{"tcp://foo", "tcp4://foo", "kcp://foo", "kcp4://foo", "banana://foo", "banana4://foo", "banananas!"},
+ "kcp",
+ []string{"tcp://foo", "tcp4://foo", "banana://foo", "banana4://foo", "banananas!"},
+ },
+ }
+
+ for _, tc := range cases {
+ res := filterURLSchemePrefix(tc.before, tc.prefix)
+ if !reflect.DeepEqual(res, tc.after) {
+ t.Errorf("filterURLSchemePrefix => %q, expected %q", res, tc.after)
+ }
+ }
+}
+
// defaultConfigAsMap returns a valid default config as a JSON-decoded
// map[string]interface{}. This is useful to override random elements and
// re-encode into JSON.
diff --git a/lib/config/optionsconfiguration.go b/lib/config/optionsconfiguration.go
index 578bd6ad2..2f2e6197e 100644
--- a/lib/config/optionsconfiguration.go
+++ b/lib/config/optionsconfiguration.go
@@ -134,14 +134,6 @@ type OptionsConfiguration struct {
UnackedNotificationIDs []string `xml:"unackedNotificationID" json:"unackedNotificationIDs"`
TrafficClass int `xml:"trafficClass" json:"trafficClass"`
WeakHashSelectionMethod WeakHashSelectionMethod `xml:"weakHashSelectionMethod" json:"weakHashSelectionMethod" restart:"true"`
- StunServers []string `xml:"stunServer" json:"stunServers" default:"default"`
- StunKeepaliveS int `xml:"stunKeepaliveSeconds" json:"stunKeepaliveSeconds" default:"24"`
- KCPNoDelay bool `xml:"kcpNoDelay" json:"kcpNoDelay" default:"false"`
- KCPUpdateIntervalMs int `xml:"kcpUpdateIntervalMs" json:"kcpUpdateIntervalMs" default:"25"`
- KCPFastResend bool `xml:"kcpFastResend" json:"kcpFastResend" default:"false"`
- KCPCongestionControl bool `xml:"kcpCongestionControl" json:"kcpCongestionControl" default:"true"`
- KCPSendWindowSize int `xml:"kcpSendWindowSize" json:"kcpSendWindowSize" default:"128"`
- KCPReceiveWindowSize int `xml:"kcpReceiveWindowSize" json:"kcpReceiveWindowSize" default:"128"`
DefaultFolderPath string `xml:"defaultFolderPath" json:"defaultFolderPath" default:"~"`
SetLowPriority bool `xml:"setLowPriority" json:"setLowPriority" default:"true"`
diff --git a/lib/config/testdata/overridenvalues.xml b/lib/config/testdata/overridenvalues.xml
index d8387aa4a..84cde1b4e 100644
--- a/lib/config/testdata/overridenvalues.xml
+++ b/lib/config/testdata/overridenvalues.xml
@@ -35,14 +35,6 @@
true
100
never
- 10
- a.stun.com
- b.stun.com
- false
- 1280
- 1280
- 1000
- true
/media/syncthing
false
diff --git a/lib/config/wrapper.go b/lib/config/wrapper.go
index aa6a97a06..058ca263d 100644
--- a/lib/config/wrapper.go
+++ b/lib/config/wrapper.go
@@ -15,7 +15,6 @@ import (
"github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
- "github.com/syncthing/syncthing/lib/rand"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/util"
)
@@ -433,29 +432,6 @@ func (w *Wrapper) setRequiresRestart() {
atomic.StoreUint32(&w.requiresRestart, 1)
}
-func (w *Wrapper) StunServers() []string {
- var addresses []string
- for _, addr := range w.cfg.Options.StunServers {
- switch addr {
- case "default":
- addresses = append(addresses, DefaultStunServers...)
- default:
- addresses = append(addresses, addr)
- }
- }
-
- addresses = util.UniqueStrings(addresses)
-
- // Shuffle
- l := len(addresses)
- for i := range addresses {
- r := rand.Intn(l)
- addresses[i], addresses[r] = addresses[r], addresses[i]
- }
-
- return addresses
-}
-
func (w *Wrapper) MyName() string {
w.mut.Lock()
myID := w.cfg.MyID
diff --git a/lib/connections/config.go b/lib/connections/config.go
index 7824ae7b8..659b39234 100644
--- a/lib/connections/config.go
+++ b/lib/connections/config.go
@@ -6,28 +6,7 @@
package connections
-import (
- "time"
-
- "github.com/xtaci/smux"
-)
-
const (
tcpPriority = 10
- kcpPriority = 50
relayPriority = 200
-
- // KCP filter priorities
- kcpNoFilterPriority = 100
- kcpConversationFilterPriority = 20
- kcpStunFilterPriority = 10
-)
-
-var (
- smuxConfig = &smux.Config{
- KeepAliveInterval: 10 * time.Second,
- KeepAliveTimeout: 30 * time.Second,
- MaxFrameSize: 4096,
- MaxReceiveBuffer: 4 * 1024 * 1024,
- }
)
diff --git a/lib/connections/connections_test.go b/lib/connections/connections_test.go
index eead14431..f42f18390 100644
--- a/lib/connections/connections_test.go
+++ b/lib/connections/connections_test.go
@@ -6,8 +6,13 @@
package connections
-import "testing"
-import "net/url"
+import (
+ "net/url"
+ "testing"
+
+ "github.com/syncthing/syncthing/lib/config"
+ "github.com/syncthing/syncthing/lib/protocol"
+)
func TestFixupPort(t *testing.T) {
cases := [][2]string{
@@ -105,3 +110,60 @@ func TestAllowedNetworks(t *testing.T) {
}
}
}
+
+func TestGetDialer(t *testing.T) {
+ mustParseURI := func(v string) *url.URL {
+ uri, err := url.Parse(v)
+ if err != nil {
+ panic(err)
+ }
+ return uri
+ }
+
+ cases := []struct {
+ uri *url.URL
+ ok bool
+ disabled bool
+ deprecated bool
+ }{
+ {mustParseURI("tcp://1.2.3.4:5678"), true, false, false}, // ok
+ {mustParseURI("tcp4://1.2.3.4:5678"), true, false, false}, // ok
+ {mustParseURI("kcp://1.2.3.4:5678"), false, false, true}, // deprecated
+ {mustParseURI("relay://1.2.3.4:5678"), false, true, false}, // disabled
+ {mustParseURI("http://1.2.3.4:5678"), false, false, false}, // generally bad
+ {mustParseURI("bananas!"), false, false, false}, // wat
+ }
+
+ cfg := config.New(protocol.LocalDeviceID)
+ cfg.Options.RelaysEnabled = false
+
+ for _, tc := range cases {
+ df, err := getDialerFactory(cfg, tc.uri)
+ if tc.ok && err != nil {
+ t.Errorf("getDialerFactory(%q) => %v, expected nil err", tc.uri, err)
+ }
+ if tc.ok && df == nil {
+ t.Errorf("getDialerFactory(%q) => nil factory, expected non-nil", tc.uri)
+ }
+ if tc.deprecated && err != errDeprecated {
+ t.Errorf("getDialerFactory(%q) => %v, expected %v", tc.uri, err, errDeprecated)
+ }
+ if tc.disabled && err != errDisabled {
+ t.Errorf("getDialerFactory(%q) => %v, expected %v", tc.uri, err, errDisabled)
+ }
+
+ lf, err := getListenerFactory(cfg, tc.uri)
+ if tc.ok && err != nil {
+ t.Errorf("getListenerFactory(%q) => %v, expected nil err", tc.uri, err)
+ }
+ if tc.ok && lf == nil {
+ t.Errorf("getListenerFactory(%q) => nil factory, expected non-nil", tc.uri)
+ }
+ if tc.deprecated && err != errDeprecated {
+ t.Errorf("getListenerFactory(%q) => %v, expected %v", tc.uri, err, errDeprecated)
+ }
+ if tc.disabled && err != errDisabled {
+ t.Errorf("getListenerFactory(%q) => %v, expected %v", tc.uri, err, errDisabled)
+ }
+ }
+}
diff --git a/lib/connections/deprecated.go b/lib/connections/deprecated.go
new file mode 100644
index 000000000..2438008b3
--- /dev/null
+++ b/lib/connections/deprecated.go
@@ -0,0 +1,36 @@
+// Copyright (C) 2018 The Syncthing Authors.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at https://mozilla.org/MPL/2.0/.
+
+package connections
+
+import "github.com/syncthing/syncthing/lib/config"
+
+// deprecatedListener is never valid
+type deprecatedListener struct {
+ listenerFactory
+}
+
+func (deprecatedListener) Valid(_ config.Configuration) error {
+ return errDeprecated
+}
+
+// deprecatedDialer is never valid
+type deprecatedDialer struct {
+ dialerFactory
+}
+
+func (deprecatedDialer) Valid(_ config.Configuration) error {
+ return errDeprecated
+}
+
+func init() {
+ listeners["kcp"] = deprecatedListener{}
+ listeners["kcp4"] = deprecatedListener{}
+ listeners["kcp6"] = deprecatedListener{}
+ dialers["kcp"] = deprecatedDialer{}
+ dialers["kcp4"] = deprecatedDialer{}
+ dialers["kcp6"] = deprecatedDialer{}
+}
diff --git a/lib/connections/kcp_dial.go b/lib/connections/kcp_dial.go
deleted file mode 100644
index 7d1650c51..000000000
--- a/lib/connections/kcp_dial.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (C) 2016 The Syncthing Authors.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-package connections
-
-import (
- "crypto/tls"
- "net/url"
- "time"
-
- "github.com/syncthing/syncthing/lib/config"
- "github.com/syncthing/syncthing/lib/protocol"
- "github.com/xtaci/kcp-go"
- "github.com/xtaci/smux"
-)
-
-func init() {
- factory := &kcpDialerFactory{}
- for _, scheme := range []string{"kcp", "kcp4", "kcp6"} {
- dialers[scheme] = factory
- }
-}
-
-type kcpDialer struct {
- cfg *config.Wrapper
- tlsCfg *tls.Config
-}
-
-func (d *kcpDialer) Dial(id protocol.DeviceID, uri *url.URL) (internalConn, error) {
- uri = fixupPort(uri, config.DefaultKCPPort)
-
- var conn *kcp.UDPSession
- var err error
-
- // Try to dial via an existing listening connection
- // giving better changes punching through NAT.
- if f := getDialingFilter(); f != nil {
- conn, err = kcp.NewConn(uri.Host, nil, 0, 0, f.NewConn(kcpConversationFilterPriority, &kcpConversationFilter{}))
- l.Debugf("dial %s using existing conn on %s", uri.String(), conn.LocalAddr())
- } else {
- conn, err = kcp.DialWithOptions(uri.Host, nil, 0, 0)
- }
- if err != nil {
- return internalConn{}, err
- }
-
- opts := d.cfg.Options()
-
- conn.SetStreamMode(true)
- conn.SetACKNoDelay(false)
- conn.SetWindowSize(opts.KCPSendWindowSize, opts.KCPReceiveWindowSize)
- conn.SetNoDelay(boolInt(opts.KCPNoDelay), opts.KCPUpdateIntervalMs, boolInt(opts.KCPFastResend), boolInt(!opts.KCPCongestionControl))
-
- ses, err := smux.Client(conn, smuxConfig)
- if err != nil {
- conn.Close()
- return internalConn{}, err
- }
-
- ses.SetDeadline(time.Now().Add(10 * time.Second))
- stream, err := ses.OpenStream()
- if err != nil {
- ses.Close()
- return internalConn{}, err
- }
- ses.SetDeadline(time.Time{})
-
- tc := tls.Client(&sessionClosingStream{stream, ses}, d.tlsCfg)
- tc.SetDeadline(time.Now().Add(time.Second * 10))
- err = tc.Handshake()
- if err != nil {
- tc.Close()
- return internalConn{}, err
- }
- tc.SetDeadline(time.Time{})
-
- return internalConn{tc, connTypeKCPClient, kcpPriority}, nil
-}
-
-func (d *kcpDialer) RedialFrequency() time.Duration {
- // For restricted NATs, the UDP mapping will potentially only be open for 20-30 seconds
- // hence try dialing just as often.
- return time.Duration(d.cfg.Options().StunKeepaliveS) * time.Second
-}
-
-type kcpDialerFactory struct{}
-
-func (kcpDialerFactory) New(cfg *config.Wrapper, tlsCfg *tls.Config) genericDialer {
- return &kcpDialer{
- cfg: cfg,
- tlsCfg: tlsCfg,
- }
-}
-
-func (kcpDialerFactory) Priority() int {
- return kcpPriority
-}
-
-func (kcpDialerFactory) AlwaysWAN() bool {
- return false
-}
-
-func (kcpDialerFactory) Enabled(cfg config.Configuration) bool {
- return true
-}
-
-func (kcpDialerFactory) String() string {
- return "KCP Dialer"
-}
diff --git a/lib/connections/kcp_listen.go b/lib/connections/kcp_listen.go
deleted file mode 100644
index fb02b1cc4..000000000
--- a/lib/connections/kcp_listen.go
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright (C) 2016 The Syncthing Authors.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-package connections
-
-import (
- "crypto/tls"
- "net"
- "net/url"
- "strings"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/AudriusButkevicius/pfilter"
- "github.com/ccding/go-stun/stun"
- "github.com/xtaci/kcp-go"
- "github.com/xtaci/smux"
-
- "github.com/syncthing/syncthing/lib/config"
- "github.com/syncthing/syncthing/lib/nat"
-)
-
-const stunRetryInterval = 5 * time.Minute
-
-func init() {
- factory := &kcpListenerFactory{}
- for _, scheme := range []string{"kcp", "kcp4", "kcp6"} {
- listeners[scheme] = factory
- }
-}
-
-type kcpListener struct {
- onAddressesChangedNotifier
-
- uri *url.URL
- cfg *config.Wrapper
- tlsCfg *tls.Config
- stop chan struct{}
- conns chan internalConn
- factory listenerFactory
- nat atomic.Value
-
- address *url.URL
- err error
- mut sync.RWMutex
-}
-
-func (t *kcpListener) Serve() {
- t.mut.Lock()
- t.err = nil
- t.mut.Unlock()
-
- network := strings.Replace(t.uri.Scheme, "kcp", "udp", -1)
-
- packetConn, err := net.ListenPacket(network, t.uri.Host)
- if err != nil {
- t.mut.Lock()
- t.err = err
- t.mut.Unlock()
- l.Infoln("Listen (BEP/kcp):", err)
- return
- }
- filterConn := pfilter.NewPacketFilter(packetConn)
- kcpConn := filterConn.NewConn(kcpNoFilterPriority, nil)
- stunConn := filterConn.NewConn(kcpStunFilterPriority, &stunFilter{
- ids: make(map[string]time.Time),
- })
-
- filterConn.Start()
- registerFilter(filterConn)
-
- listener, err := kcp.ServeConn(nil, 0, 0, kcpConn)
- if err != nil {
- t.mut.Lock()
- t.err = err
- t.mut.Unlock()
- l.Infoln("Listen (BEP/kcp):", err)
- return
- }
-
- defer listener.Close()
- defer stunConn.Close()
- defer kcpConn.Close()
- defer deregisterFilter(filterConn)
- defer packetConn.Close()
-
- l.Infof("KCP listener (%v) starting", kcpConn.LocalAddr())
- defer l.Infof("KCP listener (%v) shutting down", kcpConn.LocalAddr())
-
- go t.stunRenewal(stunConn)
-
- for {
- listener.SetDeadline(time.Now().Add(time.Second))
- conn, err := listener.AcceptKCP()
-
- select {
- case <-t.stop:
- if err == nil {
- conn.Close()
- }
- return
- default:
- }
- if err != nil {
- if err, ok := err.(net.Error); !ok || !err.Timeout() {
- l.Warnln("Listen (BEP/kcp): Accepting connection:", err)
- }
- continue
- }
-
- opts := t.cfg.Options()
-
- conn.SetStreamMode(true)
- conn.SetACKNoDelay(false)
- conn.SetWindowSize(opts.KCPSendWindowSize, opts.KCPReceiveWindowSize)
- conn.SetNoDelay(boolInt(opts.KCPNoDelay), opts.KCPUpdateIntervalMs, boolInt(opts.KCPFastResend), boolInt(!opts.KCPCongestionControl))
-
- l.Debugln("connect from", conn.RemoteAddr())
-
- ses, err := smux.Server(conn, smuxConfig)
- if err != nil {
- l.Debugln("smux server:", err)
- conn.Close()
- continue
- }
-
- ses.SetDeadline(time.Now().Add(10 * time.Second))
- stream, err := ses.AcceptStream()
- if err != nil {
- l.Debugln("smux accept:", err)
- ses.Close()
- continue
- }
- ses.SetDeadline(time.Time{})
-
- tc := tls.Server(&sessionClosingStream{stream, ses}, t.tlsCfg)
- tc.SetDeadline(time.Now().Add(time.Second * 10))
- err = tc.Handshake()
- if err != nil {
- l.Debugln("TLS handshake (BEP/kcp):", err)
- tc.Close()
- continue
- }
- tc.SetDeadline(time.Time{})
-
- t.conns <- internalConn{tc, connTypeKCPServer, kcpPriority}
- }
-}
-
-func (t *kcpListener) Stop() {
- close(t.stop)
-}
-
-func (t *kcpListener) URI() *url.URL {
- return t.uri
-}
-
-func (t *kcpListener) WANAddresses() []*url.URL {
- uris := t.LANAddresses()
- t.mut.RLock()
- if t.address != nil {
- uris = append(uris, t.address)
- }
- t.mut.RUnlock()
- return uris
-}
-
-func (t *kcpListener) LANAddresses() []*url.URL {
- return []*url.URL{t.uri}
-}
-
-func (t *kcpListener) Error() error {
- t.mut.RLock()
- err := t.err
- t.mut.RUnlock()
- return err
-}
-
-func (t *kcpListener) String() string {
- return t.uri.String()
-}
-
-func (t *kcpListener) Factory() listenerFactory {
- return t.factory
-}
-
-func (t *kcpListener) NATType() string {
- v := t.nat.Load().(stun.NATType)
- if v == stun.NATUnknown || v == stun.NATError {
- return "unknown"
- }
- return v.String()
-}
-
-func (t *kcpListener) stunRenewal(listener net.PacketConn) {
- client := stun.NewClientWithConnection(listener)
- client.SetSoftwareName("syncthing")
-
- var natType stun.NATType
- var extAddr *stun.Host
- var udpAddr *net.UDPAddr
- var err error
-
- oldType := stun.NATUnknown
-
- for {
-
- disabled:
- if t.cfg.Options().StunKeepaliveS < 1 {
- time.Sleep(time.Second)
- oldType = stun.NATUnknown
- t.nat.Store(stun.NATUnknown)
- t.mut.Lock()
- t.address = nil
- t.mut.Unlock()
- continue
- }
-
- for _, addr := range t.cfg.StunServers() {
- // Resolve the address, so that in case the server advertises two
- // IPs, we always hit the same one, as otherwise, the mapping might
- // expire as we hit the other address, and cause us to flip flop
- // between servers/external addresses, as a result flooding discovery
- // servers.
- udpAddr, err = net.ResolveUDPAddr("udp", addr)
- if err != nil {
- l.Debugf("%s stun addr resolution on %s: %s", t.uri, addr, err)
- continue
- }
- client.SetServerAddr(udpAddr.String())
-
- natType, extAddr, err = client.Discover()
- if err != nil || extAddr == nil {
- l.Debugf("%s stun discovery on %s: %s", t.uri, addr, err)
- continue
- }
-
- // The stun server is most likely borked, try another one.
- if natType == stun.NATError || natType == stun.NATUnknown || natType == stun.NATBlocked {
- l.Debugf("%s stun discovery on %s resolved to %s", t.uri, addr, natType)
- continue
- }
-
- if oldType != natType {
- l.Infof("%s detected NAT type: %s", t.uri, natType)
- t.nat.Store(natType)
- oldType = natType
- }
-
- // We can't punch through this one, so no point doing keepalives
- // and such, just try again in a minute and hope that the NAT type changes.
- if !isPunchable(natType) {
- break
- }
-
- for {
- changed := false
-
- uri := *t.uri
- uri.Host = extAddr.TransportAddr()
-
- t.mut.Lock()
-
- if t.address == nil || t.address.String() != uri.String() {
- l.Infof("%s resolved external address %s (via %s)", t.uri, uri.String(), addr)
- t.address = &uri
- changed = true
- }
- t.mut.Unlock()
-
- // This will most likely result in a call to WANAddresses() which tries to
- // get t.mut, so notify while unlocked.
- if changed {
- t.notifyAddressesChanged(t)
- }
-
- select {
- case <-time.After(time.Duration(t.cfg.Options().StunKeepaliveS) * time.Second):
- case <-t.stop:
- return
- }
-
- if t.cfg.Options().StunKeepaliveS < 1 {
- goto disabled
- }
-
- extAddr, err = client.Keepalive()
- if err != nil {
- l.Debugf("%s stun keepalive on %s: %s (%v)", t.uri, addr, err, extAddr)
- break
- }
- }
- }
-
- // We failed to contact all provided stun servers or the nat is not punchable.
- // Chillout for a while.
- time.Sleep(stunRetryInterval)
- }
-}
-
-type kcpListenerFactory struct{}
-
-func (f *kcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.Config, conns chan internalConn, natService *nat.Service) genericListener {
- l := &kcpListener{
- uri: fixupPort(uri, config.DefaultKCPPort),
- cfg: cfg,
- tlsCfg: tlsCfg,
- conns: conns,
- stop: make(chan struct{}),
- factory: f,
- }
- l.nat.Store(stun.NATUnknown)
- return l
-}
-
-func (kcpListenerFactory) Enabled(cfg config.Configuration) bool {
- return true
-}
-
-func isPunchable(natType stun.NATType) bool {
- return natType == stun.NATNone || natType == stun.NATPortRestricted || natType == stun.NATRestricted || natType == stun.NATFull
-}
diff --git a/lib/connections/kcp_misc.go b/lib/connections/kcp_misc.go
deleted file mode 100644
index b71441e9c..000000000
--- a/lib/connections/kcp_misc.go
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright (C) 2016 The Syncthing Authors.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-package connections
-
-import (
- "bytes"
- "encoding/binary"
- "net"
- "sort"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/AudriusButkevicius/pfilter"
- "github.com/xtaci/kcp-go"
- "github.com/xtaci/smux"
-)
-
-var (
- mut sync.Mutex
- filters filterList
-)
-
-func init() {
- kcp.BlacklistDuration = 10 * time.Minute
-}
-
-type filterList []*pfilter.PacketFilter
-
-// Sort connections by whether they are unspecified or not, as connections
-// listening on all addresses are more useful.
-func (f filterList) Len() int { return len(f) }
-func (f filterList) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-func (f filterList) Less(i, j int) bool {
- iIsUnspecified := false
- jIsUnspecified := false
- if host, _, err := net.SplitHostPort(f[i].LocalAddr().String()); err == nil {
- iIsUnspecified = net.ParseIP(host).IsUnspecified()
- }
- if host, _, err := net.SplitHostPort(f[j].LocalAddr().String()); err == nil {
- jIsUnspecified = net.ParseIP(host).IsUnspecified()
- }
- return (iIsUnspecified && !jIsUnspecified) || (iIsUnspecified && jIsUnspecified)
-}
-
-// As we open listen KCP connections, we register them here, so that Dial calls through
-// KCP could reuse them. This way we will hopefully work around restricted NATs by
-// dialing via the same connection we are listening on, creating a mapping on our NAT
-// to that IP, and hoping that the other end will try to dial our listen address and
-// using the mapping we've established when we dialed.
-func getDialingFilter() *pfilter.PacketFilter {
- mut.Lock()
- defer mut.Unlock()
- if len(filters) == 0 {
- return nil
- }
- return filters[0]
-}
-
-func registerFilter(filter *pfilter.PacketFilter) {
- mut.Lock()
- defer mut.Unlock()
- filters = append(filters, filter)
- sort.Sort(filterList(filters))
-}
-
-func deregisterFilter(filter *pfilter.PacketFilter) {
- mut.Lock()
- defer mut.Unlock()
-
- for i, f := range filters {
- if f == filter {
- copy(filters[i:], filters[i+1:])
- filters[len(filters)-1] = nil
- filters = filters[:len(filters)-1]
- break
- }
- }
- sort.Sort(filterList(filters))
-}
-
-// Filters
-
-type kcpConversationFilter struct {
- convID uint32
-}
-
-func (f *kcpConversationFilter) Outgoing(out []byte, addr net.Addr) {
- if !f.isKCPConv(out) {
- panic("not a kcp conversation")
- }
- atomic.StoreUint32(&f.convID, binary.LittleEndian.Uint32(out[:4]))
-}
-
-func (kcpConversationFilter) isKCPConv(data []byte) bool {
- // Need at least 5 bytes
- if len(data) < 5 {
- return false
- }
-
- // First 4 bytes convID
- // 5th byte is cmd
- // IKCP_CMD_PUSH = 81 // cmd: push data
- // IKCP_CMD_ACK = 82 // cmd: ack
- // IKCP_CMD_WASK = 83 // cmd: window probe (ask)
- // IKCP_CMD_WINS = 84 // cmd: window size (tell)
- return 80 < data[4] && data[4] < 85
-}
-
-func (f *kcpConversationFilter) ClaimIncoming(in []byte, addr net.Addr) bool {
- if f.isKCPConv(in) {
- convID := atomic.LoadUint32(&f.convID)
- return convID != 0 && binary.LittleEndian.Uint32(in[:4]) == convID
- }
- return false
-}
-
-type stunFilter struct {
- ids map[string]time.Time
- mut sync.Mutex
-}
-
-func (f *stunFilter) Outgoing(out []byte, addr net.Addr) {
- if !f.isStunPayload(out) {
- panic("not a stun payload")
- }
- id := string(out[8:20])
- f.mut.Lock()
- f.ids[id] = time.Now().Add(time.Minute)
- f.reap()
- f.mut.Unlock()
-}
-
-func (f *stunFilter) ClaimIncoming(in []byte, addr net.Addr) bool {
- if f.isStunPayload(in) {
- id := string(in[8:20])
- f.mut.Lock()
- _, ok := f.ids[id]
- f.reap()
- f.mut.Unlock()
- return ok
- }
- return false
-}
-
-func (f *stunFilter) isStunPayload(data []byte) bool {
- // Need at least 20 bytes
- if len(data) < 20 {
- return false
- }
-
- // First two bits always unset, and should always send magic cookie.
- return data[0]&0xc0 == 0 && bytes.Equal(data[4:8], []byte{0x21, 0x12, 0xA4, 0x42})
-}
-
-func (f *stunFilter) reap() {
- now := time.Now()
- for id, timeout := range f.ids {
- if timeout.Before(now) {
- delete(f.ids, id)
- }
- }
-}
-
-type sessionClosingStream struct {
- *smux.Stream
- session *smux.Session
-}
-
-func (w *sessionClosingStream) Close() error {
- err1 := w.Stream.Close()
-
- deadline := time.Now().Add(5 * time.Second)
- for w.session.NumStreams() > 0 && time.Now().Before(deadline) {
- time.Sleep(200 * time.Millisecond)
- }
-
- err2 := w.session.Close()
- if err1 != nil {
- return err1
- }
- return err2
-}
-
-func boolInt(b bool) int {
- if b {
- return 1
- }
- return 0
-}
diff --git a/lib/connections/relay_dial.go b/lib/connections/relay_dial.go
index cd8a10773..5d08e337a 100644
--- a/lib/connections/relay_dial.go
+++ b/lib/connections/relay_dial.go
@@ -85,8 +85,11 @@ func (relayDialerFactory) AlwaysWAN() bool {
return true
}
-func (relayDialerFactory) Enabled(cfg config.Configuration) bool {
- return cfg.Options.RelaysEnabled
+func (relayDialerFactory) Valid(cfg config.Configuration) error {
+ if !cfg.Options.RelaysEnabled {
+ return errDisabled
+ }
+ return nil
}
func (relayDialerFactory) String() string {
diff --git a/lib/connections/relay_listen.go b/lib/connections/relay_listen.go
index b2a1dc933..889ce3ad8 100644
--- a/lib/connections/relay_listen.go
+++ b/lib/connections/relay_listen.go
@@ -190,6 +190,9 @@ func (f *relayListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tl
}
}
-func (relayListenerFactory) Enabled(cfg config.Configuration) bool {
- return cfg.Options.RelaysEnabled
+func (relayListenerFactory) Valid(cfg config.Configuration) error {
+ if !cfg.Options.RelaysEnabled {
+ return errDisabled
+ }
+ return nil
}
diff --git a/lib/connections/service.go b/lib/connections/service.go
index 4e8bcb58e..b1ab44875 100644
--- a/lib/connections/service.go
+++ b/lib/connections/service.go
@@ -39,6 +39,11 @@ var (
listeners = make(map[string]listenerFactory, 0)
)
+var (
+ errDisabled = errors.New("disabled by configuration")
+ errDeprecated = errors.New("deprecated protocol")
+)
+
const (
perDeviceWarningIntv = 15 * time.Minute
tlsHandshakeTimeout = 10 * time.Second
@@ -149,10 +154,6 @@ func NewService(cfg *config.Wrapper, myID protocol.DeviceID, mdl Model, tlsCfg *
return service
}
-var (
- errDisabled = errors.New("disabled by configuration")
-)
-
func (s *Service) handle() {
next:
for c := range s.conns {
@@ -293,7 +294,7 @@ func (s *Service) connect() {
bestDialerPrio := 1<<31 - 1 // worse prio won't build on 32 bit
for _, df := range dialers {
- if !df.Enabled(cfg) {
+ if df.Valid(cfg) != nil {
continue
}
if prio := df.Priority(); prio < bestDialerPrio {
@@ -367,13 +368,18 @@ func (s *Service) connect() {
}
}
- dialerFactory, err := s.getDialerFactory(cfg, uri)
- if err == errDisabled {
- l.Debugln(dialerFactory, "for", uri, "is disabled")
+ dialerFactory, err := getDialerFactory(cfg, uri)
+ switch err {
+ case nil:
+ // all good
+ case errDisabled:
+ l.Debugln("Dialer for", uri, "is disabled")
continue
- }
- if err != nil {
- l.Infof("%v for %v: %v", dialerFactory, uri, err)
+ case errDeprecated:
+ l.Debugln("Dialer for", uri, "is deprecated")
+ continue
+ default:
+ l.Infof("Dialer for %v: %v", uri, err)
continue
}
@@ -537,13 +543,18 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
continue
}
- factory, err := s.getListenerFactory(to, uri)
- if err == errDisabled {
+ factory, err := getListenerFactory(to, uri)
+ switch err {
+ case nil:
+ // all good
+ case errDisabled:
l.Debugln("Listener for", uri, "is disabled")
continue
- }
- if err != nil {
- l.Infof("Getting listener factory for %v: %v", uri, err)
+ case errDeprecated:
+ l.Debugln("Listener for", uri, "is deprecated")
+ continue
+ default:
+ l.Infof("Listener for %v: %v", uri, err)
continue
}
@@ -552,7 +563,7 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
}
for addr, listener := range s.listeners {
- if _, ok := seen[addr]; !ok || !listener.Factory().Enabled(to) {
+ if _, ok := seen[addr]; !ok || listener.Factory().Valid(to) != nil {
l.Debugln("Stopping listener", addr)
s.listenerSupervisor.Remove(s.listenerTokens[addr])
delete(s.listenerTokens, addr)
@@ -633,27 +644,25 @@ func (s *Service) NATType() string {
return "unknown"
}
-func (s *Service) getDialerFactory(cfg config.Configuration, uri *url.URL) (dialerFactory, error) {
+func getDialerFactory(cfg config.Configuration, uri *url.URL) (dialerFactory, error) {
dialerFactory, ok := dialers[uri.Scheme]
if !ok {
return nil, fmt.Errorf("unknown address scheme %q", uri.Scheme)
}
-
- if !dialerFactory.Enabled(cfg) {
- return nil, errDisabled
+ if err := dialerFactory.Valid(cfg); err != nil {
+ return nil, err
}
return dialerFactory, nil
}
-func (s *Service) getListenerFactory(cfg config.Configuration, uri *url.URL) (listenerFactory, error) {
+func getListenerFactory(cfg config.Configuration, uri *url.URL) (listenerFactory, error) {
listenerFactory, ok := listeners[uri.Scheme]
if !ok {
return nil, fmt.Errorf("unknown address scheme %q", uri.Scheme)
}
-
- if !listenerFactory.Enabled(cfg) {
- return nil, errDisabled
+ if err := listenerFactory.Valid(cfg); err != nil {
+ return nil, err
}
return listenerFactory, nil
diff --git a/lib/connections/structs.go b/lib/connections/structs.go
index b6187f784..4e243cc34 100644
--- a/lib/connections/structs.go
+++ b/lib/connections/structs.go
@@ -54,8 +54,6 @@ const (
connTypeRelayServer
connTypeTCPClient
connTypeTCPServer
- connTypeKCPClient
- connTypeKCPServer
)
func (t connType) String() string {
@@ -68,10 +66,6 @@ func (t connType) String() string {
return "tcp-client"
case connTypeTCPServer:
return "tcp-server"
- case connTypeKCPClient:
- return "kcp-client"
- case connTypeKCPServer:
- return "kcp-server"
default:
return "unknown-type"
}
@@ -83,8 +77,6 @@ func (t connType) Transport() string {
return "relay"
case connTypeTCPClient, connTypeTCPServer:
return "tcp"
- case connTypeKCPClient, connTypeKCPServer:
- return "kcp"
default:
return "unknown"
}
@@ -122,7 +114,7 @@ type dialerFactory interface {
New(*config.Wrapper, *tls.Config) genericDialer
Priority() int
AlwaysWAN() bool
- Enabled(config.Configuration) bool
+ Valid(config.Configuration) error
String() string
}
@@ -133,7 +125,7 @@ type genericDialer interface {
type listenerFactory interface {
New(*url.URL, *config.Wrapper, *tls.Config, chan internalConn, *nat.Service) genericListener
- Enabled(config.Configuration) bool
+ Valid(config.Configuration) error
}
type genericListener interface {
diff --git a/lib/connections/tcp_dial.go b/lib/connections/tcp_dial.go
index d2c68cfad..750db415c 100644
--- a/lib/connections/tcp_dial.go
+++ b/lib/connections/tcp_dial.go
@@ -77,8 +77,9 @@ func (tcpDialerFactory) AlwaysWAN() bool {
return false
}
-func (tcpDialerFactory) Enabled(cfg config.Configuration) bool {
- return true
+func (tcpDialerFactory) Valid(_ config.Configuration) error {
+ // Always valid
+ return nil
}
func (tcpDialerFactory) String() string {
diff --git a/lib/connections/tcp_listen.go b/lib/connections/tcp_listen.go
index 1b9d48820..21205e119 100644
--- a/lib/connections/tcp_listen.go
+++ b/lib/connections/tcp_listen.go
@@ -193,6 +193,7 @@ func (f *tcpListenerFactory) New(uri *url.URL, cfg *config.Wrapper, tlsCfg *tls.
}
}
-func (tcpListenerFactory) Enabled(cfg config.Configuration) bool {
- return true
+func (tcpListenerFactory) Valid(_ config.Configuration) error {
+ // Always valid
+ return nil
}
diff --git a/lib/protocol/benchmark_test.go b/lib/protocol/benchmark_test.go
index a46953242..0b35d9c55 100644
--- a/lib/protocol/benchmark_test.go
+++ b/lib/protocol/benchmark_test.go
@@ -9,7 +9,6 @@ import (
"testing"
"github.com/syncthing/syncthing/lib/dialer"
- "github.com/xtaci/kcp-go"
)
func BenchmarkRequestsRawTCP(b *testing.B) {
@@ -29,25 +28,6 @@ func BenchmarkRequestsRawTCP(b *testing.B) {
benchmarkRequestsConnPair(b, conn0, conn1)
}
-func BenchmarkRequestsRawKCP(b *testing.B) {
- b.Skip("KCP broken")
-
- // Benchmarks the rate at which we can serve requests over a single,
- // unencrypted KCP channel over the loopback interface.
-
- // Get a connected KCP pair
- conn0, conn1, err := getKCPConnectionPair()
- if err != nil {
- b.Fatal(err)
- }
-
- defer conn0.Close()
- defer conn1.Close()
-
- // Bench it
- benchmarkRequestsConnPair(b, conn0, conn1)
-}
-
func BenchmarkRequestsTLSoTCP(b *testing.B) {
conn0, conn1, err := getTCPConnectionPair()
if err != nil {
@@ -58,18 +38,6 @@ func BenchmarkRequestsTLSoTCP(b *testing.B) {
benchmarkRequestsTLS(b, conn0, conn1)
}
-func BenchmarkRequestsTLSoKCP(b *testing.B) {
- b.Skip("KCP broken")
-
- conn0, conn1, err := getKCPConnectionPair()
- if err != nil {
- b.Fatal(err)
- }
- defer conn0.Close()
- defer conn1.Close()
- benchmarkRequestsTLS(b, conn0, conn1)
-}
-
func benchmarkRequestsTLS(b *testing.B, conn0, conn1 net.Conn) {
// Benchmarks the rate at which we can serve requests over a single,
// TLS encrypted channel over the loopback interface.
@@ -170,35 +138,6 @@ func getTCPConnectionPair() (net.Conn, net.Conn, error) {
return conn0, conn1, nil
}
-func getKCPConnectionPair() (net.Conn, net.Conn, error) {
- lst, err := kcp.Listen("127.0.0.1:0")
- if err != nil {
- return nil, nil, err
- }
-
- var conn0 net.Conn
- var err0 error
- done := make(chan struct{})
- go func() {
- conn0, err0 = lst.Accept()
- close(done)
- }()
-
- // Dial the connection
- conn1, err := kcp.Dial(lst.Addr().String())
- if err != nil {
- return nil, nil, err
- }
-
- // Check any error from accept
- <-done
- if err0 != nil {
- return nil, nil, err0
- }
-
- return conn0, conn1, nil
-}
-
func negotiateTLS(cert tls.Certificate, conn0, conn1 net.Conn) (net.Conn, net.Conn) {
cfg := &tls.Config{
Certificates: []tls.Certificate{cert},
diff --git a/test/h1/config.xml b/test/h1/config.xml
index 5900cf421..d7e384c4e 100644
--- a/test/h1/config.xml
+++ b/test/h1/config.xml
@@ -44,22 +44,27 @@
tcp://127.0.0.1:22004
false
+ false
tcp://127.0.0.1:22001
false
+ false
tcp://127.0.0.1:22002
false
+ false
tcp://127.0.0.1:22003
false
+ false
tcp://127.0.0.1:22004
false
+ false
127.0.0.1:8081
@@ -85,7 +90,7 @@
0
30
10
- -1
+ 3
2
tmwxxCqi
https://data.syncthing.net/newdata
@@ -104,18 +109,8 @@
10
0
auto
- default
- 24
- false
- 25
- false
- true
- 128
- 128
~
- true
- 30
- 10
+ true
0
diff --git a/test/h2/config.xml b/test/h2/config.xml
index 2e35e1154..4c94a7903 100644
--- a/test/h2/config.xml
+++ b/test/h2/config.xml
@@ -20,6 +20,26 @@
25
.stfolder
+
+ basic
+
+
+ 1
+
+ 1
+ 16
+ 0
+ random
+ false
+ 0
+ 0
+ -1
+ false
+ false
+ false
+ 25
+ .stfolder
+
basic
@@ -40,37 +60,20 @@
25
.stfolder
-
- basic
-
-
- 1
-
- 1
- 16
- 0
- random
- false
- 0
- 0
- -1
- false
- false
- false
- 25
- .stfolder
-
tcp://127.0.0.1:22001
false
+ false
tcp://127.0.0.1:22002
false
+ false
tcp://127.0.0.1:22003
false
+ false
127.0.0.1:8082
@@ -95,7 +98,7 @@
0
1
10
- -1
+ 3
2
x7AWqz5k
https://data.syncthing.net/newdata
@@ -114,15 +117,8 @@
10
0
auto
- default
- 24
- false
- 25
- false
- true
- 128
- 128
~
+ true
0
diff --git a/test/h3/config.xml b/test/h3/config.xml
index 3e6bce97e..fce12731e 100644
--- a/test/h3/config.xml
+++ b/test/h3/config.xml
@@ -1,24 +1,4 @@
-
- basic
-
-
- 1
-
- 1
- 16
- 0
- random
- false
- 0
- 0
- -1
- false
- false
- false
- 25
- .stfolder
-
basic
@@ -42,17 +22,40 @@
25
.stfolder
+
+ basic
+
+
+ 1
+
+ 1
+ 16
+ 0
+ random
+ false
+ 0
+ 0
+ -1
+ false
+ false
+ false
+ 25
+ .stfolder
+
tcp://127.0.0.1:22001
false
+ false
tcp://127.0.0.1:22002
false
+ false
tcp://127.0.0.1:22003
false
+ false
127.0.0.1:8083
@@ -77,7 +80,7 @@
0
30
10
- -1
+ 3
2
UL4yowgK
https://data.syncthing.net/newdata
@@ -96,15 +99,8 @@
10
0
auto
- default
- 24
- false
- 25
- false
- true
- 128
- 128
~
+ true
0
diff --git a/test/h4/config.xml b/test/h4/config.xml
index 3ebd8d32e..647c9b5e2 100644
--- a/test/h4/config.xml
+++ b/test/h4/config.xml
@@ -21,6 +21,7 @@
dynamic
false
+ false
127.0.0.1:8084
@@ -45,9 +46,9 @@
60
30
10
- -1
+ 3
2
-
+ vF5srHmT
https://data.syncthing.net/newdata
false
1800
@@ -64,15 +65,8 @@
10
0
auto
- default
- 24
- false
- 25
- false
- true
- 128
- 128
~
+ true
0
diff --git a/vendor/github.com/ccding/go-stun/LICENSE b/vendor/github.com/ccding/go-stun/LICENSE
deleted file mode 100644
index 37ec93a14..000000000
--- a/vendor/github.com/ccding/go-stun/LICENSE
+++ /dev/null
@@ -1,191 +0,0 @@
-Apache License
-Version 2.0, January 2004
-http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-"License" shall mean the terms and conditions for use, reproduction, and
-distribution as defined by Sections 1 through 9 of this document.
-
-"Licensor" shall mean the copyright owner or entity authorized by the copyright
-owner that is granting the License.
-
-"Legal Entity" shall mean the union of the acting entity and all other entities
-that control, are controlled by, or are under common control with that entity.
-For the purposes of this definition, "control" means (i) the power, direct or
-indirect, to cause the direction or management of such entity, whether by
-contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
-outstanding shares, or (iii) beneficial ownership of such entity.
-
-"You" (or "Your") shall mean an individual or Legal Entity exercising
-permissions granted by this License.
-
-"Source" form shall mean the preferred form for making modifications, including
-but not limited to software source code, documentation source, and configuration
-files.
-
-"Object" form shall mean any form resulting from mechanical transformation or
-translation of a Source form, including but not limited to compiled object code,
-generated documentation, and conversions to other media types.
-
-"Work" shall mean the work of authorship, whether in Source or Object form, made
-available under the License, as indicated by a copyright notice that is included
-in or attached to the work (an example is provided in the Appendix below).
-
-"Derivative Works" shall mean any work, whether in Source or Object form, that
-is based on (or derived from) the Work and for which the editorial revisions,
-annotations, elaborations, or other modifications represent, as a whole, an
-original work of authorship. For the purposes of this License, Derivative Works
-shall not include works that remain separable from, or merely link (or bind by
-name) to the interfaces of, the Work and Derivative Works thereof.
-
-"Contribution" shall mean any work of authorship, including the original version
-of the Work and any modifications or additions to that Work or Derivative Works
-thereof, that is intentionally submitted to Licensor for inclusion in the Work
-by the copyright owner or by an individual or Legal Entity authorized to submit
-on behalf of the copyright owner. For the purposes of this definition,
-"submitted" means any form of electronic, verbal, or written communication sent
-to the Licensor or its representatives, including but not limited to
-communication on electronic mailing lists, source code control systems, and
-issue tracking systems that are managed by, or on behalf of, the Licensor for
-the purpose of discussing and improving the Work, but excluding communication
-that is conspicuously marked or otherwise designated in writing by the copyright
-owner as "Not a Contribution."
-
-"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
-of whom a Contribution has been received by Licensor and subsequently
-incorporated within the Work.
-
-2. Grant of Copyright License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable copyright license to reproduce, prepare Derivative Works of,
-publicly display, publicly perform, sublicense, and distribute the Work and such
-Derivative Works in Source or Object form.
-
-3. Grant of Patent License.
-
-Subject to the terms and conditions of this License, each Contributor hereby
-grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
-irrevocable (except as stated in this section) patent license to make, have
-made, use, offer to sell, sell, import, and otherwise transfer the Work, where
-such license applies only to those patent claims licensable by such Contributor
-that are necessarily infringed by their Contribution(s) alone or by combination
-of their Contribution(s) with the Work to which such Contribution(s) was
-submitted. If You institute patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Work or a
-Contribution incorporated within the Work constitutes direct or contributory
-patent infringement, then any patent licenses granted to You under this License
-for that Work shall terminate as of the date such litigation is filed.
-
-4. Redistribution.
-
-You may reproduce and distribute copies of the Work or Derivative Works thereof
-in any medium, with or without modifications, and in Source or Object form,
-provided that You meet the following conditions:
-
-You must give any other recipients of the Work or Derivative Works a copy of
-this License; and
-You must cause any modified files to carry prominent notices stating that You
-changed the files; and
-You must retain, in the Source form of any Derivative Works that You distribute,
-all copyright, patent, trademark, and attribution notices from the Source form
-of the Work, excluding those notices that do not pertain to any part of the
-Derivative Works; and
-If the Work includes a "NOTICE" text file as part of its distribution, then any
-Derivative Works that You distribute must include a readable copy of the
-attribution notices contained within such NOTICE file, excluding those notices
-that do not pertain to any part of the Derivative Works, in at least one of the
-following places: within a NOTICE text file distributed as part of the
-Derivative Works; within the Source form or documentation, if provided along
-with the Derivative Works; or, within a display generated by the Derivative
-Works, if and wherever such third-party notices normally appear. The contents of
-the NOTICE file are for informational purposes only and do not modify the
-License. You may add Your own attribution notices within Derivative Works that
-You distribute, alongside or as an addendum to the NOTICE text from the Work,
-provided that such additional attribution notices cannot be construed as
-modifying the License.
-You may add Your own copyright statement to Your modifications and may provide
-additional or different license terms and conditions for use, reproduction, or
-distribution of Your modifications, or for any such Derivative Works as a whole,
-provided Your use, reproduction, and distribution of the Work otherwise complies
-with the conditions stated in this License.
-
-5. Submission of Contributions.
-
-Unless You explicitly state otherwise, any Contribution intentionally submitted
-for inclusion in the Work by You to the Licensor shall be under the terms and
-conditions of this License, without any additional terms or conditions.
-Notwithstanding the above, nothing herein shall supersede or modify the terms of
-any separate license agreement you may have executed with Licensor regarding
-such Contributions.
-
-6. Trademarks.
-
-This License does not grant permission to use the trade names, trademarks,
-service marks, or product names of the Licensor, except as required for
-reasonable and customary use in describing the origin of the Work and
-reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty.
-
-Unless required by applicable law or agreed to in writing, Licensor provides the
-Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
-including, without limitation, any warranties or conditions of TITLE,
-NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
-solely responsible for determining the appropriateness of using or
-redistributing the Work and assume any risks associated with Your exercise of
-permissions under this License.
-
-8. Limitation of Liability.
-
-In no event and under no legal theory, whether in tort (including negligence),
-contract, or otherwise, unless required by applicable law (such as deliberate
-and grossly negligent acts) or agreed to in writing, shall any Contributor be
-liable to You for damages, including any direct, indirect, special, incidental,
-or consequential damages of any character arising as a result of this License or
-out of the use or inability to use the Work (including but not limited to
-damages for loss of goodwill, work stoppage, computer failure or malfunction, or
-any and all other commercial damages or losses), even if such Contributor has
-been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability.
-
-While redistributing the Work or Derivative Works thereof, You may choose to
-offer, and charge a fee for, acceptance of support, warranty, indemnity, or
-other liability obligations and/or rights consistent with this License. However,
-in accepting such obligations, You may act only on Your own behalf and on Your
-sole responsibility, not on behalf of any other Contributor, and only if You
-agree to indemnify, defend, and hold each Contributor harmless for any liability
-incurred by, or claims asserted against, such Contributor by reason of your
-accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work
-
-To apply the Apache License to your work, attach the following boilerplate
-notice, with the fields enclosed by brackets "[]" replaced with your own
-identifying information. (Don't include the brackets!) The text should be
-enclosed in the appropriate comment syntax for the file format. We also
-recommend that a file or class name and description of purpose be included on
-the same "printed page" as the copyright notice for easier identification within
-third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/ccding/go-stun/main.go b/vendor/github.com/ccding/go-stun/main.go
deleted file mode 100644
index 925f7d20f..000000000
--- a/vendor/github.com/ccding/go-stun/main.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// author: Cong Ding
-
-package main
-
-import (
- "flag"
- "fmt"
-
- "github.com/ccding/go-stun/stun"
-)
-
-func main() {
- var serverAddr = flag.String("s", stun.DefaultServerAddr, "STUN server address")
- var v = flag.Bool("v", false, "verbose mode")
- var vv = flag.Bool("vv", false, "double verbose mode (includes -v)")
- var vvv = flag.Bool("vvv", false, "triple verbose mode (includes -v and -vv)")
- flag.Parse()
-
- // Creates a STUN client. NewClientWithConnection can also be used if
- // you want to handle the UDP listener by yourself.
- client := stun.NewClient()
- // The default addr (stun.DefaultServerAddr) will be used unless we
- // call SetServerAddr.
- client.SetServerAddr(*serverAddr)
- // Non verbose mode will be used by default unless we call
- // SetVerbose(true) or SetVVerbose(true).
- client.SetVerbose(*v || *vv || *vvv)
- client.SetVVerbose(*vv || *vvv)
- // Discover the NAT and return the result.
- nat, host, err := client.Discover()
- if err != nil {
- fmt.Println(err)
- return
- }
-
- fmt.Println("NAT Type:", nat)
- if host != nil {
- fmt.Println("External IP Family:", host.Family())
- fmt.Println("External IP:", host.IP())
- fmt.Println("External Port:", host.Port())
- }
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/attribute.go b/vendor/github.com/ccding/go-stun/stun/attribute.go
deleted file mode 100644
index 61732a917..000000000
--- a/vendor/github.com/ccding/go-stun/stun/attribute.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "encoding/binary"
- "hash/crc32"
- "net"
-)
-
-type attribute struct {
- types uint16
- length uint16
- value []byte
-}
-
-func newAttribute(types uint16, value []byte) *attribute {
- att := new(attribute)
- att.types = types
- att.value = padding(value)
- att.length = uint16(len(att.value))
- return att
-}
-
-func newFingerprintAttribute(packet *packet) *attribute {
- crc := crc32.ChecksumIEEE(packet.bytes()) ^ fingerprint
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, crc)
- return newAttribute(attributeFingerprint, buf)
-}
-
-func newSoftwareAttribute(name string) *attribute {
- return newAttribute(attributeSoftware, []byte(name))
-}
-
-func newChangeReqAttribute(changeIP bool, changePort bool) *attribute {
- value := make([]byte, 4)
- if changeIP {
- value[3] |= 0x04
- }
- if changePort {
- value[3] |= 0x02
- }
- return newAttribute(attributeChangeRequest, value)
-}
-
-// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |x x x x x x x x| Family | X-Port |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | X-Address (Variable)
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// Figure 6: Format of XOR-MAPPED-ADDRESS Attribute
-func (v *attribute) xorAddr(transID []byte) *Host {
- xorIP := make([]byte, 16)
- for i := 0; i < len(v.value)-4; i++ {
- xorIP[i] = v.value[i+4] ^ transID[i]
- }
- family := uint16(v.value[1])
- port := binary.BigEndian.Uint16(v.value[2:4])
- // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
- if family == attributeFamilyIPv4 {
- xorIP = xorIP[:4]
- }
- x := binary.BigEndian.Uint16(transID[:2])
- return &Host{family, net.IP(xorIP).String(), port ^ x}
-}
-
-// 0 1 2 3
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// |0 0 0 0 0 0 0 0| Family | Port |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | |
-// | Address (32 bits or 128 bits) |
-// | |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// Figure 5: Format of MAPPED-ADDRESS Attribute
-func (v *attribute) rawAddr() *Host {
- host := new(Host)
- host.family = uint16(v.value[1])
- host.port = binary.BigEndian.Uint16(v.value[2:4])
- // Truncate if IPv4, otherwise net.IP sometimes renders it as an IPv6 address.
- if host.family == attributeFamilyIPv4 {
- v.value = v.value[:8]
- }
- host.ip = net.IP(v.value[4:]).String()
- return host
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/client.go b/vendor/github.com/ccding/go-stun/stun/client.go
deleted file mode 100644
index 89be70464..000000000
--- a/vendor/github.com/ccding/go-stun/stun/client.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "errors"
- "net"
- "strconv"
-)
-
-// Client is a STUN client, which can be set STUN server address and is used
-// to discover NAT type.
-type Client struct {
- serverAddr string
- softwareName string
- conn net.PacketConn
- logger *Logger
-}
-
-// NewClient returns a client without network connection. The network
-// connection will be build when calling Discover function.
-func NewClient() *Client {
- c := new(Client)
- c.SetSoftwareName(DefaultSoftwareName)
- c.logger = NewLogger()
- return c
-}
-
-// NewClientWithConnection returns a client which uses the given connection.
-// Please note the connection should be acquired via net.Listen* method.
-func NewClientWithConnection(conn net.PacketConn) *Client {
- c := new(Client)
- c.conn = conn
- c.SetSoftwareName(DefaultSoftwareName)
- c.logger = NewLogger()
- return c
-}
-
-// SetVerbose sets the client to be in the verbose mode, which prints
-// information in the discover process.
-func (c *Client) SetVerbose(v bool) {
- c.logger.SetDebug(v)
-}
-
-// SetVVerbose sets the client to be in the double verbose mode, which prints
-// information and packet in the discover process.
-func (c *Client) SetVVerbose(v bool) {
- c.logger.SetInfo(v)
-}
-
-// SetServerHost allows user to set the STUN hostname and port.
-func (c *Client) SetServerHost(host string, port int) {
- c.serverAddr = net.JoinHostPort(host, strconv.Itoa(port))
-}
-
-// SetServerAddr allows user to set the transport layer STUN server address.
-func (c *Client) SetServerAddr(address string) {
- c.serverAddr = address
-}
-
-// SetSoftwareName allows user to set the name of the software, which is used
-// for logging purpose (NOT used in the current implementation).
-func (c *Client) SetSoftwareName(name string) {
- c.softwareName = name
-}
-
-// Discover contacts the STUN server and gets the response of NAT type, host
-// for UDP punching.
-func (c *Client) Discover() (NATType, *Host, error) {
- if c.serverAddr == "" {
- c.SetServerAddr(DefaultServerAddr)
- }
- serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr)
- if err != nil {
- return NATError, nil, err
- }
- // Use the connection passed to the client if it is not nil, otherwise
- // create a connection and close it at the end.
- conn := c.conn
- if conn == nil {
- conn, err = net.ListenUDP("udp", nil)
- if err != nil {
- return NATError, nil, err
- }
- defer conn.Close()
- }
- return c.discover(conn, serverUDPAddr)
-}
-
-// Keepalive sends and receives a bind request, which ensures the mapping stays open
-// Only applicable when client was created with a connection.
-func (c *Client) Keepalive() (*Host, error) {
- if c.conn == nil {
- return nil, errors.New("no connection available")
- }
- if c.serverAddr == "" {
- c.SetServerAddr(DefaultServerAddr)
- }
- serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr)
- if err != nil {
- return nil, err
- }
-
- resp, err := c.test1(c.conn, serverUDPAddr)
- if err != nil {
- return nil, err
- }
- if resp == nil || resp.packet == nil {
- return nil, errors.New("failed to contact")
- }
- return resp.mappedAddr, nil
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/const.go b/vendor/github.com/ccding/go-stun/stun/const.go
deleted file mode 100644
index c0285588b..000000000
--- a/vendor/github.com/ccding/go-stun/stun/const.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-// Default server address and client name.
-const (
- DefaultServerAddr = "stun.ekiga.net:3478"
- DefaultSoftwareName = "StunClient"
-)
-
-const (
- magicCookie = 0x2112A442
- fingerprint = 0x5354554e
-)
-
-// NATType is the type of NAT described by int.
-type NATType int
-
-// NAT types.
-const (
- NATError NATType = iota
- NATUnknown
- NATNone
- NATBlocked
- NATFull
- NATSymmetric
- NATRestricted
- NATPortRestricted
- NATSymmetricUDPFirewall
-
- // Deprecated spellings of these constants
- NATSymetric = NATSymmetric
- NATSymetricUDPFirewall = NATSymmetricUDPFirewall
-)
-
-var natStr map[NATType]string
-
-func init() {
- natStr = map[NATType]string{
- NATError: "Test failed",
- NATUnknown: "Unexpected response from the STUN server",
- NATBlocked: "UDP is blocked",
- NATFull: "Full cone NAT",
- NATSymmetric: "Symmetric NAT",
- NATRestricted: "Restricted NAT",
- NATPortRestricted: "Port restricted NAT",
- NATNone: "Not behind a NAT",
- NATSymmetricUDPFirewall: "Symmetric UDP firewall",
- }
-}
-
-func (nat NATType) String() string {
- if s, ok := natStr[nat]; ok {
- return s
- }
- return "Unknown"
-}
-
-const (
- errorTryAlternate = 300
- errorBadRequest = 400
- errorUnauthorized = 401
- errorUnassigned402 = 402
- errorForbidden = 403
- errorUnknownAttribute = 420
- errorAllocationMismatch = 437
- errorStaleNonce = 438
- errorUnassigned439 = 439
- errorAddressFamilyNotSupported = 440
- errorWrongCredentials = 441
- errorUnsupportedTransportProtocol = 442
- errorPeerAddressFamilyMismatch = 443
- errorConnectionAlreadyExists = 446
- errorConnectionTimeoutOrFailure = 447
- errorAllocationQuotaReached = 486
- errorRoleConflict = 487
- errorServerError = 500
- errorInsufficientCapacity = 508
-)
-const (
- attributeFamilyIPv4 = 0x01
- attributeFamilyIPV6 = 0x02
-)
-
-const (
- attributeMappedAddress = 0x0001
- attributeResponseAddress = 0x0002
- attributeChangeRequest = 0x0003
- attributeSourceAddress = 0x0004
- attributeChangedAddress = 0x0005
- attributeUsername = 0x0006
- attributePassword = 0x0007
- attributeMessageIntegrity = 0x0008
- attributeErrorCode = 0x0009
- attributeUnknownAttributes = 0x000a
- attributeReflectedFrom = 0x000b
- attributeChannelNumber = 0x000c
- attributeLifetime = 0x000d
- attributeBandwidth = 0x0010
- attributeXorPeerAddress = 0x0012
- attributeData = 0x0013
- attributeRealm = 0x0014
- attributeNonce = 0x0015
- attributeXorRelayedAddress = 0x0016
- attributeRequestedAddressFamily = 0x0017
- attributeEvenPort = 0x0018
- attributeRequestedTransport = 0x0019
- attributeDontFragment = 0x001a
- attributeXorMappedAddress = 0x0020
- attributeTimerVal = 0x0021
- attributeReservationToken = 0x0022
- attributePriority = 0x0024
- attributeUseCandidate = 0x0025
- attributePadding = 0x0026
- attributeResponsePort = 0x0027
- attributeConnectionID = 0x002a
- attributeXorMappedAddressExp = 0x8020
- attributeSoftware = 0x8022
- attributeAlternateServer = 0x8023
- attributeCacheTimeout = 0x8027
- attributeFingerprint = 0x8028
- attributeIceControlled = 0x8029
- attributeIceControlling = 0x802a
- attributeResponseOrigin = 0x802b
- attributeOtherAddress = 0x802c
- attributeEcnCheckStun = 0x802d
- attributeCiscoFlowdata = 0xc000
-)
-
-const (
- typeBindingRequest = 0x0001
- typeBindingResponse = 0x0101
- typeBindingErrorResponse = 0x0111
- typeSharedSecretRequest = 0x0002
- typeSharedSecretResponse = 0x0102
- typeSharedErrorResponse = 0x0112
- typeAllocate = 0x0003
- typeAllocateResponse = 0x0103
- typeAllocateErrorResponse = 0x0113
- typeRefresh = 0x0004
- typeRefreshResponse = 0x0104
- typeRefreshErrorResponse = 0x0114
- typeSend = 0x0006
- typeSendResponse = 0x0106
- typeSendErrorResponse = 0x0116
- typeData = 0x0007
- typeDataResponse = 0x0107
- typeDataErrorResponse = 0x0117
- typeCreatePermisiion = 0x0008
- typeCreatePermisiionResponse = 0x0108
- typeCreatePermisiionErrorResponse = 0x0118
- typeChannelBinding = 0x0009
- typeChannelBindingResponse = 0x0109
- typeChannelBindingErrorResponse = 0x0119
- typeConnect = 0x000a
- typeConnectResponse = 0x010a
- typeConnectErrorResponse = 0x011a
- typeConnectionBind = 0x000b
- typeConnectionBindResponse = 0x010b
- typeConnectionBindErrorResponse = 0x011b
- typeConnectionAttempt = 0x000c
- typeConnectionAttemptResponse = 0x010c
- typeConnectionAttemptErrorResponse = 0x011c
-)
diff --git a/vendor/github.com/ccding/go-stun/stun/discover.go b/vendor/github.com/ccding/go-stun/stun/discover.go
deleted file mode 100644
index 96d91be01..000000000
--- a/vendor/github.com/ccding/go-stun/stun/discover.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "errors"
- "net"
-)
-
-// Follow RFC 3489 and RFC 5389.
-// Figure 2: Flow for type discovery process (from RFC 3489).
-// +--------+
-// | Test |
-// | I |
-// +--------+
-// |
-// |
-// V
-// /\ /\
-// N / \ Y / \ Y +--------+
-// UDP <-------/Resp\--------->/ IP \------------->| Test |
-// Blocked \ ? / \Same/ | II |
-// \ / \? / +--------+
-// \/ \/ |
-// | N |
-// | V
-// V /\
-// +--------+ Sym. N / \
-// | Test | UDP <---/Resp\
-// | II | Firewall \ ? /
-// +--------+ \ /
-// | \/
-// V |Y
-// /\ /\ |
-// Symmetric N / \ +--------+ N / \ V
-// NAT <--- / IP \<-----| Test |<--- /Resp\ Open
-// \Same/ | I | \ ? / Internet
-// \? / +--------+ \ /
-// \/ \/
-// |Y |Y
-// | |
-// | V
-// | Full
-// | Cone
-// V /\
-// +--------+ / \ Y
-// | Test |------>/Resp\---->Restricted
-// | III | \ ? /
-// +--------+ \ /
-// \/
-// |N
-// | Port
-// +------>Restricted
-func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (NATType, *Host, error) {
- // Perform test1 to check if it is under NAT.
- c.logger.Debugln("Do Test1")
- c.logger.Debugln("Send To:", addr)
- resp, err := c.test1(conn, addr)
- if err != nil {
- return NATError, nil, err
- }
- c.logger.Debugln("Received:", resp)
- if resp == nil {
- return NATBlocked, nil, nil
- }
- // identical used to check if it is open Internet or not.
- identical := resp.identical
- // changedAddr is used to perform second time test1 and test3.
- changedAddr := resp.changedAddr
- // mappedAddr is used as the return value, its IP is used for tests
- mappedAddr := resp.mappedAddr
- // Make sure IP and port are not changed.
- if resp.serverAddr.IP() != addr.IP.String() ||
- resp.serverAddr.Port() != uint16(addr.Port) {
- return NATError, mappedAddr, errors.New("Server error: response IP/port")
- }
- // if changedAddr is not available, use otherAddr as changedAddr,
- // which is updated in RFC 5780
- if changedAddr == nil {
- changedAddr = resp.otherAddr
- }
- // changedAddr shall not be nil
- if changedAddr == nil {
- return NATError, mappedAddr, errors.New("Server error: no changed address.")
- }
- // Perform test2 to see if the client can receive packet sent from
- // another IP and port.
- c.logger.Debugln("Do Test2")
- c.logger.Debugln("Send To:", addr)
- resp, err = c.test2(conn, addr)
- if err != nil {
- return NATError, mappedAddr, err
- }
- c.logger.Debugln("Received:", resp)
- // Make sure IP and port are changed.
- if resp != nil &&
- (resp.serverAddr.IP() == addr.IP.String() ||
- resp.serverAddr.Port() == uint16(addr.Port)) {
- return NATError, mappedAddr, errors.New("Server error: response IP/port")
- }
- if identical {
- if resp == nil {
- return NATSymmetricUDPFirewall, mappedAddr, nil
- }
- return NATNone, mappedAddr, nil
- }
- if resp != nil {
- return NATFull, mappedAddr, nil
- }
- // Perform test1 to another IP and port to see if the NAT use the same
- // external IP.
- c.logger.Debugln("Do Test1")
- c.logger.Debugln("Send To:", changedAddr)
- caddr, err := net.ResolveUDPAddr("udp", changedAddr.String())
- resp, err = c.test1(conn, caddr)
- if err != nil {
- return NATError, mappedAddr, err
- }
- c.logger.Debugln("Received:", resp)
- if resp == nil {
- // It should be NAT_BLOCKED, but will be detected in the first
- // step. So this will never happen.
- return NATUnknown, mappedAddr, nil
- }
- // Make sure IP/port is not changed.
- if resp.serverAddr.IP() != caddr.IP.String() ||
- resp.serverAddr.Port() != uint16(caddr.Port) {
- return NATError, mappedAddr, errors.New("Server error: response IP/port")
- }
- if mappedAddr.IP() == resp.mappedAddr.IP() && mappedAddr.Port() == resp.mappedAddr.Port() {
- // Perform test3 to see if the client can receive packet sent
- // from another port.
- c.logger.Debugln("Do Test3")
- c.logger.Debugln("Send To:", caddr)
- resp, err = c.test3(conn, caddr)
- if err != nil {
- return NATError, mappedAddr, err
- }
- c.logger.Debugln("Received:", resp)
- if resp == nil {
- return NATPortRestricted, mappedAddr, nil
- }
- // Make sure IP is not changed, and port is changed.
- if resp.serverAddr.IP() != caddr.IP.String() ||
- resp.serverAddr.Port() == uint16(caddr.Port) {
- return NATError, mappedAddr, errors.New("Server error: response IP/port")
- }
- return NATRestricted, mappedAddr, nil
- }
- return NATSymmetric, mappedAddr, nil
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/doc.go b/vendor/github.com/ccding/go-stun/stun/doc.go
deleted file mode 100644
index d1c9aba19..000000000
--- a/vendor/github.com/ccding/go-stun/stun/doc.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-// Package stun is a STUN (RFC 3489 and RFC 5389) client implementation in
-// golang.
-//
-// It is extremely easy to use -- just one line of code.
-//
-// nat, host, err := stun.NewClient().Discover()
-//
-// More details please go to `main.go`.
-package stun
diff --git a/vendor/github.com/ccding/go-stun/stun/host.go b/vendor/github.com/ccding/go-stun/stun/host.go
deleted file mode 100644
index cee1e9d12..000000000
--- a/vendor/github.com/ccding/go-stun/stun/host.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "net"
- "strconv"
-)
-
-// Host defines the network address including address family, IP address and port.
-type Host struct {
- family uint16
- ip string
- port uint16
-}
-
-func newHostFromStr(s string) *Host {
- udpAddr, err := net.ResolveUDPAddr("udp", s)
- if err != nil {
- return nil
- }
- host := new(Host)
- if udpAddr.IP.To4() != nil {
- host.family = attributeFamilyIPv4
- } else {
- host.family = attributeFamilyIPV6
- }
- host.ip = udpAddr.IP.String()
- host.port = uint16(udpAddr.Port)
- return host
-}
-
-// Family returns the family type of a host (IPv4 or IPv6).
-func (h *Host) Family() uint16 {
- return h.family
-}
-
-// IP returns the internet protocol address of the host.
-func (h *Host) IP() string {
- return h.ip
-}
-
-// Port returns the port number of the host.
-func (h *Host) Port() uint16 {
- return h.port
-}
-
-// TransportAddr returns the transport layer address of the host.
-func (h *Host) TransportAddr() string {
- return net.JoinHostPort(h.ip, strconv.Itoa(int(h.port)))
-}
-
-// String returns the string representation of the host address.
-func (h *Host) String() string {
- return h.TransportAddr()
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/log.go b/vendor/github.com/ccding/go-stun/stun/log.go
deleted file mode 100644
index 52f9fd2b5..000000000
--- a/vendor/github.com/ccding/go-stun/stun/log.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2016, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "log"
- "os"
-)
-
-// Logger is a simple logger specified for this STUN client.
-type Logger struct {
- log.Logger
- debug bool
- info bool
-}
-
-// NewLogger creates a default logger.
-func NewLogger() *Logger {
- logger := &Logger{*log.New(os.Stdout, "", log.LstdFlags), false, false}
- return logger
-}
-
-// SetDebug sets the logger running in debug mode or not.
-func (l *Logger) SetDebug(v bool) {
- l.debug = v
-}
-
-// SetInfo sets the logger running in info mode or not.
-func (l *Logger) SetInfo(v bool) {
- l.info = v
-}
-
-// Debug outputs the log in the format of log.Print.
-func (l *Logger) Debug(v ...interface{}) {
- if l.debug {
- l.Print(v...)
- }
-}
-
-// Debugf outputs the log in the format of log.Printf.
-func (l *Logger) Debugf(format string, v ...interface{}) {
- if l.debug {
- l.Printf(format, v...)
- }
-}
-
-// Debugln outputs the log in the format of log.Println.
-func (l *Logger) Debugln(v ...interface{}) {
- if l.debug {
- l.Println(v...)
- }
-}
-
-// Info outputs the log in the format of log.Print.
-func (l *Logger) Info(v ...interface{}) {
- if l.info {
- l.Print(v...)
- }
-}
-
-// Infof outputs the log in the format of log.Printf.
-func (l *Logger) Infof(format string, v ...interface{}) {
- if l.info {
- l.Printf(format, v...)
- }
-}
-
-// Infoln outputs the log in the format of log.Println.
-func (l *Logger) Infoln(v ...interface{}) {
- if l.info {
- l.Println(v...)
- }
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/net.go b/vendor/github.com/ccding/go-stun/stun/net.go
deleted file mode 100644
index a9c7ae5f4..000000000
--- a/vendor/github.com/ccding/go-stun/stun/net.go
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2016, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "bytes"
- "encoding/hex"
- "errors"
- "net"
- "time"
-)
-
-const (
- numRetransmit = 9
- defaultTimeout = 100
- maxTimeout = 1600
- maxPacketSize = 1024
-)
-
-func (c *Client) sendBindingReq(conn net.PacketConn, addr net.Addr, changeIP bool, changePort bool) (*response, error) {
- // Construct packet.
- pkt, err := newPacket()
- if err != nil {
- return nil, err
- }
- pkt.types = typeBindingRequest
- attribute := newSoftwareAttribute(c.softwareName)
- pkt.addAttribute(*attribute)
- if changeIP || changePort {
- attribute = newChangeReqAttribute(changeIP, changePort)
- pkt.addAttribute(*attribute)
- }
- attribute = newFingerprintAttribute(pkt)
- pkt.addAttribute(*attribute)
- // Send packet.
- return c.send(pkt, conn, addr)
-}
-
-// RFC 3489: Clients SHOULD retransmit the request starting with an interval
-// of 100ms, doubling every retransmit until the interval reaches 1.6s.
-// Retransmissions continue with intervals of 1.6s until a response is
-// received, or a total of 9 requests have been sent.
-func (c *Client) send(pkt *packet, conn net.PacketConn, addr net.Addr) (*response, error) {
- c.logger.Info("\n" + hex.Dump(pkt.bytes()))
- timeout := defaultTimeout
- packetBytes := make([]byte, maxPacketSize)
- for i := 0; i < numRetransmit; i++ {
- // Send packet to the server.
- length, err := conn.WriteTo(pkt.bytes(), addr)
- if err != nil {
- return nil, err
- }
- if length != len(pkt.bytes()) {
- return nil, errors.New("Error in sending data.")
- }
- err = conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Millisecond))
- if err != nil {
- return nil, err
- }
- if timeout < maxTimeout {
- timeout *= 2
- }
- for {
- // Read from the port.
- length, raddr, err := conn.ReadFrom(packetBytes)
- if err != nil {
- if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
- break
- }
- return nil, err
- }
- p, err := newPacketFromBytes(packetBytes[0:length])
- if err != nil {
- return nil, err
- }
- // If transId mismatches, keep reading until get a
- // matched packet or timeout.
- if !bytes.Equal(pkt.transID, p.transID) {
- continue
- }
- c.logger.Info("\n" + hex.Dump(packetBytes[0:length]))
- resp := newResponse(p, conn)
- resp.serverAddr = newHostFromStr(raddr.String())
- return resp, err
- }
- }
- return nil, nil
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/packet.go b/vendor/github.com/ccding/go-stun/stun/packet.go
deleted file mode 100644
index ca569004f..000000000
--- a/vendor/github.com/ccding/go-stun/stun/packet.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2013, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "crypto/rand"
- "encoding/binary"
- "errors"
-)
-
-type packet struct {
- types uint16
- length uint16
- transID []byte // 4 bytes magic cookie + 12 bytes transaction id
- attributes []attribute
-}
-
-func newPacket() (*packet, error) {
- v := new(packet)
- v.transID = make([]byte, 16)
- binary.BigEndian.PutUint32(v.transID[:4], magicCookie)
- _, err := rand.Read(v.transID[4:])
- if err != nil {
- return nil, err
- }
- v.attributes = make([]attribute, 0, 10)
- v.length = 0
- return v, nil
-}
-
-func newPacketFromBytes(packetBytes []byte) (*packet, error) {
- if len(packetBytes) < 24 {
- return nil, errors.New("Received data length too short.")
- }
- pkt := new(packet)
- pkt.types = binary.BigEndian.Uint16(packetBytes[0:2])
- pkt.length = binary.BigEndian.Uint16(packetBytes[2:4])
- pkt.transID = packetBytes[4:20]
- pkt.attributes = make([]attribute, 0, 10)
- for pos := uint16(20); pos < uint16(len(packetBytes)); {
- types := binary.BigEndian.Uint16(packetBytes[pos : pos+2])
- length := binary.BigEndian.Uint16(packetBytes[pos+2 : pos+4])
- if pos+4+length > uint16(len(packetBytes)) {
- return nil, errors.New("Received data format mismatch.")
- }
- value := packetBytes[pos+4 : pos+4+length]
- attribute := newAttribute(types, value)
- pkt.addAttribute(*attribute)
- pos += align(length) + 4
- }
- return pkt, nil
-}
-
-func (v *packet) addAttribute(a attribute) {
- v.attributes = append(v.attributes, a)
- v.length += align(a.length) + 4
-}
-
-func (v *packet) bytes() []byte {
- packetBytes := make([]byte, 4)
- binary.BigEndian.PutUint16(packetBytes[0:2], v.types)
- binary.BigEndian.PutUint16(packetBytes[2:4], v.length)
- packetBytes = append(packetBytes, v.transID...)
- for _, a := range v.attributes {
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, a.types)
- packetBytes = append(packetBytes, buf...)
- binary.BigEndian.PutUint16(buf, a.length)
- packetBytes = append(packetBytes, buf...)
- packetBytes = append(packetBytes, a.value...)
- }
- return packetBytes
-}
-
-func (v *packet) getSourceAddr() *Host {
- return v.getRawAddr(attributeSourceAddress)
-}
-
-func (v *packet) getMappedAddr() *Host {
- return v.getRawAddr(attributeMappedAddress)
-}
-
-func (v *packet) getChangedAddr() *Host {
- return v.getRawAddr(attributeChangedAddress)
-}
-
-func (v *packet) getOtherAddr() *Host {
- return v.getRawAddr(attributeOtherAddress)
-}
-
-func (v *packet) getRawAddr(attribute uint16) *Host {
- for _, a := range v.attributes {
- if a.types == attribute {
- return a.rawAddr()
- }
- }
- return nil
-}
-
-func (v *packet) getXorMappedAddr() *Host {
- addr := v.getXorAddr(attributeXorMappedAddress)
- if addr == nil {
- addr = v.getXorAddr(attributeXorMappedAddressExp)
- }
- return addr
-}
-
-func (v *packet) getXorAddr(attribute uint16) *Host {
- for _, a := range v.attributes {
- if a.types == attribute {
- return a.xorAddr(v.transID)
- }
- }
- return nil
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/response.go b/vendor/github.com/ccding/go-stun/stun/response.go
deleted file mode 100644
index c9a75cb41..000000000
--- a/vendor/github.com/ccding/go-stun/stun/response.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2016, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "fmt"
- "net"
-)
-
-type response struct {
- packet *packet // the original packet from the server
- serverAddr *Host // the address received packet
- changedAddr *Host // parsed from packet
- mappedAddr *Host // parsed from packet, external addr of client NAT
- otherAddr *Host // parsed from packet, to replace changedAddr in RFC 5780
- identical bool // if mappedAddr is in local addr list
-}
-
-func newResponse(pkt *packet, conn net.PacketConn) *response {
- resp := &response{pkt, nil, nil, nil, nil, false}
- if pkt == nil {
- return resp
- }
- // RFC 3489 doesn't require the server return XOR mapped address.
- mappedAddr := pkt.getXorMappedAddr()
- if mappedAddr == nil {
- mappedAddr = pkt.getMappedAddr()
- }
- resp.mappedAddr = mappedAddr
- // compute identical
- localAddrStr := conn.LocalAddr().String()
- if mappedAddr != nil {
- mappedAddrStr := mappedAddr.String()
- resp.identical = isLocalAddress(localAddrStr, mappedAddrStr)
- }
- // compute changedAddr
- changedAddr := pkt.getChangedAddr()
- if changedAddr != nil {
- changedAddrHost := newHostFromStr(changedAddr.String())
- resp.changedAddr = changedAddrHost
- }
- // compute otherAddr
- otherAddr := pkt.getOtherAddr()
- if otherAddr != nil {
- otherAddrHost := newHostFromStr(otherAddr.String())
- resp.otherAddr = otherAddrHost
- }
-
- return resp
-}
-
-// String is only used for verbose mode output.
-func (r *response) String() string {
- if r == nil {
- return "Nil"
- }
- return fmt.Sprintf("{packet nil: %v, local: %v, remote: %v, changed: %v, other: %v, identical: %v}",
- r.packet == nil,
- r.mappedAddr,
- r.serverAddr,
- r.changedAddr,
- r.otherAddr,
- r.identical)
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/tests.go b/vendor/github.com/ccding/go-stun/stun/tests.go
deleted file mode 100644
index 013c803e1..000000000
--- a/vendor/github.com/ccding/go-stun/stun/tests.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "net"
-)
-
-func (c *Client) test1(conn net.PacketConn, addr net.Addr) (*response, error) {
- return c.sendBindingReq(conn, addr, false, false)
-}
-
-func (c *Client) test2(conn net.PacketConn, addr net.Addr) (*response, error) {
- return c.sendBindingReq(conn, addr, true, true)
-}
-
-func (c *Client) test3(conn net.PacketConn, addr net.Addr) (*response, error) {
- return c.sendBindingReq(conn, addr, false, true)
-}
diff --git a/vendor/github.com/ccding/go-stun/stun/utils.go b/vendor/github.com/ccding/go-stun/stun/utils.go
deleted file mode 100644
index 7242316b2..000000000
--- a/vendor/github.com/ccding/go-stun/stun/utils.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016, Cong Ding. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Author: Cong Ding
-
-package stun
-
-import (
- "net"
-)
-
-// Padding the length of the byte slice to multiple of 4.
-func padding(bytes []byte) []byte {
- length := uint16(len(bytes))
- return append(bytes, make([]byte, align(length)-length)...)
-}
-
-// Align the uint16 number to the smallest multiple of 4, which is larger than
-// or equal to the uint16 number.
-func align(n uint16) uint16 {
- return (n + 3) & 0xfffc
-}
-
-// isLocalAddress check if localRemote is a local address.
-func isLocalAddress(local, localRemote string) bool {
- // Resolve the IP returned by the STUN server first.
- localRemoteAddr, err := net.ResolveUDPAddr("udp", localRemote)
- if err != nil {
- return false
- }
- // Try comparing with the local address on the socket first, but only if
- // it's actually specified.
- addr, err := net.ResolveUDPAddr("udp", local)
- if err == nil && addr.IP != nil && !addr.IP.IsUnspecified() {
- return addr.IP.Equal(localRemoteAddr.IP)
- }
- // Fallback to checking IPs of all interfaces
- addrs, err := net.InterfaceAddrs()
- if err != nil {
- return false
- }
- for _, addr := range addrs {
- ip, _, err := net.ParseCIDR(addr.String())
- if err != nil {
- continue
- }
- if ip.Equal(localRemoteAddr.IP) {
- return true
- }
- }
- return false
-}
diff --git a/vendor/github.com/xtaci/kcp-go/LICENSE b/vendor/github.com/xtaci/kcp-go/LICENSE
deleted file mode 100644
index 8294d134d..000000000
--- a/vendor/github.com/xtaci/kcp-go/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Daniel Fu
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
diff --git a/vendor/github.com/xtaci/kcp-go/blacklist.go b/vendor/github.com/xtaci/kcp-go/blacklist.go
deleted file mode 100644
index 1d910af96..000000000
--- a/vendor/github.com/xtaci/kcp-go/blacklist.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package kcp
-
-import (
- "sync"
- "time"
-)
-
-var (
- // BlacklistDuration sets a duration for which a session is blacklisted
- // once it's established. This is simillar to TIME_WAIT state in TCP, whereby
- // any connection attempt with the same session parameters is ignored for
- // some amount of time.
- //
- // This is only useful when dial attempts happen from a pre-determined port,
- // for example when you are dialing from the same connection you are listening on
- // to punch through NAT, and helps with the fact that KCP is state-less.
- // This helps better deal with scenarios where a process on one of the side (A)
- // get's restarted, and stray packets from other side (B) makes it look like
- // as if someone is trying to connect to A. Even if session dies on B,
- // new stray reply packets from A resurrect the session on B, causing the
- // session to be alive forever.
- BlacklistDuration time.Duration
- blacklist = blacklistMap{
- entries: make(map[sessionKey]time.Time),
- }
-)
-
-// a global map for blacklisting conversations
-type blacklistMap struct {
- entries map[sessionKey]time.Time
- reapAt time.Time
- mut sync.Mutex
-}
-
-func (m *blacklistMap) add(address string, conv uint32) {
- if BlacklistDuration == 0 {
- return
- }
- m.mut.Lock()
- timeout := time.Now().Add(BlacklistDuration)
- m.entries[sessionKey{
- addr: address,
- convID: conv,
- }] = timeout
- m.reap()
- m.mut.Unlock()
-}
-
-func (m *blacklistMap) has(address string, conv uint32) bool {
- if BlacklistDuration == 0 {
- return false
- }
- m.mut.Lock()
- t, ok := m.entries[sessionKey{
- addr: address,
- convID: conv,
- }]
- m.mut.Unlock()
- return ok && t.After(time.Now())
-}
-
-func (m *blacklistMap) reap() {
- now := time.Now()
- for k, t := range m.entries {
- if t.Before(now) {
- delete(m.entries, k)
- }
- }
-}
diff --git a/vendor/github.com/xtaci/kcp-go/crypt.go b/vendor/github.com/xtaci/kcp-go/crypt.go
deleted file mode 100644
index d9b8af9c2..000000000
--- a/vendor/github.com/xtaci/kcp-go/crypt.go
+++ /dev/null
@@ -1,288 +0,0 @@
-package kcp
-
-import (
- "crypto/aes"
- "crypto/cipher"
- "crypto/des"
- "crypto/sha1"
-
- "github.com/templexxx/xor"
- "github.com/tjfoc/gmsm/sm4"
-
- "golang.org/x/crypto/blowfish"
- "golang.org/x/crypto/cast5"
- "golang.org/x/crypto/pbkdf2"
- "golang.org/x/crypto/salsa20"
- "golang.org/x/crypto/tea"
- "golang.org/x/crypto/twofish"
- "golang.org/x/crypto/xtea"
-)
-
-var (
- initialVector = []byte{167, 115, 79, 156, 18, 172, 27, 1, 164, 21, 242, 193, 252, 120, 230, 107}
- saltxor = `sH3CIVoF#rWLtJo6`
-)
-
-// BlockCrypt defines encryption/decryption methods for a given byte slice.
-// Notes on implementing: the data to be encrypted contains a builtin
-// nonce at the first 16 bytes
-type BlockCrypt interface {
- // Encrypt encrypts the whole block in src into dst.
- // Dst and src may point at the same memory.
- Encrypt(dst, src []byte)
-
- // Decrypt decrypts the whole block in src into dst.
- // Dst and src may point at the same memory.
- Decrypt(dst, src []byte)
-}
-
-type salsa20BlockCrypt struct {
- key [32]byte
-}
-
-// NewSalsa20BlockCrypt https://en.wikipedia.org/wiki/Salsa20
-func NewSalsa20BlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(salsa20BlockCrypt)
- copy(c.key[:], key)
- return c, nil
-}
-
-func (c *salsa20BlockCrypt) Encrypt(dst, src []byte) {
- salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key)
- copy(dst[:8], src[:8])
-}
-func (c *salsa20BlockCrypt) Decrypt(dst, src []byte) {
- salsa20.XORKeyStream(dst[8:], src[8:], src[:8], &c.key)
- copy(dst[:8], src[:8])
-}
-
-type sm4BlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewSM4BlockCrypt https://github.com/tjfoc/gmsm/tree/master/sm4
-func NewSM4BlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(sm4BlockCrypt)
- block, err := sm4.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, sm4.BlockSize)
- c.decbuf = make([]byte, 2*sm4.BlockSize)
- return c, nil
-}
-
-func (c *sm4BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *sm4BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type twofishBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewTwofishBlockCrypt https://en.wikipedia.org/wiki/Twofish
-func NewTwofishBlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(twofishBlockCrypt)
- block, err := twofish.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, twofish.BlockSize)
- c.decbuf = make([]byte, 2*twofish.BlockSize)
- return c, nil
-}
-
-func (c *twofishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *twofishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type tripleDESBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewTripleDESBlockCrypt https://en.wikipedia.org/wiki/Triple_DES
-func NewTripleDESBlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(tripleDESBlockCrypt)
- block, err := des.NewTripleDESCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, des.BlockSize)
- c.decbuf = make([]byte, 2*des.BlockSize)
- return c, nil
-}
-
-func (c *tripleDESBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *tripleDESBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type cast5BlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewCast5BlockCrypt https://en.wikipedia.org/wiki/CAST-128
-func NewCast5BlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(cast5BlockCrypt)
- block, err := cast5.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, cast5.BlockSize)
- c.decbuf = make([]byte, 2*cast5.BlockSize)
- return c, nil
-}
-
-func (c *cast5BlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *cast5BlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type blowfishBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewBlowfishBlockCrypt https://en.wikipedia.org/wiki/Blowfish_(cipher)
-func NewBlowfishBlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(blowfishBlockCrypt)
- block, err := blowfish.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, blowfish.BlockSize)
- c.decbuf = make([]byte, 2*blowfish.BlockSize)
- return c, nil
-}
-
-func (c *blowfishBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *blowfishBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type aesBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewAESBlockCrypt https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
-func NewAESBlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(aesBlockCrypt)
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, aes.BlockSize)
- c.decbuf = make([]byte, 2*aes.BlockSize)
- return c, nil
-}
-
-func (c *aesBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *aesBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type teaBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewTEABlockCrypt https://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
-func NewTEABlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(teaBlockCrypt)
- block, err := tea.NewCipherWithRounds(key, 16)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, tea.BlockSize)
- c.decbuf = make([]byte, 2*tea.BlockSize)
- return c, nil
-}
-
-func (c *teaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *teaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type xteaBlockCrypt struct {
- encbuf []byte
- decbuf []byte
- block cipher.Block
-}
-
-// NewXTEABlockCrypt https://en.wikipedia.org/wiki/XTEA
-func NewXTEABlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(xteaBlockCrypt)
- block, err := xtea.NewCipher(key)
- if err != nil {
- return nil, err
- }
- c.block = block
- c.encbuf = make([]byte, xtea.BlockSize)
- c.decbuf = make([]byte, 2*xtea.BlockSize)
- return c, nil
-}
-
-func (c *xteaBlockCrypt) Encrypt(dst, src []byte) { encrypt(c.block, dst, src, c.encbuf) }
-func (c *xteaBlockCrypt) Decrypt(dst, src []byte) { decrypt(c.block, dst, src, c.decbuf) }
-
-type simpleXORBlockCrypt struct {
- xortbl []byte
-}
-
-// NewSimpleXORBlockCrypt simple xor with key expanding
-func NewSimpleXORBlockCrypt(key []byte) (BlockCrypt, error) {
- c := new(simpleXORBlockCrypt)
- c.xortbl = pbkdf2.Key(key, []byte(saltxor), 32, mtuLimit, sha1.New)
- return c, nil
-}
-
-func (c *simpleXORBlockCrypt) Encrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) }
-func (c *simpleXORBlockCrypt) Decrypt(dst, src []byte) { xor.Bytes(dst, src, c.xortbl) }
-
-type noneBlockCrypt struct{}
-
-// NewNoneBlockCrypt does nothing but copying
-func NewNoneBlockCrypt(key []byte) (BlockCrypt, error) {
- return new(noneBlockCrypt), nil
-}
-
-func (c *noneBlockCrypt) Encrypt(dst, src []byte) { copy(dst, src) }
-func (c *noneBlockCrypt) Decrypt(dst, src []byte) { copy(dst, src) }
-
-// packet encryption with local CFB mode
-func encrypt(block cipher.Block, dst, src, buf []byte) {
- blocksize := block.BlockSize()
- tbl := buf[:blocksize]
- block.Encrypt(tbl, initialVector)
- n := len(src) / blocksize
- base := 0
- for i := 0; i < n; i++ {
- xor.BytesSrc1(dst[base:], src[base:], tbl)
- block.Encrypt(tbl, dst[base:])
- base += blocksize
- }
- xor.BytesSrc0(dst[base:], src[base:], tbl)
-}
-
-func decrypt(block cipher.Block, dst, src, buf []byte) {
- blocksize := block.BlockSize()
- tbl := buf[:blocksize]
- next := buf[blocksize:]
- block.Encrypt(tbl, initialVector)
- n := len(src) / blocksize
- base := 0
- for i := 0; i < n; i++ {
- block.Encrypt(next, src[base:])
- xor.BytesSrc1(dst[base:], src[base:], tbl)
- tbl, next = next, tbl
- base += blocksize
- }
- xor.BytesSrc0(dst[base:], src[base:], tbl)
-}
diff --git a/vendor/github.com/xtaci/kcp-go/fec.go b/vendor/github.com/xtaci/kcp-go/fec.go
deleted file mode 100644
index 6a12824da..000000000
--- a/vendor/github.com/xtaci/kcp-go/fec.go
+++ /dev/null
@@ -1,311 +0,0 @@
-package kcp
-
-import (
- "encoding/binary"
- "sync/atomic"
-
- "github.com/klauspost/reedsolomon"
-)
-
-const (
- fecHeaderSize = 6
- fecHeaderSizePlus2 = fecHeaderSize + 2 // plus 2B data size
- typeData = 0xf1
- typeFEC = 0xf2
-)
-
-type (
- // fecPacket is a decoded FEC packet
- fecPacket struct {
- seqid uint32
- flag uint16
- data []byte
- }
-
- // fecDecoder for decoding incoming packets
- fecDecoder struct {
- rxlimit int // queue size limit
- dataShards int
- parityShards int
- shardSize int
- rx []fecPacket // ordered receive queue
-
- // caches
- decodeCache [][]byte
- flagCache []bool
-
- // zeros
- zeros []byte
-
- // RS decoder
- codec reedsolomon.Encoder
- }
-)
-
-func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder {
- if dataShards <= 0 || parityShards <= 0 {
- return nil
- }
- if rxlimit < dataShards+parityShards {
- return nil
- }
-
- dec := new(fecDecoder)
- dec.rxlimit = rxlimit
- dec.dataShards = dataShards
- dec.parityShards = parityShards
- dec.shardSize = dataShards + parityShards
- codec, err := reedsolomon.New(dataShards, parityShards)
- if err != nil {
- return nil
- }
- dec.codec = codec
- dec.decodeCache = make([][]byte, dec.shardSize)
- dec.flagCache = make([]bool, dec.shardSize)
- dec.zeros = make([]byte, mtuLimit)
- return dec
-}
-
-// decodeBytes a fec packet
-func (dec *fecDecoder) decodeBytes(data []byte) fecPacket {
- var pkt fecPacket
- pkt.seqid = binary.LittleEndian.Uint32(data)
- pkt.flag = binary.LittleEndian.Uint16(data[4:])
- // allocate memory & copy
- buf := xmitBuf.Get().([]byte)[:len(data)-6]
- copy(buf, data[6:])
- pkt.data = buf
- return pkt
-}
-
-// decode a fec packet
-func (dec *fecDecoder) decode(pkt fecPacket) (recovered [][]byte) {
- // insertion
- n := len(dec.rx) - 1
- insertIdx := 0
- for i := n; i >= 0; i-- {
- if pkt.seqid == dec.rx[i].seqid { // de-duplicate
- xmitBuf.Put(pkt.data)
- return nil
- } else if _itimediff(pkt.seqid, dec.rx[i].seqid) > 0 { // insertion
- insertIdx = i + 1
- break
- }
- }
-
- // insert into ordered rx queue
- if insertIdx == n+1 {
- dec.rx = append(dec.rx, pkt)
- } else {
- dec.rx = append(dec.rx, fecPacket{})
- copy(dec.rx[insertIdx+1:], dec.rx[insertIdx:]) // shift right
- dec.rx[insertIdx] = pkt
- }
-
- // shard range for current packet
- shardBegin := pkt.seqid - pkt.seqid%uint32(dec.shardSize)
- shardEnd := shardBegin + uint32(dec.shardSize) - 1
-
- // max search range in ordered queue for current shard
- searchBegin := insertIdx - int(pkt.seqid%uint32(dec.shardSize))
- if searchBegin < 0 {
- searchBegin = 0
- }
- searchEnd := searchBegin + dec.shardSize - 1
- if searchEnd >= len(dec.rx) {
- searchEnd = len(dec.rx) - 1
- }
-
- // re-construct datashards
- if searchEnd-searchBegin+1 >= dec.dataShards {
- var numshard, numDataShard, first, maxlen int
-
- // zero cache
- shards := dec.decodeCache
- shardsflag := dec.flagCache
- for k := range dec.decodeCache {
- shards[k] = nil
- shardsflag[k] = false
- }
-
- // shard assembly
- for i := searchBegin; i <= searchEnd; i++ {
- seqid := dec.rx[i].seqid
- if _itimediff(seqid, shardEnd) > 0 {
- break
- } else if _itimediff(seqid, shardBegin) >= 0 {
- shards[seqid%uint32(dec.shardSize)] = dec.rx[i].data
- shardsflag[seqid%uint32(dec.shardSize)] = true
- numshard++
- if dec.rx[i].flag == typeData {
- numDataShard++
- }
- if numshard == 1 {
- first = i
- }
- if len(dec.rx[i].data) > maxlen {
- maxlen = len(dec.rx[i].data)
- }
- }
- }
-
- if numDataShard == dec.dataShards {
- // case 1: no lost data shards
- dec.rx = dec.freeRange(first, numshard, dec.rx)
- } else if numshard >= dec.dataShards {
- // case 2: data shard lost, but recoverable from parity shard
- for k := range shards {
- if shards[k] != nil {
- dlen := len(shards[k])
- shards[k] = shards[k][:maxlen]
- copy(shards[k][dlen:], dec.zeros)
- }
- }
- if err := dec.codec.ReconstructData(shards); err == nil {
- for k := range shards[:dec.dataShards] {
- if !shardsflag[k] {
- recovered = append(recovered, shards[k])
- }
- }
- }
- dec.rx = dec.freeRange(first, numshard, dec.rx)
- }
- }
-
- // keep rxlimit
- if len(dec.rx) > dec.rxlimit {
- if dec.rx[0].flag == typeData { // record unrecoverable data
- atomic.AddUint64(&DefaultSnmp.FECShortShards, 1)
- }
- dec.rx = dec.freeRange(0, 1, dec.rx)
- }
- return
-}
-
-// free a range of fecPacket, and zero for GC recycling
-func (dec *fecDecoder) freeRange(first, n int, q []fecPacket) []fecPacket {
- for i := first; i < first+n; i++ { // free
- xmitBuf.Put(q[i].data)
- }
- copy(q[first:], q[first+n:])
- for i := 0; i < n; i++ { // dereference data
- q[len(q)-1-i].data = nil
- }
- return q[:len(q)-n]
-}
-
-type (
- // fecEncoder for encoding outgoing packets
- fecEncoder struct {
- dataShards int
- parityShards int
- shardSize int
- paws uint32 // Protect Against Wrapped Sequence numbers
- next uint32 // next seqid
-
- shardCount int // count the number of datashards collected
- maxSize int // record maximum data length in datashard
-
- headerOffset int // FEC header offset
- payloadOffset int // FEC payload offset
-
- // caches
- shardCache [][]byte
- encodeCache [][]byte
-
- // zeros
- zeros []byte
-
- // RS encoder
- codec reedsolomon.Encoder
- }
-)
-
-func newFECEncoder(dataShards, parityShards, offset int) *fecEncoder {
- if dataShards <= 0 || parityShards <= 0 {
- return nil
- }
- enc := new(fecEncoder)
- enc.dataShards = dataShards
- enc.parityShards = parityShards
- enc.shardSize = dataShards + parityShards
- enc.paws = (0xffffffff/uint32(enc.shardSize) - 1) * uint32(enc.shardSize)
- enc.headerOffset = offset
- enc.payloadOffset = enc.headerOffset + fecHeaderSize
-
- codec, err := reedsolomon.New(dataShards, parityShards)
- if err != nil {
- return nil
- }
- enc.codec = codec
-
- // caches
- enc.encodeCache = make([][]byte, enc.shardSize)
- enc.shardCache = make([][]byte, enc.shardSize)
- for k := range enc.shardCache {
- enc.shardCache[k] = make([]byte, mtuLimit)
- }
- enc.zeros = make([]byte, mtuLimit)
- return enc
-}
-
-// encode the packet, output parity shards if we have enough datashards
-// the content of returned parityshards will change in next encode
-func (enc *fecEncoder) encode(b []byte) (ps [][]byte) {
- enc.markData(b[enc.headerOffset:])
- binary.LittleEndian.PutUint16(b[enc.payloadOffset:], uint16(len(b[enc.payloadOffset:])))
-
- // copy data to fec datashards
- sz := len(b)
- enc.shardCache[enc.shardCount] = enc.shardCache[enc.shardCount][:sz]
- copy(enc.shardCache[enc.shardCount], b)
- enc.shardCount++
-
- // record max datashard length
- if sz > enc.maxSize {
- enc.maxSize = sz
- }
-
- // calculate Reed-Solomon Erasure Code
- if enc.shardCount == enc.dataShards {
- // bzero each datashard's tail
- for i := 0; i < enc.dataShards; i++ {
- shard := enc.shardCache[i]
- slen := len(shard)
- copy(shard[slen:enc.maxSize], enc.zeros)
- }
-
- // construct equal-sized slice with stripped header
- cache := enc.encodeCache
- for k := range cache {
- cache[k] = enc.shardCache[k][enc.payloadOffset:enc.maxSize]
- }
-
- // rs encode
- if err := enc.codec.Encode(cache); err == nil {
- ps = enc.shardCache[enc.dataShards:]
- for k := range ps {
- enc.markFEC(ps[k][enc.headerOffset:])
- ps[k] = ps[k][:enc.maxSize]
- }
- }
-
- // reset counters to zero
- enc.shardCount = 0
- enc.maxSize = 0
- }
-
- return
-}
-
-func (enc *fecEncoder) markData(data []byte) {
- binary.LittleEndian.PutUint32(data, enc.next)
- binary.LittleEndian.PutUint16(data[4:], typeData)
- enc.next++
-}
-
-func (enc *fecEncoder) markFEC(data []byte) {
- binary.LittleEndian.PutUint32(data, enc.next)
- binary.LittleEndian.PutUint16(data[4:], typeFEC)
- enc.next = (enc.next + 1) % enc.paws
-}
diff --git a/vendor/github.com/xtaci/kcp-go/kcp.go b/vendor/github.com/xtaci/kcp-go/kcp.go
deleted file mode 100644
index 21cdde192..000000000
--- a/vendor/github.com/xtaci/kcp-go/kcp.go
+++ /dev/null
@@ -1,997 +0,0 @@
-// Package kcp - A Fast and Reliable ARQ Protocol
-package kcp
-
-import (
- "encoding/binary"
- "sync/atomic"
-)
-
-const (
- IKCP_RTO_NDL = 30 // no delay min rto
- IKCP_RTO_MIN = 100 // normal min rto
- IKCP_RTO_DEF = 200
- IKCP_RTO_MAX = 60000
- IKCP_CMD_PUSH = 81 // cmd: push data
- IKCP_CMD_ACK = 82 // cmd: ack
- IKCP_CMD_WASK = 83 // cmd: window probe (ask)
- IKCP_CMD_WINS = 84 // cmd: window size (tell)
- IKCP_ASK_SEND = 1 // need to send IKCP_CMD_WASK
- IKCP_ASK_TELL = 2 // need to send IKCP_CMD_WINS
- IKCP_WND_SND = 32
- IKCP_WND_RCV = 32
- IKCP_MTU_DEF = 1400
- IKCP_ACK_FAST = 3
- IKCP_INTERVAL = 100
- IKCP_OVERHEAD = 24
- IKCP_DEADLINK = 20
- IKCP_THRESH_INIT = 2
- IKCP_THRESH_MIN = 2
- IKCP_PROBE_INIT = 7000 // 7 secs to probe window size
- IKCP_PROBE_LIMIT = 120000 // up to 120 secs to probe window
-)
-
-// output_callback is a prototype which ought capture conn and call conn.Write
-type output_callback func(buf []byte, size int)
-
-/* encode 8 bits unsigned int */
-func ikcp_encode8u(p []byte, c byte) []byte {
- p[0] = c
- return p[1:]
-}
-
-/* decode 8 bits unsigned int */
-func ikcp_decode8u(p []byte, c *byte) []byte {
- *c = p[0]
- return p[1:]
-}
-
-/* encode 16 bits unsigned int (lsb) */
-func ikcp_encode16u(p []byte, w uint16) []byte {
- binary.LittleEndian.PutUint16(p, w)
- return p[2:]
-}
-
-/* decode 16 bits unsigned int (lsb) */
-func ikcp_decode16u(p []byte, w *uint16) []byte {
- *w = binary.LittleEndian.Uint16(p)
- return p[2:]
-}
-
-/* encode 32 bits unsigned int (lsb) */
-func ikcp_encode32u(p []byte, l uint32) []byte {
- binary.LittleEndian.PutUint32(p, l)
- return p[4:]
-}
-
-/* decode 32 bits unsigned int (lsb) */
-func ikcp_decode32u(p []byte, l *uint32) []byte {
- *l = binary.LittleEndian.Uint32(p)
- return p[4:]
-}
-
-func _imin_(a, b uint32) uint32 {
- if a <= b {
- return a
- }
- return b
-}
-
-func _imax_(a, b uint32) uint32 {
- if a >= b {
- return a
- }
- return b
-}
-
-func _ibound_(lower, middle, upper uint32) uint32 {
- return _imin_(_imax_(lower, middle), upper)
-}
-
-func _itimediff(later, earlier uint32) int32 {
- return (int32)(later - earlier)
-}
-
-// segment defines a KCP segment
-type segment struct {
- conv uint32
- cmd uint8
- frg uint8
- wnd uint16
- ts uint32
- sn uint32
- una uint32
- rto uint32
- xmit uint32
- resendts uint32
- fastack uint32
- data []byte
-}
-
-// encode a segment into buffer
-func (seg *segment) encode(ptr []byte) []byte {
- ptr = ikcp_encode32u(ptr, seg.conv)
- ptr = ikcp_encode8u(ptr, seg.cmd)
- ptr = ikcp_encode8u(ptr, seg.frg)
- ptr = ikcp_encode16u(ptr, seg.wnd)
- ptr = ikcp_encode32u(ptr, seg.ts)
- ptr = ikcp_encode32u(ptr, seg.sn)
- ptr = ikcp_encode32u(ptr, seg.una)
- ptr = ikcp_encode32u(ptr, uint32(len(seg.data)))
- atomic.AddUint64(&DefaultSnmp.OutSegs, 1)
- return ptr
-}
-
-// KCP defines a single KCP connection
-type KCP struct {
- conv, mtu, mss, state uint32
- snd_una, snd_nxt, rcv_nxt uint32
- ssthresh uint32
- rx_rttvar, rx_srtt int32
- rx_rto, rx_minrto uint32
- snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32
- interval, ts_flush uint32
- nodelay, updated uint32
- ts_probe, probe_wait uint32
- dead_link, incr uint32
-
- fastresend int32
- nocwnd, stream int32
-
- snd_queue []segment
- rcv_queue []segment
- snd_buf []segment
- rcv_buf []segment
-
- acklist []ackItem
-
- buffer []byte
- output output_callback
-}
-
-type ackItem struct {
- sn uint32
- ts uint32
-}
-
-// NewKCP create a new kcp control object, 'conv' must equal in two endpoint
-// from the same connection.
-func NewKCP(conv uint32, output output_callback) *KCP {
- kcp := new(KCP)
- kcp.conv = conv
- kcp.snd_wnd = IKCP_WND_SND
- kcp.rcv_wnd = IKCP_WND_RCV
- kcp.rmt_wnd = IKCP_WND_RCV
- kcp.mtu = IKCP_MTU_DEF
- kcp.mss = kcp.mtu - IKCP_OVERHEAD
- kcp.buffer = make([]byte, (kcp.mtu+IKCP_OVERHEAD)*3)
- kcp.rx_rto = IKCP_RTO_DEF
- kcp.rx_minrto = IKCP_RTO_MIN
- kcp.interval = IKCP_INTERVAL
- kcp.ts_flush = IKCP_INTERVAL
- kcp.ssthresh = IKCP_THRESH_INIT
- kcp.dead_link = IKCP_DEADLINK
- kcp.output = output
- return kcp
-}
-
-// newSegment creates a KCP segment
-func (kcp *KCP) newSegment(size int) (seg segment) {
- seg.data = xmitBuf.Get().([]byte)[:size]
- return
-}
-
-// delSegment recycles a KCP segment
-func (kcp *KCP) delSegment(seg segment) {
- xmitBuf.Put(seg.data)
-}
-
-// PeekSize checks the size of next message in the recv queue
-func (kcp *KCP) PeekSize() (length int) {
- if len(kcp.rcv_queue) == 0 {
- return -1
- }
-
- seg := &kcp.rcv_queue[0]
- if seg.frg == 0 {
- return len(seg.data)
- }
-
- if len(kcp.rcv_queue) < int(seg.frg+1) {
- return -1
- }
-
- for k := range kcp.rcv_queue {
- seg := &kcp.rcv_queue[k]
- length += len(seg.data)
- if seg.frg == 0 {
- break
- }
- }
- return
-}
-
-// Recv is user/upper level recv: returns size, returns below zero for EAGAIN
-func (kcp *KCP) Recv(buffer []byte) (n int) {
- if len(kcp.rcv_queue) == 0 {
- return -1
- }
-
- peeksize := kcp.PeekSize()
- if peeksize < 0 {
- return -2
- }
-
- if peeksize > len(buffer) {
- return -3
- }
-
- var fast_recover bool
- if len(kcp.rcv_queue) >= int(kcp.rcv_wnd) {
- fast_recover = true
- }
-
- // merge fragment
- count := 0
- for k := range kcp.rcv_queue {
- seg := &kcp.rcv_queue[k]
- copy(buffer, seg.data)
- buffer = buffer[len(seg.data):]
- n += len(seg.data)
- count++
- kcp.delSegment(*seg)
- if seg.frg == 0 {
- break
- }
- }
- if count > 0 {
- kcp.rcv_queue = kcp.remove_front(kcp.rcv_queue, count)
- }
-
- // move available data from rcv_buf -> rcv_queue
- count = 0
- for k := range kcp.rcv_buf {
- seg := &kcp.rcv_buf[k]
- if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
- kcp.rcv_nxt++
- count++
- } else {
- break
- }
- }
-
- if count > 0 {
- kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...)
- kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count)
- }
-
- // fast recover
- if len(kcp.rcv_queue) < int(kcp.rcv_wnd) && fast_recover {
- // ready to send back IKCP_CMD_WINS in ikcp_flush
- // tell remote my window size
- kcp.probe |= IKCP_ASK_TELL
- }
- return
-}
-
-// Send is user/upper level send, returns below zero for error
-func (kcp *KCP) Send(buffer []byte) int {
- var count int
- if len(buffer) == 0 {
- return -1
- }
-
- // append to previous segment in streaming mode (if possible)
- if kcp.stream != 0 {
- n := len(kcp.snd_queue)
- if n > 0 {
- seg := &kcp.snd_queue[n-1]
- if len(seg.data) < int(kcp.mss) {
- capacity := int(kcp.mss) - len(seg.data)
- extend := capacity
- if len(buffer) < capacity {
- extend = len(buffer)
- }
-
- // grow slice, the underlying cap is guaranteed to
- // be larger than kcp.mss
- oldlen := len(seg.data)
- seg.data = seg.data[:oldlen+extend]
- copy(seg.data[oldlen:], buffer)
- buffer = buffer[extend:]
- }
- }
-
- if len(buffer) == 0 {
- return 0
- }
- }
-
- if len(buffer) <= int(kcp.mss) {
- count = 1
- } else {
- count = (len(buffer) + int(kcp.mss) - 1) / int(kcp.mss)
- }
-
- if count > 255 {
- return -2
- }
-
- if count == 0 {
- count = 1
- }
-
- for i := 0; i < count; i++ {
- var size int
- if len(buffer) > int(kcp.mss) {
- size = int(kcp.mss)
- } else {
- size = len(buffer)
- }
- seg := kcp.newSegment(size)
- copy(seg.data, buffer[:size])
- if kcp.stream == 0 { // message mode
- seg.frg = uint8(count - i - 1)
- } else { // stream mode
- seg.frg = 0
- }
- kcp.snd_queue = append(kcp.snd_queue, seg)
- buffer = buffer[size:]
- }
- return 0
-}
-
-func (kcp *KCP) update_ack(rtt int32) {
- // https://tools.ietf.org/html/rfc6298
- var rto uint32
- if kcp.rx_srtt == 0 {
- kcp.rx_srtt = rtt
- kcp.rx_rttvar = rtt >> 1
- } else {
- delta := rtt - kcp.rx_srtt
- kcp.rx_srtt += delta >> 3
- if delta < 0 {
- delta = -delta
- }
- if rtt < kcp.rx_srtt-kcp.rx_rttvar {
- // if the new RTT sample is below the bottom of the range of
- // what an RTT measurement is expected to be.
- // give an 8x reduced weight versus its normal weighting
- kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 5
- } else {
- kcp.rx_rttvar += (delta - kcp.rx_rttvar) >> 2
- }
- }
- rto = uint32(kcp.rx_srtt) + _imax_(kcp.interval, uint32(kcp.rx_rttvar)<<2)
- kcp.rx_rto = _ibound_(kcp.rx_minrto, rto, IKCP_RTO_MAX)
-}
-
-func (kcp *KCP) shrink_buf() {
- if len(kcp.snd_buf) > 0 {
- seg := &kcp.snd_buf[0]
- kcp.snd_una = seg.sn
- } else {
- kcp.snd_una = kcp.snd_nxt
- }
-}
-
-func (kcp *KCP) parse_ack(sn uint32) {
- if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 {
- return
- }
-
- for k := range kcp.snd_buf {
- seg := &kcp.snd_buf[k]
- if sn == seg.sn {
- kcp.delSegment(*seg)
- copy(kcp.snd_buf[k:], kcp.snd_buf[k+1:])
- kcp.snd_buf[len(kcp.snd_buf)-1] = segment{}
- kcp.snd_buf = kcp.snd_buf[:len(kcp.snd_buf)-1]
- break
- }
- if _itimediff(sn, seg.sn) < 0 {
- break
- }
- }
-}
-
-func (kcp *KCP) parse_fastack(sn uint32) {
- if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 {
- return
- }
-
- for k := range kcp.snd_buf {
- seg := &kcp.snd_buf[k]
- if _itimediff(sn, seg.sn) < 0 {
- break
- } else if sn != seg.sn {
- seg.fastack++
- }
- }
-}
-
-func (kcp *KCP) parse_una(una uint32) {
- count := 0
- for k := range kcp.snd_buf {
- seg := &kcp.snd_buf[k]
- if _itimediff(una, seg.sn) > 0 {
- kcp.delSegment(*seg)
- count++
- } else {
- break
- }
- }
- if count > 0 {
- kcp.snd_buf = kcp.remove_front(kcp.snd_buf, count)
- }
-}
-
-// ack append
-func (kcp *KCP) ack_push(sn, ts uint32) {
- kcp.acklist = append(kcp.acklist, ackItem{sn, ts})
-}
-
-func (kcp *KCP) parse_data(newseg segment) {
- sn := newseg.sn
- if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 ||
- _itimediff(sn, kcp.rcv_nxt) < 0 {
- kcp.delSegment(newseg)
- return
- }
-
- n := len(kcp.rcv_buf) - 1
- insert_idx := 0
- repeat := false
- for i := n; i >= 0; i-- {
- seg := &kcp.rcv_buf[i]
- if seg.sn == sn {
- repeat = true
- atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
- break
- }
- if _itimediff(sn, seg.sn) > 0 {
- insert_idx = i + 1
- break
- }
- }
-
- if !repeat {
- if insert_idx == n+1 {
- kcp.rcv_buf = append(kcp.rcv_buf, newseg)
- } else {
- kcp.rcv_buf = append(kcp.rcv_buf, segment{})
- copy(kcp.rcv_buf[insert_idx+1:], kcp.rcv_buf[insert_idx:])
- kcp.rcv_buf[insert_idx] = newseg
- }
- } else {
- kcp.delSegment(newseg)
- }
-
- // move available data from rcv_buf -> rcv_queue
- count := 0
- for k := range kcp.rcv_buf {
- seg := &kcp.rcv_buf[k]
- if seg.sn == kcp.rcv_nxt && len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
- kcp.rcv_nxt++
- count++
- } else {
- break
- }
- }
- if count > 0 {
- kcp.rcv_queue = append(kcp.rcv_queue, kcp.rcv_buf[:count]...)
- kcp.rcv_buf = kcp.remove_front(kcp.rcv_buf, count)
- }
-}
-
-// Input when you received a low level packet (eg. UDP packet), call it
-// regular indicates a regular packet has received(not from FEC)
-func (kcp *KCP) Input(data []byte, regular, ackNoDelay bool) int {
- una := kcp.snd_una
- if len(data) < IKCP_OVERHEAD {
- return -1
- }
-
- var maxack uint32
- var lastackts uint32
- var flag int
- var inSegs uint64
-
- for {
- var ts, sn, length, una, conv uint32
- var wnd uint16
- var cmd, frg uint8
-
- if len(data) < int(IKCP_OVERHEAD) {
- break
- }
-
- data = ikcp_decode32u(data, &conv)
- if conv != kcp.conv {
- return -1
- }
-
- data = ikcp_decode8u(data, &cmd)
- data = ikcp_decode8u(data, &frg)
- data = ikcp_decode16u(data, &wnd)
- data = ikcp_decode32u(data, &ts)
- data = ikcp_decode32u(data, &sn)
- data = ikcp_decode32u(data, &una)
- data = ikcp_decode32u(data, &length)
- if len(data) < int(length) {
- return -2
- }
-
- if cmd != IKCP_CMD_PUSH && cmd != IKCP_CMD_ACK &&
- cmd != IKCP_CMD_WASK && cmd != IKCP_CMD_WINS {
- return -3
- }
-
- // only trust window updates from regular packets. i.e: latest update
- if regular {
- kcp.rmt_wnd = uint32(wnd)
- }
- kcp.parse_una(una)
- kcp.shrink_buf()
-
- if cmd == IKCP_CMD_ACK {
- kcp.parse_ack(sn)
- kcp.shrink_buf()
- if flag == 0 {
- flag = 1
- maxack = sn
- lastackts = ts
- } else if _itimediff(sn, maxack) > 0 {
- maxack = sn
- lastackts = ts
- }
- } else if cmd == IKCP_CMD_PUSH {
- if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 {
- kcp.ack_push(sn, ts)
- if _itimediff(sn, kcp.rcv_nxt) >= 0 {
- seg := kcp.newSegment(int(length))
- seg.conv = conv
- seg.cmd = cmd
- seg.frg = frg
- seg.wnd = wnd
- seg.ts = ts
- seg.sn = sn
- seg.una = una
- copy(seg.data, data[:length])
- kcp.parse_data(seg)
- } else {
- atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
- }
- } else {
- atomic.AddUint64(&DefaultSnmp.RepeatSegs, 1)
- }
- } else if cmd == IKCP_CMD_WASK {
- // ready to send back IKCP_CMD_WINS in Ikcp_flush
- // tell remote my window size
- kcp.probe |= IKCP_ASK_TELL
- } else if cmd == IKCP_CMD_WINS {
- // do nothing
- } else {
- return -3
- }
-
- inSegs++
- data = data[length:]
- }
- atomic.AddUint64(&DefaultSnmp.InSegs, inSegs)
-
- if flag != 0 && regular {
- kcp.parse_fastack(maxack)
- current := currentMs()
- if _itimediff(current, lastackts) >= 0 {
- kcp.update_ack(_itimediff(current, lastackts))
- }
- }
-
- if _itimediff(kcp.snd_una, una) > 0 {
- if kcp.cwnd < kcp.rmt_wnd {
- mss := kcp.mss
- if kcp.cwnd < kcp.ssthresh {
- kcp.cwnd++
- kcp.incr += mss
- } else {
- if kcp.incr < mss {
- kcp.incr = mss
- }
- kcp.incr += (mss*mss)/kcp.incr + (mss / 16)
- if (kcp.cwnd+1)*mss <= kcp.incr {
- kcp.cwnd++
- }
- }
- if kcp.cwnd > kcp.rmt_wnd {
- kcp.cwnd = kcp.rmt_wnd
- kcp.incr = kcp.rmt_wnd * mss
- }
- }
- }
-
- if ackNoDelay && len(kcp.acklist) > 0 { // ack immediately
- kcp.flush(true)
- }
- return 0
-}
-
-func (kcp *KCP) wnd_unused() uint16 {
- if len(kcp.rcv_queue) < int(kcp.rcv_wnd) {
- return uint16(int(kcp.rcv_wnd) - len(kcp.rcv_queue))
- }
- return 0
-}
-
-// flush pending data
-func (kcp *KCP) flush(ackOnly bool) {
- var seg segment
- seg.conv = kcp.conv
- seg.cmd = IKCP_CMD_ACK
- seg.wnd = kcp.wnd_unused()
- seg.una = kcp.rcv_nxt
-
- buffer := kcp.buffer
- // flush acknowledges
- ptr := buffer
- for i, ack := range kcp.acklist {
- size := len(buffer) - len(ptr)
- if size+IKCP_OVERHEAD > int(kcp.mtu) {
- kcp.output(buffer, size)
- ptr = buffer
- }
- // filter jitters caused by bufferbloat
- if ack.sn >= kcp.rcv_nxt || len(kcp.acklist)-1 == i {
- seg.sn, seg.ts = ack.sn, ack.ts
- ptr = seg.encode(ptr)
- }
- }
- kcp.acklist = kcp.acklist[0:0]
-
- if ackOnly { // flash remain ack segments
- size := len(buffer) - len(ptr)
- if size > 0 {
- kcp.output(buffer, size)
- }
- return
- }
-
- // probe window size (if remote window size equals zero)
- if kcp.rmt_wnd == 0 {
- current := currentMs()
- if kcp.probe_wait == 0 {
- kcp.probe_wait = IKCP_PROBE_INIT
- kcp.ts_probe = current + kcp.probe_wait
- } else {
- if _itimediff(current, kcp.ts_probe) >= 0 {
- if kcp.probe_wait < IKCP_PROBE_INIT {
- kcp.probe_wait = IKCP_PROBE_INIT
- }
- kcp.probe_wait += kcp.probe_wait / 2
- if kcp.probe_wait > IKCP_PROBE_LIMIT {
- kcp.probe_wait = IKCP_PROBE_LIMIT
- }
- kcp.ts_probe = current + kcp.probe_wait
- kcp.probe |= IKCP_ASK_SEND
- }
- }
- } else {
- kcp.ts_probe = 0
- kcp.probe_wait = 0
- }
-
- // flush window probing commands
- if (kcp.probe & IKCP_ASK_SEND) != 0 {
- seg.cmd = IKCP_CMD_WASK
- size := len(buffer) - len(ptr)
- if size+IKCP_OVERHEAD > int(kcp.mtu) {
- kcp.output(buffer, size)
- ptr = buffer
- }
- ptr = seg.encode(ptr)
- }
-
- // flush window probing commands
- if (kcp.probe & IKCP_ASK_TELL) != 0 {
- seg.cmd = IKCP_CMD_WINS
- size := len(buffer) - len(ptr)
- if size+IKCP_OVERHEAD > int(kcp.mtu) {
- kcp.output(buffer, size)
- ptr = buffer
- }
- ptr = seg.encode(ptr)
- }
-
- kcp.probe = 0
-
- // calculate window size
- cwnd := _imin_(kcp.snd_wnd, kcp.rmt_wnd)
- if kcp.nocwnd == 0 {
- cwnd = _imin_(kcp.cwnd, cwnd)
- }
-
- // sliding window, controlled by snd_nxt && sna_una+cwnd
- newSegsCount := 0
- for k := range kcp.snd_queue {
- if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 {
- break
- }
- newseg := kcp.snd_queue[k]
- newseg.conv = kcp.conv
- newseg.cmd = IKCP_CMD_PUSH
- newseg.sn = kcp.snd_nxt
- kcp.snd_buf = append(kcp.snd_buf, newseg)
- kcp.snd_nxt++
- newSegsCount++
- kcp.snd_queue[k].data = nil
- }
- if newSegsCount > 0 {
- kcp.snd_queue = kcp.remove_front(kcp.snd_queue, newSegsCount)
- }
-
- // calculate resent
- resent := uint32(kcp.fastresend)
- if kcp.fastresend <= 0 {
- resent = 0xffffffff
- }
-
- // check for retransmissions
- current := currentMs()
- var change, lost, lostSegs, fastRetransSegs, earlyRetransSegs uint64
- for k := range kcp.snd_buf {
- segment := &kcp.snd_buf[k]
- needsend := false
- if segment.xmit == 0 { // initial transmit
- needsend = true
- segment.rto = kcp.rx_rto
- segment.resendts = current + segment.rto
- } else if _itimediff(current, segment.resendts) >= 0 { // RTO
- needsend = true
- if kcp.nodelay == 0 {
- segment.rto += kcp.rx_rto
- } else {
- segment.rto += kcp.rx_rto / 2
- }
- segment.resendts = current + segment.rto
- lost++
- lostSegs++
- } else if segment.fastack >= resent { // fast retransmit
- needsend = true
- segment.fastack = 0
- segment.rto = kcp.rx_rto
- segment.resendts = current + segment.rto
- change++
- fastRetransSegs++
- } else if segment.fastack > 0 && newSegsCount == 0 { // early retransmit
- needsend = true
- segment.fastack = 0
- segment.rto = kcp.rx_rto
- segment.resendts = current + segment.rto
- change++
- earlyRetransSegs++
- }
-
- if needsend {
- segment.xmit++
- segment.ts = current
- segment.wnd = seg.wnd
- segment.una = seg.una
-
- size := len(buffer) - len(ptr)
- need := IKCP_OVERHEAD + len(segment.data)
-
- if size+need > int(kcp.mtu) {
- kcp.output(buffer, size)
- current = currentMs() // time update for a blocking call
- ptr = buffer
- }
-
- ptr = segment.encode(ptr)
- copy(ptr, segment.data)
- ptr = ptr[len(segment.data):]
-
- if segment.xmit >= kcp.dead_link {
- kcp.state = 0xFFFFFFFF
- }
- }
- }
-
- // flash remain segments
- size := len(buffer) - len(ptr)
- if size > 0 {
- kcp.output(buffer, size)
- }
-
- // counter updates
- sum := lostSegs
- if lostSegs > 0 {
- atomic.AddUint64(&DefaultSnmp.LostSegs, lostSegs)
- }
- if fastRetransSegs > 0 {
- atomic.AddUint64(&DefaultSnmp.FastRetransSegs, fastRetransSegs)
- sum += fastRetransSegs
- }
- if earlyRetransSegs > 0 {
- atomic.AddUint64(&DefaultSnmp.EarlyRetransSegs, earlyRetransSegs)
- sum += earlyRetransSegs
- }
- if sum > 0 {
- atomic.AddUint64(&DefaultSnmp.RetransSegs, sum)
- }
-
- // update ssthresh
- // rate halving, https://tools.ietf.org/html/rfc6937
- if change > 0 {
- inflight := kcp.snd_nxt - kcp.snd_una
- kcp.ssthresh = inflight / 2
- if kcp.ssthresh < IKCP_THRESH_MIN {
- kcp.ssthresh = IKCP_THRESH_MIN
- }
- kcp.cwnd = kcp.ssthresh + resent
- kcp.incr = kcp.cwnd * kcp.mss
- }
-
- // congestion control, https://tools.ietf.org/html/rfc5681
- if lost > 0 {
- kcp.ssthresh = cwnd / 2
- if kcp.ssthresh < IKCP_THRESH_MIN {
- kcp.ssthresh = IKCP_THRESH_MIN
- }
- kcp.cwnd = 1
- kcp.incr = kcp.mss
- }
-
- if kcp.cwnd < 1 {
- kcp.cwnd = 1
- kcp.incr = kcp.mss
- }
-}
-
-// Update updates state (call it repeatedly, every 10ms-100ms), or you can ask
-// ikcp_check when to call it again (without ikcp_input/_send calling).
-// 'current' - current timestamp in millisec.
-func (kcp *KCP) Update() {
- var slap int32
-
- current := currentMs()
- if kcp.updated == 0 {
- kcp.updated = 1
- kcp.ts_flush = current
- }
-
- slap = _itimediff(current, kcp.ts_flush)
-
- if slap >= 10000 || slap < -10000 {
- kcp.ts_flush = current
- slap = 0
- }
-
- if slap >= 0 {
- kcp.ts_flush += kcp.interval
- if _itimediff(current, kcp.ts_flush) >= 0 {
- kcp.ts_flush = current + kcp.interval
- }
- kcp.flush(false)
- }
-}
-
-// Check determines when should you invoke ikcp_update:
-// returns when you should invoke ikcp_update in millisec, if there
-// is no ikcp_input/_send calling. you can call ikcp_update in that
-// time, instead of call update repeatly.
-// Important to reduce unnacessary ikcp_update invoking. use it to
-// schedule ikcp_update (eg. implementing an epoll-like mechanism,
-// or optimize ikcp_update when handling massive kcp connections)
-func (kcp *KCP) Check() uint32 {
- current := currentMs()
- ts_flush := kcp.ts_flush
- tm_flush := int32(0x7fffffff)
- tm_packet := int32(0x7fffffff)
- minimal := uint32(0)
- if kcp.updated == 0 {
- return current
- }
-
- if _itimediff(current, ts_flush) >= 10000 ||
- _itimediff(current, ts_flush) < -10000 {
- ts_flush = current
- }
-
- if _itimediff(current, ts_flush) >= 0 {
- return current
- }
-
- tm_flush = _itimediff(ts_flush, current)
-
- for k := range kcp.snd_buf {
- seg := &kcp.snd_buf[k]
- diff := _itimediff(seg.resendts, current)
- if diff <= 0 {
- return current
- }
- if diff < tm_packet {
- tm_packet = diff
- }
- }
-
- minimal = uint32(tm_packet)
- if tm_packet >= tm_flush {
- minimal = uint32(tm_flush)
- }
- if minimal >= kcp.interval {
- minimal = kcp.interval
- }
-
- return current + minimal
-}
-
-// SetMtu changes MTU size, default is 1400
-func (kcp *KCP) SetMtu(mtu int) int {
- if mtu < 50 || mtu < IKCP_OVERHEAD {
- return -1
- }
- buffer := make([]byte, (mtu+IKCP_OVERHEAD)*3)
- if buffer == nil {
- return -2
- }
- kcp.mtu = uint32(mtu)
- kcp.mss = kcp.mtu - IKCP_OVERHEAD
- kcp.buffer = buffer
- return 0
-}
-
-// NoDelay options
-// fastest: ikcp_nodelay(kcp, 1, 20, 2, 1)
-// nodelay: 0:disable(default), 1:enable
-// interval: internal update timer interval in millisec, default is 100ms
-// resend: 0:disable fast resend(default), 1:enable fast resend
-// nc: 0:normal congestion control(default), 1:disable congestion control
-func (kcp *KCP) NoDelay(nodelay, interval, resend, nc int) int {
- if nodelay >= 0 {
- kcp.nodelay = uint32(nodelay)
- if nodelay != 0 {
- kcp.rx_minrto = IKCP_RTO_NDL
- } else {
- kcp.rx_minrto = IKCP_RTO_MIN
- }
- }
- if interval >= 0 {
- if interval > 5000 {
- interval = 5000
- } else if interval < 10 {
- interval = 10
- }
- kcp.interval = uint32(interval)
- }
- if resend >= 0 {
- kcp.fastresend = int32(resend)
- }
- if nc >= 0 {
- kcp.nocwnd = int32(nc)
- }
- return 0
-}
-
-// WndSize sets maximum window size: sndwnd=32, rcvwnd=32 by default
-func (kcp *KCP) WndSize(sndwnd, rcvwnd int) int {
- if sndwnd > 0 {
- kcp.snd_wnd = uint32(sndwnd)
- }
- if rcvwnd > 0 {
- kcp.rcv_wnd = uint32(rcvwnd)
- }
- return 0
-}
-
-// WaitSnd gets how many packet is waiting to be sent
-func (kcp *KCP) WaitSnd() int {
- return len(kcp.snd_buf) + len(kcp.snd_queue)
-}
-
-// remove front n elements from queue
-func (kcp *KCP) remove_front(q []segment, n int) []segment {
- newn := copy(q, q[n:])
- for i := newn; i < len(q); i++ {
- q[i] = segment{} // manual set nil for GC
- }
- return q[:newn]
-}
diff --git a/vendor/github.com/xtaci/kcp-go/rand.go b/vendor/github.com/xtaci/kcp-go/rand.go
deleted file mode 100644
index 15697fb2a..000000000
--- a/vendor/github.com/xtaci/kcp-go/rand.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package kcp
-
-import (
- "crypto/md5"
- "crypto/rand"
- "io"
-)
-
-// nonceMD5 is a nonce generator for each packet header
-// which took the advantages of both MD5 and CSPRNG(like /dev/urandom).
-// The benchmark shows it's faster than previous CSPRNG only method.
-type nonceMD5 struct {
- data [md5.Size]byte
-}
-
-// Nonce fills a nonce into the provided slice with no more than md5.Size bytes
-// the entropy will be updated whenever a leading 0 appears
-func (n *nonceMD5) Fill(nonce []byte) {
- if n.data[0] == 0 { // 1/256 chance for entropy update
- io.ReadFull(rand.Reader, n.data[:])
- }
- n.data = md5.Sum(n.data[:])
- copy(nonce, n.data[:])
- return
-}
diff --git a/vendor/github.com/xtaci/kcp-go/sess.go b/vendor/github.com/xtaci/kcp-go/sess.go
deleted file mode 100644
index f3539f6b7..000000000
--- a/vendor/github.com/xtaci/kcp-go/sess.go
+++ /dev/null
@@ -1,964 +0,0 @@
-package kcp
-
-import (
- "crypto/rand"
- "encoding/binary"
- "hash/crc32"
- "net"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/pkg/errors"
- "golang.org/x/net/ipv4"
-)
-
-type errTimeout struct {
- error
-}
-
-func (errTimeout) Timeout() bool { return true }
-func (errTimeout) Temporary() bool { return true }
-func (errTimeout) Error() string { return "i/o timeout" }
-
-const (
- // 16-bytes magic number for each packet
- nonceSize = 16
-
- // 4-bytes packet checksum
- crcSize = 4
-
- // overall crypto header size
- cryptHeaderSize = nonceSize + crcSize
-
- // maximum packet size
- mtuLimit = 1500
-
- // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
- rxFECMulti = 3
-
- // accept backlog
- acceptBacklog = 128
-
- // prerouting(to session) queue
- qlen = 128
-)
-
-const (
- errBrokenPipe = "broken pipe"
- errInvalidOperation = "invalid operation"
-)
-
-var (
- // global packet buffer
- // shared among sending/receiving/FEC
- xmitBuf sync.Pool
-)
-
-func init() {
- xmitBuf.New = func() interface{} {
- return make([]byte, mtuLimit)
- }
-}
-
-type (
- // UDPSession defines a KCP session implemented by UDP
- UDPSession struct {
- updaterIdx int // record slice index in updater
- conn net.PacketConn // the underlying packet connection
- kcp *KCP // KCP ARQ protocol
- l *Listener // point to the Listener if it's accepted by Listener
- block BlockCrypt // block encryption
-
- // kcp receiving is based on packets
- // recvbuf turns packets into stream
- recvbuf []byte
- bufptr []byte
- // extended output buffer(with header)
- ext []byte
-
- // FEC
- fecDecoder *fecDecoder
- fecEncoder *fecEncoder
-
- // settings
- remote net.Addr // remote peer address
- rd time.Time // read deadline
- wd time.Time // write deadline
- headerSize int // the overall header size added before KCP frame
- ackNoDelay bool // send ack immediately for each incoming packet
- writeDelay bool // delay kcp.flush() for Write() for bulk transfer
- dup int // duplicate udp packets
-
- // notifications
- die chan struct{} // notify session has Closed
- chReadEvent chan struct{} // notify Read() can be called without blocking
- chWriteEvent chan struct{} // notify Write() can be called without blocking
- chErrorEvent chan error // notify Read() have an error
-
- // nonce generator
- nonce nonceMD5
-
- isClosed bool // flag the session has Closed
- mu sync.Mutex
- }
-
- setReadBuffer interface {
- SetReadBuffer(bytes int) error
- }
-
- setWriteBuffer interface {
- SetWriteBuffer(bytes int) error
- }
-)
-
-// newUDPSession create a new udp session for client or server
-func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn net.PacketConn, remote net.Addr, block BlockCrypt) *UDPSession {
- sess := new(UDPSession)
- sess.die = make(chan struct{})
- sess.chReadEvent = make(chan struct{}, 1)
- sess.chWriteEvent = make(chan struct{}, 1)
- sess.chErrorEvent = make(chan error, 1)
- sess.remote = remote
- sess.conn = conn
- sess.l = l
- sess.block = block
- sess.recvbuf = make([]byte, mtuLimit)
-
- // FEC initialization
- sess.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
- if sess.block != nil {
- sess.fecEncoder = newFECEncoder(dataShards, parityShards, cryptHeaderSize)
- } else {
- sess.fecEncoder = newFECEncoder(dataShards, parityShards, 0)
- }
-
- // calculate header size
- if sess.block != nil {
- sess.headerSize += cryptHeaderSize
- }
- if sess.fecEncoder != nil {
- sess.headerSize += fecHeaderSizePlus2
- }
-
- // only allocate extended packet buffer
- // when the extra header is required
- if sess.headerSize > 0 {
- sess.ext = make([]byte, mtuLimit)
- }
-
- sess.kcp = NewKCP(conv, func(buf []byte, size int) {
- if size >= IKCP_OVERHEAD {
- sess.output(buf[:size])
- }
- })
- sess.kcp.SetMtu(IKCP_MTU_DEF - sess.headerSize)
- blacklist.add(remote.String(), conv)
-
- // add current session to the global updater,
- // which periodically calls sess.update()
- updater.addSession(sess)
-
- if sess.l == nil { // it's a client connection
- go sess.readLoop()
- atomic.AddUint64(&DefaultSnmp.ActiveOpens, 1)
- } else {
- atomic.AddUint64(&DefaultSnmp.PassiveOpens, 1)
- }
- currestab := atomic.AddUint64(&DefaultSnmp.CurrEstab, 1)
- maxconn := atomic.LoadUint64(&DefaultSnmp.MaxConn)
- if currestab > maxconn {
- atomic.CompareAndSwapUint64(&DefaultSnmp.MaxConn, maxconn, currestab)
- }
-
- return sess
-}
-
-// Read implements net.Conn
-func (s *UDPSession) Read(b []byte) (n int, err error) {
- for {
- s.mu.Lock()
- if len(s.bufptr) > 0 { // copy from buffer into b
- n = copy(b, s.bufptr)
- s.bufptr = s.bufptr[n:]
- s.mu.Unlock()
- return n, nil
- }
-
- if s.isClosed {
- s.mu.Unlock()
- return 0, errors.New(errBrokenPipe)
- }
-
- if size := s.kcp.PeekSize(); size > 0 { // peek data size from kcp
- atomic.AddUint64(&DefaultSnmp.BytesReceived, uint64(size))
- if len(b) >= size { // direct write to b
- s.kcp.Recv(b)
- s.mu.Unlock()
- return size, nil
- }
-
- // resize kcp receive buffer
- // to make sure recvbuf has enough capacity
- if cap(s.recvbuf) < size {
- s.recvbuf = make([]byte, size)
- }
-
- // resize recvbuf slice length
- s.recvbuf = s.recvbuf[:size]
- s.kcp.Recv(s.recvbuf)
- n = copy(b, s.recvbuf) // copy to b
- s.bufptr = s.recvbuf[n:] // update pointer
- s.mu.Unlock()
- return n, nil
- }
-
- // read deadline
- var timeout *time.Timer
- var c <-chan time.Time
- if !s.rd.IsZero() {
- if time.Now().After(s.rd) {
- s.mu.Unlock()
- return 0, errTimeout{}
- }
-
- delay := s.rd.Sub(time.Now())
- timeout = time.NewTimer(delay)
- c = timeout.C
- }
- s.mu.Unlock()
-
- // wait for read event or timeout
- select {
- case <-s.chReadEvent:
- case <-c:
- case <-s.die:
- case err = <-s.chErrorEvent:
- if timeout != nil {
- timeout.Stop()
- }
- return n, err
- }
-
- if timeout != nil {
- timeout.Stop()
- }
- }
-}
-
-// Write implements net.Conn
-func (s *UDPSession) Write(b []byte) (n int, err error) {
- for {
- s.mu.Lock()
- if s.isClosed {
- s.mu.Unlock()
- return 0, errors.New(errBrokenPipe)
- }
-
- // api flow control
- if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) {
- n = len(b)
- for {
- if len(b) <= int(s.kcp.mss) {
- s.kcp.Send(b)
- break
- } else {
- s.kcp.Send(b[:s.kcp.mss])
- b = b[s.kcp.mss:]
- }
- }
-
- if !s.writeDelay {
- s.kcp.flush(false)
- }
- s.mu.Unlock()
- atomic.AddUint64(&DefaultSnmp.BytesSent, uint64(n))
- return n, nil
- }
-
- // write deadline
- var timeout *time.Timer
- var c <-chan time.Time
- if !s.wd.IsZero() {
- if time.Now().After(s.wd) {
- s.mu.Unlock()
- return 0, errTimeout{}
- }
- delay := s.wd.Sub(time.Now())
- timeout = time.NewTimer(delay)
- c = timeout.C
- }
- s.mu.Unlock()
-
- // wait for write event or timeout
- select {
- case <-s.chWriteEvent:
- case <-c:
- case <-s.die:
- }
-
- if timeout != nil {
- timeout.Stop()
- }
- }
-}
-
-// Close closes the connection.
-func (s *UDPSession) Close() error {
- // remove this session from updater & listener(if necessary)
- updater.removeSession(s)
- if s.l != nil { // notify listener
- s.l.closeSession(sessionKey{
- addr: s.remote.String(),
- convID: s.kcp.conv,
- })
- }
-
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.isClosed {
- return errors.New(errBrokenPipe)
- }
- close(s.die)
- s.isClosed = true
- atomic.AddUint64(&DefaultSnmp.CurrEstab, ^uint64(0))
- if s.l == nil { // client socket close
- return s.conn.Close()
- }
- return nil
-}
-
-// LocalAddr returns the local network address. The Addr returned is shared by all invocations of LocalAddr, so do not modify it.
-func (s *UDPSession) LocalAddr() net.Addr { return s.conn.LocalAddr() }
-
-// RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it.
-func (s *UDPSession) RemoteAddr() net.Addr { return s.remote }
-
-// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline.
-func (s *UDPSession) SetDeadline(t time.Time) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.rd = t
- s.wd = t
- return nil
-}
-
-// SetReadDeadline implements the Conn SetReadDeadline method.
-func (s *UDPSession) SetReadDeadline(t time.Time) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.rd = t
- return nil
-}
-
-// SetWriteDeadline implements the Conn SetWriteDeadline method.
-func (s *UDPSession) SetWriteDeadline(t time.Time) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.wd = t
- return nil
-}
-
-// SetWriteDelay delays write for bulk transfer until the next update interval
-func (s *UDPSession) SetWriteDelay(delay bool) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.writeDelay = delay
-}
-
-// SetWindowSize set maximum window size
-func (s *UDPSession) SetWindowSize(sndwnd, rcvwnd int) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.kcp.WndSize(sndwnd, rcvwnd)
-}
-
-// SetMtu sets the maximum transmission unit(not including UDP header)
-func (s *UDPSession) SetMtu(mtu int) bool {
- if mtu > mtuLimit {
- return false
- }
-
- s.mu.Lock()
- defer s.mu.Unlock()
- s.kcp.SetMtu(mtu - s.headerSize)
- return true
-}
-
-// SetStreamMode toggles the stream mode on/off
-func (s *UDPSession) SetStreamMode(enable bool) {
- s.mu.Lock()
- defer s.mu.Unlock()
- if enable {
- s.kcp.stream = 1
- } else {
- s.kcp.stream = 0
- }
-}
-
-// SetACKNoDelay changes ack flush option, set true to flush ack immediately,
-func (s *UDPSession) SetACKNoDelay(nodelay bool) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.ackNoDelay = nodelay
-}
-
-// SetDUP duplicates udp packets for kcp output, for testing purpose only
-func (s *UDPSession) SetDUP(dup int) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.dup = dup
-}
-
-// SetNoDelay calls nodelay() of kcp
-// https://github.com/skywind3000/kcp/blob/master/README.en.md#protocol-configuration
-func (s *UDPSession) SetNoDelay(nodelay, interval, resend, nc int) {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.kcp.NoDelay(nodelay, interval, resend, nc)
-}
-
-// SetDSCP sets the 6bit DSCP field of IP header, no effect if it's accepted from Listener
-func (s *UDPSession) SetDSCP(dscp int) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.l == nil {
- if nc, ok := s.conn.(*connectedUDPConn); ok {
- return ipv4.NewConn(nc.UDPConn).SetTOS(dscp << 2)
- } else if nc, ok := s.conn.(net.Conn); ok {
- return ipv4.NewConn(nc).SetTOS(dscp << 2)
- }
- }
- return errors.New(errInvalidOperation)
-}
-
-// SetReadBuffer sets the socket read buffer, no effect if it's accepted from Listener
-func (s *UDPSession) SetReadBuffer(bytes int) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.l == nil {
- if nc, ok := s.conn.(setReadBuffer); ok {
- return nc.SetReadBuffer(bytes)
- }
- }
- return errors.New(errInvalidOperation)
-}
-
-// SetWriteBuffer sets the socket write buffer, no effect if it's accepted from Listener
-func (s *UDPSession) SetWriteBuffer(bytes int) error {
- s.mu.Lock()
- defer s.mu.Unlock()
- if s.l == nil {
- if nc, ok := s.conn.(setWriteBuffer); ok {
- return nc.SetWriteBuffer(bytes)
- }
- }
- return errors.New(errInvalidOperation)
-}
-
-// output pipeline entry
-// steps for output data processing:
-// 0. Header extends
-// 1. FEC
-// 2. CRC32
-// 3. Encryption
-// 4. WriteTo kernel
-func (s *UDPSession) output(buf []byte) {
- var ecc [][]byte
-
- // 0. extend buf's header space(if necessary)
- ext := buf
- if s.headerSize > 0 {
- ext = s.ext[:s.headerSize+len(buf)]
- copy(ext[s.headerSize:], buf)
- }
-
- // 1. FEC encoding
- if s.fecEncoder != nil {
- ecc = s.fecEncoder.encode(ext)
- }
-
- // 2&3. crc32 & encryption
- if s.block != nil {
- s.nonce.Fill(ext[:nonceSize])
- checksum := crc32.ChecksumIEEE(ext[cryptHeaderSize:])
- binary.LittleEndian.PutUint32(ext[nonceSize:], checksum)
- s.block.Encrypt(ext, ext)
-
- for k := range ecc {
- s.nonce.Fill(ecc[k][:nonceSize])
- checksum := crc32.ChecksumIEEE(ecc[k][cryptHeaderSize:])
- binary.LittleEndian.PutUint32(ecc[k][nonceSize:], checksum)
- s.block.Encrypt(ecc[k], ecc[k])
- }
- }
-
- // 4. WriteTo kernel
- nbytes := 0
- npkts := 0
- for i := 0; i < s.dup+1; i++ {
- if n, err := s.conn.WriteTo(ext, s.remote); err == nil {
- nbytes += n
- npkts++
- }
- }
-
- for k := range ecc {
- if n, err := s.conn.WriteTo(ecc[k], s.remote); err == nil {
- nbytes += n
- npkts++
- }
- }
- atomic.AddUint64(&DefaultSnmp.OutPkts, uint64(npkts))
- atomic.AddUint64(&DefaultSnmp.OutBytes, uint64(nbytes))
-}
-
-// kcp update, returns interval for next calling
-func (s *UDPSession) update() (interval time.Duration) {
- s.mu.Lock()
- s.kcp.flush(false)
- if s.kcp.WaitSnd() < int(s.kcp.snd_wnd) {
- s.notifyWriteEvent()
- }
- interval = time.Duration(s.kcp.interval) * time.Millisecond
- s.mu.Unlock()
- return
-}
-
-// GetConv gets conversation id of a session
-func (s *UDPSession) GetConv() uint32 { return s.kcp.conv }
-
-func (s *UDPSession) notifyReadEvent() {
- select {
- case s.chReadEvent <- struct{}{}:
- default:
- }
-}
-
-func (s *UDPSession) notifyWriteEvent() {
- select {
- case s.chWriteEvent <- struct{}{}:
- default:
- }
-}
-
-func (s *UDPSession) kcpInput(data []byte) {
- var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64
-
- if s.fecDecoder != nil {
- f := s.fecDecoder.decodeBytes(data)
- s.mu.Lock()
- if f.flag == typeData {
- if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 {
- kcpInErrors++
- }
- }
-
- if f.flag == typeData || f.flag == typeFEC {
- if f.flag == typeFEC {
- fecParityShards++
- }
-
- recovers := s.fecDecoder.decode(f)
- for _, r := range recovers {
- if len(r) >= 2 { // must be larger than 2bytes
- sz := binary.LittleEndian.Uint16(r)
- if int(sz) <= len(r) && sz >= 2 {
- if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 {
- fecRecovered++
- } else {
- kcpInErrors++
- }
- } else {
- fecErrs++
- }
- } else {
- fecErrs++
- }
- }
- }
-
- // notify reader
- if n := s.kcp.PeekSize(); n > 0 {
- s.notifyReadEvent()
- }
- s.mu.Unlock()
- } else {
- s.mu.Lock()
- if ret := s.kcp.Input(data, true, s.ackNoDelay); ret != 0 {
- kcpInErrors++
- }
- // notify reader
- if n := s.kcp.PeekSize(); n > 0 {
- s.notifyReadEvent()
- }
- s.mu.Unlock()
- }
-
- atomic.AddUint64(&DefaultSnmp.InPkts, 1)
- atomic.AddUint64(&DefaultSnmp.InBytes, uint64(len(data)))
- if fecParityShards > 0 {
- atomic.AddUint64(&DefaultSnmp.FECParityShards, fecParityShards)
- }
- if kcpInErrors > 0 {
- atomic.AddUint64(&DefaultSnmp.KCPInErrors, kcpInErrors)
- }
- if fecErrs > 0 {
- atomic.AddUint64(&DefaultSnmp.FECErrs, fecErrs)
- }
- if fecRecovered > 0 {
- atomic.AddUint64(&DefaultSnmp.FECRecovered, fecRecovered)
- }
-}
-
-func (s *UDPSession) receiver(ch chan<- []byte) {
- for {
- data := xmitBuf.Get().([]byte)[:mtuLimit]
- if n, _, err := s.conn.ReadFrom(data); err == nil && n >= s.headerSize+IKCP_OVERHEAD {
- select {
- case ch <- data[:n]:
- case <-s.die:
- return
- }
- } else if err != nil {
- s.chErrorEvent <- err
- return
- } else {
- atomic.AddUint64(&DefaultSnmp.InErrs, 1)
- }
- }
-}
-
-// read loop for client session
-func (s *UDPSession) readLoop() {
- chPacket := make(chan []byte, qlen)
- go s.receiver(chPacket)
-
- for {
- select {
- case data := <-chPacket:
- raw := data
- dataValid := false
- if s.block != nil {
- s.block.Decrypt(data, data)
- data = data[nonceSize:]
- checksum := crc32.ChecksumIEEE(data[crcSize:])
- if checksum == binary.LittleEndian.Uint32(data) {
- data = data[crcSize:]
- dataValid = true
- } else {
- atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
- }
- } else if s.block == nil {
- dataValid = true
- }
-
- if dataValid {
- s.kcpInput(data)
- }
- xmitBuf.Put(raw)
- case <-s.die:
- return
- }
- }
-}
-
-type (
- sessionKey struct {
- addr string
- convID uint32
- }
-
- // Listener defines a server listening for connections
- Listener struct {
- block BlockCrypt // block encryption
- dataShards int // FEC data shard
- parityShards int // FEC parity shard
- fecDecoder *fecDecoder // FEC mock initialization
- conn net.PacketConn // the underlying packet connection
-
- sessions map[sessionKey]*UDPSession // all sessions accepted by this Listener
- chAccepts chan *UDPSession // Listen() backlog
- chSessionClosed chan sessionKey // session close queue
- headerSize int // the overall header size added before KCP frame
- die chan struct{} // notify the listener has closed
- rd atomic.Value // read deadline for Accept()
- wd atomic.Value
- }
-
- // incoming packet
- inPacket struct {
- from net.Addr
- data []byte
- }
-)
-
-// monitor incoming data for all connections of server
-func (l *Listener) monitor() {
- // cache last session
- var lastKey sessionKey
- var lastSession *UDPSession
-
- chPacket := make(chan inPacket, qlen)
- go l.receiver(chPacket)
- for {
- select {
- case p := <-chPacket:
- raw := p.data
- data := p.data
- from := p.from
- dataValid := false
- if l.block != nil {
- l.block.Decrypt(data, data)
- data = data[nonceSize:]
- checksum := crc32.ChecksumIEEE(data[crcSize:])
- if checksum == binary.LittleEndian.Uint32(data) {
- data = data[crcSize:]
- dataValid = true
- } else {
- atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
- }
- } else if l.block == nil {
- dataValid = true
- }
-
- if dataValid {
- var conv uint32
- convValid := false
- if l.fecDecoder != nil {
- isfec := binary.LittleEndian.Uint16(data[4:])
- if isfec == typeData {
- conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:])
- convValid = true
- }
- } else {
- conv = binary.LittleEndian.Uint32(data)
- convValid = true
- }
-
- if convValid {
- key := sessionKey{
- addr: from.String(),
- convID: conv,
- }
- var s *UDPSession
- var ok bool
-
- // packets received from an address always come in batch.
- // cache the session for next packet, without querying map.
- if key == lastKey {
- s, ok = lastSession, true
- } else if s, ok = l.sessions[key]; ok {
- lastSession = s
- lastKey = key
- }
-
- if !ok { // new session
- if !blacklist.has(from.String(), conv) && len(l.chAccepts) < cap(l.chAccepts) && len(l.sessions) < 4096 { // do not let new session overwhelm accept queue and connection count
- s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, from, l.block)
- s.kcpInput(data)
- l.sessions[key] = s
- l.chAccepts <- s
- }
- } else {
- s.kcpInput(data)
- }
- }
- }
-
- xmitBuf.Put(raw)
- case key := <-l.chSessionClosed:
- if key == lastKey {
- lastKey = sessionKey{}
- }
- delete(l.sessions, key)
- case <-l.die:
- return
- }
- }
-}
-
-func (l *Listener) receiver(ch chan<- inPacket) {
- for {
- data := xmitBuf.Get().([]byte)[:mtuLimit]
- if n, from, err := l.conn.ReadFrom(data); err == nil && n >= l.headerSize+IKCP_OVERHEAD {
- select {
- case ch <- inPacket{from, data[:n]}:
- case <-l.die:
- return
- }
- } else if err != nil {
- return
- } else {
- atomic.AddUint64(&DefaultSnmp.InErrs, 1)
- }
- }
-}
-
-// SetReadBuffer sets the socket read buffer for the Listener
-func (l *Listener) SetReadBuffer(bytes int) error {
- if nc, ok := l.conn.(setReadBuffer); ok {
- return nc.SetReadBuffer(bytes)
- }
- return errors.New(errInvalidOperation)
-}
-
-// SetWriteBuffer sets the socket write buffer for the Listener
-func (l *Listener) SetWriteBuffer(bytes int) error {
- if nc, ok := l.conn.(setWriteBuffer); ok {
- return nc.SetWriteBuffer(bytes)
- }
- return errors.New(errInvalidOperation)
-}
-
-// SetDSCP sets the 6bit DSCP field of IP header
-func (l *Listener) SetDSCP(dscp int) error {
- if nc, ok := l.conn.(net.Conn); ok {
- return ipv4.NewConn(nc).SetTOS(dscp << 2)
- }
- return errors.New(errInvalidOperation)
-}
-
-// Accept implements the Accept method in the Listener interface; it waits for the next call and returns a generic Conn.
-func (l *Listener) Accept() (net.Conn, error) {
- return l.AcceptKCP()
-}
-
-// AcceptKCP accepts a KCP connection
-func (l *Listener) AcceptKCP() (*UDPSession, error) {
- var timeout <-chan time.Time
- if tdeadline, ok := l.rd.Load().(time.Time); ok && !tdeadline.IsZero() {
- timeout = time.After(tdeadline.Sub(time.Now()))
- }
-
- select {
- case <-timeout:
- return nil, &errTimeout{}
- case c := <-l.chAccepts:
- return c, nil
- case <-l.die:
- return nil, errors.New(errBrokenPipe)
- }
-}
-
-// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline.
-func (l *Listener) SetDeadline(t time.Time) error {
- l.SetReadDeadline(t)
- l.SetWriteDeadline(t)
- return nil
-}
-
-// SetReadDeadline implements the Conn SetReadDeadline method.
-func (l *Listener) SetReadDeadline(t time.Time) error {
- l.rd.Store(t)
- return nil
-}
-
-// SetWriteDeadline implements the Conn SetWriteDeadline method.
-func (l *Listener) SetWriteDeadline(t time.Time) error {
- l.wd.Store(t)
- return nil
-}
-
-// Close stops listening on the UDP address. Already Accepted connections are not closed.
-func (l *Listener) Close() error {
- close(l.die)
- return l.conn.Close()
-}
-
-// closeSession notify the listener that a session has closed
-func (l *Listener) closeSession(key sessionKey) bool {
- select {
- case l.chSessionClosed <- key:
- return true
- case <-l.die:
- return false
- }
-}
-
-// Addr returns the listener's network address, The Addr returned is shared by all invocations of Addr, so do not modify it.
-func (l *Listener) Addr() net.Addr { return l.conn.LocalAddr() }
-
-// Listen listens for incoming KCP packets addressed to the local address laddr on the network "udp",
-func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr, nil, 0, 0) }
-
-// ListenWithOptions listens for incoming KCP packets addressed to the local address laddr on the network "udp" with packet encryption,
-// dataShards, parityShards defines Reed-Solomon Erasure Coding parameters
-func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards int) (*Listener, error) {
- udpaddr, err := net.ResolveUDPAddr("udp", laddr)
- if err != nil {
- return nil, errors.Wrap(err, "net.ResolveUDPAddr")
- }
- conn, err := net.ListenUDP("udp", udpaddr)
- if err != nil {
- return nil, errors.Wrap(err, "net.ListenUDP")
- }
-
- return ServeConn(block, dataShards, parityShards, conn)
-}
-
-// ServeConn serves KCP protocol for a single packet connection.
-func ServeConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*Listener, error) {
- l := new(Listener)
- l.conn = conn
- l.sessions = make(map[sessionKey]*UDPSession)
- l.chAccepts = make(chan *UDPSession, acceptBacklog)
- l.chSessionClosed = make(chan sessionKey)
- l.die = make(chan struct{})
- l.dataShards = dataShards
- l.parityShards = parityShards
- l.block = block
- l.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
-
- // calculate header size
- if l.block != nil {
- l.headerSize += cryptHeaderSize
- }
- if l.fecDecoder != nil {
- l.headerSize += fecHeaderSizePlus2
- }
-
- go l.monitor()
- return l, nil
-}
-
-// Dial connects to the remote address "raddr" on the network "udp"
-func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0, 0) }
-
-// DialWithOptions connects to the remote address "raddr" on the network "udp" with packet encryption
-func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) {
- udpaddr, err := net.ResolveUDPAddr("udp", raddr)
- if err != nil {
- return nil, errors.Wrap(err, "net.ResolveUDPAddr")
- }
-
- udpconn, err := net.DialUDP("udp", nil, udpaddr)
- if err != nil {
- return nil, errors.Wrap(err, "net.DialUDP")
- }
-
- return NewConn(raddr, block, dataShards, parityShards, &connectedUDPConn{udpconn})
-}
-
-// NewConn establishes a session and talks KCP protocol over a packet connection.
-func NewConn(raddr string, block BlockCrypt, dataShards, parityShards int, conn net.PacketConn) (*UDPSession, error) {
- udpaddr, err := net.ResolveUDPAddr("udp", raddr)
- if err != nil {
- return nil, errors.Wrap(err, "net.ResolveUDPAddr")
- }
-
- var convid uint32
- binary.Read(rand.Reader, binary.LittleEndian, &convid)
- return newUDPSession(convid, dataShards, parityShards, nil, conn, udpaddr, block), nil
-}
-
-// returns current time in milliseconds
-func currentMs() uint32 { return uint32(time.Now().UnixNano() / int64(time.Millisecond)) }
-
-// connectedUDPConn is a wrapper for net.UDPConn which converts WriteTo syscalls
-// to Write syscalls that are 4 times faster on some OS'es. This should only be
-// used for connections that were produced by a net.Dial* call.
-type connectedUDPConn struct{ *net.UDPConn }
-
-// WriteTo redirects all writes to the Write syscall, which is 4 times faster.
-func (c *connectedUDPConn) WriteTo(b []byte, addr net.Addr) (int, error) { return c.Write(b) }
diff --git a/vendor/github.com/xtaci/kcp-go/snmp.go b/vendor/github.com/xtaci/kcp-go/snmp.go
deleted file mode 100644
index 607118e3a..000000000
--- a/vendor/github.com/xtaci/kcp-go/snmp.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package kcp
-
-import (
- "fmt"
- "sync/atomic"
-)
-
-// Snmp defines network statistics indicator
-type Snmp struct {
- BytesSent uint64 // bytes sent from upper level
- BytesReceived uint64 // bytes received to upper level
- MaxConn uint64 // max number of connections ever reached
- ActiveOpens uint64 // accumulated active open connections
- PassiveOpens uint64 // accumulated passive open connections
- CurrEstab uint64 // current number of established connections
- InErrs uint64 // UDP read errors reported from net.PacketConn
- InCsumErrors uint64 // checksum errors from CRC32
- KCPInErrors uint64 // packet iput errors reported from KCP
- InPkts uint64 // incoming packets count
- OutPkts uint64 // outgoing packets count
- InSegs uint64 // incoming KCP segments
- OutSegs uint64 // outgoing KCP segments
- InBytes uint64 // UDP bytes received
- OutBytes uint64 // UDP bytes sent
- RetransSegs uint64 // accmulated retransmited segments
- FastRetransSegs uint64 // accmulated fast retransmitted segments
- EarlyRetransSegs uint64 // accmulated early retransmitted segments
- LostSegs uint64 // number of segs infered as lost
- RepeatSegs uint64 // number of segs duplicated
- FECRecovered uint64 // correct packets recovered from FEC
- FECErrs uint64 // incorrect packets recovered from FEC
- FECParityShards uint64 // FEC segments received
- FECShortShards uint64 // number of data shards that's not enough for recovery
-}
-
-func newSnmp() *Snmp {
- return new(Snmp)
-}
-
-// Header returns all field names
-func (s *Snmp) Header() []string {
- return []string{
- "BytesSent",
- "BytesReceived",
- "MaxConn",
- "ActiveOpens",
- "PassiveOpens",
- "CurrEstab",
- "InErrs",
- "InCsumErrors",
- "KCPInErrors",
- "InPkts",
- "OutPkts",
- "InSegs",
- "OutSegs",
- "InBytes",
- "OutBytes",
- "RetransSegs",
- "FastRetransSegs",
- "EarlyRetransSegs",
- "LostSegs",
- "RepeatSegs",
- "FECParityShards",
- "FECErrs",
- "FECRecovered",
- "FECShortShards",
- }
-}
-
-// ToSlice returns current snmp info as slice
-func (s *Snmp) ToSlice() []string {
- snmp := s.Copy()
- return []string{
- fmt.Sprint(snmp.BytesSent),
- fmt.Sprint(snmp.BytesReceived),
- fmt.Sprint(snmp.MaxConn),
- fmt.Sprint(snmp.ActiveOpens),
- fmt.Sprint(snmp.PassiveOpens),
- fmt.Sprint(snmp.CurrEstab),
- fmt.Sprint(snmp.InErrs),
- fmt.Sprint(snmp.InCsumErrors),
- fmt.Sprint(snmp.KCPInErrors),
- fmt.Sprint(snmp.InPkts),
- fmt.Sprint(snmp.OutPkts),
- fmt.Sprint(snmp.InSegs),
- fmt.Sprint(snmp.OutSegs),
- fmt.Sprint(snmp.InBytes),
- fmt.Sprint(snmp.OutBytes),
- fmt.Sprint(snmp.RetransSegs),
- fmt.Sprint(snmp.FastRetransSegs),
- fmt.Sprint(snmp.EarlyRetransSegs),
- fmt.Sprint(snmp.LostSegs),
- fmt.Sprint(snmp.RepeatSegs),
- fmt.Sprint(snmp.FECParityShards),
- fmt.Sprint(snmp.FECErrs),
- fmt.Sprint(snmp.FECRecovered),
- fmt.Sprint(snmp.FECShortShards),
- }
-}
-
-// Copy make a copy of current snmp snapshot
-func (s *Snmp) Copy() *Snmp {
- d := newSnmp()
- d.BytesSent = atomic.LoadUint64(&s.BytesSent)
- d.BytesReceived = atomic.LoadUint64(&s.BytesReceived)
- d.MaxConn = atomic.LoadUint64(&s.MaxConn)
- d.ActiveOpens = atomic.LoadUint64(&s.ActiveOpens)
- d.PassiveOpens = atomic.LoadUint64(&s.PassiveOpens)
- d.CurrEstab = atomic.LoadUint64(&s.CurrEstab)
- d.InErrs = atomic.LoadUint64(&s.InErrs)
- d.InCsumErrors = atomic.LoadUint64(&s.InCsumErrors)
- d.KCPInErrors = atomic.LoadUint64(&s.KCPInErrors)
- d.InPkts = atomic.LoadUint64(&s.InPkts)
- d.OutPkts = atomic.LoadUint64(&s.OutPkts)
- d.InSegs = atomic.LoadUint64(&s.InSegs)
- d.OutSegs = atomic.LoadUint64(&s.OutSegs)
- d.InBytes = atomic.LoadUint64(&s.InBytes)
- d.OutBytes = atomic.LoadUint64(&s.OutBytes)
- d.RetransSegs = atomic.LoadUint64(&s.RetransSegs)
- d.FastRetransSegs = atomic.LoadUint64(&s.FastRetransSegs)
- d.EarlyRetransSegs = atomic.LoadUint64(&s.EarlyRetransSegs)
- d.LostSegs = atomic.LoadUint64(&s.LostSegs)
- d.RepeatSegs = atomic.LoadUint64(&s.RepeatSegs)
- d.FECParityShards = atomic.LoadUint64(&s.FECParityShards)
- d.FECErrs = atomic.LoadUint64(&s.FECErrs)
- d.FECRecovered = atomic.LoadUint64(&s.FECRecovered)
- d.FECShortShards = atomic.LoadUint64(&s.FECShortShards)
- return d
-}
-
-// Reset values to zero
-func (s *Snmp) Reset() {
- atomic.StoreUint64(&s.BytesSent, 0)
- atomic.StoreUint64(&s.BytesReceived, 0)
- atomic.StoreUint64(&s.MaxConn, 0)
- atomic.StoreUint64(&s.ActiveOpens, 0)
- atomic.StoreUint64(&s.PassiveOpens, 0)
- atomic.StoreUint64(&s.CurrEstab, 0)
- atomic.StoreUint64(&s.InErrs, 0)
- atomic.StoreUint64(&s.InCsumErrors, 0)
- atomic.StoreUint64(&s.KCPInErrors, 0)
- atomic.StoreUint64(&s.InPkts, 0)
- atomic.StoreUint64(&s.OutPkts, 0)
- atomic.StoreUint64(&s.InSegs, 0)
- atomic.StoreUint64(&s.OutSegs, 0)
- atomic.StoreUint64(&s.InBytes, 0)
- atomic.StoreUint64(&s.OutBytes, 0)
- atomic.StoreUint64(&s.RetransSegs, 0)
- atomic.StoreUint64(&s.FastRetransSegs, 0)
- atomic.StoreUint64(&s.EarlyRetransSegs, 0)
- atomic.StoreUint64(&s.LostSegs, 0)
- atomic.StoreUint64(&s.RepeatSegs, 0)
- atomic.StoreUint64(&s.FECParityShards, 0)
- atomic.StoreUint64(&s.FECErrs, 0)
- atomic.StoreUint64(&s.FECRecovered, 0)
- atomic.StoreUint64(&s.FECShortShards, 0)
-}
-
-// DefaultSnmp is the global KCP connection statistics collector
-var DefaultSnmp *Snmp
-
-func init() {
- DefaultSnmp = newSnmp()
-}
diff --git a/vendor/github.com/xtaci/kcp-go/updater.go b/vendor/github.com/xtaci/kcp-go/updater.go
deleted file mode 100644
index a5bfc6654..000000000
--- a/vendor/github.com/xtaci/kcp-go/updater.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package kcp
-
-import (
- "container/heap"
- "sync"
- "time"
-)
-
-var updater updateHeap
-
-func init() {
- updater.init()
- go updater.updateTask()
-}
-
-// entry contains a session update info
-type entry struct {
- ts time.Time
- s *UDPSession
-}
-
-// a global heap managed kcp.flush() caller
-type updateHeap struct {
- entries []entry
- mu sync.Mutex
- chWakeUp chan struct{}
-}
-
-func (h *updateHeap) Len() int { return len(h.entries) }
-func (h *updateHeap) Less(i, j int) bool { return h.entries[i].ts.Before(h.entries[j].ts) }
-func (h *updateHeap) Swap(i, j int) {
- h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
- h.entries[i].s.updaterIdx = i
- h.entries[j].s.updaterIdx = j
-}
-
-func (h *updateHeap) Push(x interface{}) {
- h.entries = append(h.entries, x.(entry))
- n := len(h.entries)
- h.entries[n-1].s.updaterIdx = n - 1
-}
-
-func (h *updateHeap) Pop() interface{} {
- n := len(h.entries)
- x := h.entries[n-1]
- h.entries[n-1].s.updaterIdx = -1
- h.entries[n-1] = entry{} // manual set nil for GC
- h.entries = h.entries[0 : n-1]
- return x
-}
-
-func (h *updateHeap) init() {
- h.chWakeUp = make(chan struct{}, 1)
-}
-
-func (h *updateHeap) addSession(s *UDPSession) {
- h.mu.Lock()
- heap.Push(h, entry{time.Now(), s})
- h.mu.Unlock()
- h.wakeup()
-}
-
-func (h *updateHeap) removeSession(s *UDPSession) {
- h.mu.Lock()
- if s.updaterIdx != -1 {
- heap.Remove(h, s.updaterIdx)
- }
- h.mu.Unlock()
-}
-
-func (h *updateHeap) wakeup() {
- select {
- case h.chWakeUp <- struct{}{}:
- default:
- }
-}
-
-func (h *updateHeap) updateTask() {
- var timer <-chan time.Time
- for {
- select {
- case <-timer:
- case <-h.chWakeUp:
- }
-
- h.mu.Lock()
- hlen := h.Len()
- now := time.Now()
- for i := 0; i < hlen; i++ {
- entry := heap.Pop(h).(entry)
- if now.After(entry.ts) {
- entry.ts = now.Add(entry.s.update())
- heap.Push(h, entry)
- } else {
- heap.Push(h, entry)
- break
- }
- }
-
- if hlen > 0 {
- timer = time.After(h.entries[0].ts.Sub(now))
- }
- h.mu.Unlock()
- }
-}
diff --git a/vendor/github.com/xtaci/kcp-go/xor.go b/vendor/github.com/xtaci/kcp-go/xor.go
deleted file mode 100644
index ee7133a34..000000000
--- a/vendor/github.com/xtaci/kcp-go/xor.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package kcp
-
-import (
- "runtime"
- "unsafe"
-)
-
-const wordSize = int(unsafe.Sizeof(uintptr(0)))
-const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
-
-// fastXORBytes xors in bulk. It only works on architectures that
-// support unaligned read/writes.
-func fastXORBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
-
- w := n / wordSize
- if w > 0 {
- wordBytes := w * wordSize
- fastXORWords(dst[:wordBytes], a[:wordBytes], b[:wordBytes])
- }
-
- for i := (n - n%wordSize); i < n; i++ {
- dst[i] = a[i] ^ b[i]
- }
-
- return n
-}
-
-func safeXORBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- ex := n % 8
- for i := 0; i < ex; i++ {
- dst[i] = a[i] ^ b[i]
- }
-
- for i := ex; i < n; i += 8 {
- _dst := dst[i : i+8]
- _a := a[i : i+8]
- _b := b[i : i+8]
- _dst[0] = _a[0] ^ _b[0]
- _dst[1] = _a[1] ^ _b[1]
- _dst[2] = _a[2] ^ _b[2]
- _dst[3] = _a[3] ^ _b[3]
-
- _dst[4] = _a[4] ^ _b[4]
- _dst[5] = _a[5] ^ _b[5]
- _dst[6] = _a[6] ^ _b[6]
- _dst[7] = _a[7] ^ _b[7]
- }
- return n
-}
-
-// xorBytes xors the bytes in a and b. The destination is assumed to have enough
-// space. Returns the number of bytes xor'd.
-func xorBytes(dst, a, b []byte) int {
- if supportsUnaligned {
- return fastXORBytes(dst, a, b)
- }
- // TODO(hanwen): if (dst, a, b) have common alignment
- // we could still try fastXORBytes. It is not clear
- // how often this happens, and it's only worth it if
- // the block encryption itself is hardware
- // accelerated.
- return safeXORBytes(dst, a, b)
-}
-
-// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
-// The arguments are assumed to be of equal length.
-func fastXORWords(dst, a, b []byte) {
- dw := *(*[]uintptr)(unsafe.Pointer(&dst))
- aw := *(*[]uintptr)(unsafe.Pointer(&a))
- bw := *(*[]uintptr)(unsafe.Pointer(&b))
- n := len(b) / wordSize
- ex := n % 8
- for i := 0; i < ex; i++ {
- dw[i] = aw[i] ^ bw[i]
- }
-
- for i := ex; i < n; i += 8 {
- _dw := dw[i : i+8]
- _aw := aw[i : i+8]
- _bw := bw[i : i+8]
- _dw[0] = _aw[0] ^ _bw[0]
- _dw[1] = _aw[1] ^ _bw[1]
- _dw[2] = _aw[2] ^ _bw[2]
- _dw[3] = _aw[3] ^ _bw[3]
- _dw[4] = _aw[4] ^ _bw[4]
- _dw[5] = _aw[5] ^ _bw[5]
- _dw[6] = _aw[6] ^ _bw[6]
- _dw[7] = _aw[7] ^ _bw[7]
- }
-}
-
-func xorWords(dst, a, b []byte) {
- if supportsUnaligned {
- fastXORWords(dst, a, b)
- } else {
- safeXORBytes(dst, a, b)
- }
-}
diff --git a/vendor/github.com/xtaci/smux/LICENSE b/vendor/github.com/xtaci/smux/LICENSE
deleted file mode 100644
index eed41acb1..000000000
--- a/vendor/github.com/xtaci/smux/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2016-2017 Daniel Fu
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/github.com/xtaci/smux/frame.go b/vendor/github.com/xtaci/smux/frame.go
deleted file mode 100644
index 36062d7be..000000000
--- a/vendor/github.com/xtaci/smux/frame.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package smux
-
-import (
- "encoding/binary"
- "fmt"
-)
-
-const (
- version = 1
-)
-
-const ( // cmds
- cmdSYN byte = iota // stream open
- cmdFIN // stream close, a.k.a EOF mark
- cmdPSH // data push
- cmdNOP // no operation
-)
-
-const (
- sizeOfVer = 1
- sizeOfCmd = 1
- sizeOfLength = 2
- sizeOfSid = 4
- headerSize = sizeOfVer + sizeOfCmd + sizeOfSid + sizeOfLength
-)
-
-// Frame defines a packet from or to be multiplexed into a single connection
-type Frame struct {
- ver byte
- cmd byte
- sid uint32
- data []byte
-}
-
-func newFrame(cmd byte, sid uint32) Frame {
- return Frame{ver: version, cmd: cmd, sid: sid}
-}
-
-type rawHeader []byte
-
-func (h rawHeader) Version() byte {
- return h[0]
-}
-
-func (h rawHeader) Cmd() byte {
- return h[1]
-}
-
-func (h rawHeader) Length() uint16 {
- return binary.LittleEndian.Uint16(h[2:])
-}
-
-func (h rawHeader) StreamID() uint32 {
- return binary.LittleEndian.Uint32(h[4:])
-}
-
-func (h rawHeader) String() string {
- return fmt.Sprintf("Version:%d Cmd:%d StreamID:%d Length:%d",
- h.Version(), h.Cmd(), h.StreamID(), h.Length())
-}
diff --git a/vendor/github.com/xtaci/smux/mux.go b/vendor/github.com/xtaci/smux/mux.go
deleted file mode 100644
index afcf58b49..000000000
--- a/vendor/github.com/xtaci/smux/mux.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package smux
-
-import (
- "fmt"
- "io"
- "time"
-
- "github.com/pkg/errors"
-)
-
-// Config is used to tune the Smux session
-type Config struct {
- // KeepAliveInterval is how often to send a NOP command to the remote
- KeepAliveInterval time.Duration
-
- // KeepAliveTimeout is how long the session
- // will be closed if no data has arrived
- KeepAliveTimeout time.Duration
-
- // MaxFrameSize is used to control the maximum
- // frame size to sent to the remote
- MaxFrameSize int
-
- // MaxReceiveBuffer is used to control the maximum
- // number of data in the buffer pool
- MaxReceiveBuffer int
-}
-
-// DefaultConfig is used to return a default configuration
-func DefaultConfig() *Config {
- return &Config{
- KeepAliveInterval: 10 * time.Second,
- KeepAliveTimeout: 30 * time.Second,
- MaxFrameSize: 4096,
- MaxReceiveBuffer: 4194304,
- }
-}
-
-// VerifyConfig is used to verify the sanity of configuration
-func VerifyConfig(config *Config) error {
- if config.KeepAliveInterval == 0 {
- return errors.New("keep-alive interval must be positive")
- }
- if config.KeepAliveTimeout < config.KeepAliveInterval {
- return fmt.Errorf("keep-alive timeout must be larger than keep-alive interval")
- }
- if config.MaxFrameSize <= 0 {
- return errors.New("max frame size must be positive")
- }
- if config.MaxFrameSize > 65535 {
- return errors.New("max frame size must not be larger than 65535")
- }
- if config.MaxReceiveBuffer <= 0 {
- return errors.New("max receive buffer must be positive")
- }
- return nil
-}
-
-// Server is used to initialize a new server-side connection.
-func Server(conn io.ReadWriteCloser, config *Config) (*Session, error) {
- if config == nil {
- config = DefaultConfig()
- }
- if err := VerifyConfig(config); err != nil {
- return nil, err
- }
- return newSession(config, conn, false), nil
-}
-
-// Client is used to initialize a new client-side connection.
-func Client(conn io.ReadWriteCloser, config *Config) (*Session, error) {
- if config == nil {
- config = DefaultConfig()
- }
-
- if err := VerifyConfig(config); err != nil {
- return nil, err
- }
- return newSession(config, conn, true), nil
-}
diff --git a/vendor/github.com/xtaci/smux/session.go b/vendor/github.com/xtaci/smux/session.go
deleted file mode 100644
index e93317eed..000000000
--- a/vendor/github.com/xtaci/smux/session.go
+++ /dev/null
@@ -1,350 +0,0 @@
-package smux
-
-import (
- "encoding/binary"
- "io"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/pkg/errors"
-)
-
-const (
- defaultAcceptBacklog = 1024
-)
-
-const (
- errBrokenPipe = "broken pipe"
- errInvalidProtocol = "invalid protocol version"
- errGoAway = "stream id overflows, should start a new connection"
-)
-
-type writeRequest struct {
- frame Frame
- result chan writeResult
-}
-
-type writeResult struct {
- n int
- err error
-}
-
-// Session defines a multiplexed connection for streams
-type Session struct {
- conn io.ReadWriteCloser
-
- config *Config
- nextStreamID uint32 // next stream identifier
- nextStreamIDLock sync.Mutex
-
- bucket int32 // token bucket
- bucketNotify chan struct{} // used for waiting for tokens
-
- streams map[uint32]*Stream // all streams in this session
- streamLock sync.Mutex // locks streams
-
- die chan struct{} // flag session has died
- dieLock sync.Mutex
- chAccepts chan *Stream
-
- dataReady int32 // flag data has arrived
-
- goAway int32 // flag id exhausted
-
- deadline atomic.Value
-
- writes chan writeRequest
-}
-
-func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
- s := new(Session)
- s.die = make(chan struct{})
- s.conn = conn
- s.config = config
- s.streams = make(map[uint32]*Stream)
- s.chAccepts = make(chan *Stream, defaultAcceptBacklog)
- s.bucket = int32(config.MaxReceiveBuffer)
- s.bucketNotify = make(chan struct{}, 1)
- s.writes = make(chan writeRequest)
-
- if client {
- s.nextStreamID = 1
- } else {
- s.nextStreamID = 0
- }
- go s.recvLoop()
- go s.sendLoop()
- go s.keepalive()
- return s
-}
-
-// OpenStream is used to create a new stream
-func (s *Session) OpenStream() (*Stream, error) {
- if s.IsClosed() {
- return nil, errors.New(errBrokenPipe)
- }
-
- // generate stream id
- s.nextStreamIDLock.Lock()
- if s.goAway > 0 {
- s.nextStreamIDLock.Unlock()
- return nil, errors.New(errGoAway)
- }
-
- s.nextStreamID += 2
- sid := s.nextStreamID
- if sid == sid%2 { // stream-id overflows
- s.goAway = 1
- s.nextStreamIDLock.Unlock()
- return nil, errors.New(errGoAway)
- }
- s.nextStreamIDLock.Unlock()
-
- stream := newStream(sid, s.config.MaxFrameSize, s)
-
- if _, err := s.writeFrame(newFrame(cmdSYN, sid)); err != nil {
- return nil, errors.Wrap(err, "writeFrame")
- }
-
- s.streamLock.Lock()
- s.streams[sid] = stream
- s.streamLock.Unlock()
- return stream, nil
-}
-
-// AcceptStream is used to block until the next available stream
-// is ready to be accepted.
-func (s *Session) AcceptStream() (*Stream, error) {
- var deadline <-chan time.Time
- if d, ok := s.deadline.Load().(time.Time); ok && !d.IsZero() {
- timer := time.NewTimer(time.Until(d))
- defer timer.Stop()
- deadline = timer.C
- }
- select {
- case stream := <-s.chAccepts:
- return stream, nil
- case <-deadline:
- return nil, errTimeout
- case <-s.die:
- return nil, errors.New(errBrokenPipe)
- }
-}
-
-// Close is used to close the session and all streams.
-func (s *Session) Close() (err error) {
- s.dieLock.Lock()
-
- select {
- case <-s.die:
- s.dieLock.Unlock()
- return errors.New(errBrokenPipe)
- default:
- close(s.die)
- s.dieLock.Unlock()
- s.streamLock.Lock()
- for k := range s.streams {
- s.streams[k].sessionClose()
- }
- s.streamLock.Unlock()
- s.notifyBucket()
- return s.conn.Close()
- }
-}
-
-// notifyBucket notifies recvLoop that bucket is available
-func (s *Session) notifyBucket() {
- select {
- case s.bucketNotify <- struct{}{}:
- default:
- }
-}
-
-// IsClosed does a safe check to see if we have shutdown
-func (s *Session) IsClosed() bool {
- select {
- case <-s.die:
- return true
- default:
- return false
- }
-}
-
-// NumStreams returns the number of currently open streams
-func (s *Session) NumStreams() int {
- if s.IsClosed() {
- return 0
- }
- s.streamLock.Lock()
- defer s.streamLock.Unlock()
- return len(s.streams)
-}
-
-// SetDeadline sets a deadline used by Accept* calls.
-// A zero time value disables the deadline.
-func (s *Session) SetDeadline(t time.Time) error {
- s.deadline.Store(t)
- return nil
-}
-
-// notify the session that a stream has closed
-func (s *Session) streamClosed(sid uint32) {
- s.streamLock.Lock()
- if n := s.streams[sid].recycleTokens(); n > 0 { // return remaining tokens to the bucket
- if atomic.AddInt32(&s.bucket, int32(n)) > 0 {
- s.notifyBucket()
- }
- }
- delete(s.streams, sid)
- s.streamLock.Unlock()
-}
-
-// returnTokens is called by stream to return token after read
-func (s *Session) returnTokens(n int) {
- if atomic.AddInt32(&s.bucket, int32(n)) > 0 {
- s.notifyBucket()
- }
-}
-
-// session read a frame from underlying connection
-// it's data is pointed to the input buffer
-func (s *Session) readFrame(buffer []byte) (f Frame, err error) {
- if _, err := io.ReadFull(s.conn, buffer[:headerSize]); err != nil {
- return f, errors.Wrap(err, "readFrame")
- }
-
- dec := rawHeader(buffer)
- if dec.Version() != version {
- return f, errors.New(errInvalidProtocol)
- }
-
- f.ver = dec.Version()
- f.cmd = dec.Cmd()
- f.sid = dec.StreamID()
- if length := dec.Length(); length > 0 {
- if _, err := io.ReadFull(s.conn, buffer[headerSize:headerSize+length]); err != nil {
- return f, errors.Wrap(err, "readFrame")
- }
- f.data = buffer[headerSize : headerSize+length]
- }
- return f, nil
-}
-
-// recvLoop keeps on reading from underlying connection if tokens are available
-func (s *Session) recvLoop() {
- buffer := make([]byte, (1<<16)+headerSize)
- for {
- for atomic.LoadInt32(&s.bucket) <= 0 && !s.IsClosed() {
- <-s.bucketNotify
- }
-
- if f, err := s.readFrame(buffer); err == nil {
- atomic.StoreInt32(&s.dataReady, 1)
-
- switch f.cmd {
- case cmdNOP:
- case cmdSYN:
- s.streamLock.Lock()
- if _, ok := s.streams[f.sid]; !ok {
- stream := newStream(f.sid, s.config.MaxFrameSize, s)
- s.streams[f.sid] = stream
- select {
- case s.chAccepts <- stream:
- case <-s.die:
- }
- }
- s.streamLock.Unlock()
- case cmdFIN:
- s.streamLock.Lock()
- if stream, ok := s.streams[f.sid]; ok {
- stream.markRST()
- stream.notifyReadEvent()
- }
- s.streamLock.Unlock()
- case cmdPSH:
- s.streamLock.Lock()
- if stream, ok := s.streams[f.sid]; ok {
- atomic.AddInt32(&s.bucket, -int32(len(f.data)))
- stream.pushBytes(f.data)
- stream.notifyReadEvent()
- }
- s.streamLock.Unlock()
- default:
- s.Close()
- return
- }
- } else {
- s.Close()
- return
- }
- }
-}
-
-func (s *Session) keepalive() {
- tickerPing := time.NewTicker(s.config.KeepAliveInterval)
- tickerTimeout := time.NewTicker(s.config.KeepAliveTimeout)
- defer tickerPing.Stop()
- defer tickerTimeout.Stop()
- for {
- select {
- case <-tickerPing.C:
- s.writeFrame(newFrame(cmdNOP, 0))
- s.notifyBucket() // force a signal to the recvLoop
- case <-tickerTimeout.C:
- if !atomic.CompareAndSwapInt32(&s.dataReady, 1, 0) {
- s.Close()
- return
- }
- case <-s.die:
- return
- }
- }
-}
-
-func (s *Session) sendLoop() {
- buf := make([]byte, (1<<16)+headerSize)
- for {
- select {
- case <-s.die:
- return
- case request := <-s.writes:
- buf[0] = request.frame.ver
- buf[1] = request.frame.cmd
- binary.LittleEndian.PutUint16(buf[2:], uint16(len(request.frame.data)))
- binary.LittleEndian.PutUint32(buf[4:], request.frame.sid)
- copy(buf[headerSize:], request.frame.data)
- n, err := s.conn.Write(buf[:headerSize+len(request.frame.data)])
-
- n -= headerSize
- if n < 0 {
- n = 0
- }
-
- result := writeResult{
- n: n,
- err: err,
- }
-
- request.result <- result
- close(request.result)
- }
- }
-}
-
-// writeFrame writes the frame to the underlying connection
-// and returns the number of bytes written if successful
-func (s *Session) writeFrame(f Frame) (n int, err error) {
- req := writeRequest{
- frame: f,
- result: make(chan writeResult, 1),
- }
- select {
- case <-s.die:
- return 0, errors.New(errBrokenPipe)
- case s.writes <- req:
- }
-
- result := <-req.result
- return result.n, result.err
-}
diff --git a/vendor/github.com/xtaci/smux/stream.go b/vendor/github.com/xtaci/smux/stream.go
deleted file mode 100644
index 1b3ebe0f3..000000000
--- a/vendor/github.com/xtaci/smux/stream.go
+++ /dev/null
@@ -1,253 +0,0 @@
-package smux
-
-import (
- "bytes"
- "io"
- "net"
- "sync"
- "sync/atomic"
- "time"
-
- "github.com/pkg/errors"
-)
-
-// Stream implements net.Conn
-type Stream struct {
- id uint32
- rstflag int32
- sess *Session
- buffer bytes.Buffer
- bufferLock sync.Mutex
- frameSize int
- chReadEvent chan struct{} // notify a read event
- die chan struct{} // flag the stream has closed
- dieLock sync.Mutex
- readDeadline atomic.Value
- writeDeadline atomic.Value
-}
-
-// newStream initiates a Stream struct
-func newStream(id uint32, frameSize int, sess *Session) *Stream {
- s := new(Stream)
- s.id = id
- s.chReadEvent = make(chan struct{}, 1)
- s.frameSize = frameSize
- s.sess = sess
- s.die = make(chan struct{})
- return s
-}
-
-// ID returns the unique stream ID.
-func (s *Stream) ID() uint32 {
- return s.id
-}
-
-// Read implements net.Conn
-func (s *Stream) Read(b []byte) (n int, err error) {
- var deadline <-chan time.Time
- if d, ok := s.readDeadline.Load().(time.Time); ok && !d.IsZero() {
- timer := time.NewTimer(time.Until(d))
- defer timer.Stop()
- deadline = timer.C
- }
-
-READ:
- s.bufferLock.Lock()
- n, err = s.buffer.Read(b)
- s.bufferLock.Unlock()
-
- if n > 0 {
- s.sess.returnTokens(n)
- return n, nil
- } else if atomic.LoadInt32(&s.rstflag) == 1 {
- _ = s.Close()
- return 0, io.EOF
- }
-
- select {
- case <-s.chReadEvent:
- goto READ
- case <-deadline:
- return n, errTimeout
- case <-s.die:
- return 0, errors.New(errBrokenPipe)
- }
-}
-
-// Write implements net.Conn
-func (s *Stream) Write(b []byte) (n int, err error) {
- var deadline <-chan time.Time
- if d, ok := s.writeDeadline.Load().(time.Time); ok && !d.IsZero() {
- timer := time.NewTimer(time.Until(d))
- defer timer.Stop()
- deadline = timer.C
- }
-
- select {
- case <-s.die:
- return 0, errors.New(errBrokenPipe)
- default:
- }
-
- frames := s.split(b, cmdPSH, s.id)
- sent := 0
- for k := range frames {
- req := writeRequest{
- frame: frames[k],
- result: make(chan writeResult, 1),
- }
-
- select {
- case s.sess.writes <- req:
- case <-s.die:
- return sent, errors.New(errBrokenPipe)
- case <-deadline:
- return sent, errTimeout
- }
-
- select {
- case result := <-req.result:
- sent += result.n
- if result.err != nil {
- return sent, result.err
- }
- case <-s.die:
- return sent, errors.New(errBrokenPipe)
- case <-deadline:
- return sent, errTimeout
- }
- }
- return sent, nil
-}
-
-// Close implements net.Conn
-func (s *Stream) Close() error {
- s.dieLock.Lock()
-
- select {
- case <-s.die:
- s.dieLock.Unlock()
- return errors.New(errBrokenPipe)
- default:
- close(s.die)
- s.dieLock.Unlock()
- s.sess.streamClosed(s.id)
- _, err := s.sess.writeFrame(newFrame(cmdFIN, s.id))
- return err
- }
-}
-
-// SetReadDeadline sets the read deadline as defined by
-// net.Conn.SetReadDeadline.
-// A zero time value disables the deadline.
-func (s *Stream) SetReadDeadline(t time.Time) error {
- s.readDeadline.Store(t)
- return nil
-}
-
-// SetWriteDeadline sets the write deadline as defined by
-// net.Conn.SetWriteDeadline.
-// A zero time value disables the deadline.
-func (s *Stream) SetWriteDeadline(t time.Time) error {
- s.writeDeadline.Store(t)
- return nil
-}
-
-// SetDeadline sets both read and write deadlines as defined by
-// net.Conn.SetDeadline.
-// A zero time value disables the deadlines.
-func (s *Stream) SetDeadline(t time.Time) error {
- if err := s.SetReadDeadline(t); err != nil {
- return err
- }
- if err := s.SetWriteDeadline(t); err != nil {
- return err
- }
- return nil
-}
-
-// session closes the stream
-func (s *Stream) sessionClose() {
- s.dieLock.Lock()
- defer s.dieLock.Unlock()
-
- select {
- case <-s.die:
- default:
- close(s.die)
- }
-}
-
-// LocalAddr satisfies net.Conn interface
-func (s *Stream) LocalAddr() net.Addr {
- if ts, ok := s.sess.conn.(interface {
- LocalAddr() net.Addr
- }); ok {
- return ts.LocalAddr()
- }
- return nil
-}
-
-// RemoteAddr satisfies net.Conn interface
-func (s *Stream) RemoteAddr() net.Addr {
- if ts, ok := s.sess.conn.(interface {
- RemoteAddr() net.Addr
- }); ok {
- return ts.RemoteAddr()
- }
- return nil
-}
-
-// pushBytes a slice into buffer
-func (s *Stream) pushBytes(p []byte) {
- s.bufferLock.Lock()
- s.buffer.Write(p)
- s.bufferLock.Unlock()
-}
-
-// recycleTokens transform remaining bytes to tokens(will truncate buffer)
-func (s *Stream) recycleTokens() (n int) {
- s.bufferLock.Lock()
- n = s.buffer.Len()
- s.buffer.Reset()
- s.bufferLock.Unlock()
- return
-}
-
-// split large byte buffer into smaller frames, reference only
-func (s *Stream) split(bts []byte, cmd byte, sid uint32) []Frame {
- frames := make([]Frame, 0, len(bts)/s.frameSize+1)
- for len(bts) > s.frameSize {
- frame := newFrame(cmd, sid)
- frame.data = bts[:s.frameSize]
- bts = bts[s.frameSize:]
- frames = append(frames, frame)
- }
- if len(bts) > 0 {
- frame := newFrame(cmd, sid)
- frame.data = bts
- frames = append(frames, frame)
- }
- return frames
-}
-
-// notify read event
-func (s *Stream) notifyReadEvent() {
- select {
- case s.chReadEvent <- struct{}{}:
- default:
- }
-}
-
-// mark this stream has been reset
-func (s *Stream) markRST() {
- atomic.StoreInt32(&s.rstflag, 1)
-}
-
-var errTimeout error = &timeoutError{}
-
-type timeoutError struct{}
-
-func (e *timeoutError) Error() string { return "i/o timeout" }
-func (e *timeoutError) Timeout() bool { return true }
-func (e *timeoutError) Temporary() bool { return true }
diff --git a/vendor/manifest b/vendor/manifest
index a403a3ce6..86ebcbeda 100644
--- a/vendor/manifest
+++ b/vendor/manifest
@@ -82,14 +82,6 @@
"branch": "master",
"notests": true
},
- {
- "importpath": "github.com/ccding/go-stun",
- "repository": "https://github.com/ccding/go-stun",
- "vcs": "git",
- "revision": "d9bbe8f8fa7bf7ed03e6cfc6a2796bb36139e1f4",
- "branch": "master",
- "notests": true
- },
{
"importpath": "github.com/cheggaaa/pb",
"repository": "https://github.com/cheggaaa/pb",
@@ -524,22 +516,6 @@
"path": "/qr",
"notests": true
},
- {
- "importpath": "github.com/xtaci/kcp-go",
- "repository": "https://github.com/xtaci/kcp-go",
- "vcs": "git",
- "revision": "86eebd5cadb519b7c9306082c7eb3bcee2c49a7b",
- "branch": "master",
- "notests": true
- },
- {
- "importpath": "github.com/xtaci/smux",
- "repository": "https://github.com/xtaci/smux",
- "vcs": "git",
- "revision": "c3e18246ff2252a6e9d6b529fcbf22ae5c74c007",
- "branch": "master",
- "notests": true
- },
{
"importpath": "github.com/zillode/notify",
"repository": "https://github.com/zillode/notify",