summaryrefslogtreecommitdiff
path: root/src/pkg/net/ipsock.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/net/ipsock.go')
-rw-r--r--src/pkg/net/ipsock.go247
1 files changed, 56 insertions, 191 deletions
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 640695256..705fc075a 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -34,125 +34,47 @@ func listenBacklog() int {
return syscall.SOMAXCONN
}
-// ListenerTCP is a TCP network listener.
-// Clients should typically use variables of type Listener
-// instead of assuming TCP.
-type ListenerTCP struct {
- fd *netFD;
-}
-
-// ListenTCP announces on the TCP address laddr and returns a TCP listener.
-// Net must be "tcp", "tcp4", or "tcp6".
-// If laddr has a port of 0, it means to listen on some available port.
-// The caller can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net, laddr string) (l *ListenerTCP, err os.Error) {
- fd, e := internetSocket(net, laddr, "", syscall.SOCK_STREAM, "listen");
- if e != nil {
- return nil, e
- }
- e1 := syscall.Listen(fd.fd, listenBacklog());
- if e1 != 0 {
- syscall.Close(fd.fd);
- return nil, &OpError{"listen", "tcp", laddr, os.Errno(e1)};
- }
- l = new(ListenerTCP);
- l.fd = fd;
- return l, nil
-}
-
-// AcceptTCP accepts the next incoming call and returns the new connection
-// and the remote address.
-func (l *ListenerTCP) AcceptTCP() (c *ConnTCP, raddr string, err os.Error) {
- if l == nil || l.fd == nil || l.fd.fd < 0 {
- return nil, "", os.EINVAL
- }
- fd, e := l.fd.accept();
- if e != nil {
- return nil, "", e
- }
- return newConnTCP(fd, fd.raddr), fd.raddr, nil
-}
-
-// Accept implements the Accept method in the Listener interface;
-// it waits for the next call and returns a generic Conn.
-func (l *ListenerTCP) Accept() (c Conn, raddr string, err os.Error) {
- c1, r1, e1 := l.AcceptTCP();
- if e1 != nil {
- return nil, "", e1
- }
- return c1, r1, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *ListenerTCP) Close() os.Error {
- if l == nil || l.fd == nil {
- return os.EINVAL
- }
- return l.fd.Close()
-}
-
-// Addr returns the listener's network address.
-func (l *ListenerTCP) Addr() string {
- return l.fd.addr();
-}
-
// Internet sockets (TCP, UDP)
-func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD, err os.Error) {
- // Parse addresses (unless they are empty).
- var lip, rip IP;
- var lport, rport int;
-
- if laddr != "" {
- if lip, lport, err = hostPortToIP(net, laddr, mode); err != nil {
- goto Error;
- }
- }
- if raddr != "" {
- if rip, rport, err = hostPortToIP(net, raddr, mode); err != nil {
- goto Error;
- }
- }
+// A sockaddr represents a TCP or UDP network address that can
+// be converted into a syscall.Sockaddr.
+type sockaddr interface {
+ Addr;
+ sockaddr(family int) (syscall.Sockaddr, os.Error);
+ family() int;
+}
+func internetSocket(net string, laddr, raddr sockaddr, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
// Figure out IP version.
// If network has a suffix like "tcp4", obey it.
- vers := 0;
+ family := syscall.AF_INET6;
switch net[len(net)-1] {
case '4':
- vers = 4;
+ family = syscall.AF_INET
case '6':
- vers = 6;
+ // nothing to do
default:
// Otherwise, guess.
// If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
- if preferIPv4 && (lip == nil || lip.To4() != nil) && (rip == nil || rip.To4() != nil) {
- vers = 4
- } else {
- vers = 6
+ if preferIPv4 &&
+ (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ family = syscall.AF_INET;
}
}
- var family int;
- if vers == 4 {
- family = syscall.AF_INET
- } else {
- family = syscall.AF_INET6
- }
-
var la, ra syscall.Sockaddr;
- if lip != nil {
- if la, err = ipToSockaddr(family, lip, lport); err != nil {
+ if laddr != nil {
+ if la, err = laddr.sockaddr(family); err != nil {
goto Error;
}
}
- if rip != nil {
- if ra, err = ipToSockaddr(family, rip, rport); err != nil {
+ if raddr != nil {
+ if ra, err = raddr.sockaddr(family); err != nil {
goto Error;
}
}
-
- fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra);
+ fd, err = socket(net, family, proto, 0, la, ra, toAddr);
if err != nil {
goto Error;
}
@@ -166,77 +88,31 @@ Error:
return nil, &OpError{mode, net, addr, err};
}
-
-// TCP connections.
-
-// ConnTCP is an implementation of the Conn interface
-// for TCP network connections.
-type ConnTCP struct {
- connBase
-}
-
-func (c *ConnTCP) SetNoDelay(nodelay bool) os.Error {
- if c == nil {
- return os.EINVAL
- }
- return setsockoptInt(c.sysFD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay))
-}
-
-func newConnTCP(fd *netFD, raddr string) *ConnTCP {
- c := new(ConnTCP);
- c.fd = fd;
- c.raddr = raddr;
- c.SetNoDelay(true);
- return c
-}
-
-// DialTCP is like Dial but can only connect to TCP networks
-// and returns a ConnTCP structure.
-func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
- if raddr == "" {
- return nil, &OpError{"dial", "tcp", "", errMissingAddress}
- }
- fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_STREAM, "dial");
- if e != nil {
- return nil, e
- }
- return newConnTCP(fd, raddr), nil
-}
-
-
-// UDP connections.
-
-// TODO(rsc): UDP headers mode
-
-// ConnUDP is an implementation of the Conn interface
-// for UDP network connections.
-type ConnUDP struct {
- connBase
-}
-
-func newConnUDP(fd *netFD, raddr string) *ConnUDP {
- c := new(ConnUDP);
- c.fd = fd;
- c.raddr = raddr;
- return c
-}
-
-// DialUDP is like Dial but can only connect to UDP networks
-// and returns a ConnUDP structure.
-func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
- if raddr == "" {
- return nil, &OpError{"dial", "udp", "", errMissingAddress}
+func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
+ // No attempt at error reporting because
+ // there are no possible errors, and the
+ // caller won't report them anyway.
+ var sa syscall.Sockaddr;
+ if remote {
+ sa, _ = syscall.Getpeername(fd);
+ } else {
+ sa, _ = syscall.Getsockname(fd);
}
- fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_DGRAM, "dial");
- if e != nil {
- return nil, e
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &sa.Addr, sa.Port, true;
+ case *syscall.SockaddrInet6:
+ return &sa.Addr, sa.Port, true;
}
- return newConnUDP(fd, raddr), nil
+ return;
}
func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
switch family {
case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero;
+ }
if ip = ip.To4(); ip == nil {
return nil, os.EINVAL
}
@@ -247,6 +123,9 @@ func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
s.Port = port;
return s, nil;
case syscall.AF_INET6:
+ if len(ip) == 0 {
+ ip = IPzero;
+ }
// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
// which it refuses to do. Rewrite to the IPv6 all zeros.
@@ -302,43 +181,29 @@ func joinHostPort(host, port string) string {
}
// Convert "host:port" into IP address and port.
-// For now, host and port must be numeric literals.
-// Eventually, we'll have name resolution.
-func hostPortToIP(net, hostport, mode string) (ip IP, iport int, err os.Error) {
+func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
host, port, err := splitHostPort(hostport);
if err != nil {
goto Error;
}
var addr IP;
- if host == "" {
- if mode != "listen" {
- err = &AddrError{"no host in address", hostport};
- goto Error;
- }
- if preferIPv4 {
- addr = IPv4zero;
- } else {
- addr = IPzero; // wildcard - listen to all
- }
- }
-
- // Try as an IP address.
- if addr == nil {
+ if host != "" {
+ // Try as an IP address.
addr = ParseIP(host);
- }
- if addr == nil {
- // Not an IP address. Try as a DNS name.
- _, addrs, err1 := LookupHost(host);
- if err1 != nil {
- err = err1;
- goto Error;
- }
- addr = ParseIP(addrs[0]);
if addr == nil {
- // should not happen
- err = &AddrError{"LookupHost returned invalid address", addrs[0]};
- goto Error;
+ // Not an IP address. Try as a DNS name.
+ _, addrs, err1 := LookupHost(host);
+ if err1 != nil {
+ err = err1;
+ goto Error;
+ }
+ addr = ParseIP(addrs[0]);
+ if addr == nil {
+ // should not happen
+ err = &AddrError{"LookupHost returned invalid address", addrs[0]};
+ goto Error;
+ }
}
}