Skip to content

Commit 8851113

Browse files
committed
net: fix inconsistent error values on File
This change fixes inconsistent error values on File{Conn,Listener,PacketConn} and File method of Conn, Listener. Updates #4856. Change-Id: I3197b9277bef0e034427e3a44fa77523acaa2520 Reviewed-on: https://go-review.googlesource.com/9101 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 0088ddc commit 8851113

14 files changed

+217
-97
lines changed

src/net/error_test.go

+114
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package net
77
import (
88
"fmt"
99
"io"
10+
"io/ioutil"
1011
"net/internal/socktest"
1112
"os"
1213
"runtime"
@@ -56,6 +57,10 @@ func (e *OpError) isValid() error {
5657
if addr == nil {
5758
return fmt.Errorf("OpError.Addr is empty: %v", e)
5859
}
60+
case fileAddr:
61+
if addr == "" {
62+
return fmt.Errorf("OpError.Addr is empty: %v", e)
63+
}
5964
}
6065
if e.Err == nil {
6166
return fmt.Errorf("OpError.Err is empty: %v", e)
@@ -503,3 +508,112 @@ func TestAcceptError(t *testing.T) {
503508
time.Sleep(100 * time.Millisecond)
504509
ls.teardown()
505510
}
511+
512+
// parseCommonError parses nestedErr and reports whether it is a valid
513+
// error value from miscellaneous functions.
514+
// It returns nil when nestedErr is valid.
515+
func parseCommonError(nestedErr error) error {
516+
if nestedErr == nil {
517+
return nil
518+
}
519+
520+
switch err := nestedErr.(type) {
521+
case *OpError:
522+
if err := err.isValid(); err != nil {
523+
return err
524+
}
525+
nestedErr = err.Err
526+
goto second
527+
}
528+
return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
529+
530+
second:
531+
if isPlatformError(nestedErr) {
532+
return nil
533+
}
534+
switch err := nestedErr.(type) {
535+
case *os.SyscallError:
536+
nestedErr = err.Err
537+
goto third
538+
case *os.LinkError:
539+
nestedErr = err.Err
540+
goto third
541+
case *os.PathError:
542+
nestedErr = err.Err
543+
goto third
544+
}
545+
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
546+
547+
third:
548+
if isPlatformError(nestedErr) {
549+
return nil
550+
}
551+
return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
552+
}
553+
554+
func TestFileError(t *testing.T) {
555+
switch runtime.GOOS {
556+
case "windows":
557+
t.Skip("not supported on %s", runtime.GOOS)
558+
}
559+
560+
f, err := ioutil.TempFile("", "nettest")
561+
if err != nil {
562+
t.Fatal(err)
563+
}
564+
defer f.Close()
565+
566+
c, err := FileConn(f)
567+
if err != nil {
568+
if c != nil {
569+
t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
570+
}
571+
if perr := parseCommonError(err); perr != nil {
572+
t.Error(perr)
573+
}
574+
} else {
575+
c.Close()
576+
t.Error("should fail")
577+
}
578+
ln, err := FileListener(f)
579+
if err != nil {
580+
if ln != nil {
581+
t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
582+
}
583+
if perr := parseCommonError(err); perr != nil {
584+
t.Error(perr)
585+
}
586+
} else {
587+
ln.Close()
588+
t.Error("should fail")
589+
}
590+
pc, err := FilePacketConn(f)
591+
if err != nil {
592+
if pc != nil {
593+
t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
594+
}
595+
if perr := parseCommonError(err); perr != nil {
596+
t.Error(perr)
597+
}
598+
} else {
599+
pc.Close()
600+
t.Error("should fail")
601+
}
602+
603+
ln, err = newLocalListener("tcp")
604+
if err != nil {
605+
t.Fatal(err)
606+
}
607+
608+
for i := 0; i < 3; i++ {
609+
f, err := ln.(*TCPListener).File()
610+
if err != nil {
611+
if perr := parseCommonError(err); perr != nil {
612+
t.Error(perr)
613+
}
614+
} else {
615+
f.Close()
616+
}
617+
ln.Close()
618+
}
619+
}

src/net/fd_plan9.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
202202
dfd, err := syscall.Dup(int(f.Fd()), -1)
203203
syscall.ForkLock.RUnlock()
204204
if err != nil {
205-
return nil, &OpError{"dup", s, fd.laddr, err}
205+
return nil, err
206206
}
207207
return os.NewFile(uintptr(dfd), s), nil
208208
}

src/net/fd_unix.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -459,15 +459,15 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
459459
func (fd *netFD) dup() (f *os.File, err error) {
460460
ns, err := dupCloseOnExec(fd.sysfd)
461461
if err != nil {
462-
return nil, &OpError{"dup", fd.net, fd.laddr, err}
462+
return nil, err
463463
}
464464

465465
// We want blocking mode for the new fd, hence the double negative.
466466
// This also puts the old fd into blocking mode, meaning that
467467
// I/O will block the thread instead of letting us use the epoll server.
468468
// Everything will still work, just with more threads.
469469
if err = syscall.SetNonblock(ns, false); err != nil {
470-
return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
470+
return nil, err
471471
}
472472

473473
return os.NewFile(uintptr(ns), fd.name()), nil

src/net/fd_windows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ func (fd *netFD) accept() (*netFD, error) {
605605

606606
func (fd *netFD) dup() (*os.File, error) {
607607
// TODO: Implement this
608-
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
608+
return nil, syscall.EWINDOWS
609609
}
610610

611611
func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {

src/net/file.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// 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+
5+
package net
6+
7+
import "os"
8+
9+
type fileAddr string
10+
11+
func (fileAddr) Network() string { return "file+net" }
12+
func (f fileAddr) String() string { return string(f) }
13+
14+
// FileConn returns a copy of the network connection corresponding to
15+
// the open file f.
16+
// It is the caller's responsibility to close f when finished.
17+
// Closing c does not affect f, and closing f does not affect c.
18+
func FileConn(f *os.File) (c Conn, err error) {
19+
c, err = fileConn(f)
20+
if err != nil {
21+
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
22+
}
23+
return
24+
}
25+
26+
// FileListener returns a copy of the network listener corresponding
27+
// to the open file f.
28+
// It is the caller's responsibility to close ln when finished.
29+
// Closing ln does not affect f, and closing f does not affect ln.
30+
func FileListener(f *os.File) (ln Listener, err error) {
31+
ln, err = fileListener(f)
32+
if err != nil {
33+
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
34+
}
35+
return
36+
}
37+
38+
// FilePacketConn returns a copy of the packet network connection
39+
// corresponding to the open file f.
40+
// It is the caller's responsibility to close f when finished.
41+
// Closing c does not affect f, and closing f does not affect c.
42+
func FilePacketConn(f *os.File) (c PacketConn, err error) {
43+
c, err = filePacketConn(f)
44+
if err != nil {
45+
err = &OpError{Op: "file", Net: "file+net", Addr: fileAddr(f.Name()), Err: err}
46+
}
47+
return
48+
}

src/net/file_plan9.go

+5-25
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
3939

4040
path, err := syscall.Fd2path(int(f.Fd()))
4141
if err != nil {
42-
return nil, os.NewSyscallError("fd2path", err)
42+
return nil, err
4343
}
4444
comp := splitAtBytes(path, "/")
4545
n := len(comp)
@@ -54,7 +54,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
5454
fd, err := syscall.Dup(int(f.Fd()), -1)
5555
syscall.ForkLock.RUnlock()
5656
if err != nil {
57-
return nil, os.NewSyscallError("dup", err)
57+
return nil, err
5858
}
5959
defer close(fd)
6060

@@ -86,7 +86,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
8686
return newFD(comp[1], name, ctl, nil, laddr, nil)
8787
}
8888

89-
func newFileConn(f *os.File) (c Conn, err error) {
89+
func fileConn(f *os.File) (Conn, error) {
9090
fd, err := newFileFD(f)
9191
if err != nil {
9292
return nil, err
@@ -109,7 +109,7 @@ func newFileConn(f *os.File) (c Conn, err error) {
109109
return nil, syscall.EPLAN9
110110
}
111111

112-
func newFileListener(f *os.File) (l Listener, err error) {
112+
func fileListener(f *os.File) (Listener, error) {
113113
fd, err := newFileFD(f)
114114
if err != nil {
115115
return nil, err
@@ -132,26 +132,6 @@ func newFileListener(f *os.File) (l Listener, err error) {
132132
return &TCPListener{fd}, nil
133133
}
134134

135-
// FileConn returns a copy of the network connection corresponding to
136-
// the open file f. It is the caller's responsibility to close f when
137-
// finished. Closing c does not affect f, and closing f does not
138-
// affect c.
139-
func FileConn(f *os.File) (c Conn, err error) {
140-
return newFileConn(f)
141-
}
142-
143-
// FileListener returns a copy of the network listener corresponding
144-
// to the open file f. It is the caller's responsibility to close l
145-
// when finished. Closing l does not affect f, and closing f does not
146-
// affect l.
147-
func FileListener(f *os.File) (l Listener, err error) {
148-
return newFileListener(f)
149-
}
150-
151-
// FilePacketConn returns a copy of the packet network connection
152-
// corresponding to the open file f. It is the caller's
153-
// responsibility to close f when finished. Closing c does not affect
154-
// f, and closing f does not affect c.
155-
func FilePacketConn(f *os.File) (c PacketConn, err error) {
135+
func filePacketConn(f *os.File) (PacketConn, error) {
156136
return nil, syscall.EPLAN9
157137
}

src/net/file_stub.go

+3-25
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,6 @@ import (
1111
"syscall"
1212
)
1313

14-
// FileConn returns a copy of the network connection corresponding to
15-
// the open file f. It is the caller's responsibility to close f when
16-
// finished. Closing c does not affect f, and closing f does not
17-
// affect c.
18-
func FileConn(f *os.File) (c Conn, err error) {
19-
return nil, syscall.ENOPROTOOPT
20-
21-
}
22-
23-
// FileListener returns a copy of the network listener corresponding
24-
// to the open file f. It is the caller's responsibility to close l
25-
// when finished. Closing l does not affect f, and closing f does not
26-
// affect l.
27-
func FileListener(f *os.File) (l Listener, err error) {
28-
return nil, syscall.ENOPROTOOPT
29-
30-
}
31-
32-
// FilePacketConn returns a copy of the packet network connection
33-
// corresponding to the open file f. It is the caller's
34-
// responsibility to close f when finished. Closing c does not affect
35-
// f, and closing f does not affect c.
36-
func FilePacketConn(f *os.File) (c PacketConn, err error) {
37-
return nil, syscall.ENOPROTOOPT
38-
}
14+
func fileConn(f *os.File) (Conn, error) { return nil, syscall.ENOPROTOOPT }
15+
func fileListener(f *os.File) (Listener, error) { return nil, syscall.ENOPROTOOPT }
16+
func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }

src/net/file_unix.go

+8-20
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func newFileFD(f *os.File) (*netFD, error) {
1515
fd, err := dupCloseOnExec(int(f.Fd()))
1616
if err != nil {
17-
return nil, os.NewSyscallError("dup", err)
17+
return nil, err
1818
}
1919

2020
if err = syscall.SetNonblock(fd, true); err != nil {
@@ -25,16 +25,13 @@ func newFileFD(f *os.File) (*netFD, error) {
2525
sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
2626
if err != nil {
2727
closeFunc(fd)
28-
return nil, os.NewSyscallError("getsockopt", err)
28+
return nil, err
2929
}
3030

3131
family := syscall.AF_UNSPEC
3232
toAddr := sockaddrToTCP
3333
lsa, _ := syscall.Getsockname(fd)
3434
switch lsa.(type) {
35-
default:
36-
closeFunc(fd)
37-
return nil, syscall.EINVAL
3835
case *syscall.SockaddrInet4:
3936
family = syscall.AF_INET
4037
if sotype == syscall.SOCK_DGRAM {
@@ -57,6 +54,9 @@ func newFileFD(f *os.File) (*netFD, error) {
5754
} else if sotype == syscall.SOCK_SEQPACKET {
5855
toAddr = sockaddrToUnixpacket
5956
}
57+
default:
58+
closeFunc(fd)
59+
return nil, syscall.EPROTONOSUPPORT
6060
}
6161
laddr := toAddr(lsa)
6262
rsa, _ := syscall.Getpeername(fd)
@@ -75,11 +75,7 @@ func newFileFD(f *os.File) (*netFD, error) {
7575
return netfd, nil
7676
}
7777

78-
// FileConn returns a copy of the network connection corresponding to
79-
// the open file f. It is the caller's responsibility to close f when
80-
// finished. Closing c does not affect f, and closing f does not
81-
// affect c.
82-
func FileConn(f *os.File) (c Conn, err error) {
78+
func fileConn(f *os.File) (Conn, error) {
8379
fd, err := newFileFD(f)
8480
if err != nil {
8581
return nil, err
@@ -98,11 +94,7 @@ func FileConn(f *os.File) (c Conn, err error) {
9894
return nil, syscall.EINVAL
9995
}
10096

101-
// FileListener returns a copy of the network listener corresponding
102-
// to the open file f. It is the caller's responsibility to close l
103-
// when finished. Closing l does not affect f, and closing f does not
104-
// affect l.
105-
func FileListener(f *os.File) (l Listener, err error) {
97+
func fileListener(f *os.File) (Listener, error) {
10698
fd, err := newFileFD(f)
10799
if err != nil {
108100
return nil, err
@@ -117,11 +109,7 @@ func FileListener(f *os.File) (l Listener, err error) {
117109
return nil, syscall.EINVAL
118110
}
119111

120-
// FilePacketConn returns a copy of the packet network connection
121-
// corresponding to the open file f. It is the caller's
122-
// responsibility to close f when finished. Closing c does not affect
123-
// f, and closing f does not affect c.
124-
func FilePacketConn(f *os.File) (c PacketConn, err error) {
112+
func filePacketConn(f *os.File) (PacketConn, error) {
125113
fd, err := newFileFD(f)
126114
if err != nil {
127115
return nil, err

0 commit comments

Comments
 (0)