You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
4.8 KiB
194 lines
4.8 KiB
6 years ago
|
package sockaddr
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"sort"
|
||
|
)
|
||
|
|
||
|
// SockAddrs is a slice of SockAddrs
|
||
|
type SockAddrs []SockAddr
|
||
|
|
||
|
func (s SockAddrs) Len() int { return len(s) }
|
||
|
func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||
|
|
||
|
// CmpAddrFunc is the function signature that must be met to be used in the
|
||
|
// OrderedAddrBy multiAddrSorter
|
||
|
type CmpAddrFunc func(p1, p2 *SockAddr) int
|
||
|
|
||
|
// multiAddrSorter implements the Sort interface, sorting the SockAddrs within.
|
||
|
type multiAddrSorter struct {
|
||
|
addrs SockAddrs
|
||
|
cmp []CmpAddrFunc
|
||
|
}
|
||
|
|
||
|
// Sort sorts the argument slice according to the Cmp functions passed to
|
||
|
// OrderedAddrBy.
|
||
|
func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) {
|
||
|
ms.addrs = sockAddrs
|
||
|
sort.Sort(ms)
|
||
|
}
|
||
|
|
||
|
// OrderedAddrBy sorts SockAddr by the list of sort function pointers.
|
||
|
func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter {
|
||
|
return &multiAddrSorter{
|
||
|
cmp: cmpFuncs,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Len is part of sort.Interface.
|
||
|
func (ms *multiAddrSorter) Len() int {
|
||
|
return len(ms.addrs)
|
||
|
}
|
||
|
|
||
|
// Less is part of sort.Interface. It is implemented by looping along the
|
||
|
// Cmp() functions until it finds a comparison that is either less than,
|
||
|
// equal to, or greater than.
|
||
|
func (ms *multiAddrSorter) Less(i, j int) bool {
|
||
|
p, q := &ms.addrs[i], &ms.addrs[j]
|
||
|
// Try all but the last comparison.
|
||
|
var k int
|
||
|
for k = 0; k < len(ms.cmp)-1; k++ {
|
||
|
cmp := ms.cmp[k]
|
||
|
x := cmp(p, q)
|
||
|
switch x {
|
||
|
case -1:
|
||
|
// p < q, so we have a decision.
|
||
|
return true
|
||
|
case 1:
|
||
|
// p > q, so we have a decision.
|
||
|
return false
|
||
|
}
|
||
|
// p == q; try the next comparison.
|
||
|
}
|
||
|
// All comparisons to here said "equal", so just return whatever the
|
||
|
// final comparison reports.
|
||
|
switch ms.cmp[k](p, q) {
|
||
|
case -1:
|
||
|
return true
|
||
|
case 1:
|
||
|
return false
|
||
|
default:
|
||
|
// Still a tie! Now what?
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Swap is part of sort.Interface.
|
||
|
func (ms *multiAddrSorter) Swap(i, j int) {
|
||
|
ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i]
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
// NOTE (sean@): These constants are here for code readability only and
|
||
|
// are sprucing up the code for readability purposes. Some of the
|
||
|
// Cmp*() variants have confusing logic (especially when dealing with
|
||
|
// mixed-type comparisons) and this, I think, has made it easier to grok
|
||
|
// the code faster.
|
||
|
sortReceiverBeforeArg = -1
|
||
|
sortDeferDecision = 0
|
||
|
sortArgBeforeReceiver = 1
|
||
|
)
|
||
|
|
||
|
// AscAddress is a sorting function to sort SockAddrs by their respective
|
||
|
// address type. Non-equal types are deferred in the sort.
|
||
|
func AscAddress(p1Ptr, p2Ptr *SockAddr) int {
|
||
|
p1 := *p1Ptr
|
||
|
p2 := *p2Ptr
|
||
|
|
||
|
switch v := p1.(type) {
|
||
|
case IPv4Addr:
|
||
|
return v.CmpAddress(p2)
|
||
|
case IPv6Addr:
|
||
|
return v.CmpAddress(p2)
|
||
|
case UnixSock:
|
||
|
return v.CmpAddress(p2)
|
||
|
default:
|
||
|
return sortDeferDecision
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AscPort is a sorting function to sort SockAddrs by their respective address
|
||
|
// type. Non-equal types are deferred in the sort.
|
||
|
func AscPort(p1Ptr, p2Ptr *SockAddr) int {
|
||
|
p1 := *p1Ptr
|
||
|
p2 := *p2Ptr
|
||
|
|
||
|
switch v := p1.(type) {
|
||
|
case IPv4Addr:
|
||
|
return v.CmpPort(p2)
|
||
|
case IPv6Addr:
|
||
|
return v.CmpPort(p2)
|
||
|
default:
|
||
|
return sortDeferDecision
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AscPrivate is a sorting function to sort "more secure" private values before
|
||
|
// "more public" values. Both IPv4 and IPv6 are compared against RFC6890
|
||
|
// (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and
|
||
|
// IPv6 includes RFC4193).
|
||
|
func AscPrivate(p1Ptr, p2Ptr *SockAddr) int {
|
||
|
p1 := *p1Ptr
|
||
|
p2 := *p2Ptr
|
||
|
|
||
|
switch v := p1.(type) {
|
||
|
case IPv4Addr, IPv6Addr:
|
||
|
return v.CmpRFC(6890, p2)
|
||
|
default:
|
||
|
return sortDeferDecision
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AscNetworkSize is a sorting function to sort SockAddrs based on their network
|
||
|
// size. Non-equal types are deferred in the sort.
|
||
|
func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int {
|
||
|
p1 := *p1Ptr
|
||
|
p2 := *p2Ptr
|
||
|
p1Type := p1.Type()
|
||
|
p2Type := p2.Type()
|
||
|
|
||
|
// Network size operations on non-IP types make no sense
|
||
|
if p1Type != p2Type && p1Type != TypeIP {
|
||
|
return sortDeferDecision
|
||
|
}
|
||
|
|
||
|
ipA := p1.(IPAddr)
|
||
|
ipB := p2.(IPAddr)
|
||
|
|
||
|
return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask()))
|
||
|
}
|
||
|
|
||
|
// AscType is a sorting function to sort "more secure" types before
|
||
|
// "less-secure" types.
|
||
|
func AscType(p1Ptr, p2Ptr *SockAddr) int {
|
||
|
p1 := *p1Ptr
|
||
|
p2 := *p2Ptr
|
||
|
p1Type := p1.Type()
|
||
|
p2Type := p2.Type()
|
||
|
switch {
|
||
|
case p1Type < p2Type:
|
||
|
return sortReceiverBeforeArg
|
||
|
case p1Type == p2Type:
|
||
|
return sortDeferDecision
|
||
|
case p1Type > p2Type:
|
||
|
return sortArgBeforeReceiver
|
||
|
default:
|
||
|
return sortDeferDecision
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// FilterByType returns two lists: a list of matched and unmatched SockAddrs
|
||
|
func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) {
|
||
|
matched = make(SockAddrs, 0, len(sas))
|
||
|
excluded = make(SockAddrs, 0, len(sas))
|
||
|
|
||
|
for _, sa := range sas {
|
||
|
if sa.Type()&type_ != 0 {
|
||
|
matched = append(matched, sa)
|
||
|
} else {
|
||
|
excluded = append(excluded, sa)
|
||
|
}
|
||
|
}
|
||
|
return matched, excluded
|
||
|
}
|