split ipsock.go, sock.go, and unixsock.go out of net.go
prior to cleanup. no changes, only moving.
remove dependencies on strconv and strings
R=r
http://go/go-review/1017010
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 5fb49d4..8669ed3 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -4,52 +4,11 @@
package net
-import (
- "os";
- "reflect";
- "strconv";
- "strings";
- "syscall";
-)
+// TODO(rsc):
+// support for raw IP sockets
+// support for raw ethernet sockets
-var errMissingAddress = os.ErrorString("missing address")
-
-type OpError struct {
- Op string;
- Net string;
- Addr string;
- Error os.Error;
-}
-
-func (e *OpError) String() string {
- s := e.Op;
- if e.Net != "" {
- s += " " + e.Net;
- }
- if e.Addr != "" {
- s += " " + e.Addr;
- }
- s += ": " + e.Error.String();
- return s;
-}
-
-type AddrError struct {
- Error string;
- Addr string;
-}
-
-func (e *AddrError) String() string {
- s := e.Error;
- if e.Addr != "" {
- s += " " + e.Addr;
- }
- return s;
-}
-
-type UnknownNetworkError string
-func (e UnknownNetworkError) String() string {
- return "unknown network " + string(e);
-}
+import "os"
// Conn is a generic network connection.
type Conn interface {
@@ -134,681 +93,12 @@
BindToDevice(dev string) os.Error;
}
-// Should we try to use the IPv4 socket interface if we're
-// only dealing with IPv4 sockets? As long as the host system
-// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
-// interface. That simplifies our code and is most general.
-// Unfortunately, we need to run on kernels built without IPv6 support too.
-// So probe the kernel to figure it out.
-func kernelSupportsIPv6() bool {
- fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP);
- if fd >= 0 {
- syscall.Close(fd)
- }
- return e == 0
-}
-
-var preferIPv4 = !kernelSupportsIPv6()
-
-// TODO(rsc): if syscall.OS == "linux", we're supposd to read
-// /proc/sys/net/core/somaxconn,
-// to take advantage of kernels that have raised the limit.
-func listenBacklog() int {
- return syscall.SOMAXCONN
-}
-
-// Split "host:port" into "host" and "port".
-// Host cannot contain colons unless it is bracketed.
-func splitHostPort(hostport string) (host, port string, err os.Error) {
- // The port starts after the last colon.
- i := strings.LastIndex(hostport, ":");
- if i < 0 {
- err = &AddrError{"missing port in address", hostport};
- return;
- }
-
- host, port = hostport[0:i], hostport[i+1:len(hostport)];
-
- // Can put brackets around host ...
- if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
- host = host[1:len(host)-1]
- } else {
- // ... but if there are no brackets, no colons.
- if byteIndex(host, ':') >= 0 {
- err = &AddrError{"too many colons in address", hostport};
- return;
- }
- }
- return;
-}
-
-// Join "host" and "port" into "host:port".
-// If host contains colons, will join into "[host]:port".
-func joinHostPort(host, port string) string {
- // If host has colons, have to bracket it.
- if byteIndex(host, ':') >= 0 {
- return "[" + host + "]:" + port
- }
- return host + ":" + port
-}
-
-// 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) {
- 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 {
- 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;
- }
- }
-
- p, i, ok := dtoi(port, 0);
- if !ok || i != len(port) {
- p, err = LookupPort(net, port);
- if err != nil {
- goto Error;
- }
- }
- if p < 0 || p > 0xFFFF {
- err = &AddrError{"invalid port", port};
- goto Error;
- }
-
- return addr, p, nil;
-
-Error:
- return nil, 0, err;
-}
-
-type UnknownSocketError struct {
- sa syscall.Sockaddr;
-}
-func (e *UnknownSocketError) String() string {
- return "unknown socket address type " + reflect.Typeof(e.sa).String()
-}
-
-func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
- switch a := sa.(type) {
- case *syscall.SockaddrInet4:
- return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil;
- case *syscall.SockaddrInet6:
- return joinHostPort(IP(&a.Addr).String(), strconv.Itoa(a.Port)), nil;
- case *syscall.SockaddrUnix:
- return a.Name, nil;
- }
-
- return "", &UnknownSocketError{sa};
-}
-
-func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
- switch family {
- case syscall.AF_INET:
- if ip = ip.To4(); ip == nil {
- return nil, os.EINVAL
- }
- s := new(syscall.SockaddrInet4);
- for i := 0; i < IPv4len; i++ {
- s.Addr[i] = ip[i];
- }
- s.Port = port;
- return s, nil;
- case syscall.AF_INET6:
- // 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.
- if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 {
- ip = IPzero;
- }
- if ip = ip.To16(); ip == nil {
- return nil, os.EINVAL
- }
- s := new(syscall.SockaddrInet6);
- for i := 0; i < IPv6len; i++ {
- s.Addr[i] = ip[i];
- }
- s.Port = port;
- return s, nil;
- }
- return nil, os.EINVAL;
-}
-
-// Boolean to int.
-func boolint(b bool) int {
- if b {
- return 1
- }
- return 0
-}
-
-// Generic socket creation.
-func socket(net, laddr, raddr string, f, p, t int, la, ra syscall.Sockaddr) (fd *netFD, err os.Error) {
- // See ../syscall/exec.go for description of ForkLock.
- syscall.ForkLock.RLock();
- s, e := syscall.Socket(f, p, t);
- if e != 0 {
- syscall.ForkLock.RUnlock();
- return nil, os.Errno(e)
- }
- syscall.CloseOnExec(s);
- syscall.ForkLock.RUnlock();
-
- // Allow reuse of recently-used addresses.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1);
-
- if la != nil {
- e = syscall.Bind(s, la);
- if e != 0 {
- syscall.Close(s);
- return nil, os.Errno(e)
- }
- }
-
- if ra != nil {
- e = syscall.Connect(s, ra);
- if e != 0 {
- syscall.Close(s);
- return nil, os.Errno(e)
- }
- }
-
- fd, err = newFD(s, net, laddr, raddr);
- if err != nil {
- syscall.Close(s);
- return nil, err
- }
-
- return fd, nil
-}
-
-
-// Generic implementation of Conn interface; not exported.
-type connBase struct {
- fd *netFD;
- raddr string;
-}
-
-func (c *connBase) LocalAddr() string {
- if c == nil {
- return ""
- }
- return c.fd.addr();
-}
-
-func (c *connBase) RemoteAddr() string {
- if c == nil {
- return ""
- }
- return c.fd.remoteAddr();
-}
-
-func (c *connBase) File() *os.File {
- if c == nil {
- return nil
- }
- return c.fd.file;
-}
-
-func (c *connBase) sysFD() int {
- if c == nil || c.fd == nil {
- return -1;
- }
- return c.fd.fd;
-}
-
-func (c *connBase) Read(b []byte) (n int, err os.Error) {
- n, err = c.fd.Read(b);
- return n, err
-}
-
-func (c *connBase) Write(b []byte) (n int, err os.Error) {
- n, err = c.fd.Write(b);
- return n, err
-}
-
-func (c *connBase) ReadFrom(b []byte) (n int, raddr string, err os.Error) {
- if c == nil {
- return -1, "", os.EINVAL
- }
- n, err = c.Read(b);
- return n, c.raddr, err
-}
-
-func (c *connBase) WriteTo(raddr string, b []byte) (n int, err os.Error) {
- if c == nil {
- return -1, os.EINVAL
- }
- if raddr != c.raddr {
- return -1, os.EINVAL
- }
- n, err = c.Write(b);
- return n, err
-}
-
-func (c *connBase) Close() os.Error {
- if c == nil {
- return os.EINVAL
- }
- return c.fd.Close()
-}
-
-
-func setsockoptInt(fd, level, opt int, value int) os.Error {
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value));
-}
-
-func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
- var tv = syscall.NsecToTimeval(nsec);
- return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv));
-}
-
-func (c *connBase) SetReadBuffer(bytes int) os.Error {
- return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes);
-}
-
-func (c *connBase) SetWriteBuffer(bytes int) os.Error {
- return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes);
-}
-
-func (c *connBase) SetReadTimeout(nsec int64) os.Error {
- c.fd.rdeadline_delta = nsec;
- return nil;
-}
-
-func (c *connBase) SetWriteTimeout(nsec int64) os.Error {
- c.fd.wdeadline_delta = nsec;
- return nil;
-}
-
-func (c *connBase) SetTimeout(nsec int64) os.Error {
- if e := c.SetReadTimeout(nsec); e != nil {
- return e
- }
- return c.SetWriteTimeout(nsec)
-}
-
-func (c *connBase) SetReuseAddr(reuse bool) os.Error {
- return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse));
-}
-
-func (c *connBase) BindToDevice(dev string) os.Error {
- // TODO(rsc): call setsockopt with null-terminated string pointer
- return os.EINVAL
-}
-
-func (c *connBase) SetDontRoute(dontroute bool) os.Error {
- return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute));
-}
-
-func (c *connBase) SetKeepAlive(keepalive bool) os.Error {
- return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive));
-}
-
-func (c *connBase) SetLinger(sec int) os.Error {
- var l syscall.Linger;
- if sec >= 0 {
- l.Onoff = 1;
- l.Linger = int32(sec);
- } else {
- l.Onoff = 0;
- l.Linger = 0;
- }
- e := syscall.SetsockoptLinger(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_LINGER, &l);
- return os.NewSyscallError("setsockopt", e);
-}
-
-
-// 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;
- }
- }
-
- // Figure out IP version.
- // If network has a suffix like "tcp4", obey it.
- vers := 0;
- switch net[len(net)-1] {
- case '4':
- vers = 4;
- case '6':
- vers = 6;
- 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
- }
- }
-
- 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 {
- goto Error;
- }
- }
- if rip != nil {
- if ra, err = ipToSockaddr(family, rip, rport); err != nil {
- goto Error;
- }
- }
-
- fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra);
- if err != nil {
- goto Error;
- }
- return fd, nil;
-
-Error:
- addr := raddr;
- if mode == "listen" {
- addr = laddr;
- }
- 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}
- }
- fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_DGRAM, "dial");
- if e != nil {
- return nil, e
- }
- return newConnUDP(fd, raddr), nil
-}
-
-
-// TODO: raw IP connections
-
-// TODO: raw ethernet connections
-
-
-// Unix domain sockets
-
-func unixSocket(net, laddr, raddr string, mode string) (fd *netFD, err os.Error) {
- var proto int;
- switch net {
- default:
- return nil, UnknownNetworkError(net);
- case "unix":
- proto = syscall.SOCK_STREAM;
- case "unix-dgram":
- proto = syscall.SOCK_DGRAM;
- }
-
- var la, ra syscall.Sockaddr;
- switch mode {
- default:
- panic("unixSocket", mode);
-
- case "dial":
- if laddr != "" {
- return nil, &OpError{mode, net, raddr, &AddrError{"unexpected local address", laddr}}
- }
- if raddr == "" {
- return nil, &OpError{mode, net, "", errMissingAddress}
- }
- ra = &syscall.SockaddrUnix{Name: raddr};
-
- case "listen":
- if laddr == "" {
- return nil, &OpError{mode, net, "", errMissingAddress}
- }
- la = &syscall.SockaddrUnix{Name: laddr};
- if raddr != "" {
- return nil, &OpError{mode, net, laddr, &AddrError{"unexpected remote address", raddr}}
- }
- }
-
- fd, err = socket(net, laddr, raddr, syscall.AF_UNIX, proto, 0, la, ra);
- if err != nil {
- goto Error;
- }
- return fd, nil;
-
-Error:
- addr := raddr;
- if mode == "listen" {
- addr = laddr;
- }
- return nil, &OpError{mode, net, addr, err};
-}
-
-// ConnUnix is an implementation of the Conn interface
-// for connections to Unix domain sockets.
-type ConnUnix struct {
- connBase
-}
-
-func newConnUnix(fd *netFD, raddr string) *ConnUnix {
- c := new(ConnUnix);
- c.fd = fd;
- c.raddr = raddr;
- return c;
-}
-
-// DialUnix is like Dial but can only connect to Unix domain sockets
-// and returns a ConnUnix structure. The laddr argument must be
-// the empty string; it is included only to match the signature of
-// the other dial routines.
-func DialUnix(net, laddr, raddr string) (c *ConnUnix, err os.Error) {
- fd, e := unixSocket(net, laddr, raddr, "dial");
- if e != nil {
- return nil, e
- }
- return newConnUnix(fd, raddr), nil;
-}
-
-// ListenerUnix is a Unix domain socket listener.
-// Clients should typically use variables of type Listener
-// instead of assuming Unix domain sockets.
-type ListenerUnix struct {
- fd *netFD;
- laddr string
-}
-
-// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
-// Net can be either "unix" (stream sockets) or "unix-dgram" (datagram sockets).
-func ListenUnix(net, laddr string) (l *ListenerUnix, err os.Error) {
- fd, e := unixSocket(net, laddr, "", "listen");
- if e != nil {
- if pe, ok := e.(*os.PathError); ok {
- e = pe.Error;
- }
- // Check for socket ``in use'' but ``refusing connections,''
- // which means some program created it and exited
- // without unlinking it from the file system.
- // Clean up on that program's behalf and try again.
- // Don't do this for Linux's ``abstract'' sockets, which begin with @.
- if e != os.EADDRINUSE || laddr[0] == '@' {
- return nil, e;
- }
- fd1, e1 := unixSocket(net, "", laddr, "dial");
- if e1 == nil {
- fd1.Close();
- }
- if pe, ok := e1.(*os.PathError); ok {
- e1 = pe.Error;
- }
- if e1 != os.ECONNREFUSED {
- return nil, e;
- }
- syscall.Unlink(laddr);
- fd1, e1 = unixSocket(net, laddr, "", "listen");
- if e1 != nil {
- return nil, e;
- }
- fd = fd1;
- }
- e1 := syscall.Listen(fd.fd, 8); // listenBacklog());
- if e1 != 0 {
- syscall.Close(fd.fd);
- return nil, &OpError{"listen", "unix", laddr, os.Errno(e1)};
- }
- return &ListenerUnix{fd, laddr}, nil;
-}
-
-// AcceptUnix accepts the next incoming call and returns the new connection
-// and the remote address.
-func (l *ListenerUnix) AcceptUnix() (c *ConnUnix, 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 newConnUnix(fd, fd.raddr), raddr, nil
-}
-
-// Accept implements the Accept method in the Listener interface;
-// it waits for the next call and returns a generic Conn.
-func (l *ListenerUnix) Accept() (c Conn, raddr string, err os.Error) {
- // TODO(rsc): Should return l.AcceptUnix() be okay here?
- // There is a type conversion -- the first return arg of
- // l.AcceptUnix() is *ConnUnix and it gets converted to Conn
- // in the explicit assignment.
- c, raddr, err = l.AcceptUnix();
- return;
-}
-
-
-// Close stops listening on the Unix address.
-// Already accepted connections are not closed.
-func (l *ListenerUnix) Close() os.Error {
- if l == nil || l.fd == nil {
- return os.EINVAL
- }
-
- // The operating system doesn't clean up
- // the file that announcing created, so
- // we have to clean it up ourselves.
- // There's a race here--we can't know for
- // sure whether someone else has come along
- // and replaced our socket name already--
- // but this sequence (remove then close)
- // is at least compatible with the auto-remove
- // sequence in ListenUnix. It's only non-Go
- // programs that can mess us up.
- if l.laddr[0] != '@' {
- syscall.Unlink(l.laddr);
- }
- err := l.fd.Close();
- l.fd = nil;
- return err;
-}
-
-// Addr returns the listener's network address.
-func (l *ListenerUnix) Addr() string {
- return l.fd.addr();
+// A Listener is a generic network listener.
+// Accept waits for the next connection and Close closes the connection.
+type Listener interface {
+ Accept() (c Conn, raddr string, err os.Error);
+ Close() os.Error;
+ Addr() string; // Listener's network address
}
// Dial connects to the remote address raddr on the network net.
@@ -840,92 +130,10 @@
case "unix", "unix-dgram":
c, err := DialUnix(net, laddr, raddr);
return c, err;
-/*
- case "ether":
- c, err := DialEther(net, laddr, raddr);
- return c, err;
- case "ipv4":
- c, err := DialIPv4(net, laddr, raddr);
- return c, err;
- case "ipv6":
- c, err := DialIPv6(net, laddr, raddr);
- return c, err
-*/
}
return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)};
}
-// A Listener is a generic network listener.
-// Accept waits for the next connection and Close closes the connection.
-type Listener interface {
- Accept() (c Conn, raddr string, err os.Error);
- Close() os.Error;
- Addr() string; // Listener's network address
-}
-
-// ListenerTCP is a TCP network listener.
-// 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();
-}
-
// Listen announces on the local network address laddr.
// The network string net must be "tcp", "tcp4", "tcp6",
// "unix", or "unix-dgram".
@@ -943,11 +151,47 @@
return nil, err;
}
return l, nil;
-/*
- more here
-*/
// BUG(rsc): Listen should support UDP.
}
return nil, UnknownNetworkError(net);
}
+var errMissingAddress = os.ErrorString("missing address")
+
+type OpError struct {
+ Op string;
+ Net string;
+ Addr string;
+ Error os.Error;
+}
+
+func (e *OpError) String() string {
+ s := e.Op;
+ if e.Net != "" {
+ s += " " + e.Net;
+ }
+ if e.Addr != "" {
+ s += " " + e.Addr;
+ }
+ s += ": " + e.Error.String();
+ return s;
+}
+
+type AddrError struct {
+ Error string;
+ Addr string;
+}
+
+func (e *AddrError) String() string {
+ s := e.Error;
+ if e.Addr != "" {
+ s += " " + e.Addr;
+ }
+ return s;
+}
+
+type UnknownNetworkError string
+func (e UnknownNetworkError) String() string {
+ return "unknown network " + string(e);
+}
+