-
Notifications
You must be signed in to change notification settings - Fork 23
/
net.go
335 lines (274 loc) · 8.35 KB
/
net.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
package openflow
import (
"bufio"
"crypto/tls"
"fmt"
"net"
"sync"
"time"
)
// A ConnState represents the state of a client connection to a server. It's
// used by the optional Server.ConnState hook.
type ConnState int
const (
// StateNew represents a new connection that is expected to
// send a request immediately. Connections begin at this
// state and the transition to either StateHandshake or
// StateClosed.
StateNew ConnState = iota
// StateHandshake represents a connection that has initiated
// OpenFlow handshake routine. After the request is handled,
// the state transitions to one of: StateHandshake, StateActive,
// StateIdle or StateClosed.
StateHandshake
// StateActive represents a connection that has read 1 or more
// bytes of the request. The Server.ConnState hook for StateActive
// fires before the request has been handled.
StateActive
// StateIdle represents a connection that has finished
// handling a request and is in the keep-alive state, waiting
// for a new request. Connections transition from StateIdle
// to StateHandshake, StateActive or StateClosed
StateIdle
// StateClosed represents a closed connection. This is a
// terminal state.
StateClosed
)
// String returns the string presentation of the ConnState.
func (c ConnState) String() string {
text, ok := connStateText[c]
if !ok {
return fmt.Sprintf("ConnState(%d)", c)
}
return text
}
var connStateText = map[ConnState]string{
StateNew: "StateNew",
StateHandshake: "StateHandshake",
StateActive: "StateActive",
StateIdle: "StateIdle",
StateClosed: "StateClosed",
}
// Conn is an generic OpenFlow connection.
//
// Multiple goroutines may invoke methods on conn simultaneously.
type Conn interface {
// Receive receives message from input buffer
Receive() (*Request, error)
// Send writes message to output buffer
Send(*Request) error
// Close closes the connection. Any blocked Read or Write operations
// will be unblocked and return errors.
Close() error
// Flush writes the messages from output buffer to the connection.
Flush() error
// LocalAddr returns the local network address.
LocalAddr() net.Addr
// RemoteAddr returns the remote network address.
RemoteAddr() net.Addr
// SetDeadline sets the read and write deadlines associated with the
// connection.
SetDeadline(t time.Time) error
// SetReadDeadline sets the deadline for the future Receive calls.
// If the deadline is reached, Receive will fail with a timeout (see
// type Error) instead of blocking.
SetReadDeadline(t time.Time) error
// SetWriteDeadLine sets the deadline for the future Send calls.
// If the deadline is reached, Send will fail with a timeout (see
// type Error) instead of blocking.
SetWriteDeadline(t time.Time) error
}
// conn is an OpenFlow protocol connection.
type conn struct {
// A read-write connection.
rwc net.Conn
// An input and output buffer.
buf *bufio.ReadWriter
mu sync.Mutex
// Maximum duration before timing out the read of the request.
ReadTimeout time.Duration
// Maximum duration before timing out the write of the response.
WriteTimeout time.Duration
}
// NewConn creates a new OpenFlow protocol connection.
func NewConn(c net.Conn) Conn {
return newConn(c)
}
// newConn creates a new OpenFlow protocol connection from the
// given one.
func newConn(c net.Conn) *conn {
br := bufio.NewReader(c)
bw := bufio.NewWriter(c)
brw := bufio.NewReadWriter(br, bw)
return &conn{rwc: c, buf: brw}
}
// Read reads data from the connection.
func (c *conn) Read(b []byte) (int, error) {
return c.buf.Read(b)
}
// Receive reads OpenFlow data from the connection.
func (c *conn) Receive() (*Request, error) {
if d := c.ReadTimeout; d != 0 {
c.SetReadDeadline(time.Now().Add(d))
}
r := &Request{Addr: c.rwc.RemoteAddr(), conn: c}
_, err := r.ReadFrom(c)
if err != nil {
return nil, err
}
return r, nil
}
// Write writes data to the connection. Write can be made to time out.
func (c *conn) Write(b []byte) (int, error) {
c.mu.Lock()
defer c.mu.Unlock()
return c.buf.Write(b)
}
// Flush writes any buffered data to the connection.
func (c *conn) Flush() error {
c.mu.Lock()
defer c.mu.Unlock()
return c.buf.Flush()
}
// forceWrite writes given data and any buffered data to the connection.
func (c *conn) forceWrite(b []byte) error {
c.mu.Lock()
defer c.mu.Unlock()
_, err := c.buf.Write(b)
if err != nil {
return err
}
return c.buf.Flush()
}
// Send writes OpenFlow data to the connection.
func (c *conn) Send(r *Request) error {
if d := c.WriteTimeout; d != 0 {
defer func() {
c.SetWriteDeadline(time.Now().Add(d))
}()
}
_, err := r.WriteTo(c)
return err
}
// Close closes the connection. Any blocked Read or Write operations will
// be unblocked and return errors.
func (c *conn) Close() error {
return c.rwc.Close()
}
// LocalAddr returns the local network address.
func (c *conn) LocalAddr() net.Addr {
return c.rwc.LocalAddr()
}
// RemoteAddr returns the remote network address.
func (c *conn) RemoteAddr() net.Addr {
return c.rwc.RemoteAddr()
}
// SetDeadline sets the read and write deadlines associated with the
// connection.
func (c *conn) SetDeadline(t time.Time) error {
return c.rwc.SetDeadline(t)
}
// SetReadDeadline sets the deadline for the future Receive calls. If the
// deadline is reached, Receive will fail with a timeout (see type Error)
// instead of blocking.
func (c *conn) SetReadDeadline(t time.Time) error {
return c.rwc.SetReadDeadline(t)
}
// SetWriteDeadLine sets the deadline for the future Send calls. If the
// deadline is reached, Send will fail with a timeout (see type Error)
// instead of blocking.
func (c *conn) SetWriteDeadline(t time.Time) error {
return c.rwc.SetWriteDeadline(t)
}
// Send allows to send multiple requests at once to the connection.
//
// The requests will be written to the per-call buffer. If the
// serialization of all given requests succeeded it will be flushed
// to the OpenFlow connection.
//
// No data will be written when any of the request failed.
func Send(c Conn, requests ...*Request) error {
for _, request := range requests {
if err := c.Send(request); err != nil {
return err
}
}
return c.Flush()
}
// Dial establishes the remote connection to the address on the
// given network.
func Dial(network, addr string) (Conn, error) {
conn, err := net.Dial(network, addr)
if err != nil {
return nil, err
}
return NewConn(conn), nil
}
// DialTLS establishes the remote connection to the address on the
// given network and then initiates TLS handshake, returning the
// resulting TLS connection.
func DialTLS(network, addr string, config *tls.Config) (Conn, error) {
conn, err := tls.Dial(network, addr, config)
if err != nil {
return nil, err
}
return NewConn(conn), nil
}
// Listener is an OpenFlow network listener. Clients should typically
// use variables of type net.Listener instead of assuming OFP.
type Listener interface {
// Accept waits for and returns the next connection.
Accept() (Conn, error)
// Close closes the listener.
Close() error
// Addr returns the listener network address.
Addr() net.Addr
}
// listener implements the Listener interface.
type listener struct {
ln net.Listener
}
// NewListener creates a new instance of the OpenFlow listener from
// the given network listener.
//
// This function could be used to establish the communication channel
// over non-TCP sockets, like Unix sockets.
func NewListener(ln net.Listener) Listener {
return &listener{ln}
}
// Accept waits for and returns the next connection to the listener.
func (l *listener) Accept() (Conn, error) {
conn, err := l.ln.Accept()
if err != nil {
return nil, err
}
return NewConn(conn), nil
}
// Close closes an OpenFlow server connection.
func (l *listener) Close() error {
return l.ln.Close()
}
// Addr returns the network address of the listener.
func (l *listener) Addr() net.Addr {
return l.ln.Addr()
}
// Listen announces on the local network address laddr.
func Listen(network, laddr string) (Listener, error) {
tcpaddr, err := net.ResolveTCPAddr(network, laddr)
if err != nil {
return nil, err
}
ln, err := net.ListenTCP(network, tcpaddr)
if err != nil {
return nil, err
}
return &listener{ln}, err
}
// ListenTLS announces on the local network address.
func ListenTLS(network, laddr string, config *tls.Config) (Listener, error) {
ln, err := tls.Listen(network, laddr, config)
if err != nil {
return nil, err
}
return &listener{ln}, err
}