@@ -16,11 +16,17 @@ var (
16
16
RFC6587 = & format.RFC6587 {} // RFC6587: http://www.ietf.org/rfc/rfc6587.txt
17
17
)
18
18
19
+ const (
20
+ datagramChannelBufferSize = 10
21
+ datagramReadBufferSize = 64 * 1024
22
+ )
23
+
19
24
type Server struct {
20
25
listeners []* net.TCPListener
21
26
connections []net.Conn
22
27
wait sync.WaitGroup
23
28
doneTcp chan bool
29
+ datagramChannel chan DatagramMessage
24
30
format format.Format
25
31
handler Handler
26
32
lastError error
@@ -58,6 +64,7 @@ func (s *Server) ListenUDP(addr string) error {
58
64
if err != nil {
59
65
return err
60
66
}
67
+ connection .SetReadBuffer (datagramReadBufferSize )
61
68
62
69
s .connections = append (s .connections , connection )
63
70
return nil
@@ -74,6 +81,7 @@ func (s *Server) ListenUnixgram(addr string) error {
74
81
if err != nil {
75
82
return err
76
83
}
84
+ connection .SetReadBuffer (datagramReadBufferSize )
77
85
78
86
s .connections = append (s .connections , connection )
79
87
return nil
@@ -110,8 +118,12 @@ func (s *Server) Boot() error {
110
118
s .goAcceptConnection (listener )
111
119
}
112
120
121
+ if len (s .connections ) > 0 {
122
+ s .goParseDatagrams ()
123
+ }
124
+
113
125
for _ , connection := range s .connections {
114
- s .goScanConnection (connection , false )
126
+ s .goReceiveDatagrams (connection )
115
127
}
116
128
117
129
return nil
@@ -132,56 +144,44 @@ func (s *Server) goAcceptConnection(listener *net.TCPListener) {
132
144
continue
133
145
}
134
146
135
- s .goScanConnection (connection , true )
147
+ s .goScanConnection (connection )
136
148
}
137
149
138
150
s .wait .Done ()
139
151
}(listener )
140
152
}
141
153
142
- func (s * Server ) goScanConnection (connection net.Conn , needClose bool ) {
154
+ func (s * Server ) goScanConnection (connection net.Conn ) {
143
155
scanner := bufio .NewScanner (connection )
144
156
if sf := s .format .GetSplitFunc (); sf != nil {
145
157
scanner .Split (sf )
146
158
}
147
159
148
160
var scanCloser * ScanCloser
149
- if needClose {
150
- scanCloser = & ScanCloser {scanner , connection }
151
- } else {
152
- scanCloser = & ScanCloser {scanner , nil }
153
- }
161
+ scanCloser = & ScanCloser {scanner , connection }
154
162
155
163
s .wait .Add (1 )
156
164
go s .scan (scanCloser )
157
165
}
158
166
159
167
func (s * Server ) scan (scanCloser * ScanCloser ) {
160
- if scanCloser .closer == nil {
161
- // UDP
162
- for scanCloser .Scan () {
163
- s .parser ([]byte (scanCloser .Text ()))
168
+ loop:
169
+ for {
170
+ select {
171
+ case <- s .doneTcp :
172
+ break loop
173
+ default :
164
174
}
165
- } else {
166
- // TCP
167
- loop:
168
- for {
169
- select {
170
- case <- s .doneTcp :
171
- break loop
172
- default :
173
- }
174
- if s .readTimeoutMilliseconds > 0 {
175
- scanCloser .closer .SetReadDeadline (time .Now ().Add (time .Duration (s .readTimeoutMilliseconds ) * time .Millisecond ))
176
- }
177
- if scanCloser .Scan () {
178
- s .parser ([]byte (scanCloser .Text ()))
179
- } else {
180
- break loop
181
- }
175
+ if s .readTimeoutMilliseconds > 0 {
176
+ scanCloser .closer .SetReadDeadline (time .Now ().Add (time .Duration (s .readTimeoutMilliseconds ) * time .Millisecond ))
177
+ }
178
+ if scanCloser .Scan () {
179
+ s .parser ([]byte (scanCloser .Text ()))
180
+ } else {
181
+ break loop
182
182
}
183
- scanCloser .closer .Close ()
184
183
}
184
+ scanCloser .closer .Close ()
185
185
186
186
s .wait .Done ()
187
187
}
@@ -220,6 +220,9 @@ func (s *Server) Kill() error {
220
220
if s .doneTcp != nil {
221
221
close (s .doneTcp )
222
222
}
223
+ if s .datagramChannel != nil {
224
+ close (s .datagramChannel )
225
+ }
223
226
return nil
224
227
}
225
228
@@ -237,3 +240,58 @@ type ScanCloser struct {
237
240
* bufio.Scanner
238
241
closer TimeoutCloser
239
242
}
243
+
244
+ type DatagramMessage struct {
245
+ message []byte
246
+ client string
247
+ }
248
+
249
+ func (s * Server ) goReceiveDatagrams (connection net.Conn ) {
250
+ packetconn , ok := connection .(net.PacketConn )
251
+ if ! ok {
252
+ panic ("Connection is not a packet connection" )
253
+ }
254
+ s .wait .Add (1 )
255
+ go func () {
256
+ defer s .wait .Done ()
257
+ for {
258
+ buf := make ([]byte , 65536 )
259
+ n , addr , err := packetconn .ReadFrom (buf )
260
+ if err == nil {
261
+ // Ignore trailing control characters and NULs
262
+ for ; (n > 0 ) && (buf [n - 1 ] < 32 ); n -- {
263
+ }
264
+ if n > 0 {
265
+ s .datagramChannel <- DatagramMessage {buf [:n ], addr .String ()}
266
+ }
267
+ } else {
268
+ // there has been an error. Either the server has been killed
269
+ // or may be getting a transitory error due to (e.g.) the
270
+ // interface being shutdown in which case sleep() to avoid busy wait.
271
+ opError , ok := err .(* net.OpError )
272
+ if (ok ) && ! opError .Temporary () && ! opError .Timeout () {
273
+ return
274
+ }
275
+ time .Sleep (10 * time .Millisecond )
276
+ }
277
+ }
278
+ }()
279
+ }
280
+
281
+ func (s * Server ) goParseDatagrams () {
282
+ s .datagramChannel = make (chan DatagramMessage , datagramChannelBufferSize )
283
+
284
+ s .wait .Add (1 )
285
+ go func () {
286
+ defer s .wait .Done ()
287
+ for {
288
+ select {
289
+ case msg , ok := (<- s .datagramChannel ):
290
+ if ! ok {
291
+ return
292
+ }
293
+ s .parser (msg .message )
294
+ }
295
+ }
296
+ }()
297
+ }
0 commit comments