diff options
Diffstat (limited to 'libgo/go/net/net.go')
-rw-r--r-- | libgo/go/net/net.go | 241 |
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{}{} } |