From 5d2ee9d90afc8277d20a1f40056caa047fae695b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 17 Jun 2009 21:44:26 -0700 Subject: [PATCH] add Addr() string to net.Listener interface. use it to avoid use of fixed ports in tests. convert google/net/rpc to gotest R=r DELTA=523 (275 added, 229 deleted, 19 changed) OCL=30458 CL=30460 --- src/pkg/Makefile | 2 ++ src/pkg/net/fd.go | 9 ++++++ src/pkg/net/net.go | 35 ++++++++++++++---------- src/pkg/net/server_test.go | 25 +++++++++++------ src/pkg/syscall/syscall_darwin.go | 22 +++++++++++++-- src/pkg/syscall/syscall_linux.go | 18 ++++++++++++ src/pkg/syscall/syscall_linux_386.go | 13 ++++++++- src/pkg/syscall/syscall_linux_amd64.go | 2 ++ src/pkg/syscall/zsyscall_darwin_386.go | 12 ++++++++ src/pkg/syscall/zsyscall_darwin_amd64.go | 12 ++++++++ src/pkg/syscall/zsyscall_linux_amd64.go | 12 ++++++++ 11 files changed, 136 insertions(+), 26 deletions(-) diff --git a/src/pkg/Makefile b/src/pkg/Makefile index 3339a9d369..b8eb8641ab 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -70,12 +70,14 @@ TEST=\ archive/tar\ bignum\ bufio\ + bytes\ compress/flate\ compress/gzip\ container/list\ container/vector\ crypto/aes\ crypto/block\ + crypto/hmac\ crypto/md5\ crypto/sha1\ datafmt\ diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go index 9404ed0bd4..befcd554fe 100644 --- a/src/pkg/net/fd.go +++ b/src/pkg/net/fd.go @@ -427,3 +427,12 @@ func (fd *netFD) accept() (nfd *netFD, err os.Error) { return nfd, nil } +func (fd *netFD) addr() string { + sa, err := syscall.Getsockname(fd.fd); + if err != 0 { + return ""; + } + // TODO(rsc): woud like to say err not err1 but 6g complains + addr, err1 := sockaddrToString(sa); + return addr; +} diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go index 5c442e6a45..8d7e7ba328 100644 --- a/src/pkg/net/net.go +++ b/src/pkg/net/net.go @@ -440,18 +440,15 @@ func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD // Parse addresses (unless they are empty). var lip, rip IP; var lport, rport int; - var lerr, rerr os.Error; if laddr != "" { - lip, lport, lerr = hostPortToIP(net, laddr, mode); - if lerr != nil { - return nil, lerr + if lip, lport, err = hostPortToIP(net, laddr, mode); err != nil { + return } } if raddr != "" { - rip, rport, rerr = hostPortToIP(net, raddr, mode); - if rerr != nil { - return nil, rerr + if rip, rport, err = hostPortToIP(net, raddr, mode); err != nil { + return } } @@ -482,15 +479,13 @@ func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD var la, ra syscall.Sockaddr; if lip != nil { - la, lerr = ipToSockaddr(family, lip, lport); - if lerr != nil { - return nil, lerr + if la, err = ipToSockaddr(family, lip, lport); err != nil { + return } } if rip != nil { - ra, rerr = ipToSockaddr(family, rip, rport); - if rerr != nil { - return nil, rerr + if ra, err = ipToSockaddr(family, rip, rport); err != nil { + return } } @@ -727,6 +722,11 @@ func (l *ListenerUnix) Close() os.Error { return err; } +// Addr returns the listener's network address. +func (l *ListenerUnix) Addr() string { + return l.fd.addr(); +} + // Dial connects to the remote address raddr on the network net. // If the string laddr is not empty, it is used as the local address // for the connection. @@ -776,6 +776,7 @@ func Dial(net, laddr, raddr string) (c Conn, err os.Error) { type Listener interface { Accept() (c Conn, raddr string, err os.Error); Close() os.Error; + Addr() string; // Listener's network address } // ListenerTCP is a TCP network listener. @@ -783,11 +784,12 @@ type Listener interface { // instead of assuming TCP. type ListenerTCP struct { fd *netFD; - laddr string } // ListenTCP announces on the TCP address laddr and returns a TCP listener. // Net must be "tcp", "tcp4", or "tcp6". +// If laddr has a port of 0, it means to listen on some available port. +// The caller can use l.Addr() to retrieve the chosen address. func ListenTCP(net, laddr string) (l *ListenerTCP, err os.Error) { fd, e := internetSocket(net, laddr, "", syscall.SOCK_STREAM, "listen"); if e != nil { @@ -835,6 +837,11 @@ func (l *ListenerTCP) Close() os.Error { return l.fd.Close() } +// Addr returns the listener's network address. +func (l *ListenerTCP) Addr() string { + return l.fd.addr(); +} + // Listen announces on the local network address laddr. // The network string net must be "tcp", "tcp4", "tcp6", // "unix", or "unix-dgram". diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go index 586b553659..f1c7134e44 100644 --- a/src/pkg/net/server_test.go +++ b/src/pkg/net/server_test.go @@ -8,6 +8,7 @@ import ( "io"; "net"; "os"; + "strings"; "syscall"; "testing"; ) @@ -25,12 +26,12 @@ func runEcho(fd io.ReadWriter, done chan<- int) { done <- 1 } -func runServe(t *testing.T, network, addr string, listening, done chan<- int) { +func runServe(t *testing.T, network, addr string, listening chan<- string, done chan<- int) { l, err := net.Listen(network, addr); if err != nil { t.Fatalf("net.Listen(%q, %q) = _, %v", network, addr, err); } - listening <- 1; + listening <- l.Addr(); for { fd, addr, err := l.Accept(); @@ -68,20 +69,26 @@ func connect(t *testing.T, network, addr string) { func doTest(t *testing.T, network, listenaddr, dialaddr string) { t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr); - listening := make(chan int); + listening := make(chan string); done := make(chan int); + if network == "tcp" { + listenaddr += ":0"; // any available port + } go runServe(t, network, listenaddr, listening, done); - <-listening; // wait for server to start + addr := <-listening; // wait for server to start + if network == "tcp" { + dialaddr += addr[strings.LastIndex(addr, ":"):len(addr)]; + } connect(t, network, dialaddr); <-done; // make sure server stopped } func TestTcpServer(t *testing.T) { - doTest(t, "tcp", "0.0.0.0:9997", "127.0.0.1:9997"); - doTest(t, "tcp", "[::]:9997", "[::ffff:127.0.0.1]:9997"); - doTest(t, "tcp", "[::]:9997", "127.0.0.1:9997"); - doTest(t, "tcp", ":9997", "127.0.0.1:9997"); - doTest(t, "tcp", "0.0.0.0:9997", "[::ffff:127.0.0.1]:9997"); + doTest(t, "tcp", "0.0.0.0", "127.0.0.1"); + doTest(t, "tcp", "[::]", "[::ffff:127.0.0.1]"); + doTest(t, "tcp", "[::]", "127.0.0.1"); + doTest(t, "tcp", "", "127.0.0.1"); + doTest(t, "tcp", "0.0.0.0", "[::ffff:127.0.0.1]"); } func TestUnixServer(t *testing.T) { diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go index 8ea78c6675..dcb92e0aca 100644 --- a/src/pkg/syscall/syscall_darwin.go +++ b/src/pkg/syscall/syscall_darwin.go @@ -164,6 +164,8 @@ func Sleep(ns int64) (errno int) { //sys connect(s int, addr uintptr, addrlen _Socklen) (errno int) //sys socket(domain int, typ int, proto int) (fd int, errno int) //sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) +//sys getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) +//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) // For testing: clients can set this flag to force // creation of IPv6 sockets to return EAFNOSUPPORT. @@ -292,6 +294,24 @@ func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return; } +func Getsockname(fd int) (sa Sockaddr, errno int) { + var rsa RawSockaddrAny; + var len _Socklen = SizeofSockaddrAny; + if errno = getsockname(fd, &rsa, &len); errno != 0 { + return; + } + return anyToSockaddr(&rsa); +} + +func Getpeername(fd int) (sa Sockaddr, errno int) { + var rsa RawSockaddrAny; + var len _Socklen = SizeofSockaddrAny; + if errno = getpeername(fd, &rsa, &len); errno != 0 { + return; + } + return anyToSockaddr(&rsa); +} + func Bind(fd int, sa Sockaddr) (errno int) { ptr, n, err := sa.sockaddr(); if err != 0 { @@ -345,8 +365,6 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, errno // Acct(name nil-string) (errno int) // Futimes(fd int, timeval *Timeval) (errno int) // Pointer to 2 timevals! // Gethostuuid(uuid *byte, timeout *Timespec) (errno int) -// Getpeername(fd int, addr *Sockaddr, addrlen *int) (errno int) -// Getsockname(fd int, addr *Sockaddr, addrlen *int) (errno int) // Getsockopt(s int, level int, name int, val *byte, vallen *int) (errno int) // Madvise(addr *byte, len int, behav int) (errno int) // Mprotect(addr *byte, len int, prot int) (errno int) diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go index ae3eee777c..4c9ac28756 100644 --- a/src/pkg/syscall/syscall_linux.go +++ b/src/pkg/syscall/syscall_linux.go @@ -324,6 +324,24 @@ func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return; } +func Getsockname(fd int) (sa Sockaddr, errno int) { + var rsa RawSockaddrAny; + var len _Socklen = SizeofSockaddrAny; + if errno = getsockname(fd, &rsa, &len); errno != 0 { + return; + } + return anyToSockaddr(&rsa); +} + +func Getpeername(fd int) (sa Sockaddr, errno int) { + var rsa RawSockaddrAny; + var len _Socklen = SizeofSockaddrAny; + if errno = getpeername(fd, &rsa, &len); errno != 0 { + return; + } + return anyToSockaddr(&rsa); +} + func Bind(fd int, sa Sockaddr) (errno int) { ptr, n, err := sa.sockaddr(); if err != 0 { diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go index f20ec10614..b44428e119 100644 --- a/src/pkg/syscall/syscall_linux_386.go +++ b/src/pkg/syscall/syscall_linux_386.go @@ -99,6 +99,18 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) { return; } +func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + var _ int; + _, errno = socketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0); + return; +} + +func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + var _ int; + _, errno = socketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0); + return; +} + func bind(s int, addr uintptr, addrlen _Socklen) (errno int) { var _ int; _, errno = socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0); @@ -127,4 +139,3 @@ func Listen(s int, n int) (errno int) { _, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0); return; } - diff --git a/src/pkg/syscall/syscall_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go index 3455184796..4f7b33bc12 100644 --- a/src/pkg/syscall/syscall_linux_amd64.go +++ b/src/pkg/syscall/syscall_linux_amd64.go @@ -36,6 +36,8 @@ import "syscall" //sys setgroups(n int, list *_Gid_t) (errno int) //sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) //sys socket(domain int, typ int, proto int) (fd int, errno int) +//sys getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) +//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) func Getpagesize() int { return 4096 diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go index 6974c83bf8..6241efa514 100644 --- a/src/pkg/syscall/zsyscall_darwin_386.go +++ b/src/pkg/syscall/zsyscall_darwin_386.go @@ -68,6 +68,18 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) return; } +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { r0, r1, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))); n = int(r0); diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go index e6b99916e4..49e17d43b1 100644 --- a/src/pkg/syscall/zsyscall_darwin_amd64.go +++ b/src/pkg/syscall/zsyscall_darwin_amd64.go @@ -68,6 +68,18 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int) return; } +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) { r0, r1, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout))); n = int(r0); diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go index 0766b8318f..09f21df2ab 100644 --- a/src/pkg/syscall/zsyscall_linux_amd64.go +++ b/src/pkg/syscall/zsyscall_linux_amd64.go @@ -760,5 +760,17 @@ func socket(domain int, typ int, proto int) (fd int, errno int) { return; } +func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + +func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) { + r0, r1, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))); + errno = int(e1); + return; +} + -- 2.48.1