diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-06-03 11:31:24 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-06-03 11:38:02 +0200 |
commit | 13f4fcd5bf09c70942b6c85a2b919ffa1ca0c6a8 (patch) | |
tree | 717e1ceeef3a60af29e7897c7629d1502b797838 /src/pkg/net | |
parent | 6bf52070ef1028f7fcc98fad1e73795a7efd7ce7 (diff) | |
download | golang-13f4fcd5bf09c70942b6c85a2b919ffa1ca0c6a8.tar.gz |
Imported Upstream version 2011.06.02
Diffstat (limited to 'src/pkg/net')
-rw-r--r-- | src/pkg/net/Makefile | 29 | ||||
-rw-r--r-- | src/pkg/net/fd_linux.go | 11 | ||||
-rw-r--r-- | src/pkg/net/fd_windows.go | 4 | ||||
-rw-r--r-- | src/pkg/net/ip.go | 4 | ||||
-rw-r--r-- | src/pkg/net/ipsock.go | 4 | ||||
-rw-r--r-- | src/pkg/net/sendfile_linux.go | 84 | ||||
-rw-r--r-- | src/pkg/net/sendfile_stub.go | 14 | ||||
-rw-r--r-- | src/pkg/net/server_test.go | 11 | ||||
-rw-r--r-- | src/pkg/net/sock.go | 12 | ||||
-rw-r--r-- | src/pkg/net/tcpsock.go | 9 | ||||
-rw-r--r-- | src/pkg/net/textproto/reader.go | 2 | ||||
-rw-r--r-- | src/pkg/net/udpsock.go | 8 |
12 files changed, 166 insertions, 26 deletions
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile index 376e9c6dc..d4adbffc0 100644 --- a/src/pkg/net/Makefile +++ b/src/pkg/net/Makefile @@ -23,12 +23,13 @@ GOFILES=\ unixsock.go\ GOFILES_freebsd=\ - newpollserver.go\ + dnsclient.go\ + dnsconfig.go\ fd.go\ file.go\ - dnsconfig.go\ - dnsclient.go\ + newpollserver.go\ port.go\ + sendfile_stub.go\ sock_bsd.go\ CGOFILES_freebsd=\ @@ -36,27 +37,32 @@ CGOFILES_freebsd=\ cgo_unix.go\ GOFILES_darwin=\ - newpollserver.go\ + dnsclient.go\ + dnsconfig.go\ fd.go\ file.go\ - dnsconfig.go\ - dnsclient.go\ + newpollserver.go\ port.go\ + sendfile_stub.go\ sock_bsd.go\ CGOFILES_darwin=\ cgo_bsd.go\ cgo_unix.go\ - + GOFILES_linux=\ - newpollserver.go\ + dnsclient.go\ + dnsconfig.go\ fd.go\ file.go\ - dnsconfig.go\ - dnsclient.go\ + newpollserver.go\ port.go\ + sendfile_linux.go\ sock_linux.go\ +GOFILES_plan9=\ + sendfile_stub.go\ + ifeq ($(GOARCH),arm) # ARM has no cgo, so use the stubs. GOFILES_linux+=cgo_stub.go @@ -68,8 +74,9 @@ endif GOFILES_windows=\ cgo_stub.go\ - resolv_windows.go\ file_windows.go\ + resolv_windows.go\ + sendfile_stub.go\ sock_windows.go\ GOFILES+=$(GOFILES_$(GOOS)) diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go index dcf65c014..70fc344b2 100644 --- a/src/pkg/net/fd_linux.go +++ b/src/pkg/net/fd_linux.go @@ -117,6 +117,17 @@ func (p *pollster) DelFD(fd int, mode int) { } else { p.StopWaiting(fd, writeFlags) } + + // Discard any queued up events. + i := 0 + for i < len(p.waitEvents) { + if fd == int(p.waitEvents[i].Fd) { + copy(p.waitEvents[i:], p.waitEvents[i+1:]) + p.waitEvents = p.waitEvents[:len(p.waitEvents)-1] + } else { + i++ + } + } } func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) { diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index c2f736cc1..9ed7801d2 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -84,7 +84,7 @@ func (o *bufOp) Init(fd *netFD, buf []byte) { } } -// resultSrv will retreive all io completion results from +// resultSrv will retrieve all io completion results from // iocp and send them to the correspondent waiting client // goroutine via channel supplied in the request. type resultSrv struct { @@ -513,7 +513,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os. return nfd, nil } -// Not implemeted functions. +// Unimplemented functions. func (fd *netFD) dup() (f *os.File, err os.Error) { // TODO: Implement this diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go index a3000af8a..b0e2c4205 100644 --- a/src/pkg/net/ip.go +++ b/src/pkg/net/ip.go @@ -113,7 +113,7 @@ func (ip IP) IsInterfaceLocalMulticast() bool { return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01 } -// IsLinkLinkLocalMulticast returns true if ip is a link-local +// IsLinkLocalMulticast returns true if ip is a link-local // multicast address. func (ip IP) IsLinkLocalMulticast() bool { if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 { @@ -122,7 +122,7 @@ func (ip IP) IsLinkLocalMulticast() bool { return ip[0] == 0xff && ip[1]&0x0f == 0x02 } -// IsLinkLinkLocalUnicast returns true if ip is a link-local +// IsLinkLocalUnicast returns true if ip is a link-local // unicast address. func (ip IP) IsLinkLocalUnicast() bool { if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 { diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go index b83284d36..0b8c388f1 100644 --- a/src/pkg/net/ipsock.go +++ b/src/pkg/net/ipsock.go @@ -62,7 +62,7 @@ var supportsIPv6, supportsIPv4map = probeIPv6Stack() // favoriteAddrFamily returns the appropriate address family to // the given net, raddr, laddr and mode. At first it figures // address family out from the net. If mode indicates "listen" -// and laddr.(type).IP is nil, it assuumes that the user wants to +// and laddr.(type).IP is nil, it assumes that the user wants to // make a passive connection with wildcard address family, both // INET and INET6, and wildcard address. Otherwise guess: if the // addresses are IPv4 then returns INET, or else returns INET6. @@ -145,7 +145,7 @@ func ipv6only(x IP) IP { return nil } -// TODO(rsc): if syscall.OS == "linux", we're supposd to read +// TODO(rsc): if syscall.OS == "linux", we're supposed to read // /proc/sys/net/core/somaxconn, // to take advantage of kernels that have raised the limit. func listenBacklog() int { return syscall.SOMAXCONN } diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go new file mode 100644 index 000000000..6a5a06c8c --- /dev/null +++ b/src/pkg/net/sendfile_linux.go @@ -0,0 +1,84 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "io" + "os" + "syscall" +) + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// sendFile copies the contents of r to c using the sendfile +// system call to minimize copies. +// +// if handled == true, sendFile returns the number of bytes copied and any +// non-EOF error. +// +// if handled == false, sendFile performed no work. +func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) { + var remain int64 = 1 << 62 // by default, copy until EOF + + lr, ok := r.(*io.LimitedReader) + if ok { + remain, r = lr.N, lr.R + if remain <= 0 { + return 0, nil, true + } + } + f, ok := r.(*os.File) + if !ok { + return 0, nil, false + } + + c.wio.Lock() + defer c.wio.Unlock() + c.incref() + defer c.decref() + if c.wdeadline_delta > 0 { + // This is a little odd that we're setting the timeout + // for the entire file but Write has the same issue + // (if one slurps the whole file into memory and + // do one large Write). At least they're consistent. + c.wdeadline = pollserver.Now() + c.wdeadline_delta + } else { + c.wdeadline = 0 + } + + dst := c.sysfd + src := f.Fd() + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + n, errno := syscall.Sendfile(dst, src, nil, n) + if n > 0 { + written += int64(n) + remain -= int64(n) + } + if n == 0 && errno == 0 { + break + } + if errno == syscall.EAGAIN && c.wdeadline >= 0 { + pollserver.WaitWrite(c) + continue + } + if errno != 0 { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile together) + err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)} + break + } + } + if lr != nil { + lr.N = remain + } + return written, err, written > 0 +} diff --git a/src/pkg/net/sendfile_stub.go b/src/pkg/net/sendfile_stub.go new file mode 100644 index 000000000..43e8104e9 --- /dev/null +++ b/src/pkg/net/sendfile_stub.go @@ -0,0 +1,14 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "io" + "os" +) + +func sendFile(c *netFD, r io.Reader) (n int64, err os.Error, handled bool) { + return 0, nil, false +} diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go index 107de3e1c..36780d789 100644 --- a/src/pkg/net/server_test.go +++ b/src/pkg/net/server_test.go @@ -92,10 +92,13 @@ func connect(t *testing.T, network, addr string, isEmpty bool) { } func doTest(t *testing.T, network, listenaddr, dialaddr string) { - if listenaddr == "" { - t.Logf("Test %s %s %s\n", network, "<nil>", dialaddr) - } else { - t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr) + t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr) + switch listenaddr { + case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]": + if testing.Short() || avoidMacFirewall { + t.Logf("skip wildcard listen during short test") + return + } } listening := make(chan string) done := make(chan int) diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go index 5c47e4f77..eae7f3711 100644 --- a/src/pkg/net/sock.go +++ b/src/pkg/net/sock.go @@ -7,6 +7,7 @@ package net import ( + "io" "os" "reflect" "syscall" @@ -153,3 +154,14 @@ type UnknownSocketError struct { func (e *UnknownSocketError) String() string { return "unknown socket address type " + reflect.TypeOf(e.sa).String() } + +type writerOnly struct { + io.Writer +} + +// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't +// applicable. +func genericReadFrom(w io.Writer, r io.Reader) (n int64, err os.Error) { + // Use wrapper to hide existing r.ReadFrom from io.Copy. + return io.Copy(writerOnly{w}, r) +} diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go index 8aeed4895..9ee6c14f7 100644 --- a/src/pkg/net/tcpsock.go +++ b/src/pkg/net/tcpsock.go @@ -7,6 +7,7 @@ package net import ( + "io" "os" "syscall" ) @@ -95,6 +96,14 @@ func (c *TCPConn) Read(b []byte) (n int, err os.Error) { return c.fd.Read(b) } +// ReadFrom implements the io.ReaderFrom ReadFrom method. +func (c *TCPConn) ReadFrom(r io.Reader) (int64, os.Error) { + if n, err, handled := sendFile(c.fd, r); handled { + return n, err + } + return genericReadFrom(c, r) +} + // Write implements the net.Conn Write method. func (c *TCPConn) Write(b []byte) (n int, err os.Error) { if !c.ok() { diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go index ac1278689..e65374903 100644 --- a/src/pkg/net/textproto/reader.go +++ b/src/pkg/net/textproto/reader.go @@ -237,7 +237,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os. // to a method on r. // // Dot encoding is a common framing used for data blocks -// in text protcols like SMTP. The data consists of a sequence +// in text protocols such as SMTP. The data consists of a sequence // of lines, each of which ends in "\r\n". The sequence itself // ends at a line containing just a dot: ".\r\n". Lines beginning // with a dot are escaped with an additional dot to avoid diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go index 409355667..5469acffa 100644 --- a/src/pkg/net/udpsock.go +++ b/src/pkg/net/udpsock.go @@ -293,10 +293,10 @@ func (c *UDPConn) JoinGroup(addr IP) os.Error { if ip == nil { return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast} } - mreq := &syscall.IpMreq{ + mreq := &syscall.IPMreq{ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}, } - err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)) + err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)) if err != nil { return &OpError{"joingroup", "udp", &IPAddr{ip}, err} } @@ -312,10 +312,10 @@ func (c *UDPConn) LeaveGroup(addr IP) os.Error { if ip == nil { return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast} } - mreq := &syscall.IpMreq{ + mreq := &syscall.IPMreq{ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}, } - err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)) + err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)) if err != nil { return &OpError{"leavegroup", "udp", &IPAddr{ip}, err} } |