| 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 |
| } |