From 48080209fa53b6ea88c86e9f445c431b4cd1e47b Mon Sep 17 00:00:00 2001 From: ian Date: Fri, 21 Jan 2011 18:19:03 +0000 Subject: Remove the types float and complex. Update to current version of Go library. Update testsuite for removed types. * go-lang.c (go_langhook_init): Omit float_type_size when calling go_create_gogo. * go-c.h: Update declaration of go_create_gogo. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@169098 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgo/go/net/dial.go | 6 +- libgo/go/net/dnsclient.go | 54 +++++++- libgo/go/net/dnsname_test.go | 18 +-- libgo/go/net/fd.go | 79 ++++++++++++ libgo/go/net/fd_windows.go | 269 ++++++++++++++++++++++++++++++++------- libgo/go/net/hosts.go | 31 ++++- libgo/go/net/ipsock.go | 2 +- libgo/go/net/net_test.go | 49 +++++++ libgo/go/net/port.go | 4 +- libgo/go/net/resolv_windows.go | 29 +++++ libgo/go/net/server_test.go | 3 + libgo/go/net/sock.go | 6 +- libgo/go/net/tcpsock.go | 2 +- libgo/go/net/textproto/reader.go | 6 +- libgo/go/net/timeout_test.go | 5 - libgo/go/net/unixsock.go | 85 ++++++++++--- 16 files changed, 548 insertions(+), 100 deletions(-) (limited to 'libgo/go/net') diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index 9a4c8f68893..03b9d87be33 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -59,7 +59,7 @@ func Dial(net, laddr, raddr string) (c Conn, err os.Error) { return nil, err } return c, nil - case "unix", "unixgram": + case "unix", "unixgram", "unixpacket": var la, ra *UnixAddr if raddr != "" { if ra, err = ResolveUnixAddr(net, raddr); err != nil { @@ -102,7 +102,7 @@ Error: // Listen announces on the local network address laddr. // The network string net must be a stream-oriented -// network: "tcp", "tcp4", "tcp6", or "unix". +// network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket". func Listen(net, laddr string) (l Listener, err os.Error) { switch net { case "tcp", "tcp4", "tcp6": @@ -117,7 +117,7 @@ func Listen(net, laddr string) (l Listener, err os.Error) { return nil, err } return l, nil - case "unix": + case "unix", "unixpacket": var la *UnixAddr if laddr != "" { if la, err = ResolveUnixAddr(net, laddr); err != nil { diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go index f1cd47bb19c..87d76261f8e 100644 --- a/libgo/go/net/dnsclient.go +++ b/libgo/go/net/dnsclient.go @@ -15,6 +15,8 @@ package net import ( + "bytes" + "fmt" "os" "rand" "sync" @@ -357,9 +359,59 @@ func LookupMX(name string) (entries []*MX, err os.Error) { return } entries = make([]*MX, len(records)) - for i := 0; i < len(records); i++ { + for i := range records { r := records[i].(*dnsRR_MX) entries[i] = &MX{r.Mx, r.Pref} } return } + +// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP +// address addr suitable for rDNS (PTR) record lookup or an error if it fails +// to parse the IP address. +func reverseaddr(addr string) (arpa string, err os.Error) { + ip := ParseIP(addr) + if ip == nil { + return "", &DNSError{Error: "unrecognized address", Name: addr} + } + if ip.To4() != nil { + return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil + } + // Must be IPv6 + var buf bytes.Buffer + // Add it, in reverse, to the buffer + for i := len(ip) - 1; i >= 0; i-- { + s := fmt.Sprintf("%02x", ip[i]) + buf.WriteByte(s[1]) + buf.WriteByte('.') + buf.WriteByte(s[0]) + buf.WriteByte('.') + } + // Append "ip6.arpa." and return (buf already has the final .) + return buf.String() + "ip6.arpa.", nil +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +func LookupAddr(addr string) (name []string, err os.Error) { + name = lookupStaticAddr(addr) + if len(name) > 0 { + return + } + var arpa string + arpa, err = reverseaddr(addr) + if err != nil { + return + } + var records []dnsRR + _, records, err = lookup(arpa, dnsTypePTR) + if err != nil { + return + } + name = make([]string, len(records)) + for i := range records { + r := records[i].(*dnsRR_PTR) + name[i] = r.Ptr + } + return +} diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go index fd65dcb1720..f4089c5db8a 100644 --- a/libgo/go/net/dnsname_test.go +++ b/libgo/go/net/dnsname_test.go @@ -16,15 +16,15 @@ type testCase struct { var tests = []testCase{ // RFC2181, section 11. - testCase{"_xmpp-server._tcp.google.com", true}, - testCase{"_xmpp-server._tcp.google.com", true}, - testCase{"foo.com", true}, - testCase{"1foo.com", true}, - testCase{"26.0.0.73.com", true}, - testCase{"fo-o.com", true}, - testCase{"fo1o.com", true}, - testCase{"foo1.com", true}, - testCase{"a.b..com", false}, + {"_xmpp-server._tcp.google.com", true}, + {"_xmpp-server._tcp.google.com", true}, + {"foo.com", true}, + {"1foo.com", true}, + {"26.0.0.73.com", true}, + {"fo-o.com", true}, + {"fo1o.com", true}, + {"foo1.com", true}, + {"a.b..com", false}, } func getTestCases(ch chan<- *testCase) { diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go index d300e4bda53..896178f18ef 100644 --- a/libgo/go/net/fd.go +++ b/libgo/go/net/fd.go @@ -401,6 +401,42 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { return } +func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) { + if fd == nil || fd.sysfile == nil { + return 0, 0, 0, nil, os.EINVAL + } + fd.rio.Lock() + defer fd.rio.Unlock() + fd.incref() + defer fd.decref() + if fd.rdeadline_delta > 0 { + fd.rdeadline = pollserver.Now() + fd.rdeadline_delta + } else { + fd.rdeadline = 0 + } + var oserr os.Error + for { + var errno int + n, oobn, flags, sa, errno = syscall.Recvmsg(fd.sysfd, p, oob, 0) + if errno == syscall.EAGAIN && fd.rdeadline >= 0 { + pollserver.WaitRead(fd) + continue + } + if errno != 0 { + oserr = os.Errno(errno) + } + if n == 0 { + oserr = os.EOF + } + break + } + if oserr != nil { + err = &OpError{"read", fd.net, fd.laddr, oserr} + return + } + return +} + func (fd *netFD) Write(p []byte) (n int, err os.Error) { if fd == nil { return 0, os.EINVAL @@ -481,6 +517,41 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { return } +func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) { + if fd == nil || fd.sysfile == nil { + return 0, 0, os.EINVAL + } + fd.wio.Lock() + defer fd.wio.Unlock() + fd.incref() + defer fd.decref() + if fd.wdeadline_delta > 0 { + fd.wdeadline = pollserver.Now() + fd.wdeadline_delta + } else { + fd.wdeadline = 0 + } + var oserr os.Error + for { + var errno int + errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0) + if errno == syscall.EAGAIN && fd.wdeadline >= 0 { + pollserver.WaitWrite(fd) + continue + } + if errno != 0 { + oserr = os.Errno(errno) + } + break + } + if oserr == nil { + n = len(p) + oobn = len(oob) + } else { + err = &OpError{"write", fd.net, fd.raddr, oserr} + } + return +} + func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { if fd == nil || fd.sysfile == nil { return nil, os.EINVAL @@ -496,6 +567,10 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. var s, e int var sa syscall.Sockaddr for { + if fd.closing { + syscall.ForkLock.RUnlock() + return nil, os.EINVAL + } s, sa, e = syscall.Accept(fd.sysfd) if e != syscall.EAGAIN { break @@ -531,3 +606,7 @@ func (fd *netFD) dup() (f *os.File, err os.Error) { return os.NewFile(ns, fd.sysfile.Name()), nil } + +func closesocket(s int) (errno int) { + return syscall.Close(s) +} diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index 1da2ca47ff1..9b91eb398cb 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -6,13 +6,13 @@ package net import ( "os" + "runtime" "sync" "syscall" + "time" "unsafe" ) -// BUG(brainman): The Windows implementation does not implement SetTimeout. - // IO completion result parameters. type ioResult struct { key uint32 @@ -28,15 +28,14 @@ type netFD struct { closing bool // immutable until Close - sysfd int - family int - proto int - sysfile *os.File - cr chan *ioResult - cw chan *ioResult - net string - laddr Addr - raddr Addr + sysfd int + family int + proto int + cr chan *ioResult + cw chan *ioResult + net string + laddr Addr + raddr Addr // owned by client rdeadline_delta int64 @@ -79,6 +78,8 @@ type ioPacket struct { // Link to the io owner. c chan *ioResult + + w *syscall.WSABuf } func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) { @@ -126,6 +127,8 @@ func startServer() { panic("Start pollServer: " + err.String() + "\n") } pollserver = p + + go timeoutIO() } var initErr os.Error @@ -143,20 +146,13 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err sysfd: fd, family: family, proto: proto, - cr: make(chan *ioResult), - cw: make(chan *ioResult), + cr: make(chan *ioResult, 1), + cw: make(chan *ioResult, 1), net: net, laddr: laddr, raddr: raddr, } - var ls, rs string - if laddr != nil { - ls = laddr.String() - } - if raddr != nil { - rs = raddr.String() - } - f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs) + runtime.SetFinalizer(f, (*netFD).Close) return f, nil } @@ -178,15 +174,16 @@ func (fd *netFD) decref() { // can handle the extra OS processes. Otherwise we'll need to // use the pollserver for Close too. Sigh. syscall.SetNonblock(fd.sysfd, false) - fd.sysfile.Close() - fd.sysfile = nil + closesocket(fd.sysfd) fd.sysfd = -1 + // no need for a finalizer anymore + runtime.SetFinalizer(fd, nil) } fd.sysmu.Unlock() } func (fd *netFD) Close() os.Error { - if fd == nil || fd.sysfile == nil { + if fd == nil || fd.sysfd == -1 { return os.EINVAL } @@ -205,6 +202,80 @@ func newWSABuf(p []byte) *syscall.WSABuf { return &syscall.WSABuf{uint32(len(p)), p0} } +func waitPacket(fd *netFD, pckt *ioPacket, mode int) (r *ioResult) { + var delta int64 + if mode == 'r' { + delta = fd.rdeadline_delta + } + if mode == 'w' { + delta = fd.wdeadline_delta + } + if delta <= 0 { + return <-pckt.c + } + + select { + case r = <-pckt.c: + case <-time.After(delta): + a := &arg{f: cancel, fd: fd, pckt: pckt, c: make(chan int)} + ioChan <- a + <-a.c + r = <-pckt.c + if r.errno == 995 { // IO Canceled + r.errno = syscall.EWOULDBLOCK + } + } + return r +} + +const ( + read = iota + readfrom + write + writeto + cancel +) + +type arg struct { + f int + fd *netFD + pckt *ioPacket + done *uint32 + flags *uint32 + rsa *syscall.RawSockaddrAny + size *int32 + sa *syscall.Sockaddr + c chan int +} + +var ioChan chan *arg = make(chan *arg) + +func timeoutIO() { + // CancelIO only cancels all pending input and output (I/O) operations that are + // issued by the calling thread for the specified file, does not cancel I/O + // operations that other threads issue for a file handle. So we need do all timeout + // I/O in single OS thread. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + for { + o := <-ioChan + var e int + switch o.f { + case read: + e = syscall.WSARecv(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, &o.pckt.o, nil) + case readfrom: + e = syscall.WSARecvFrom(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, o.flags, o.rsa, o.size, &o.pckt.o, nil) + case write: + e = syscall.WSASend(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, uint32(0), &o.pckt.o, nil) + case writeto: + e = syscall.WSASendto(uint32(o.fd.sysfd), o.pckt.w, 1, o.done, 0, *o.sa, &o.pckt.o, nil) + case cancel: + _, e = syscall.CancelIo(uint32(o.fd.sysfd)) + } + o.c <- e + } +} + func (fd *netFD) Read(p []byte) (n int, err os.Error) { if fd == nil { return 0, os.EINVAL @@ -213,15 +284,23 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { defer fd.rio.Unlock() fd.incref() defer fd.decref() - if fd.sysfile == nil { + if fd.sysfd == -1 { return 0, os.EINVAL } // Submit receive request. var pckt ioPacket pckt.c = fd.cr + pckt.w = newWSABuf(p) var done uint32 flags := uint32(0) - e := syscall.WSARecv(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &pckt.o, nil) + var e int + if fd.rdeadline_delta > 0 { + a := &arg{f: read, fd: fd, pckt: &pckt, done: &done, flags: &flags, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSARecv(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -231,7 +310,7 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'r') if r.errno != 0 { err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -243,8 +322,51 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) { } func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) { - var r syscall.Sockaddr - return 0, r, nil + if fd == nil { + return 0, nil, os.EINVAL + } + if len(p) == 0 { + return 0, nil, nil + } + fd.rio.Lock() + defer fd.rio.Unlock() + fd.incref() + defer fd.decref() + if fd.sysfd == -1 { + return 0, nil, os.EINVAL + } + // Submit receive request. + var pckt ioPacket + pckt.c = fd.cr + pckt.w = newWSABuf(p) + var done uint32 + flags := uint32(0) + var rsa syscall.RawSockaddrAny + l := int32(unsafe.Sizeof(rsa)) + var e int + if fd.rdeadline_delta > 0 { + a := &arg{f: readfrom, fd: fd, pckt: &pckt, done: &done, flags: &flags, rsa: &rsa, size: &l, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSARecvFrom(uint32(fd.sysfd), pckt.w, 1, &done, &flags, &rsa, &l, &pckt.o, nil) + } + switch e { + case 0: + // IO completed immediately, but we need to get our completion message anyway. + case syscall.ERROR_IO_PENDING: + // IO started, and we have to wait for it's completion. + default: + return 0, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)} + } + // Wait for our request to complete. + r := waitPacket(fd, &pckt, 'r') + if r.errno != 0 { + err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)} + } + n = int(r.qty) + sa, _ = rsa.Sockaddr() + return } func (fd *netFD) Write(p []byte) (n int, err os.Error) { @@ -255,14 +377,22 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { defer fd.wio.Unlock() fd.incref() defer fd.decref() - if fd.sysfile == nil { + if fd.sysfd == -1 { return 0, os.EINVAL } // Submit send request. var pckt ioPacket pckt.c = fd.cw + pckt.w = newWSABuf(p) var done uint32 - e := syscall.WSASend(uint32(fd.sysfd), newWSABuf(p), 1, &done, uint32(0), &pckt.o, nil) + var e int + if fd.wdeadline_delta > 0 { + a := &arg{f: write, fd: fd, pckt: &pckt, done: &done, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSASend(uint32(fd.sysfd), pckt.w, 1, &done, uint32(0), &pckt.o, nil) + } switch e { case 0: // IO completed immediately, but we need to get our completion message anyway. @@ -272,7 +402,7 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)} } // Wait for our request to complete. - r := <-pckt.c + r := waitPacket(fd, &pckt, 'w') if r.errno != 0 { err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -281,11 +411,51 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) { } func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) { - return 0, nil + if fd == nil { + return 0, os.EINVAL + } + if len(p) == 0 { + return 0, nil + } + fd.wio.Lock() + defer fd.wio.Unlock() + fd.incref() + defer fd.decref() + if fd.sysfd == -1 { + return 0, os.EINVAL + } + // Submit send request. + var pckt ioPacket + pckt.c = fd.cw + pckt.w = newWSABuf(p) + var done uint32 + var e int + if fd.wdeadline_delta > 0 { + a := &arg{f: writeto, fd: fd, pckt: &pckt, done: &done, sa: &sa, c: make(chan int)} + ioChan <- a + e = <-a.c + } else { + e = syscall.WSASendto(uint32(fd.sysfd), pckt.w, 1, &done, 0, sa, &pckt.o, nil) + } + switch e { + case 0: + // IO completed immediately, but we need to get our completion message anyway. + case syscall.ERROR_IO_PENDING: + // IO started, and we have to wait for it's completion. + default: + return 0, &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(e)} + } + // Wait for our request to complete. + r := waitPacket(fd, &pckt, 'w') + if r.errno != 0 { + err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)} + } + n = int(r.qty) + return } func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) { - if fd == nil || fd.sysfile == nil { + if fd == nil || fd.sysfd == -1 { return nil, os.EINVAL } fd.incref() @@ -320,21 +490,21 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. case syscall.ERROR_IO_PENDING: // IO started, and we have to wait for it's completion. default: - syscall.Close(s) + closesocket(s) return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)} } // Wait for peer connection. r := <-pckt.c if r.errno != 0 { - syscall.Close(s) + closesocket(s) return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)} } // Inherit properties of the listening socket. e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd) if e != 0 { - syscall.Close(s) + closesocket(s) return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)} } @@ -349,23 +519,20 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. sysfd: s, family: fd.family, proto: fd.proto, - cr: make(chan *ioResult), - cw: make(chan *ioResult), + cr: make(chan *ioResult, 1), + cw: make(chan *ioResult, 1), net: fd.net, laddr: laddr, raddr: raddr, } - var ls, rs string - if laddr != nil { - ls = laddr.String() - } - if raddr != nil { - rs = raddr.String() - } - f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs) + runtime.SetFinalizer(f, (*netFD).Close) return f, nil } +func closesocket(s int) (errno int) { + return syscall.Closesocket(int32(s)) +} + func init() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x101), &d) @@ -378,3 +545,11 @@ func (fd *netFD) dup() (f *os.File, err os.Error) { // TODO: Implement this return nil, os.NewSyscallError("dup", syscall.EWINDOWS) } + +func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) { + return 0, 0, 0, nil, os.EAFNOSUPPORT +} + +func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) { + return 0, 0, os.EAFNOSUPPORT +} diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go index 556d57f112d..8525f578d74 100644 --- a/libgo/go/net/hosts.go +++ b/libgo/go/net/hosts.go @@ -19,16 +19,18 @@ var hostsPath = "/etc/hosts" // Simple cache. var hosts struct { sync.Mutex - data map[string][]string - time int64 - path string + byName map[string][]string + byAddr map[string][]string + time int64 + path string } func readHosts() { now, _, _ := os.Time() hp := hostsPath - if len(hosts.data) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp { + if len(hosts.byName) == 0 || hosts.time+cacheMaxAge <= now || hosts.path != hp { hs := make(map[string][]string) + is := make(map[string][]string) var file *file if file, _ = open(hp); file == nil { return @@ -45,12 +47,14 @@ func readHosts() { for i := 1; i < len(f); i++ { h := f[i] hs[h] = append(hs[h], f[0]) + is[f[0]] = append(is[f[0]], h) } } // Update the data cache. hosts.time, _, _ = os.Time() hosts.path = hp - hosts.data = hs + hosts.byName = hs + hosts.byAddr = is file.close() } } @@ -60,10 +64,23 @@ func lookupStaticHost(host string) []string { hosts.Lock() defer hosts.Unlock() readHosts() - if len(hosts.data) != 0 { - if ips, ok := hosts.data[host]; ok { + if len(hosts.byName) != 0 { + if ips, ok := hosts.byName[host]; ok { return ips } } return nil } + +// rlookupStaticHosts looks up the hosts for the given address from /etc/hosts. +func lookupStaticAddr(addr string) []string { + hosts.Lock() + defer hosts.Unlock() + readHosts() + if len(hosts.byAddr) != 0 { + if hosts, ok := hosts.byAddr[addr]; ok { + return hosts + } + } + return nil +} diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go index dd796bc920e..4ba6a55b96f 100644 --- a/libgo/go/net/ipsock.go +++ b/libgo/go/net/ipsock.go @@ -24,7 +24,7 @@ func kernelSupportsIPv6() bool { } fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if fd >= 0 { - syscall.Close(fd) + closesocket(fd) } return e == 0 } diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go index febfc0a5f42..275b31c0e31 100644 --- a/libgo/go/net/net_test.go +++ b/libgo/go/net/net_test.go @@ -7,6 +7,7 @@ package net import ( "flag" "regexp" + "runtime" "testing" ) @@ -52,6 +53,14 @@ var dialErrorTests = []DialErrorTest{ "unix", "", "/etc/", "dial unix /etc/: ([pP]ermission denied|[sS]ocket operation on non-socket|[cC]onnection refused)", }, + { + "unixpacket", "", "/etc/file-not-found", + "dial unixpacket /etc/file-not-found: no such file or directory", + }, + { + "unixpacket", "", "/etc/", + "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", + }, } func TestDialError(t *testing.T) { @@ -75,3 +84,43 @@ func TestDialError(t *testing.T) { } } } + +var revAddrTests = []struct { + Addr string + Reverse string + ErrPrefix string +}{ + {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, + {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, + {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, + {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, + {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, + {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1.2.3", "", "unrecognized address"}, + {"1.2.3.4.5", "", "unrecognized address"}, + {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, + {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, +} + +func TestReverseAddress(t *testing.T) { + if runtime.GOOS == "windows" { + return + } + for i, tt := range revAddrTests { + a, e := reverseaddr(tt.Addr) + if len(tt.ErrPrefix) > 0 && e == nil { + t.Errorf("#%d: expected %q, got (error)", i, tt.ErrPrefix) + continue + } + if len(tt.ErrPrefix) == 0 && e != nil { + t.Errorf("#%d: expected , got %q (error)", i, e) + } + if e != nil && e.(*DNSError).Error != tt.ErrPrefix { + t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, e.(*DNSError).Error) + } + if a != tt.Reverse { + t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) + } + } +} diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go index cd18d2b42aa..7d25058b29c 100644 --- a/libgo/go/net/port.go +++ b/libgo/go/net/port.go @@ -18,7 +18,9 @@ var onceReadServices sync.Once func readServices() { services = make(map[string]map[string]int) var file *file - file, servicesError = open("/etc/services") + if file, servicesError = open("/etc/services"); servicesError != nil { + return + } for line, ok := file.readLine(); ok; line, ok = file.readLine() { // "http 80/tcp www www-http # World Wide Web HTTP" if i := byteIndex(line, '#'); i >= 0 { diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/resolv_windows.go index d5292b8be24..f3d854ff253 100644 --- a/libgo/go/net/resolv_windows.go +++ b/libgo/go/net/resolv_windows.go @@ -78,6 +78,35 @@ func LookupPort(network, service string) (port int, err os.Error) { return int(syscall.Ntohs(s.Port)), nil } +// TODO(brainman): Following code is only to get tests running. + func isDomainName(s string) bool { panic("unimplemented") } + +func reverseaddr(addr string) (arpa string, err os.Error) { + panic("unimplemented") +} + +// DNSError represents a DNS lookup error. +type DNSError struct { + Error string // description of the error + Name string // name looked for + Server string // server used + IsTimeout bool +} + +func (e *DNSError) String() string { + if e == nil { + return "" + } + s := "lookup " + e.Name + if e.Server != "" { + s += " on " + e.Server + } + s += ": " + e.Error + return s +} + +func (e *DNSError) Timeout() bool { return e.IsTimeout } +func (e *DNSError) Temporary() bool { return e.IsTimeout } diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 46bedaa5bcb..3f2442a462d 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -117,8 +117,11 @@ func TestUnixServer(t *testing.T) { doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net") os.Remove("/tmp/gotest.net") if syscall.OS == "linux" { + doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net") + os.Remove("/tmp/gotest.net") // Test abstract unix domain socket, a Linux-ism doTest(t, "unix", "@gotest/net", "@gotest/net") + doTest(t, "unixpacket", "@gotest/net", "@gotest/net") } } diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index 3e105ad4abd..8ad3548add4 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -47,7 +47,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal if la != nil { e = syscall.Bind(s, la) if e != 0 { - syscall.Close(s) + closesocket(s) return nil, os.Errno(e) } } @@ -55,7 +55,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal if ra != nil { e = syscall.Connect(s, ra) if e != 0 { - syscall.Close(s) + closesocket(s) return nil, os.Errno(e) } } @@ -67,7 +67,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal fd, err = newFD(s, f, p, net, laddr, raddr) if err != nil { - syscall.Close(s) + closesocket(s) return nil, err } diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go index b0cb8f99926..a4bca11bb48 100644 --- a/libgo/go/net/tcpsock.go +++ b/libgo/go/net/tcpsock.go @@ -244,7 +244,7 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) { } errno := syscall.Listen(fd.sysfd, listenBacklog()) if errno != 0 { - syscall.Close(fd.sysfd) + closesocket(fd.sysfd) return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)} } l = new(TCPListener) diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go index aad25539d4e..c8e34b7589d 100644 --- a/libgo/go/net/textproto/reader.go +++ b/libgo/go/net/textproto/reader.go @@ -51,8 +51,6 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) { return line[0:n], err } -var space = []byte{' '} - // ReadContinuedLine reads a possibly continued line from r, // eliding the final trailing ASCII white space. // Lines after the first are considered continuations if they @@ -132,8 +130,8 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) { var cont []byte cont, err = r.ReadLineBytes() cont = trim(cont) - line = bytes.Add(line, space) - line = bytes.Add(line, cont) + line = append(line, ' ') + line = append(line, cont...) if err != nil { break } diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go index 092781685e1..3594c0a350f 100644 --- a/libgo/go/net/timeout_test.go +++ b/libgo/go/net/timeout_test.go @@ -8,14 +8,9 @@ import ( "os" "testing" "time" - "runtime" ) func testTimeout(t *testing.T, network, addr string, readFrom bool) { - // Timeouts are not implemented on windows. - if runtime.GOOS == "windows" { - return - } fd, err := Dial(network, "", addr) if err != nil { t.Errorf("dial %s %s failed: %v", network, addr, err) diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go index 82c0b6d05b8..8c26a7bafd5 100644 --- a/libgo/go/net/unixsock.go +++ b/libgo/go/net/unixsock.go @@ -20,6 +20,8 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err proto = syscall.SOCK_STREAM case "unixgram": proto = syscall.SOCK_DGRAM + case "unixpacket": + proto = syscall.SOCK_SEQPACKET } var la, ra syscall.Sockaddr @@ -48,9 +50,12 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err } f := sockaddrToUnix - if proto != syscall.SOCK_STREAM { + if proto == syscall.SOCK_DGRAM { f = sockaddrToUnixgram + } else if proto == syscall.SOCK_SEQPACKET { + f = sockaddrToUnixpacket } + fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f) if oserr != nil { goto Error @@ -67,30 +72,48 @@ Error: // UnixAddr represents the address of a Unix domain socket end point. type UnixAddr struct { - Name string - Datagram bool + Name string + Net string } func sockaddrToUnix(sa syscall.Sockaddr) Addr { if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &UnixAddr{s.Name, false} + return &UnixAddr{s.Name, "unix"} } return nil } func sockaddrToUnixgram(sa syscall.Sockaddr) Addr { if s, ok := sa.(*syscall.SockaddrUnix); ok { - return &UnixAddr{s.Name, true} + return &UnixAddr{s.Name, "unixgram"} } return nil } -// Network returns the address's network name, "unix" or "unixgram". -func (a *UnixAddr) Network() string { - if a == nil || !a.Datagram { +func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr { + if s, ok := sa.(*syscall.SockaddrUnix); ok { + return &UnixAddr{s.Name, "unixpacket"} + } + return nil +} + +func protoToNet(proto int) string { + switch proto { + case syscall.SOCK_STREAM: return "unix" + case syscall.SOCK_SEQPACKET: + return "unixpacket" + case syscall.SOCK_DGRAM: + return "unixgram" + default: + panic("protoToNet unknown protocol") } - return "unixgram" + return "" +} + +// Network returns the address's network name, "unix" or "unixgram". +func (a *UnixAddr) Network() string { + return a.Net } func (a *UnixAddr) String() string { @@ -108,17 +131,17 @@ func (a *UnixAddr) toAddr() Addr { } // ResolveUnixAddr parses addr as a Unix domain socket address. -// The string net gives the network name, "unix" or "unixgram". +// The string net gives the network name, "unix", "unixgram" or +// "unixpacket". func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) { - var datagram bool switch net { case "unix": + case "unixpacket": case "unixgram": - datagram = true default: return nil, UnknownNetworkError(net) } - return &UnixAddr{addr, datagram}, nil + return &UnixAddr{addr, net}, nil } // UnixConn is an implementation of the Conn interface @@ -234,7 +257,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) n, sa, err := c.fd.ReadFrom(b) switch sa := sa.(type) { case *syscall.SockaddrUnix: - addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM} + addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} } return } @@ -258,7 +281,7 @@ func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) { if !c.ok() { return 0, os.EINVAL } - if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) { + if addr.Net != protoToNet(c.fd.proto) { return 0, os.EAFNOSUPPORT } sa := &syscall.SockaddrUnix{Name: addr.Name} @@ -277,6 +300,32 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) { return c.WriteToUnix(b, a) } +func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) { + if !c.ok() { + return 0, 0, 0, nil, os.EINVAL + } + n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob) + switch sa := sa.(type) { + case *syscall.SockaddrUnix: + addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)} + } + return +} + +func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) { + if !c.ok() { + return 0, 0, os.EINVAL + } + if addr != nil { + if addr.Net != protoToNet(c.fd.proto) { + return 0, 0, os.EAFNOSUPPORT + } + sa := &syscall.SockaddrUnix{Name: addr.Name} + return c.fd.WriteMsg(b, oob, sa) + } + return c.fd.WriteMsg(b, oob, nil) +} + // File returns a copy of the underlying os.File, set to blocking mode. // It is the caller's responsibility to close f when finished. // Closing c does not affect f, and closing f does not affect c. @@ -304,11 +353,11 @@ type UnixListener struct { // ListenUnix announces on the Unix domain socket laddr and returns a Unix listener. // Net must be "unix" (stream sockets). func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) { - if net != "unix" && net != "unixgram" { + if net != "unix" && net != "unixgram" && net != "unixpacket" { return nil, UnknownNetworkError(net) } if laddr != nil { - laddr = &UnixAddr{laddr.Name, net == "unixgram"} // make our own copy + laddr = &UnixAddr{laddr.Name, net} // make our own copy } fd, err := unixSocket(net, laddr, nil, "listen") if err != nil { @@ -316,7 +365,7 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) { } e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); if e1 != 0 { - syscall.Close(fd.sysfd) + closesocket(fd.sysfd) return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)} } return &UnixListener{fd, laddr.Name}, nil -- cgit v1.2.1