diff options
Diffstat (limited to 'libgo/go/net')
31 files changed, 1285 insertions, 278 deletions
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go index 7867fa8..868388e 100644 --- a/libgo/go/net/file_test.go +++ b/libgo/go/net/file_test.go @@ -8,7 +8,6 @@ import ( "os" "reflect" "runtime" - "syscall" "testing" ) @@ -67,7 +66,7 @@ func TestFileListener(t *testing.T) { testFileListener(t, "tcp", "127.0.0.1") testFileListener(t, "tcp", "[::ffff:127.0.0.1]") } - if syscall.OS == "linux" { + if runtime.GOOS == "linux" { testFileListener(t, "unix", "@gotest/net") testFileListener(t, "unixpacket", "@gotest/net") } @@ -132,7 +131,7 @@ func TestFilePacketConn(t *testing.T) { if supportsIPv6 && supportsIPv4map { testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345") } - if syscall.OS == "linux" { + if runtime.GOOS == "linux" { testFilePacketConnListen(t, "unixgram", "@gotest1/net") } } diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go index cad8522..2e30bbf 100644 --- a/libgo/go/net/http/cookie.go +++ b/libgo/go/net/http/cookie.go @@ -96,7 +96,7 @@ func readSetCookies(h Header) []*Cookie { continue case "max-age": secs, err := strconv.Atoi(val) - if err != nil || secs < 0 || secs != 0 && val[0] == '0' { + if err != nil || secs != 0 && val[0] == '0' { break } if secs <= 0 { diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 6617849..2603010 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -368,8 +368,8 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err if err != nil { return err } - bw.Flush() - return nil + + return bw.Flush() } // Convert decimal at s[i:len(s)] to integer, diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go index 95486a6..5e7b352 100644 --- a/libgo/go/net/interface.go +++ b/libgo/go/net/interface.go @@ -12,6 +12,14 @@ import ( "fmt" ) +var ( + errInvalidInterface = errors.New("net: invalid interface") + errInvalidInterfaceIndex = errors.New("net: invalid interface index") + errInvalidInterfaceName = errors.New("net: invalid interface name") + errNoSuchInterface = errors.New("net: no such interface") + errNoSuchMulticastInterface = errors.New("net: no such multicast interface") +) + // A HardwareAddr represents a physical hardware address. type HardwareAddr []byte @@ -131,7 +139,7 @@ func (f Flags) String() string { // Addrs returns interface addresses for a specific interface. func (ifi *Interface) Addrs() ([]Addr, error) { if ifi == nil { - return nil, errors.New("net: invalid interface") + return nil, errInvalidInterface } return interfaceAddrTable(ifi.Index) } @@ -140,7 +148,7 @@ func (ifi *Interface) Addrs() ([]Addr, error) { // a specific interface. func (ifi *Interface) MulticastAddrs() ([]Addr, error) { if ifi == nil { - return nil, errors.New("net: invalid interface") + return nil, errInvalidInterface } return interfaceMulticastAddrTable(ifi.Index) } @@ -159,7 +167,7 @@ func InterfaceAddrs() ([]Addr, error) { // InterfaceByIndex returns the interface specified by index. func InterfaceByIndex(index int) (*Interface, error) { if index <= 0 { - return nil, errors.New("net: invalid interface index") + return nil, errInvalidInterfaceIndex } ift, err := interfaceTable(index) if err != nil { @@ -168,13 +176,13 @@ func InterfaceByIndex(index int) (*Interface, error) { for _, ifi := range ift { return &ifi, nil } - return nil, errors.New("net: no such interface") + return nil, errNoSuchInterface } // InterfaceByName returns the interface specified by name. func InterfaceByName(name string) (*Interface, error) { if name == "" { - return nil, errors.New("net: invalid interface name") + return nil, errInvalidInterfaceName } ift, err := interfaceTable(0) if err != nil { @@ -185,5 +193,5 @@ func InterfaceByName(name string) (*Interface, error) { return &ifi, nil } } - return nil, errors.New("net: no such interface") + return nil, errNoSuchInterface } diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go index 7e4bc56..3fd9dce 100644 --- a/libgo/go/net/iprawsock_plan9.go +++ b/libgo/go/net/iprawsock_plan9.go @@ -84,8 +84,8 @@ func splitNetProto(netProto string) (net string, proto int, err error) { return } -// DialIP connects to the remote address raddr on the network net, -// which must be "ip", "ip4", or "ip6". +// DialIP connects to the remote address raddr on the network protocol netProto, +// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name. func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error) { return nil, os.EPLAN9 } diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go index 7bb4c7d..103c4f6 100644 --- a/libgo/go/net/iprawsock_posix.go +++ b/libgo/go/net/iprawsock_posix.go @@ -224,8 +224,8 @@ func splitNetProto(netProto string) (net string, proto int, err error) { return net, proto, nil } -// DialIP connects to the remote address raddr on the network net, -// which must be "ip", "ip4", or "ip6". +// DialIP connects to the remote address raddr on the network protocol netProto, +// which must be "ip", "ip4", or "ip6" followed by a colon and a protocol number or name. func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err error) { net, proto, err := splitNetProto(netProto) if err != nil { @@ -260,7 +260,7 @@ func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err error) { default: return nil, UnknownNetworkError(net) } - fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP) + fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "listen", sockaddrToIP) if e != nil { return nil, e } diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index d141c05..45fe0d9 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -91,11 +91,6 @@ func favoriteAddrFamily(net string, raddr, laddr sockaddr, mode string) int { return syscall.AF_INET6 } -// 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 } - // Internet sockets (TCP, UDP) // A sockaddr represents a TCP or UDP network address that can diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go index a66250c..183d5a8 100644 --- a/libgo/go/net/multicast_test.go +++ b/libgo/go/net/multicast_test.go @@ -13,7 +13,7 @@ import ( var multicast = flag.Bool("multicast", false, "enable multicast tests") -var joinAndLeaveGroupUDPTests = []struct { +var multicastUDPTests = []struct { net string laddr IP gaddr IP @@ -32,8 +32,8 @@ var joinAndLeaveGroupUDPTests = []struct { {"udp6", IPv6unspecified, ParseIP("ff0e::114"), (FlagUp | FlagLoopback), true}, } -func TestJoinAndLeaveGroupUDP(t *testing.T) { - if runtime.GOOS == "windows" { +func TestMulticastUDP(t *testing.T) { + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" { return } if !*multicast { @@ -41,7 +41,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { return } - for _, tt := range joinAndLeaveGroupUDPTests { + for _, tt := range multicastUDPTests { var ( ifi *Interface found bool @@ -51,7 +51,7 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { } ift, err := Interfaces() if err != nil { - t.Fatalf("Interfaces() failed: %v", err) + t.Fatalf("Interfaces failed: %v", err) } for _, x := range ift { if x.Flags&tt.flags == tt.flags { @@ -65,15 +65,20 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { } c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr}) if err != nil { - t.Fatal(err) + t.Fatalf("ListenUDP failed: %v", err) } defer c.Close() if err := c.JoinGroup(ifi, tt.gaddr); err != nil { - t.Fatal(err) + t.Fatalf("JoinGroup failed: %v", err) + } + if !tt.ipv6 { + testIPv4MulticastSocketOptions(t, c.fd, ifi) + } else { + testIPv6MulticastSocketOptions(t, c.fd, ifi) } ifmat, err := ifi.MulticastAddrs() if err != nil { - t.Fatalf("MulticastAddrs() failed: %v", err) + t.Fatalf("MulticastAddrs failed: %v", err) } for _, ifma := range ifmat { if ifma.(*IPAddr).IP.Equal(tt.gaddr) { @@ -85,7 +90,114 @@ func TestJoinAndLeaveGroupUDP(t *testing.T) { t.Fatalf("%q not found in RIB", tt.gaddr.String()) } if err := c.LeaveGroup(ifi, tt.gaddr); err != nil { - t.Fatal(err) + t.Fatalf("LeaveGroup failed: %v", err) + } + } +} + +func TestSimpleMulticastUDP(t *testing.T) { + if runtime.GOOS == "plan9" { + return + } + if !*multicast { + t.Logf("test disabled; use --multicast to enable") + return + } + + for _, tt := range multicastUDPTests { + var ifi *Interface + if tt.ipv6 { + continue + } + tt.flags = FlagUp | FlagMulticast + ift, err := Interfaces() + if err != nil { + t.Fatalf("Interfaces failed: %v", err) + } + for _, x := range ift { + if x.Flags&tt.flags == tt.flags { + ifi = &x + break + } + } + if ifi == nil { + t.Logf("an appropriate multicast interface not found") + return + } + c, err := ListenUDP(tt.net, &UDPAddr{IP: tt.laddr}) + if err != nil { + t.Fatalf("ListenUDP failed: %v", err) + } + defer c.Close() + if err := c.JoinGroup(ifi, tt.gaddr); err != nil { + t.Fatalf("JoinGroup failed: %v", err) + } + if err := c.LeaveGroup(ifi, tt.gaddr); err != nil { + t.Fatalf("LeaveGroup failed: %v", err) } } } + +func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) { + ifmc, err := ipv4MulticastInterface(fd) + if err != nil { + t.Fatalf("ipv4MulticastInterface failed: %v", err) + } + t.Logf("IPv4 multicast interface: %v", ifmc) + err = setIPv4MulticastInterface(fd, ifi) + if err != nil { + t.Fatalf("setIPv4MulticastInterface failed: %v", err) + } + + ttl, err := ipv4MulticastTTL(fd) + if err != nil { + t.Fatalf("ipv4MulticastTTL failed: %v", err) + } + t.Logf("IPv4 multicast TTL: %v", ttl) + err = setIPv4MulticastTTL(fd, 1) + if err != nil { + t.Fatalf("setIPv4MulticastTTL failed: %v", err) + } + + loop, err := ipv4MulticastLoopback(fd) + if err != nil { + t.Fatalf("ipv4MulticastLoopback failed: %v", err) + } + t.Logf("IPv4 multicast loopback: %v", loop) + err = setIPv4MulticastLoopback(fd, false) + if err != nil { + t.Fatalf("setIPv4MulticastLoopback failed: %v", err) + } +} + +func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) { + ifmc, err := ipv6MulticastInterface(fd) + if err != nil { + t.Fatalf("ipv6MulticastInterface failed: %v", err) + } + t.Logf("IPv6 multicast interface: %v", ifmc) + err = setIPv6MulticastInterface(fd, ifi) + if err != nil { + t.Fatalf("setIPv6MulticastInterface failed: %v", err) + } + + hoplim, err := ipv6MulticastHopLimit(fd) + if err != nil { + t.Fatalf("ipv6MulticastHopLimit failed: %v", err) + } + t.Logf("IPv6 multicast hop limit: %v", hoplim) + err = setIPv6MulticastHopLimit(fd, 1) + if err != nil { + t.Fatalf("setIPv6MulticastHopLimit failed: %v", err) + } + + loop, err := ipv6MulticastLoopback(fd) + if err != nil { + t.Fatalf("ipv6MulticastLoopback failed: %v", err) + } + t.Logf("IPv6 multicast loopback: %v", loop) + err = setIPv6MulticastLoopback(fd, false) + if err != nil { + t.Fatalf("setIPv6MulticastLoopback failed: %v", err) + } +} diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go index c1845fa..ae688c0 100644 --- a/libgo/go/net/rpc/server_test.go +++ b/libgo/go/net/rpc/server_test.go @@ -498,8 +498,7 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { once.Do(startServer) client, err := dial() if err != nil { - fmt.Println("error dialing", err) - return + b.Fatal("error dialing:", err) } // Synchronous calls @@ -534,7 +533,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { once.Do(startServer) client, err := dial() if err != nil { - b.Fatalf("error dialing:", err) + b.Fatal("error dialing:", err) } // Asynchronous calls diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 7d17ccd..5475d38 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -10,7 +10,6 @@ import ( "os" "runtime" "strings" - "syscall" "testing" ) @@ -115,7 +114,7 @@ func doTest(t *testing.T, network, listenaddr, dialaddr string) { } func TestTCPServer(t *testing.T) { - if syscall.OS != "openbsd" { + if runtime.GOOS != "openbsd" { doTest(t, "tcp", "", "127.0.0.1") } doTest(t, "tcp", "0.0.0.0", "127.0.0.1") @@ -155,7 +154,7 @@ func TestUnixServer(t *testing.T) { os.Remove("/tmp/gotest.net") doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net") os.Remove("/tmp/gotest.net") - if syscall.OS == "linux" { + if runtime.GOOS == "linux" { doTest(t, "unixpacket", "/tmp/gotest.net", "/tmp/gotest.net") os.Remove("/tmp/gotest.net") // Test abstract unix domain socket, a Linux-ism @@ -237,7 +236,7 @@ func TestUnixDatagramServer(t *testing.T) { doTestPacket(t, "unixgram", "/tmp/gotest1.net", "/tmp/gotest1.net", isEmpty) os.Remove("/tmp/gotest1.net") os.Remove("/tmp/gotest1.net.local") - if syscall.OS == "linux" { + if runtime.GOOS == "linux" { // Test abstract unix domain socket, a Linux-ism doTestPacket(t, "unixgram", "@gotest1/net", "@gotest1/net", isEmpty) } diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index dc07392..881c922 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -10,18 +10,11 @@ package net import ( "io" - "os" "reflect" "syscall" ) -// Boolean to int. -func boolint(b bool) int { - if b { - return 1 - } - return 0 -} +var listenerBacklog = maxListenerBacklog() // Generic socket creation. func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err error) { @@ -35,7 +28,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal syscall.CloseOnExec(s) syscall.ForkLock.RUnlock() - setKernelSpecificSockopt(s, f) + setDefaultSockopts(s, f, p) if la != nil { e = syscall.Bind(s, la) @@ -67,83 +60,6 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal return fd, nil } -func setsockoptInt(fd *netFD, level, opt int, value int) error { - return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value)) -} - -func setsockoptNsec(fd *netFD, level, opt int, nsec int64) error { - var tv = syscall.NsecToTimeval(nsec) - return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv)) -} - -func setReadBuffer(fd *netFD, bytes int) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) -} - -func setWriteBuffer(fd *netFD, bytes int) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes) -} - -func setReadTimeout(fd *netFD, nsec int64) error { - fd.rdeadline_delta = nsec - return nil -} - -func setWriteTimeout(fd *netFD, nsec int64) error { - fd.wdeadline_delta = nsec - return nil -} - -func setTimeout(fd *netFD, nsec int64) error { - if e := setReadTimeout(fd, nsec); e != nil { - return e - } - return setWriteTimeout(fd, nsec) -} - -func setReuseAddr(fd *netFD, reuse bool) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse)) -} - -func setDontRoute(fd *netFD, dontroute bool) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute)) -} - -func setKeepAlive(fd *netFD, keepalive bool) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive)) -} - -func setNoDelay(fd *netFD, noDelay bool) error { - fd.incref() - defer fd.decref() - return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay)) -} - -func setLinger(fd *netFD, sec int) error { - var l syscall.Linger - if sec >= 0 { - l.Onoff = 1 - l.Linger = int32(sec) - } else { - l.Onoff = 0 - l.Linger = 0 - } - fd.incref() - defer fd.decref() - e := syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l) - return os.NewSyscallError("setsockopt", e) -} - type UnknownSocketError struct { sa syscall.Sockaddr } diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go index 816e4fc..630a91e 100644 --- a/libgo/go/net/sock_bsd.go +++ b/libgo/go/net/sock_bsd.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2009 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. @@ -9,25 +9,25 @@ package net import ( + "runtime" "syscall" ) -func setKernelSpecificSockopt(s, f int) { - // Allow reuse of recently-used addresses. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) - - // Allow reuse of recently-used ports. - // This option is supported only in descendants of 4.4BSD, - // to make an effective multicast application and an application - // that requires quick draw possible. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) - - // Allow broadcast. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) - - if f == syscall.AF_INET6 { - // using ip, tcp, udp, etc. - // allow both protocols even if the OS default is otherwise. - syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) +func maxListenerBacklog() int { + var ( + n uint32 + err error + ) + switch runtime.GOOS { + case "darwin", "freebsd": + n, err = syscall.SysctlUint32("kern.ipc.somaxconn") + case "netbsd": + // NOTE: NetBSD has no somaxconn-like kernel state so far + case "openbsd": + n, err = syscall.SysctlUint32("kern.somaxconn") + } + if n == 0 || err != nil { + return syscall.SOMAXCONN } + return int(n) } diff --git a/libgo/go/net/sock_linux.go b/libgo/go/net/sock_linux.go index ec31e80..2cbc34f 100644 --- a/libgo/go/net/sock_linux.go +++ b/libgo/go/net/sock_linux.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2009 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. @@ -6,20 +6,22 @@ package net -import ( - "syscall" -) +import "syscall" -func setKernelSpecificSockopt(s, f int) { - // Allow reuse of recently-used addresses. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) - - // Allow broadcast. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) - - if f == syscall.AF_INET6 { - // using ip, tcp, udp, etc. - // allow both protocols even if the OS default is otherwise. - syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) +func maxListenerBacklog() int { + fd, err := open("/proc/sys/net/core/somaxconn") + if err != nil { + return syscall.SOMAXCONN + } + defer fd.close() + l, ok := fd.readLine() + if !ok { + return syscall.SOMAXCONN + } + f := getFields(l) + n, _, ok := dtoi(f[0], 0) + if n == 0 || !ok { + return syscall.SOMAXCONN } + return n } diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go index 9b9cd9e..2d803de 100644 --- a/libgo/go/net/sock_windows.go +++ b/libgo/go/net/sock_windows.go @@ -1,4 +1,4 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2009 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. @@ -6,24 +6,9 @@ package net -import ( - "syscall" -) +import "syscall" -func setKernelSpecificSockopt(s syscall.Handle, f int) { - // Windows will reuse recently-used addresses by default. - // SO_REUSEADDR should not be used here, as it allows - // a socket to forcibly bind to a port in use by another socket. - // This could lead to a non-deterministic behavior, where - // connection requests over the port cannot be guaranteed - // to be handled by the correct socket. - - // Allow broadcast. - syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) - - if f == syscall.AF_INET6 { - // using ip, tcp, udp, etc. - // allow both protocols even if the OS default is otherwise. - syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) - } +func maxListenerBacklog() int { + // TODO: Implement this + return syscall.SOMAXCONN } diff --git a/libgo/go/net/sockopt.go b/libgo/go/net/sockopt.go new file mode 100644 index 0000000..7fa1052 --- /dev/null +++ b/libgo/go/net/sockopt.go @@ -0,0 +1,171 @@ +// Copyright 2009 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. + +// +build darwin freebsd linux netbsd openbsd windows + +// Socket options + +package net + +import ( + "bytes" + "os" + "syscall" +) + +// Boolean to int. +func boolint(b bool) int { + if b { + return 1 + } + return 0 +} + +func ipv4AddrToInterface(ip IP) (*Interface, error) { + ift, err := Interfaces() + if err != nil { + return nil, err + } + for _, ifi := range ift { + ifat, err := ifi.Addrs() + if err != nil { + return nil, err + } + for _, ifa := range ifat { + switch v := ifa.(type) { + case *IPAddr: + if ip.Equal(v.IP) { + return &ifi, nil + } + case *IPNet: + if ip.Equal(v.IP) { + return &ifi, nil + } + } + } + } + if ip.Equal(IPv4zero) { + return nil, nil + } + return nil, errNoSuchInterface +} + +func interfaceToIPv4Addr(ifi *Interface) (IP, error) { + if ifi == nil { + return IPv4zero, nil + } + ifat, err := ifi.Addrs() + if err != nil { + return nil, err + } + for _, ifa := range ifat { + switch v := ifa.(type) { + case *IPAddr: + if v.IP.To4() != nil { + return v.IP, nil + } + case *IPNet: + if v.IP.To4() != nil { + return v.IP, nil + } + } + } + return nil, errNoSuchInterface +} + +func setIPv4MreqToInterface(mreq *syscall.IPMreq, ifi *Interface) error { + if ifi == nil { + return nil + } + ifat, err := ifi.Addrs() + if err != nil { + return err + } + for _, ifa := range ifat { + switch v := ifa.(type) { + case *IPAddr: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + case *IPNet: + if a := v.IP.To4(); a != nil { + copy(mreq.Interface[:], a) + goto done + } + } + } +done: + if bytes.Equal(mreq.Multiaddr[:], IPv4zero.To4()) { + return errNoSuchMulticastInterface + } + return nil +} + +func setReadBuffer(fd *netFD, bytes int) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)) +} + +func setWriteBuffer(fd *netFD, bytes int) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)) +} + +func setReadTimeout(fd *netFD, nsec int64) error { + fd.rdeadline_delta = nsec + return nil +} + +func setWriteTimeout(fd *netFD, nsec int64) error { + fd.wdeadline_delta = nsec + return nil +} + +func setTimeout(fd *netFD, nsec int64) error { + if e := setReadTimeout(fd, nsec); e != nil { + return e + } + return setWriteTimeout(fd, nsec) +} + +func setReuseAddr(fd *netFD, reuse bool) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))) +} + +func setDontRoute(fd *netFD, dontroute bool) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))) +} + +func setKeepAlive(fd *netFD, keepalive bool) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))) +} + +func setNoDelay(fd *netFD, noDelay bool) error { + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))) +} + +func setLinger(fd *netFD, sec int) error { + var l syscall.Linger + if sec >= 0 { + l.Onoff = 1 + l.Linger = int32(sec) + } else { + l.Onoff = 0 + l.Linger = 0 + } + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptLinger(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_LINGER, &l)) +} diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go new file mode 100644 index 0000000..e99fb41 --- /dev/null +++ b/libgo/go/net/sockopt_bsd.go @@ -0,0 +1,44 @@ +// 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. + +// +build darwin freebsd netbsd openbsd + +// Socket options for BSD variants + +package net + +import ( + "syscall" +) + +func setDefaultSockopts(s, f, p int) { + switch f { + case syscall.AF_INET6: + // Allow both IP versions even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } + + if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP { + // Allow reuse of recently-used addresses. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + + // Allow reuse of recently-used ports. + // This option is supported only in descendants of 4.4BSD, + // to make an effective multicast application and an application + // that requires quick draw possible. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) + } + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) +} + +func setDefaultMulticastSockopts(fd *netFD) { + fd.incref() + defer fd.decref() + // Allow multicast UDP and raw IP datagram sockets to listen + // concurrently across multiple listeners. + syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEPORT, 1) +} diff --git a/libgo/go/net/sockopt_linux.go b/libgo/go/net/sockopt_linux.go new file mode 100644 index 0000000..5158384 --- /dev/null +++ b/libgo/go/net/sockopt_linux.go @@ -0,0 +1,36 @@ +// 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. + +// Socket options for Linux + +package net + +import ( + "syscall" +) + +func setDefaultSockopts(s, f, p int) { + switch f { + case syscall.AF_INET6: + // Allow both IP versions even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } + + if f == syscall.AF_UNIX || p == syscall.IPPROTO_TCP { + // Allow reuse of recently-used addresses. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) + } + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + +} + +func setDefaultMulticastSockopts(fd *netFD) { + fd.incref() + defer fd.decref() + // Allow multicast UDP and raw IP datagram sockets to listen + // concurrently across multiple listeners. + syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) +} diff --git a/libgo/go/net/sockopt_windows.go b/libgo/go/net/sockopt_windows.go new file mode 100644 index 0000000..485c14a --- /dev/null +++ b/libgo/go/net/sockopt_windows.go @@ -0,0 +1,38 @@ +// 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. + +// Socket options for Windows + +package net + +import ( + "syscall" +) + +func setDefaultSockopts(s syscall.Handle, f, p int) { + switch f { + case syscall.AF_INET6: + // Allow both IP versions even if the OS default is otherwise. + syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0) + } + + // Windows will reuse recently-used addresses by default. + // SO_REUSEADDR should not be used here, as it allows + // a socket to forcibly bind to a port in use by another socket. + // This could lead to a non-deterministic behavior, where + // connection requests over the port cannot be guaranteed + // to be handled by the correct socket. + + // Allow broadcast. + syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1) + +} + +func setDefaultMulticastSockopts(fd *netFD) { + fd.incref() + defer fd.decref() + // Allow multicast UDP and raw IP datagram sockets to listen + // concurrently across multiple listeners. + syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) +} diff --git a/libgo/go/net/sockoptip.go b/libgo/go/net/sockoptip.go new file mode 100644 index 0000000..90b6f75 --- /dev/null +++ b/libgo/go/net/sockoptip.go @@ -0,0 +1,187 @@ +// 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. + +// +build darwin freebsd linux netbsd openbsd windows + +// IP-level socket options + +package net + +import ( + "os" + "syscall" +) + +func ipv4TOS(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv4TOS(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TOS, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4TTL(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv4TTL(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_TTL, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func joinIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if err := setIPv4MreqToInterface(mreq, ifi); err != nil { + return err + } + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)) +} + +func leaveIPv4Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} + if err := setIPv4MreqToInterface(mreq, ifi); err != nil { + return err + } + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)) +} + +func ipv6HopLimit(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6HopLimit(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_UNICAST_HOPS, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv6MulticastInterface(fd *netFD) (*Interface, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + if v == 0 { + return nil, nil + } + ifi, err := InterfaceByIndex(v) + if err != nil { + return nil, err + } + return ifi, nil +} + +func setIPv6MulticastInterface(fd *netFD, ifi *Interface) error { + var v int + if ifi != nil { + v = ifi.Index + } + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_IF, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv6MulticastHopLimit(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6MulticastHopLimit(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_HOPS, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv6MulticastLoopback(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv6MulticastLoopback(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_MULTICAST_LOOP, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func joinIPv6Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], ip) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)) +} + +func leaveIPv6Group(fd *netFD, ifi *Interface, ip IP) error { + mreq := &syscall.IPv6Mreq{} + copy(mreq.Multiaddr[:], ip) + if ifi != nil { + mreq.Interface = uint32(ifi.Index) + } + fd.incref() + defer fd.decref() + return os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq)) +} diff --git a/libgo/go/net/sockoptip_bsd.go b/libgo/go/net/sockoptip_bsd.go new file mode 100644 index 0000000..5f7dff2 --- /dev/null +++ b/libgo/go/net/sockoptip_bsd.go @@ -0,0 +1,54 @@ +// 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. + +// +build darwin freebsd netbsd openbsd + +// IP-level socket options for BSD variants + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastTTL(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return int(v), nil +} + +func setIPv4MulticastTTL(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, byte(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv6TrafficClass(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6TrafficClass(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} diff --git a/libgo/go/net/sockoptip_darwin.go b/libgo/go/net/sockoptip_darwin.go new file mode 100644 index 0000000..dedfd6f --- /dev/null +++ b/libgo/go/net/sockoptip_darwin.go @@ -0,0 +1,78 @@ +// 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. + +// IP-level socket options for Darwin + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + fd.incref() + defer fd.decref() + a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3])) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + ip, err := interfaceToIPv4Addr(ifi) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + var x [4]byte + copy(x[:], ip.To4()) + fd.incref() + defer fd.decref() + err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} diff --git a/libgo/go/net/sockoptip_freebsd.go b/libgo/go/net/sockoptip_freebsd.go new file mode 100644 index 0000000..55f7b1a --- /dev/null +++ b/libgo/go/net/sockoptip_freebsd.go @@ -0,0 +1,80 @@ +// 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. + +// IP-level socket options for FreeBSD + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + fd.incref() + defer fd.decref() + mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + if int(mreq.Ifindex) == 0 { + return nil, nil + } + return InterfaceByIndex(int(mreq.Ifindex)) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + var v int32 + if ifi != nil { + v = int32(ifi.Index) + } + mreq := &syscall.IPMreqn{Ifindex: v} + fd.incref() + defer fd.decref() + err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} diff --git a/libgo/go/net/sockoptip_linux.go b/libgo/go/net/sockoptip_linux.go new file mode 100644 index 0000000..360f8de --- /dev/null +++ b/libgo/go/net/sockoptip_linux.go @@ -0,0 +1,120 @@ +// 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. + +// IP-level socket options for Linux + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + fd.incref() + defer fd.decref() + mreq, err := syscall.GetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + if int(mreq.Ifindex) == 0 { + return nil, nil + } + return InterfaceByIndex(int(mreq.Ifindex)) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + var v int32 + if ifi != nil { + v = int32(ifi.Index) + } + mreq := &syscall.IPMreqn{Ifindex: v} + fd.incref() + defer fd.decref() + err := syscall.SetsockoptIPMreqn(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, mreq) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastTTL(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv4MulticastTTL(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_TTL, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_PKTINFO, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv6TrafficClass(fd *netFD) (int, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS) + if err != nil { + return -1, os.NewSyscallError("getsockopt", err) + } + return v, nil +} + +func setIPv6TrafficClass(fd *netFD, v int) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_TCLASS, v) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} diff --git a/libgo/go/net/sockoptip_openbsd.go b/libgo/go/net/sockoptip_openbsd.go new file mode 100644 index 0000000..89b8e45 --- /dev/null +++ b/libgo/go/net/sockoptip_openbsd.go @@ -0,0 +1,78 @@ +// 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. + +// IP-level socket options for OpenBSD + +package net + +import ( + "os" + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + fd.incref() + defer fd.decref() + a, err := syscall.GetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF) + if err != nil { + return nil, os.NewSyscallError("getsockopt", err) + } + return ipv4AddrToInterface(IPv4(a[0], a[1], a[2], a[3])) +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + ip, err := interfaceToIPv4Addr(ifi) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + var x [4]byte + copy(x[:], ip.To4()) + fd.incref() + defer fd.decref() + err = syscall.SetsockoptInet4Addr(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_IF, x) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptByte(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_MULTICAST_LOOP, byte(boolint(v))) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + fd.incref() + defer fd.decref() + v, err := syscall.GetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF) + if err != nil { + return false, os.NewSyscallError("getsockopt", err) + } + return v == 1, nil +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + fd.incref() + defer fd.decref() + err := syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_IP, syscall.IP_RECVIF, boolint(v)) + if err != nil { + return os.NewSyscallError("setsockopt", err) + } + return nil +} diff --git a/libgo/go/net/sockoptip_windows.go b/libgo/go/net/sockoptip_windows.go new file mode 100644 index 0000000..3320e76 --- /dev/null +++ b/libgo/go/net/sockoptip_windows.go @@ -0,0 +1,61 @@ +// 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. + +// IP-level socket options for Windows + +package net + +import ( + "syscall" +) + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + // TODO: Implement this + return nil, syscall.EWINDOWS +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + // TODO: Implement this + return syscall.EWINDOWS +} + +func ipv4MulticastTTL(fd *netFD) (int, error) { + // TODO: Implement this + return -1, syscall.EWINDOWS +} + +func setIPv4MulticastTTL(fd *netFD, v int) error { + // TODO: Implement this + return syscall.EWINDOWS +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + // TODO: Implement this + return false, syscall.EWINDOWS +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + // TODO: Implement this + return syscall.EWINDOWS +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + // TODO: Implement this + return false, syscall.EWINDOWS +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + // TODO: Implement this + return syscall.EWINDOWS +} + +func ipv6TrafficClass(fd *netFD) (int, error) { + // TODO: Implement this + return 0, syscall.EWINDOWS +} + +func setIPv6TrafficClass(fd *netFD, v int) error { + // TODO: Implement this + return syscall.EWINDOWS +} diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index a7c09c7..a492e61 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -249,10 +249,10 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err error) { if err != nil { return nil, err } - errno := syscall.Listen(fd.sysfd, listenBacklog()) - if errno != nil { + err = syscall.Listen(fd.sysfd, listenerBacklog) + if err != nil { closesocket(fd.sysfd) - return nil, &OpError{"listen", "tcp", laddr, errno} + return nil, &OpError{"listen", "tcp", laddr, err} } l = new(TCPListener) l.fd = fd diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go index 793c6c2..862cd53 100644 --- a/libgo/go/net/textproto/reader.go +++ b/libgo/go/net/textproto/reader.go @@ -22,6 +22,7 @@ import ( type Reader struct { R *bufio.Reader dot *dotReader + buf []byte // a re-usable buffer for readContinuedLineSlice } // NewReader returns a new Reader reading from r. @@ -121,74 +122,44 @@ func (r *Reader) readContinuedLineSlice() ([]byte, error) { // Read the first line. line, err := r.readLineSlice() if err != nil { - return line, err + return nil, err } if len(line) == 0 { // blank line - no continuation return line, nil } - line = trim(line) - copied := false - if r.R.Buffered() < 1 { - // ReadByte will flush the buffer; make a copy of the slice. - copied = true - line = append([]byte(nil), line...) - } - - // Look for a continuation line. - c, err := r.R.ReadByte() - if err != nil { - // Delay err until we read the byte next time. - return line, nil - } - if c != ' ' && c != '\t' { - // Not a continuation. - r.R.UnreadByte() - return line, nil - } - - if !copied { - // The next readLineSlice will invalidate the previous one. - line = append(make([]byte, 0, len(line)*2), line...) - } + // ReadByte or the next readLineSlice will flush the read buffer; + // copy the slice into buf. + r.buf = append(r.buf[:0], trim(line)...) // Read continuation lines. - for { - // Consume leading spaces; one already gone. - for { - c, err = r.R.ReadByte() - if err != nil { - break - } - if c != ' ' && c != '\t' { - r.R.UnreadByte() - break - } - } - var cont []byte - cont, err = r.readLineSlice() - cont = trim(cont) - line = append(line, ' ') - line = append(line, cont...) + for r.skipSpace() > 0 { + line, err := r.readLineSlice() if err != nil { break } + r.buf = append(r.buf, ' ') + r.buf = append(r.buf, line...) + } + return r.buf, nil +} - // Check for leading space on next line. - if c, err = r.R.ReadByte(); err != nil { +// skipSpace skips R over all spaces and returns the number of bytes skipped. +func (r *Reader) skipSpace() int { + n := 0 + for { + c, err := r.R.ReadByte() + if err != nil { + // Bufio will keep err until next read. break } if c != ' ' && c != '\t' { r.R.UnreadByte() break } + n++ } - - // Delay error until next call. - if len(line) > 0 { - err = nil - } - return line, err + return n } func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) { diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go index 0460c1c..4d03691 100644 --- a/libgo/go/net/textproto/reader_test.go +++ b/libgo/go/net/textproto/reader_test.go @@ -138,6 +138,15 @@ func TestReadMIMEHeader(t *testing.T) { } } +func TestReadMIMEHeaderSingle(t *testing.T) { + r := reader("Foo: bar\n\n") + m, err := r.ReadMIMEHeader() + want := MIMEHeader{"Foo": {"bar"}} + if !reflect.DeepEqual(m, want) || err != nil { + t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want) + } +} + func TestLargeReadMIMEHeader(t *testing.T) { data := make([]byte, 16*1024) for i := 0; i < len(data); i++ { diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go index 6bb1571..d0bdb14 100644 --- a/libgo/go/net/udpsock_posix.go +++ b/libgo/go/net/udpsock_posix.go @@ -9,7 +9,6 @@ package net import ( - "bytes" "os" "syscall" ) @@ -233,7 +232,7 @@ func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err error) { if laddr == nil { return nil, &OpError{"listen", "udp", nil, errMissingAddress} } - fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP) + fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "listen", sockaddrToUDP) if e != nil { return nil, e } @@ -252,6 +251,7 @@ func (c *UDPConn) JoinGroup(ifi *Interface, addr IP) error { if !c.ok() { return os.EINVAL } + setDefaultMulticastSockopts(c.fd) ip := addr.To4() if ip != nil { return joinIPv4GroupUDP(c, ifi, ip) @@ -272,66 +272,32 @@ func (c *UDPConn) LeaveGroup(ifi *Interface, addr IP) error { } func joinIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { - mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} - if err := setIPv4InterfaceToJoin(mreq, ifi); err != nil { - return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err} - } - if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq)); err != nil { + err := joinIPv4Group(c.fd, ifi, ip) + if err != nil { return &OpError{"joinipv4group", "udp", &IPAddr{ip}, err} } return nil } func leaveIPv4GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { - mreq := &syscall.IPMreq{Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]}} - if err := setIPv4InterfaceToJoin(mreq, ifi); err != nil { - return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err} - } - if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq)); err != nil { - return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err} - } - return nil -} - -func setIPv4InterfaceToJoin(mreq *syscall.IPMreq, ifi *Interface) error { - if ifi == nil { - return nil - } - ifat, err := ifi.Addrs() + err := leaveIPv4Group(c.fd, ifi, ip) if err != nil { - return err - } - for _, ifa := range ifat { - if x := ifa.(*IPAddr).IP.To4(); x != nil { - copy(mreq.Interface[:], x) - break - } - } - if bytes.Equal(mreq.Multiaddr[:], IPv4zero) { - return os.EINVAL + return &OpError{"leaveipv4group", "udp", &IPAddr{ip}, err} } return nil } func joinIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { - mreq := &syscall.IPv6Mreq{} - copy(mreq.Multiaddr[:], ip) - if ifi != nil { - mreq.Interface = uint32(ifi.Index) - } - if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(c.fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq)); err != nil { + err := joinIPv6Group(c.fd, ifi, ip) + if err != nil { return &OpError{"joinipv6group", "udp", &IPAddr{ip}, err} } return nil } func leaveIPv6GroupUDP(c *UDPConn, ifi *Interface, ip IP) error { - mreq := &syscall.IPv6Mreq{} - copy(mreq.Multiaddr[:], ip) - if ifi != nil { - mreq.Interface = uint32(ifi.Index) - } - if err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPv6Mreq(c.fd.sysfd, syscall.IPPROTO_IPV6, syscall.IPV6_LEAVE_GROUP, mreq)); err != nil { + err := leaveIPv6Group(c.fd, ifi, ip) + if err != nil { return &OpError{"leaveipv6group", "udp", &IPAddr{ip}, err} } return nil diff --git a/libgo/go/net/unicast_test.go b/libgo/go/net/unicast_test.go new file mode 100644 index 0000000..6ed6f59 --- /dev/null +++ b/libgo/go/net/unicast_test.go @@ -0,0 +1,99 @@ +// 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 ( + "runtime" + "testing" +) + +var unicastTests = []struct { + net string + laddr string + ipv6 bool + packet bool +}{ + {"tcp4", "127.0.0.1:0", false, false}, + {"tcp6", "[::1]:0", true, false}, + {"udp4", "127.0.0.1:0", false, true}, + {"udp6", "[::1]:0", true, true}, +} + +func TestUnicastTCPAndUDP(t *testing.T) { + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" { + return + } + + for _, tt := range unicastTests { + if tt.ipv6 && !supportsIPv6 { + continue + } + var fd *netFD + if !tt.packet { + c, err := Listen(tt.net, tt.laddr) + if err != nil { + t.Fatalf("Listen failed: %v", err) + } + defer c.Close() + fd = c.(*TCPListener).fd + } else { + c, err := ListenPacket(tt.net, tt.laddr) + if err != nil { + t.Fatalf("ListenPacket failed: %v", err) + } + defer c.Close() + fd = c.(*UDPConn).fd + } + if !tt.ipv6 { + testIPv4UnicastSocketOptions(t, fd) + } else { + testIPv6UnicastSocketOptions(t, fd) + } + } +} + +func testIPv4UnicastSocketOptions(t *testing.T, fd *netFD) { + tos, err := ipv4TOS(fd) + if err != nil { + t.Fatalf("ipv4TOS failed: %v", err) + } + t.Logf("IPv4 TOS: %v", tos) + err = setIPv4TOS(fd, 1) + if err != nil { + t.Fatalf("setIPv4TOS failed: %v", err) + } + + ttl, err := ipv4TTL(fd) + if err != nil { + t.Fatalf("ipv4TTL failed: %v", err) + } + t.Logf("IPv4 TTL: %v", ttl) + err = setIPv4TTL(fd, 1) + if err != nil { + t.Fatalf("setIPv4TTL failed: %v", err) + } +} + +func testIPv6UnicastSocketOptions(t *testing.T, fd *netFD) { + tos, err := ipv6TrafficClass(fd) + if err != nil { + t.Fatalf("ipv6TrafficClass failed: %v", err) + } + t.Logf("IPv6 TrafficClass: %v", tos) + err = setIPv6TrafficClass(fd, 1) + if err != nil { + t.Fatalf("setIPv6TrafficClass failed: %v", err) + } + + hoplim, err := ipv6HopLimit(fd) + if err != nil { + t.Fatalf("ipv6HopLimit failed: %v", err) + } + t.Logf("IPv6 HopLimit: %v", hoplim) + err = setIPv6HopLimit(fd, 1) + if err != nil { + t.Fatalf("setIPv6HopLimit failed: %v", err) + } +} diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 10632c1..00ee016 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -315,7 +315,7 @@ 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 error) { +func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { if net != "unix" && net != "unixgram" && net != "unixpacket" { return nil, UnknownNetworkError(net) } @@ -326,10 +326,10 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err error) { if err != nil { return nil, err } - e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog()); - if e1 != nil { + err = syscall.Listen(fd.sysfd, listenerBacklog) + if err != nil { closesocket(fd.sysfd) - return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: e1} + return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Err: err} } return &UnixListener{fd, laddr.Name}, nil } |