lib/connections: Add KCP support (fixes #804)
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3489
This commit is contained in:
committed by
Jakob Borg
parent
151004d645
commit
0da0774ce4
21
vendor/github.com/AudriusButkevicius/pfilter/LICENSE
generated
vendored
Normal file
21
vendor/github.com/AudriusButkevicius/pfilter/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Audrius Butkevicius
|
||||
|
||||
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.
|
||||
95
vendor/github.com/AudriusButkevicius/pfilter/conn.go
generated
vendored
Normal file
95
vendor/github.com/AudriusButkevicius/pfilter/conn.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package pfilter
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FilteredConn struct {
|
||||
source *PacketFilter
|
||||
priority int
|
||||
|
||||
recvBuffer chan packet
|
||||
|
||||
filter Filter
|
||||
|
||||
deadline atomic.Value
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
// LocalAddr returns the local address
|
||||
func (r *FilteredConn) LocalAddr() net.Addr {
|
||||
return r.source.LocalAddr()
|
||||
}
|
||||
|
||||
// SetReadDeadline sets a read deadline
|
||||
func (r *FilteredConn) SetReadDeadline(t time.Time) error {
|
||||
r.deadline.Store(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetWriteDeadline sets a write deadline
|
||||
func (r *FilteredConn) SetWriteDeadline(t time.Time) error {
|
||||
return r.source.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// SetDeadline sets a read and a write deadline
|
||||
func (r *FilteredConn) SetDeadline(t time.Time) error {
|
||||
r.SetReadDeadline(t)
|
||||
return r.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
// WriteTo writes bytes to the given address
|
||||
func (r *FilteredConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
select {
|
||||
case <-r.closed:
|
||||
return 0, errClosed
|
||||
default:
|
||||
}
|
||||
|
||||
if r.filter != nil {
|
||||
r.filter.Outgoing(b, addr)
|
||||
}
|
||||
return r.source.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
// ReadFrom reads from the filtered connection
|
||||
func (r *FilteredConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
select {
|
||||
case <-r.closed:
|
||||
return 0, nil, errClosed
|
||||
default:
|
||||
}
|
||||
|
||||
var timeout <-chan time.Time
|
||||
|
||||
if deadline, ok := r.deadline.Load().(time.Time); ok && !deadline.IsZero() {
|
||||
timer := time.NewTimer(deadline.Sub(time.Now()))
|
||||
timeout = timer.C
|
||||
defer timer.Stop()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-timeout:
|
||||
return 0, nil, &timeoutError{}
|
||||
case pkt := <-r.recvBuffer:
|
||||
copy(b[:pkt.n], pkt.buf)
|
||||
bufPool.Put(pkt.buf[:maxPacketSize])
|
||||
return pkt.n, pkt.addr, pkt.err
|
||||
case <-r.closed:
|
||||
return 0, nil, errClosed
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the filtered connection, removing it's filters
|
||||
func (r *FilteredConn) Close() error {
|
||||
select {
|
||||
case <-r.closed:
|
||||
return errClosed
|
||||
default:
|
||||
}
|
||||
close(r.closed)
|
||||
r.source.removeConn(r)
|
||||
return nil
|
||||
}
|
||||
134
vendor/github.com/AudriusButkevicius/pfilter/filter.go
generated
vendored
Normal file
134
vendor/github.com/AudriusButkevicius/pfilter/filter.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package pfilter
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Filter object receives all data sent out on the Outgoing callback,
|
||||
// and is expected to decide if it wants to receive the packet or not via
|
||||
// the Receive callback
|
||||
type Filter interface {
|
||||
Outgoing([]byte, net.Addr)
|
||||
ClaimIncoming([]byte, net.Addr) bool
|
||||
}
|
||||
|
||||
// NewPacketFilter creates a packet filter object wrapping the given packet
|
||||
// connection.
|
||||
func NewPacketFilter(conn net.PacketConn) *PacketFilter {
|
||||
d := &PacketFilter{
|
||||
PacketConn: conn,
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// PacketFilter embeds a net.PacketConn to perform the filtering.
|
||||
type PacketFilter struct {
|
||||
net.PacketConn
|
||||
|
||||
conns []*FilteredConn
|
||||
mut sync.Mutex
|
||||
|
||||
dropped uint64
|
||||
overflow uint64
|
||||
}
|
||||
|
||||
// NewConn returns a new net.PacketConn object which filters packets based
|
||||
// on the provided filter. If filter is nil, the connection will receive all
|
||||
// packets. Priority decides which connection gets the ability to claim the packet.
|
||||
func (d *PacketFilter) NewConn(priority int, filter Filter) net.PacketConn {
|
||||
conn := &FilteredConn{
|
||||
priority: priority,
|
||||
source: d,
|
||||
recvBuffer: make(chan packet, 256),
|
||||
filter: filter,
|
||||
closed: make(chan struct{}),
|
||||
}
|
||||
d.mut.Lock()
|
||||
d.conns = append(d.conns, conn)
|
||||
sort.Sort(filteredConnList(d.conns))
|
||||
d.mut.Unlock()
|
||||
return conn
|
||||
}
|
||||
|
||||
func (d *PacketFilter) removeConn(r *FilteredConn) {
|
||||
d.mut.Lock()
|
||||
for i, conn := range d.conns {
|
||||
if conn == r {
|
||||
copy(d.conns[i:], d.conns[i+1:])
|
||||
d.conns[len(d.conns)-1] = nil
|
||||
d.conns = d.conns[:len(d.conns)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
d.mut.Unlock()
|
||||
}
|
||||
|
||||
// NumberOfConns returns the number of currently active virtual connections
|
||||
func (d *PacketFilter) NumberOfConns() int {
|
||||
d.mut.Lock()
|
||||
n := len(d.conns)
|
||||
d.mut.Unlock()
|
||||
return n
|
||||
}
|
||||
|
||||
// Dropped returns number of packets dropped due to nobody claiming them.
|
||||
func (d *PacketFilter) Dropped() uint64 {
|
||||
return atomic.LoadUint64(&d.dropped)
|
||||
}
|
||||
|
||||
// Overflow returns number of packets were dropped due to receive buffers being
|
||||
// full.
|
||||
func (d *PacketFilter) Overflow() uint64 {
|
||||
return atomic.LoadUint64(&d.overflow)
|
||||
}
|
||||
|
||||
// Start starts the packet filter.
|
||||
func (d *PacketFilter) Start() {
|
||||
go d.loop()
|
||||
}
|
||||
|
||||
func (d *PacketFilter) loop() {
|
||||
var buf []byte
|
||||
next:
|
||||
for {
|
||||
buf = bufPool.Get().([]byte)
|
||||
n, addr, err := d.ReadFrom(buf)
|
||||
pkt := packet{
|
||||
n: n,
|
||||
addr: addr,
|
||||
err: err,
|
||||
buf: buf[:n],
|
||||
}
|
||||
|
||||
d.mut.Lock()
|
||||
conns := d.conns
|
||||
d.mut.Unlock()
|
||||
|
||||
if err != nil {
|
||||
for _, conn := range conns {
|
||||
select {
|
||||
case conn.recvBuffer <- pkt:
|
||||
default:
|
||||
atomic.AddUint64(&d.overflow, 1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for _, conn := range conns {
|
||||
if conn.filter == nil || conn.filter.ClaimIncoming(pkt.buf, pkt.addr) {
|
||||
select {
|
||||
case conn.recvBuffer <- pkt:
|
||||
default:
|
||||
atomic.AddUint64(&d.overflow, 1)
|
||||
}
|
||||
goto next
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddUint64(&d.dropped, 1)
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/AudriusButkevicius/pfilter/misc.go
generated
vendored
Normal file
36
vendor/github.com/AudriusButkevicius/pfilter/misc.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package pfilter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
maxPacketSize = 1500
|
||||
bufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, maxPacketSize)
|
||||
},
|
||||
}
|
||||
errClosed = fmt.Errorf("use of closed network connection")
|
||||
)
|
||||
|
||||
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 }
|
||||
|
||||
type filteredConnList []*FilteredConn
|
||||
|
||||
func (r filteredConnList) Len() int { return len(r) }
|
||||
func (r filteredConnList) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
|
||||
func (r filteredConnList) Less(i, j int) bool { return r[i].priority < r[j].priority }
|
||||
|
||||
type packet struct {
|
||||
n int
|
||||
addr net.Addr
|
||||
err error
|
||||
buf []byte
|
||||
}
|
||||
Reference in New Issue
Block a user