summaryrefslogtreecommitdiff
path: root/libgo/go/net/net.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/net.go')
-rw-r--r--libgo/go/net/net.go241
1 files changed, 196 insertions, 45 deletions
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index cb31af5e347..6e84c3a100e 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -35,12 +35,49 @@ The Listen function creates servers:
}
go handleConnection(conn)
}
+
+Name Resolution
+
+The method for resolving domain names, whether indirectly with functions like Dial
+or directly with functions like LookupHost and LookupAddr, varies by operating system.
+
+On Unix systems, the resolver has two options for resolving names.
+It can use a pure Go resolver that sends DNS requests directly to the servers
+listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C
+library routines such as getaddrinfo and getnameinfo.
+
+By default the pure Go resolver is used, because a blocked DNS request consumes
+only a goroutine, while a blocked C call consumes an operating system thread.
+When cgo is available, the cgo-based resolver is used instead under a variety of
+conditions: on systems that do not let programs make direct DNS requests (OS X),
+when the LOCALDOMAIN environment variable is present (even if empty),
+when the RES_OPTIONS or HOSTALIASES environment variable is non-empty,
+when the ASR_CONFIG environment variable is non-empty (OpenBSD only),
+when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the
+Go resolver does not implement, and when the name being looked up ends in .local
+or is an mDNS name.
+
+The resolver decision can be overridden by setting the netdns value of the
+GODEBUG environment variable (see package runtime) to go or cgo, as in:
+
+ export GODEBUG=netdns=go # force pure Go resolver
+ export GODEBUG=netdns=cgo # force cgo resolver
+
+The decision can also be forced while building the Go source tree
+by setting the netgo or netcgo build tag.
+
+A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver
+to print debugging information about its decisions.
+To force a particular resolver while also printing debugging information,
+join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
+
+On Plan 9, the resolver always accesses /net/cs and /net/dns.
+
+On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
+
*/
package net
-// TODO(rsc):
-// support for raw ethernet sockets
-
import (
"errors"
"io"
@@ -49,6 +86,20 @@ import (
"time"
)
+// netGo and netCgo contain the state of the build tags used
+// to build this binary, and whether cgo is available.
+// conf.go mirrors these into conf for easier testing.
+var (
+ netGo bool // set true in cgo_stub.go for build tag "netgo" (or no cgo)
+ netCgo bool // set true in conf_netcgo.go for build tag "netcgo"
+)
+
+func init() {
+ sysInit()
+ supportsIPv4 = probeIPv4Stack()
+ supportsIPv6, supportsIPv4map = probeIPv6Stack()
+}
+
// Addr represents a network end point address.
type Addr interface {
Network() string // name of the network
@@ -118,7 +169,11 @@ func (c *conn) Read(b []byte) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
- return c.fd.Read(b)
+ n, err := c.fd.Read(b)
+ if err != nil && err != io.EOF {
+ err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, err
}
// Write implements the Conn Write method.
@@ -126,7 +181,11 @@ func (c *conn) Write(b []byte) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
- return c.fd.Write(b)
+ n, err := c.fd.Write(b)
+ if err != nil {
+ err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, err
}
// Close closes the connection.
@@ -134,10 +193,16 @@ func (c *conn) Close() error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.Close()
+ err := c.fd.Close()
+ if err != nil {
+ err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return err
}
// LocalAddr returns the local network address.
+// The Addr returned is shared by all invocations of LocalAddr, so
+// do not modify it.
func (c *conn) LocalAddr() Addr {
if !c.ok() {
return nil
@@ -146,6 +211,8 @@ func (c *conn) LocalAddr() Addr {
}
// RemoteAddr returns the remote network address.
+// The Addr returned is shared by all invocations of RemoteAddr, so
+// do not modify it.
func (c *conn) RemoteAddr() Addr {
if !c.ok() {
return nil
@@ -158,7 +225,10 @@ func (c *conn) SetDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.setDeadline(t)
+ if err := c.fd.setDeadline(t); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+ }
+ return nil
}
// SetReadDeadline implements the Conn SetReadDeadline method.
@@ -166,7 +236,10 @@ func (c *conn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.setReadDeadline(t)
+ if err := c.fd.setReadDeadline(t); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+ }
+ return nil
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
@@ -174,7 +247,10 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
}
- return c.fd.setWriteDeadline(t)
+ if err := c.fd.setWriteDeadline(t); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+ }
+ return nil
}
// SetReadBuffer sets the size of the operating system's
@@ -183,7 +259,10 @@ func (c *conn) SetReadBuffer(bytes int) error {
if !c.ok() {
return syscall.EINVAL
}
- return setReadBuffer(c.fd, bytes)
+ if err := setReadBuffer(c.fd, bytes); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+ }
+ return nil
}
// SetWriteBuffer sets the size of the operating system's
@@ -192,7 +271,10 @@ func (c *conn) SetWriteBuffer(bytes int) error {
if !c.ok() {
return syscall.EINVAL
}
- return setWriteBuffer(c.fd, bytes)
+ if err := setWriteBuffer(c.fd, bytes); err != nil {
+ return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+ }
+ return nil
}
// File sets the underlying os.File to blocking mode and returns a copy.
@@ -202,13 +284,12 @@ func (c *conn) SetWriteBuffer(bytes int) error {
// The returned os.File's file descriptor is different from the connection's.
// Attempting to change properties of the original using this duplicate
// may or may not have the desired effect.
-func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
-
-// An Error represents a network error.
-type Error interface {
- error
- Timeout() bool // Is the error a timeout?
- Temporary() bool // Is the error temporary?
+func (c *conn) File() (f *os.File, err error) {
+ f, err = c.fd.dup()
+ if err != nil {
+ err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return
}
// PacketConn is a generic packet-oriented network connection.
@@ -274,6 +355,13 @@ type Listener interface {
Addr() Addr
}
+// An Error represents a network error.
+type Error interface {
+ error
+ Timeout() bool // Is the error a timeout?
+ Temporary() bool // Is the error temporary?
+}
+
// Various errors contained in OpError.
var (
// For connection setup and write operations.
@@ -281,6 +369,7 @@ var (
// For both read and write operations.
errTimeout error = &timeoutError{}
+ errCanceled = errors.New("operation was canceled")
errClosing = errors.New("use of closed network connection")
ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection")
)
@@ -297,7 +386,17 @@ type OpError struct {
// such as "tcp" or "udp6".
Net string
- // Addr is the network address on which this error occurred.
+ // For operations involving a remote network connection, like
+ // Dial, Read, or Write, Source is the corresponding local
+ // network address.
+ Source Addr
+
+ // Addr is the network address for which this error occurred.
+ // For local operations, like Listen or SetDeadline, Addr is
+ // the address of the local endpoint being manipulated.
+ // For operations involving a remote network connection, like
+ // Dial, Read, or Write, Addr is the remote address of that
+ // connection.
Addr Addr
// Err is the error that occurred during the operation.
@@ -312,22 +411,21 @@ func (e *OpError) Error() string {
if e.Net != "" {
s += " " + e.Net
}
+ if e.Source != nil {
+ s += " " + e.Source.String()
+ }
if e.Addr != nil {
- s += " " + e.Addr.String()
+ if e.Source != nil {
+ s += "->"
+ } else {
+ s += " "
+ }
+ s += e.Addr.String()
}
s += ": " + e.Err.Error()
return s
}
-type temporary interface {
- Temporary() bool
-}
-
-func (e *OpError) Temporary() bool {
- t, ok := e.Err.(temporary)
- return ok && t.Temporary()
-}
-
var noDeadline = time.Time{}
type timeout interface {
@@ -335,16 +433,45 @@ type timeout interface {
}
func (e *OpError) Timeout() bool {
+ if ne, ok := e.Err.(*os.SyscallError); ok {
+ t, ok := ne.Err.(timeout)
+ return ok && t.Timeout()
+ }
t, ok := e.Err.(timeout)
return ok && t.Timeout()
}
+type temporary interface {
+ Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+ if ne, ok := e.Err.(*os.SyscallError); ok {
+ t, ok := ne.Err.(temporary)
+ return ok && t.Temporary()
+ }
+ t, ok := e.Err.(temporary)
+ return ok && t.Temporary()
+}
+
type timeoutError struct{}
func (e *timeoutError) Error() string { return "i/o timeout" }
func (e *timeoutError) Timeout() bool { return true }
func (e *timeoutError) Temporary() bool { return true }
+// A ParseError is the error type of literal network address parsers.
+type ParseError struct {
+ // Type is the type of string that was expected, such as
+ // "IP address", "CIDR address".
+ Type string
+
+ // Text is the malformed text string.
+ Text string
+}
+
+func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
+
type AddrError struct {
Err string
Addr string
@@ -361,19 +488,14 @@ func (e *AddrError) Error() string {
return s
}
-func (e *AddrError) Temporary() bool {
- return false
-}
-
-func (e *AddrError) Timeout() bool {
- return false
-}
+func (e *AddrError) Timeout() bool { return false }
+func (e *AddrError) Temporary() bool { return false }
type UnknownNetworkError string
func (e UnknownNetworkError) Error() string { return "unknown network " + string(e) }
-func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool { return false }
+func (e UnknownNetworkError) Temporary() bool { return false }
type InvalidAddrError string
@@ -382,17 +504,50 @@ func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
// DNSConfigError represents an error reading the machine's DNS configuration.
+// (No longer used; kept for compatibility.)
type DNSConfigError struct {
Err error
}
-func (e *DNSConfigError) Error() string {
- return "error reading DNS config: " + e.Err.Error()
-}
-
+func (e *DNSConfigError) Error() string { return "error reading DNS config: " + e.Err.Error() }
func (e *DNSConfigError) Timeout() bool { return false }
func (e *DNSConfigError) Temporary() bool { return false }
+// Various errors contained in DNSError.
+var (
+ errNoSuchHost = errors.New("no such host")
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+ Err string // description of the error
+ Name string // name looked for
+ Server string // server used
+ IsTimeout bool // if true, timed out; not all timeouts set this
+}
+
+func (e *DNSError) Error() string {
+ if e == nil {
+ return "<nil>"
+ }
+ s := "lookup " + e.Name
+ if e.Server != "" {
+ s += " on " + e.Server
+ }
+ s += ": " + e.Err
+ return s
+}
+
+// Timeout reports whether the DNS lookup is known to have timed out.
+// This is not always known; a DNS lookup may fail due to a timeout
+// and return a DNSError for which Timeout returns false.
+func (e *DNSError) Timeout() bool { return e.IsTimeout }
+
+// Temporary reports whether the DNS error is known to be temporary.
+// This is not always known; a DNS lookup may fail due to a temporary
+// error and return a DNSError for which Temporary returns false.
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
type writerOnly struct {
io.Writer
}
@@ -412,10 +567,6 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
var threadLimit = make(chan struct{}, 500)
-// Using send for acquire is fine here because we are not using this
-// to protect any memory. All we care about is the number of goroutines
-// making calls at a time.
-
func acquireThread() {
threadLimit <- struct{}{}
}