net: introduce net.Error interface

Adds two more methods, Timeout and Temporary.
Implemented by os.Errno too.  The intent is to make
the checks for os.EAGAIN a little less clunky.
It should also let us clean up a bug that Mike Solomon
pointed out: if a network server gets an "out of file descriptors"
error from Accept, the listener should not stop.
It will be able to check this because that error would
have Temporary() == true.

Also clean up some underscore names.

Fixes #442.

R=r
CC=golang-dev, msolo
https://golang.org/cl/957045
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index 02f7319..1fa537c 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"io"
 	"once"
 	"os"
 	"sync"
@@ -44,6 +45,12 @@
 	ncr, ncw int
 }
 
+type InvalidConnError struct{}
+
+func (e *InvalidConnError) String() string  { return "invalid net.Conn" }
+func (e *InvalidConnError) Temporary() bool { return false }
+func (e *InvalidConnError) Timeout() bool   { return false }
+
 // A pollServer helps FDs determine when to retry a non-blocking
 // read or write after they get EAGAIN.  When an FD needs to wait,
 // send the fd on s.cr (for a read) or s.cw (for a write) to pass the
@@ -342,13 +349,6 @@
 	fd.sysmu.Unlock()
 }
 
-func isEAGAIN(e os.Error) bool {
-	if e1, ok := e.(*os.PathError); ok {
-		return e1.Error == os.EAGAIN
-	}
-	return e == os.EAGAIN
-}
-
 func (fd *netFD) Close() os.Error {
 	if fd == nil || fd.sysfile == nil {
 		return os.EINVAL
@@ -374,17 +374,24 @@
 	} else {
 		fd.rdeadline = 0
 	}
+	var oserr os.Error
 	for {
-		n, err = fd.sysfile.Read(p)
-		if isEAGAIN(err) && fd.rdeadline >= 0 {
+		var errno int
+		n, errno = syscall.Read(fd.sysfile.Fd(), p)
+		if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
 			pollserver.WaitRead(fd)
 			continue
 		}
+		if errno != 0 {
+			n = 0
+			oserr = os.Errno(errno)
+		} else if n == 0 && errno == 0 && fd.proto != syscall.SOCK_DGRAM {
+			err = os.EOF
+		}
 		break
 	}
-	if fd.proto == syscall.SOCK_DGRAM && err == os.EOF {
-		// 0 in datagram protocol just means 0-length packet
-		err = nil
+	if oserr != nil {
+		err = &OpError{"read", fd.net, fd.raddr, oserr}
 	}
 	return
 }
@@ -402,6 +409,7 @@
 	} else {
 		fd.rdeadline = 0
 	}
+	var oserr os.Error
 	for {
 		var errno int
 		n, sa, errno = syscall.Recvfrom(fd.sysfd, p, 0)
@@ -411,10 +419,13 @@
 		}
 		if errno != 0 {
 			n = 0
-			err = &os.PathError{"recvfrom", fd.sysfile.Name(), os.Errno(errno)}
+			oserr = os.Errno(errno)
 		}
 		break
 	}
+	if oserr != nil {
+		err = &OpError{"read", fd.net, fd.laddr, oserr}
+	}
 	return
 }
 
@@ -431,25 +442,32 @@
 	} else {
 		fd.wdeadline = 0
 	}
-	err = nil
 	nn := 0
-	first := true // force at least one Write, to send 0-length datagram packets
-	for nn < len(p) || first {
-		first = false
-		n, err = fd.sysfile.Write(p[nn:])
+	var oserr os.Error
+	for {
+		n, errno := syscall.Write(fd.sysfile.Fd(), p[nn:])
 		if n > 0 {
 			nn += n
 		}
 		if nn == len(p) {
 			break
 		}
-		if isEAGAIN(err) && fd.wdeadline >= 0 {
+		if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
 			pollserver.WaitWrite(fd)
 			continue
 		}
-		if n == 0 || err != nil {
+		if errno != 0 {
+			n = 0
+			oserr = os.Errno(errno)
 			break
 		}
+		if n == 0 {
+			oserr = io.ErrUnexpectedEOF
+			break
+		}
+	}
+	if oserr != nil {
+		err = &OpError{"write", fd.net, fd.raddr, oserr}
 	}
 	return nn, err
 }
@@ -467,7 +485,7 @@
 	} else {
 		fd.wdeadline = 0
 	}
-	err = nil
+	var oserr os.Error
 	for {
 		errno := syscall.Sendto(fd.sysfd, p, 0, sa)
 		if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
@@ -475,12 +493,14 @@
 			continue
 		}
 		if errno != 0 {
-			err = &os.PathError{"sendto", fd.sysfile.Name(), os.Errno(errno)}
+			oserr = os.Errno(errno)
 		}
 		break
 	}
-	if err == nil {
+	if oserr == nil {
 		n = len(p)
+	} else {
+		err = &OpError{"write", fd.net, fd.raddr, oserr}
 	}
 	return
 }