blob: 356fad87d3250763fd44bd45b15530c288cf1ac5 [file] [log] [blame]
Mikio Hara89b7c662015-04-13 23:45:00 +09001// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package net
6
7import (
8 "fmt"
Mikio Haraec114442015-04-16 23:10:56 +09009 "io"
Mikio Hara88511132015-04-18 16:53:55 +090010 "io/ioutil"
Mikio Hara89b7c662015-04-13 23:45:00 +090011 "net/internal/socktest"
12 "os"
13 "runtime"
14 "testing"
Mikio Hara4540e162015-04-17 14:35:54 +090015 "time"
Mikio Hara89b7c662015-04-13 23:45:00 +090016)
17
Mikio Hara89b7c662015-04-13 23:45:00 +090018func (e *OpError) isValid() error {
19 if e.Op == "" {
20 return fmt.Errorf("OpError.Op is empty: %v", e)
21 }
22 if e.Net == "" {
23 return fmt.Errorf("OpError.Net is empty: %v", e)
24 }
Mikio Haraafd2d2b2015-04-21 22:53:47 +090025 for _, addr := range []Addr{e.Source, e.Addr} {
26 if addr != nil {
27 switch addr.(type) {
28 case *TCPAddr, *UDPAddr, *IPAddr, *IPNet, *UnixAddr, *pipeAddr, fileAddr:
29 default:
30 return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
31 }
Mikio Hara88511132015-04-18 16:53:55 +090032 }
Mikio Hara89b7c662015-04-13 23:45:00 +090033 }
34 if e.Err == nil {
35 return fmt.Errorf("OpError.Err is empty: %v", e)
36 }
37 return nil
38}
39
40// parseDialError parses nestedErr and reports whether it is a valid
41// error value from Dial, Listen functions.
42// It returns nil when nestedErr is valid.
43func parseDialError(nestedErr error) error {
44 if nestedErr == nil {
45 return nil
46 }
47
48 switch err := nestedErr.(type) {
49 case *OpError:
50 if err := err.isValid(); err != nil {
51 return err
52 }
53 nestedErr = err.Err
54 goto second
55 }
56 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
57
58second:
59 if isPlatformError(nestedErr) {
60 return nil
61 }
62 switch err := nestedErr.(type) {
Mikio Hara6d3a7e72015-04-17 17:56:58 +090063 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
Mikio Hara89b7c662015-04-13 23:45:00 +090064 return nil
65 case *DNSConfigError:
66 nestedErr = err.Err
67 goto third
68 case *os.SyscallError:
69 nestedErr = err.Err
70 goto third
71 }
72 switch nestedErr {
73 case errClosing, errMissingAddress:
74 return nil
75 }
76 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
77
78third:
79 if isPlatformError(nestedErr) {
80 return nil
81 }
82 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
83}
84
85var dialErrorTests = []struct {
86 network, address string
87}{
88 {"foo", ""},
89 {"bar", "baz"},
90 {"datakit", "mh/astro/r70"},
91 {"tcp", ""},
92 {"tcp", "127.0.0.1:☺"},
93 {"tcp", "no-such-name:80"},
94 {"tcp", "mh/astro/r70:http"},
95
96 {"tcp", "127.0.0.1:0"},
97 {"udp", "127.0.0.1:0"},
98 {"ip:icmp", "127.0.0.1"},
99
100 {"unix", "/path/to/somewhere"},
101 {"unixgram", "/path/to/somewhere"},
102 {"unixpacket", "/path/to/somewhere"},
103}
104
105func TestDialError(t *testing.T) {
106 switch runtime.GOOS {
107 case "plan9":
108 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
109 }
110
111 origTestHookLookupIP := testHookLookupIP
112 defer func() { testHookLookupIP = origTestHookLookupIP }()
113 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
114 return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
115 }
116 sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
117 return nil, errOpNotSupported
118 })
119 defer sw.Set(socktest.FilterConnect, nil)
120
121 d := Dialer{Timeout: someTimeout}
122 for i, tt := range dialErrorTests {
123 c, err := d.Dial(tt.network, tt.address)
124 if err == nil {
125 t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
126 c.Close()
127 continue
128 }
Mikio Harad0f31002015-04-17 14:55:07 +0900129 if c != nil {
130 t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
131 }
Mikio Hara89b7c662015-04-13 23:45:00 +0900132 if err = parseDialError(err); err != nil {
133 t.Errorf("#%d: %v", i, err)
134 continue
135 }
136 }
137}
138
139var listenErrorTests = []struct {
140 network, address string
141}{
142 {"foo", ""},
143 {"bar", "baz"},
144 {"datakit", "mh/astro/r70"},
145 {"tcp", "127.0.0.1:☺"},
146 {"tcp", "no-such-name:80"},
147 {"tcp", "mh/astro/r70:http"},
Mikio Harad0f31002015-04-17 14:55:07 +0900148
149 {"tcp", "127.0.0.1:0"},
150
151 {"unix", "/path/to/somewhere"},
152 {"unixpacket", "/path/to/somewhere"},
Mikio Hara89b7c662015-04-13 23:45:00 +0900153}
154
155func TestListenError(t *testing.T) {
156 switch runtime.GOOS {
157 case "plan9":
158 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
159 }
160
161 origTestHookLookupIP := testHookLookupIP
162 defer func() { testHookLookupIP = origTestHookLookupIP }()
163 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
164 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
165 }
166 sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
167 return nil, errOpNotSupported
168 })
169 defer sw.Set(socktest.FilterListen, nil)
170
171 for i, tt := range listenErrorTests {
172 ln, err := Listen(tt.network, tt.address)
173 if err == nil {
174 t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
175 ln.Close()
176 continue
177 }
Mikio Harad0f31002015-04-17 14:55:07 +0900178 if ln != nil {
179 t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
180 }
181 if err = parseDialError(err); err != nil {
182 t.Errorf("#%d: %v", i, err)
183 continue
184 }
185 }
186}
187
188var listenPacketErrorTests = []struct {
189 network, address string
190}{
191 {"foo", ""},
192 {"bar", "baz"},
193 {"datakit", "mh/astro/r70"},
194 {"udp", "127.0.0.1:☺"},
195 {"udp", "no-such-name:80"},
196 {"udp", "mh/astro/r70:http"},
197}
198
199func TestListenPacketError(t *testing.T) {
200 switch runtime.GOOS {
201 case "plan9":
202 t.Skipf("%s does not have full support of socktest", runtime.GOOS)
203 }
204
205 origTestHookLookupIP := testHookLookupIP
206 defer func() { testHookLookupIP = origTestHookLookupIP }()
207 testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
208 return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
209 }
210
211 for i, tt := range listenPacketErrorTests {
212 c, err := ListenPacket(tt.network, tt.address)
213 if err == nil {
214 t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
215 c.Close()
216 continue
217 }
218 if c != nil {
219 t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c)
220 }
Mikio Hara89b7c662015-04-13 23:45:00 +0900221 if err = parseDialError(err); err != nil {
222 t.Errorf("#%d: %v", i, err)
223 continue
224 }
225 }
226}
Mikio Haraec114442015-04-16 23:10:56 +0900227
228// parseReadError parses nestedErr and reports whether it is a valid
229// error value from Read functions.
230// It returns nil when nestedErr is valid.
231func parseReadError(nestedErr error) error {
232 if nestedErr == nil {
233 return nil
234 }
235
236 switch err := nestedErr.(type) {
237 case *OpError:
238 if err := err.isValid(); err != nil {
239 return err
240 }
241 nestedErr = err.Err
242 goto second
243 }
244 if nestedErr == io.EOF {
245 return nil
246 }
247 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
248
249second:
250 if isPlatformError(nestedErr) {
251 return nil
252 }
253 switch err := nestedErr.(type) {
254 case *os.SyscallError:
255 nestedErr = err.Err
256 goto third
257 }
258 switch nestedErr {
259 case errClosing, errTimeout:
260 return nil
261 }
262 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
263
264third:
265 if isPlatformError(nestedErr) {
266 return nil
267 }
268 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
269}
Mikio Hara11b5f982015-04-16 11:26:44 +0900270
271// parseWriteError parses nestedErr and reports whether it is a valid
272// error value from Write functions.
273// It returns nil when nestedErr is valid.
274func parseWriteError(nestedErr error) error {
275 if nestedErr == nil {
276 return nil
277 }
278
279 switch err := nestedErr.(type) {
280 case *OpError:
281 if err := err.isValid(); err != nil {
282 return err
283 }
284 nestedErr = err.Err
285 goto second
286 }
287 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
288
289second:
290 if isPlatformError(nestedErr) {
291 return nil
292 }
293 switch err := nestedErr.(type) {
Mikio Hara832c5732015-04-19 23:42:11 +0900294 case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
295 return nil
296 case *DNSConfigError:
297 nestedErr = err.Err
298 goto third
Mikio Hara11b5f982015-04-16 11:26:44 +0900299 case *os.SyscallError:
300 nestedErr = err.Err
301 goto third
302 }
303 switch nestedErr {
304 case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
305 return nil
306 }
307 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
308
309third:
310 if isPlatformError(nestedErr) {
311 return nil
312 }
313 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
314}
Mikio Hara310db632015-04-17 12:24:42 +0900315
316// parseCloseError parses nestedErr and reports whether it is a valid
317// error value from Close functions.
318// It returns nil when nestedErr is valid.
319func parseCloseError(nestedErr error) error {
320 if nestedErr == nil {
321 return nil
322 }
323
324 switch err := nestedErr.(type) {
325 case *OpError:
326 if err := err.isValid(); err != nil {
327 return err
328 }
329 nestedErr = err.Err
330 goto second
331 }
332 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
333
334second:
335 if isPlatformError(nestedErr) {
336 return nil
337 }
338 switch err := nestedErr.(type) {
339 case *os.SyscallError:
340 nestedErr = err.Err
341 goto third
342 case *os.PathError: // for Plan 9
343 nestedErr = err.Err
344 goto third
345 }
346 switch nestedErr {
347 case errClosing:
348 return nil
349 }
350 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
351
352third:
353 if isPlatformError(nestedErr) {
354 return nil
355 }
356 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
357}
358
359func TestCloseError(t *testing.T) {
360 ln, err := newLocalListener("tcp")
361 if err != nil {
362 t.Fatal(err)
363 }
364 defer ln.Close()
365 c, err := Dial(ln.Addr().Network(), ln.Addr().String())
366 if err != nil {
367 t.Fatal(err)
368 }
369 defer c.Close()
370
371 for i := 0; i < 3; i++ {
372 err = c.(*TCPConn).CloseRead()
373 if perr := parseCloseError(err); perr != nil {
374 t.Errorf("#%d: %v", i, perr)
375 }
376 }
377 for i := 0; i < 3; i++ {
378 err = c.(*TCPConn).CloseWrite()
379 if perr := parseCloseError(err); perr != nil {
380 t.Errorf("#%d: %v", i, perr)
381 }
382 }
383 for i := 0; i < 3; i++ {
384 err = c.Close()
385 if perr := parseCloseError(err); perr != nil {
386 t.Errorf("#%d: %v", i, perr)
387 }
388 err = ln.Close()
389 if perr := parseCloseError(err); perr != nil {
390 t.Errorf("#%d: %v", i, perr)
391 }
392 }
393
394 pc, err := ListenPacket("udp", "127.0.0.1:0")
395 if err != nil {
396 t.Fatal(err)
397 }
398 defer pc.Close()
399
400 for i := 0; i < 3; i++ {
401 err = pc.Close()
402 if perr := parseCloseError(err); perr != nil {
403 t.Errorf("#%d: %v", i, perr)
404 }
405 }
406}
Mikio Hara4540e162015-04-17 14:35:54 +0900407
408// parseAcceptError parses nestedErr and reports whether it is a valid
409// error value from Accept functions.
410// It returns nil when nestedErr is valid.
411func parseAcceptError(nestedErr error) error {
412 if nestedErr == nil {
413 return nil
414 }
415
416 switch err := nestedErr.(type) {
417 case *OpError:
418 if err := err.isValid(); err != nil {
419 return err
420 }
421 nestedErr = err.Err
422 goto second
423 }
424 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
425
426second:
427 if isPlatformError(nestedErr) {
428 return nil
429 }
430 switch err := nestedErr.(type) {
431 case *os.SyscallError:
432 nestedErr = err.Err
433 goto third
434 }
435 switch nestedErr {
436 case errClosing, errTimeout:
437 return nil
438 }
439 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
440
441third:
442 if isPlatformError(nestedErr) {
443 return nil
444 }
445 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
446}
447
448func TestAcceptError(t *testing.T) {
449 handler := func(ls *localServer, ln Listener) {
450 for {
451 ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
452 c, err := ln.Accept()
453 if perr := parseAcceptError(err); perr != nil {
454 t.Error(perr)
455 }
456 if err != nil {
457 if c != nil {
458 t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c)
459 }
Mikio Hara98e05562015-04-28 21:17:46 +0900460 if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) {
Mikio Hara4540e162015-04-17 14:35:54 +0900461 return
462 }
463 continue
464 }
465 c.Close()
466 }
467 }
468 ls, err := newLocalServer("tcp")
469 if err != nil {
470 t.Fatal(err)
471 }
472 if err := ls.buildup(handler); err != nil {
473 ls.teardown()
474 t.Fatal(err)
475 }
476
477 time.Sleep(100 * time.Millisecond)
478 ls.teardown()
479}
Mikio Hara88511132015-04-18 16:53:55 +0900480
481// parseCommonError parses nestedErr and reports whether it is a valid
482// error value from miscellaneous functions.
483// It returns nil when nestedErr is valid.
484func parseCommonError(nestedErr error) error {
485 if nestedErr == nil {
486 return nil
487 }
488
489 switch err := nestedErr.(type) {
490 case *OpError:
491 if err := err.isValid(); err != nil {
492 return err
493 }
494 nestedErr = err.Err
495 goto second
496 }
497 return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
498
499second:
500 if isPlatformError(nestedErr) {
501 return nil
502 }
503 switch err := nestedErr.(type) {
504 case *os.SyscallError:
505 nestedErr = err.Err
506 goto third
507 case *os.LinkError:
508 nestedErr = err.Err
509 goto third
510 case *os.PathError:
511 nestedErr = err.Err
512 goto third
513 }
Mikio Hara98e05562015-04-28 21:17:46 +0900514 switch nestedErr {
515 case errClosing:
516 return nil
517 }
Mikio Hara88511132015-04-18 16:53:55 +0900518 return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
519
520third:
521 if isPlatformError(nestedErr) {
522 return nil
523 }
524 return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
525}
526
527func TestFileError(t *testing.T) {
528 switch runtime.GOOS {
529 case "windows":
530 t.Skip("not supported on %s", runtime.GOOS)
531 }
532
533 f, err := ioutil.TempFile("", "nettest")
534 if err != nil {
535 t.Fatal(err)
536 }
537 defer f.Close()
538
539 c, err := FileConn(f)
540 if err != nil {
541 if c != nil {
542 t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
543 }
544 if perr := parseCommonError(err); perr != nil {
545 t.Error(perr)
546 }
547 } else {
548 c.Close()
549 t.Error("should fail")
550 }
551 ln, err := FileListener(f)
552 if err != nil {
553 if ln != nil {
554 t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
555 }
556 if perr := parseCommonError(err); perr != nil {
557 t.Error(perr)
558 }
559 } else {
560 ln.Close()
561 t.Error("should fail")
562 }
563 pc, err := FilePacketConn(f)
564 if err != nil {
565 if pc != nil {
566 t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
567 }
568 if perr := parseCommonError(err); perr != nil {
569 t.Error(perr)
570 }
571 } else {
572 pc.Close()
573 t.Error("should fail")
574 }
575
576 ln, err = newLocalListener("tcp")
577 if err != nil {
578 t.Fatal(err)
579 }
580
581 for i := 0; i < 3; i++ {
582 f, err := ln.(*TCPListener).File()
583 if err != nil {
584 if perr := parseCommonError(err); perr != nil {
585 t.Error(perr)
586 }
587 } else {
588 f.Close()
589 }
590 ln.Close()
591 }
592}