...
1
16
17 package net
18
19 import (
20 "fmt"
21 "net"
22 "strconv"
23 "strings"
24 )
25
26
27 type Protocol string
28
29
30 const (
31 TCP Protocol = "TCP"
32 UDP Protocol = "UDP"
33 )
34
35
36
37
38 type LocalPort struct {
39
40 Description string
41
42
43 IP string
44
45
46
47 IPFamily IPFamily
48
49
50 Port int
51
52 Protocol Protocol
53 }
54
55
56
57 func NewLocalPort(desc, ip string, ipFamily IPFamily, port int, protocol Protocol) (*LocalPort, error) {
58 if protocol != TCP && protocol != UDP {
59 return nil, fmt.Errorf("Unsupported protocol %s", protocol)
60 }
61 if ipFamily != IPFamilyUnknown && ipFamily != IPv4 && ipFamily != IPv6 {
62 return nil, fmt.Errorf("Invalid IP family %s", ipFamily)
63 }
64 if ip != "" {
65 parsedIP := ParseIPSloppy(ip)
66 if parsedIP == nil {
67 return nil, fmt.Errorf("invalid ip address %s", ip)
68 }
69 if ipFamily != IPFamilyUnknown {
70 if IPFamily(parsedIP) != ipFamily {
71 return nil, fmt.Errorf("ip address and family mismatch %s, %s", ip, ipFamily)
72 }
73 }
74 }
75 return &LocalPort{Description: desc, IP: ip, IPFamily: ipFamily, Port: port, Protocol: protocol}, nil
76 }
77
78 func (lp *LocalPort) String() string {
79 ipPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port))
80 return fmt.Sprintf("%q (%s/%s%s)", lp.Description, ipPort, strings.ToLower(string(lp.Protocol)), lp.IPFamily)
81 }
82
83
84 type Closeable interface {
85 Close() error
86 }
87
88
89 type PortOpener interface {
90 OpenLocalPort(lp *LocalPort) (Closeable, error)
91 }
92
93 type listenPortOpener struct{}
94
95
96 var ListenPortOpener listenPortOpener
97
98
99 func (l *listenPortOpener) OpenLocalPort(lp *LocalPort) (Closeable, error) {
100 return openLocalPort(lp)
101 }
102
103 func openLocalPort(lp *LocalPort) (Closeable, error) {
104 var socket Closeable
105 hostPort := net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port))
106 switch lp.Protocol {
107 case TCP:
108 network := "tcp" + string(lp.IPFamily)
109 listener, err := net.Listen(network, hostPort)
110 if err != nil {
111 return nil, err
112 }
113 socket = listener
114 case UDP:
115 network := "udp" + string(lp.IPFamily)
116 addr, err := net.ResolveUDPAddr(network, hostPort)
117 if err != nil {
118 return nil, err
119 }
120 conn, err := net.ListenUDP(network, addr)
121 if err != nil {
122 return nil, err
123 }
124 socket = conn
125 default:
126 return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
127 }
128 return socket, nil
129 }
130
View as plain text