2014-02-11 19:48:44 -05:00
|
|
|
package nat
|
|
|
|
|
2015-04-08 01:31:47 -04:00
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
)
|
2014-02-11 19:48:44 -05:00
|
|
|
|
|
|
|
type portSorter struct {
|
|
|
|
ports []Port
|
|
|
|
by func(i, j Port) bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *portSorter) Len() int {
|
|
|
|
return len(s.ports)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *portSorter) Swap(i, j int) {
|
|
|
|
s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *portSorter) Less(i, j int) bool {
|
|
|
|
ip := s.ports[i]
|
|
|
|
jp := s.ports[j]
|
|
|
|
|
|
|
|
return s.by(ip, jp)
|
|
|
|
}
|
|
|
|
|
2015-07-21 09:43:32 -04:00
|
|
|
// Sort sorts a list of ports using the provided predicate
|
|
|
|
// This function should compare `i` and `j`, returning true if `i` is
|
|
|
|
// considered to be less than `j`
|
2014-02-11 19:48:44 -05:00
|
|
|
func Sort(ports []Port, predicate func(i, j Port) bool) {
|
|
|
|
s := &portSorter{ports, predicate}
|
|
|
|
sort.Sort(s)
|
|
|
|
}
|
2015-04-08 01:31:47 -04:00
|
|
|
|
|
|
|
type portMapEntry struct {
|
|
|
|
port Port
|
|
|
|
binding PortBinding
|
|
|
|
}
|
|
|
|
|
|
|
|
type portMapSorter []portMapEntry
|
|
|
|
|
|
|
|
func (s portMapSorter) Len() int { return len(s) }
|
|
|
|
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
|
|
|
|
// sort the port so that the order is:
|
|
|
|
// 1. port with larger specified bindings
|
|
|
|
// 2. larger port
|
|
|
|
// 3. port with tcp protocol
|
|
|
|
func (s portMapSorter) Less(i, j int) bool {
|
|
|
|
pi, pj := s[i].port, s[j].port
|
|
|
|
hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
|
|
|
|
return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
|
|
|
|
}
|
|
|
|
|
|
|
|
// SortPortMap sorts the list of ports and their respected mapping. The ports
|
|
|
|
// will explicit HostPort will be placed first.
|
|
|
|
func SortPortMap(ports []Port, bindings PortMap) {
|
|
|
|
s := portMapSorter{}
|
|
|
|
for _, p := range ports {
|
|
|
|
if binding, ok := bindings[p]; ok {
|
|
|
|
for _, b := range binding {
|
|
|
|
s = append(s, portMapEntry{port: p, binding: b})
|
|
|
|
}
|
2015-05-17 14:57:17 -04:00
|
|
|
bindings[p] = []PortBinding{}
|
2015-04-08 01:31:47 -04:00
|
|
|
} else {
|
|
|
|
s = append(s, portMapEntry{port: p})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(s)
|
|
|
|
var (
|
|
|
|
i int
|
|
|
|
pm = make(map[Port]struct{})
|
|
|
|
)
|
|
|
|
// reorder ports
|
|
|
|
for _, entry := range s {
|
|
|
|
if _, ok := pm[entry.port]; !ok {
|
|
|
|
ports[i] = entry.port
|
|
|
|
pm[entry.port] = struct{}{}
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
// reorder bindings for this port
|
2015-05-17 14:57:17 -04:00
|
|
|
if _, ok := bindings[entry.port]; ok {
|
|
|
|
bindings[entry.port] = append(bindings[entry.port], entry.binding)
|
|
|
|
}
|
2015-04-08 01:31:47 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func toInt(s string) int64 {
|
|
|
|
i, err := strconv.ParseInt(s, 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
i = 0
|
|
|
|
}
|
|
|
|
return i
|
|
|
|
}
|