mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 00:55:11 +00:00 
			
		
		
		
	Add an osImpl interface that can be stateful and thus more efficient
between calls. It will later be implemented by all OSes but for now
this change only adds a Linux implementation.
Remove Port.inode. It was only used by Linux and moves into its osImpl.
Don't reopen /proc/net/* files on each run. Turns out you can just
keep then open and seek to the beginning and reread and the contents
are fresh.
    name                    old time/op    new time/op    delta
    GetListIncremental-8    7.29ms ± 2%    6.53ms ± 1%  -10.50%  (p=0.000 n=9+9)
    name                   old alloc/op   new alloc/op   delta
    GetListIncremental-8    1.30kB ±13%    0.70kB ± 5%  -46.38%  (p=0.000 n=9+10)
    name                  old allocs/op  new allocs/op  delta
    GetListIncremental-8      33.2 ±11%      18.0 ± 0%  -45.82%  (p=0.000 n=9+10)
Updates #5958
Change-Id: I4be83463cbd23c2e2fa5d0bdf38560004f53401b
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
	
		
			
				
	
	
		
			82 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// This file is just the types. The bulk of the code is in poller.go.
 | 
						|
 | 
						|
// The portlist package contains code that checks what ports are open and
 | 
						|
// listening on the current machine.
 | 
						|
package portlist
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// Port is a listening port on the machine.
 | 
						|
type Port struct {
 | 
						|
	Proto   string // "tcp" or "udp"
 | 
						|
	Port    uint16 // port number
 | 
						|
	Process string // optional process name, if found
 | 
						|
}
 | 
						|
 | 
						|
// List is a list of Ports.
 | 
						|
type List []Port
 | 
						|
 | 
						|
func (a *Port) lessThan(b *Port) bool {
 | 
						|
	if a.Port != b.Port {
 | 
						|
		return a.Port < b.Port
 | 
						|
	}
 | 
						|
	if a.Proto != b.Proto {
 | 
						|
		return a.Proto < b.Proto
 | 
						|
	}
 | 
						|
	return a.Process < b.Process
 | 
						|
}
 | 
						|
 | 
						|
func (a *Port) equal(b *Port) bool {
 | 
						|
	return a.Port == b.Port &&
 | 
						|
		a.Proto == b.Proto &&
 | 
						|
		a.Process == b.Process
 | 
						|
}
 | 
						|
 | 
						|
func (a List) equal(b List) bool {
 | 
						|
	if len(a) != len(b) {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
	for i := range a {
 | 
						|
		if !a[i].equal(&b[i]) {
 | 
						|
			return false
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (pl List) String() string {
 | 
						|
	var sb strings.Builder
 | 
						|
	for _, v := range pl {
 | 
						|
		fmt.Fprintf(&sb, "%-3s %5d %#v\n",
 | 
						|
			v.Proto, v.Port, v.Process)
 | 
						|
	}
 | 
						|
	return strings.TrimRight(sb.String(), "\n")
 | 
						|
}
 | 
						|
 | 
						|
// sortAndDedup sorts ps in place (by Port.lessThan) and then returns
 | 
						|
// a subset of it with duplicate (Proto, Port) removed.
 | 
						|
func sortAndDedup(ps List) List {
 | 
						|
	sort.Slice(ps, func(i, j int) bool {
 | 
						|
		return (&ps[i]).lessThan(&ps[j])
 | 
						|
	})
 | 
						|
	out := ps[:0]
 | 
						|
	var last Port
 | 
						|
	for _, p := range ps {
 | 
						|
		protoPort := Port{Proto: p.Proto, Port: p.Port}
 | 
						|
		if last == protoPort {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		out = append(out, p)
 | 
						|
		last = protoPort
 | 
						|
	}
 | 
						|
	return out
 | 
						|
}
 |