-
Notifications
You must be signed in to change notification settings - Fork 1
/
connection.go
111 lines (93 loc) · 2.19 KB
/
connection.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package tftp
import (
"fmt"
"net"
"time"
"golang.org/x/net/ipv6"
"golang.org/x/net/ipv4"
)
type connectionError struct {
error
timeout bool
temporary bool
}
func (t *connectionError) Timeout() bool {
return t.timeout
}
func (t *connectionError) Temporary() bool {
return t.temporary
}
type connection interface {
sendTo([]byte, *net.UDPAddr) error
readFrom([]byte) (int, *net.UDPAddr, error)
setDeadline(time.Duration) error
close()
}
type connConnection struct {
conn *net.UDPConn
}
type chanConnection struct {
sendConn net.PacketConn
channel chan []byte
srcAddr, addr *net.UDPAddr
timeout time.Duration
complete chan string
}
func (c *chanConnection) sendTo(data []byte, addr *net.UDPAddr) error {
var err error
if conn, ok := c.sendConn.(*net.UDPConn); ok {
srcAddr := c.srcAddr.IP.To4()
var cmm []byte
if srcAddr != nil {
cm := &ipv4.ControlMessage{Src: srcAddr}
cmm = cm.Marshal()
} else {
cm := &ipv6.ControlMessage{Src: c.srcAddr.IP}
cmm = cm.Marshal()
}
_, _, err = conn.WriteMsgUDP(data, cmm, c.addr)
} else {
_, err = c.sendConn.WriteTo(data, addr)
}
return err
}
func (c *chanConnection) readFrom(buffer []byte) (int, *net.UDPAddr, error) {
select {
case data := <-c.channel:
for i := range data {
buffer[i] = data[i]
}
return len(data), c.addr, nil
case <-time.After(c.timeout):
return 0, nil, makeError(c.addr.String())
}
}
func (c *chanConnection) setDeadline(deadline time.Duration) error {
c.timeout = deadline
return nil
}
func (c *chanConnection) close() {
close(c.channel)
c.complete <- c.addr.String()
}
func (c *connConnection) sendTo(data []byte, addr *net.UDPAddr) error {
_, err := c.conn.WriteToUDP(data, addr)
return err
}
func makeError(addr string) net.Error {
error := connectionError{
timeout: true,
temporary: true,
}
error.error = fmt.Errorf("Channel timeout: %v", addr)
return &error
}
func (c *connConnection) readFrom(buffer []byte) (int, *net.UDPAddr, error) {
return c.conn.ReadFromUDP(buffer)
}
func (c *connConnection) setDeadline(deadline time.Duration) error {
return c.conn.SetReadDeadline(time.Now().Add(deadline))
}
func (c *connConnection) close() {
c.conn.Close()
}