net: implement non-blocking connect

Refactored bind/connect from sock.go into netFD.connect(), as
a consequence newFD() doesn't accept laddr/raddr anymore, and
expects an (optional) call to netFD.connect() followed by a
call to netFD.setAddr().
Windows code is updated, but still uses blocking connect,
since otherwise it needs support for ConnectEx syscall.

R=brainman, rsc
CC=golang-dev
https://golang.org/cl/4303060
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index df4dbce..3e87800 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -274,19 +274,25 @@
 	pollserver = p
 }
 
-func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
 	onceStartServer.Do(startServer)
 	if e := syscall.SetNonblock(fd, true); e != 0 {
-		return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
+		return nil, os.Errno(e)
 	}
 	f = &netFD{
 		sysfd:  fd,
 		family: family,
 		proto:  proto,
 		net:    net,
-		laddr:  laddr,
-		raddr:  raddr,
 	}
+	f.cr = make(chan bool, 1)
+	f.cw = make(chan bool, 1)
+	return f, nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+	fd.laddr = laddr
+	fd.raddr = raddr
 	var ls, rs string
 	if laddr != nil {
 		ls = laddr.String()
@@ -294,10 +300,31 @@
 	if raddr != nil {
 		rs = raddr.String()
 	}
-	f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
-	f.cr = make(chan bool, 1)
-	f.cw = make(chan bool, 1)
-	return f, nil
+	fd.sysfile = os.NewFile(fd.sysfd, fd.net+":"+ls+"->"+rs)
+}
+
+func (fd *netFD) connect(la, ra syscall.Sockaddr) (err os.Error) {
+	if la != nil {
+		e := syscall.Bind(fd.sysfd, la)
+		if e != 0 {
+			return os.Errno(e)
+		}
+	}
+	if ra != nil {
+		e := syscall.Connect(fd.sysfd, ra)
+		if e == syscall.EINPROGRESS {
+			var errno int
+			pollserver.WaitWrite(fd)
+			e, errno = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+			if errno != 0 {
+				return os.NewSyscallError("getsockopt", errno)
+			}
+		}
+		if e != 0 {
+			return os.Errno(e)
+		}
+	}
+	return nil
 }
 
 // Add a reference to this fd.
@@ -593,10 +620,11 @@
 	syscall.CloseOnExec(s)
 	syscall.ForkLock.RUnlock()
 
-	if nfd, err = newFD(s, fd.family, fd.proto, fd.net, fd.laddr, toAddr(sa)); err != nil {
+	if nfd, err = newFD(s, fd.family, fd.proto, fd.net); err != nil {
 		syscall.Close(s)
 		return nil, err
 	}
+	nfd.setAddr(fd.laddr, toAddr(sa))
 	return nfd, nil
 }
 
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 63a8fbc..0abf230 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -225,29 +225,48 @@
 	wio             sync.Mutex
 }
 
-func allocFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD) {
+func allocFD(fd, family, proto int, net string) (f *netFD) {
 	f = &netFD{
 		sysfd:  fd,
 		family: family,
 		proto:  proto,
 		net:    net,
-		laddr:  laddr,
-		raddr:  raddr,
 	}
 	runtime.SetFinalizer(f, (*netFD).Close)
 	return f
 }
 
-func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
+func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
 	if initErr != nil {
 		return nil, initErr
 	}
 	onceStartServer.Do(startServer)
 	// Associate our socket with resultsrv.iocp.
 	if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
-		return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
+		return nil, os.Errno(e)
 	}
-	return allocFD(fd, family, proto, net, laddr, raddr), nil
+	return allocFD(fd, family, proto, net), nil
+}
+
+func (fd *netFD) setAddr(laddr, raddr Addr) {
+	fd.laddr = laddr
+	fd.raddr = raddr
+}
+
+func (fd *netFD) connect(la, ra syscall.Sockaddr) (err os.Error) {
+	if la != nil {
+		e := syscall.Bind(fd.sysfd, la)
+		if e != 0 {
+			return os.Errno(e)
+		}
+	}
+	if ra != nil {
+		e := syscall.Connect(fd.sysfd, ra)
+		if e != 0 {
+			return os.Errno(e)
+		}
+	}
+	return nil
 }
 
 // Add a reference to this fd.
@@ -497,7 +516,9 @@
 	lsa, _ := lrsa.Sockaddr()
 	rsa, _ := rrsa.Sockaddr()
 
-	return allocFD(s, fd.family, fd.proto, fd.net, toAddr(lsa), toAddr(rsa)), nil
+	nfd = allocFD(s, fd.family, fd.proto, fd.net)
+	nfd.setAddr(toAddr(lsa), toAddr(rsa))
+	return nfd, nil
 }
 
 // Not implemeted functions.
diff --git a/src/pkg/net/file.go b/src/pkg/net/file.go
index 5439ed9..0e411a1 100644
--- a/src/pkg/net/file.go
+++ b/src/pkg/net/file.go
@@ -9,7 +9,7 @@
 	"syscall"
 )
 
-func newFileFD(f *os.File) (*netFD, os.Error) {
+func newFileFD(f *os.File) (nfd *netFD, err os.Error) {
 	fd, errno := syscall.Dup(f.Fd())
 	if errno != 0 {
 		return nil, os.NewSyscallError("dup", errno)
@@ -50,7 +50,11 @@
 	sa, _ = syscall.Getpeername(fd)
 	raddr := toAddr(sa)
 
-	return newFD(fd, 0, proto, laddr.Network(), laddr, raddr)
+	if nfd, err = newFD(fd, 0, proto, laddr.Network()); err != nil {
+		return nil, err
+	}
+	nfd.setAddr(laddr, raddr)
+	return nfd, nil
 }
 
 // FileConn returns a copy of the network connection corresponding to
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index 2681626..9b99ad5 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -44,33 +44,22 @@
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
 	}
 
-	if la != nil {
-		e = syscall.Bind(s, la)
-		if e != 0 {
-			closesocket(s)
-			return nil, os.Errno(e)
-		}
-	}
-
-	if ra != nil {
-		e = syscall.Connect(s, ra)
-		if e != 0 {
-			closesocket(s)
-			return nil, os.Errno(e)
-		}
-	}
-
-	sa, _ := syscall.Getsockname(s)
-	laddr := toAddr(sa)
-	sa, _ = syscall.Getpeername(s)
-	raddr := toAddr(sa)
-
-	fd, err = newFD(s, f, p, net, laddr, raddr)
-	if err != nil {
+	if fd, err = newFD(s, f, p, net); err != nil {
 		closesocket(s)
 		return nil, err
 	}
 
+	if err = fd.connect(la, ra); err != nil {
+		closesocket(s)
+		return nil, err
+	}
+
+	sa, _ := syscall.Getsockname(fd.sysfd)
+	laddr := toAddr(sa)
+	sa, _ = syscall.Getpeername(fd.sysfd)
+	raddr := toAddr(sa)
+
+	fd.setAddr(laddr, raddr)
 	return fd, nil
 }