preliminary network - just Dial for now

R=r,presotto
OCL=15393
CL=15399
diff --git a/src/lib/net/net.go b/src/lib/net/net.go
new file mode 100644
index 0000000..d44f2d3
--- /dev/null
+++ b/src/lib/net/net.go
@@ -0,0 +1,483 @@
+// 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.
+
+package net
+
+import (
+	"os";
+	"ip";
+	"socket";
+	"strings";
+	"syscall"
+)
+
+func NewError(s string) *os.Error {
+	e := new(os.Error);
+	e.s = s;
+	return e
+}
+
+export var (
+	BadAddress = NewError("malformed addres");
+	UnknownNetwork = NewError("unknown network");
+	UnknownHost = NewError("unknown host");
+	UnknownPort = NewError("unknown port");
+	UnknownSocketFamily = NewError("unknown socket family");
+)
+
+// 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.
+	var i int
+	for i = len(hostport)-1; i >= 0; i-- {
+		if hostport[i] == ':' {
+			break
+		}
+	}
+	if i < 0 {
+		return "", "", BadAddress
+	}
+	
+	host = hostport[0:i];
+	port = hostport[i+1:len(hostport)];
+	
+	// Can put brackets around host ...
+	if host[0] == '[' && host[len(host)-1] == ']' {
+		host = host[1:len(host)-1]
+	} else {
+		// ... but if there are no brackets, no colons.
+		for i := 0; i < len(host); i++ {
+			if host[i] == ':' {
+				return "", "", BadAddress
+			}
+		}
+	}
+	return host, port, nil
+}
+
+// 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.
+	for i := 0; i < len(host); i++ {
+		if host[i] == ':' {
+			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 string, hostport string) (ip *[]byte, iport int, err *os.Error) {
+	var host, port string;
+	host, port, err = SplitHostPort(hostport);
+	if err != nil {
+		return nil, 0, err
+	}
+	
+	// TODO: Resolve host.
+	
+	addr := ip.ParseIP(host);
+	if addr == nil {
+print("Failed to parse: ", host, "\n");
+		return nil, 0, UnknownHost
+	}
+	
+	// TODO: Resolve port.
+	
+	p, ok := strings.atoi(port);
+	if !ok || p < 0 || p > 0xFFFF {
+		return nil, 0, UnknownPort
+	}
+	
+	return addr, p, nil
+}
+
+// Convert socket address into "host:port".
+func SockaddrToHostPort(sa *socket.Sockaddr) (hostport string, err *os.Error) {
+	switch sa.family {
+	case socket.AF_INET, socket.AF_INET6:
+		addr, port, e := socket.SockaddrToIP(sa)
+		if e != nil {
+			return "", e
+		}
+		host := ip.IPToString(addr);
+		return JoinHostPort(host, strings.itoa(port)), nil
+	default:
+		return "", UnknownSocketFamily
+	}
+	return "", nil // not reached
+}
+
+// Boolean to int.
+func boolint(b bool) int {
+	if b {
+		return 1
+	} 
+	return 0
+}
+
+// Generic Socket creation.
+func Socket(f, p, t int64, la, ra *socket.Sockaddr) (fd int64, err *os.Error) {
+	s, e := socket.socket(f, p, t);
+	if e != nil {
+		return -1, e
+	}
+	
+	var r int64
+	if la != nil {
+		r, e = socket.bind(s, la)
+		if e != nil {
+			syscall.close(s)
+			return -1, e
+		}
+	}
+	
+	if ra != nil {
+		r, e = socket.connect(s, ra)
+		if e != nil {
+			syscall.close(s)
+			return -1, e
+		}
+	}
+	
+	return s, nil
+}
+
+
+// Generic implementation of Conn interface; not exported.
+
+type ConnBase struct {
+	fd *os.FD;
+	raddr string;
+}
+
+// Eventually, these will use epoll or some such.
+
+func (c *ConnBase) FD() int64 {
+	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 (c *ConnBase) SetReadBuffer(bytes int) *os.Error {
+	return socket.setsockopt_int(c.FD(), socket.SOL_SOCKET, socket.SO_RCVBUF, bytes);
+}
+
+func (c *ConnBase) SetWriteBuffer(bytes int) *os.Error {
+	return socket.setsockopt_int(c.FD(), socket.SOL_SOCKET, socket.SO_SNDBUF, bytes);
+}
+
+func (c *ConnBase) SetReadTimeout(nsec int64) *os.Error {
+	return socket.setsockopt_tv(c.FD(), socket.SOL_SOCKET, socket.SO_RCVTIMEO, nsec);
+}
+
+func (c *ConnBase) SetWriteTimeout(nsec int64) *os.Error {
+	return socket.setsockopt_tv(c.FD(), socket.SOL_SOCKET, socket.SO_SNDTIMEO, nsec);
+}
+
+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 socket.setsockopt_int(c.FD(), socket.SOL_SOCKET, socket.SO_REUSEADDR, boolint(reuse));
+}
+
+func (c *ConnBase) BindToDevice(dev string) *os.Error {
+	// TODO: call setsockopt with null-terminated string pointer
+	return os.EINVAL
+}
+
+func (c *ConnBase) SetDontRoute(dontroute bool) *os.Error {
+	return socket.setsockopt_int(c.FD(), socket.SOL_SOCKET, socket.SO_DONTROUTE, boolint(dontroute));
+}
+
+func (c *ConnBase) SetKeepAlive(keepalive bool) *os.Error {
+	return socket.setsockopt_int(c.FD(), socket.SOL_SOCKET, socket.SO_KEEPALIVE, boolint(keepalive));
+}
+
+func (c *ConnBase) SetLinger(sec int) *os.Error {
+	return socket.setsockopt_linger(c.FD(), socket.SOL_SOCKET, socket.SO_LINGER, sec);
+}
+
+
+// Internet sockets (TCP, UDP)
+
+// 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.
+// If we need to build on a system without IPv6 support, setting
+// PreferIPv4 here should fall back to the IPv4 socket interface when possible.
+const PreferIPv4 = false
+
+func DialInternet(net, laddr, raddr string, proto int64) (fd int64, err *os.Error) {
+	// Parse addresses (unless they are empty).
+	var lip, rip *[]byte
+	var lport, rport int
+	var lerr, rerr *os.Error
+	if laddr != "" {
+		lip, lport, lerr = HostPortToIP(net, laddr)
+		if lerr != nil {
+			return -1, lerr
+		}
+	}
+	if raddr != "" {
+		rip, rport, rerr = HostPortToIP(net, raddr)
+		if rerr != nil {
+			return -1, rerr
+		}
+	}
+
+	// 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 || ip.ToIPv4(lip) != nil)
+		&& (rip == nil || ip.ToIPv4(rip) != nil) {
+			vers = 4
+		} else {
+			vers = 6
+		}
+	}
+
+	var cvt *(addr *[]byte, port int) (sa *socket.Sockaddr, err *os.Error)
+	var family int64
+	if vers == 4 {
+		cvt = &socket.IPv4ToSockaddr;
+		family = socket.AF_INET
+	} else {
+		cvt = &socket.IPv6ToSockaddr;
+		family = socket.AF_INET6
+	}
+	
+	var la, ra *socket.Sockaddr;
+	if lip != nil {
+		la, lerr = cvt(lip, lport);
+		if lerr != nil {
+			return -1, lerr
+		}
+	}
+	if rip != nil {
+		ra, rerr = cvt(rip, rport);
+		if rerr != nil {
+			return -1, rerr
+		}
+	}
+
+	fd, err = Socket(family, proto, 0, la, ra);
+	return fd, err
+}
+
+
+// TCP connections.
+
+export type ConnTCP struct {
+	base ConnBase
+}
+
+// New TCP methods
+func (c *ConnTCP) SetNoDelay(nodelay bool) *os.Error {
+	if c == nil {
+		return os.EINVAL
+	}
+	return socket.setsockopt_int(c.base.fd.fd, socket.IPPROTO_TCP, socket.TCP_NODELAY, boolint(nodelay))
+}
+
+// Wrappers
+func (c *ConnTCP) Read(b *[]byte) (n int, err *os.Error) {
+	n, err = (&c.base).Read(b)
+	return n, err
+}
+func (c *ConnTCP) Write(b *[]byte) (n int, err *os.Error) {
+	n, err = (&c.base).Write(b)
+	return n, err
+}
+func (c *ConnTCP) ReadFrom(b *[]byte) (n int, raddr string, err *os.Error) {
+	n, raddr, err = (&c.base).ReadFrom(b)
+	return n, raddr, err
+}
+func (c *ConnTCP) WriteTo(raddr string, b *[]byte) (n int, err *os.Error) {
+	n, err = (&c.base).WriteTo(raddr, b)
+	return n, err
+}
+func (c *ConnTCP) Close() *os.Error {
+	return (&c.base).Close()
+}
+func (c *ConnTCP) SetReadBuffer(bytes int) *os.Error {
+	return (&c.base).SetReadBuffer(bytes)
+}
+func (c *ConnTCP) SetWriteBuffer(bytes int) *os.Error {
+	return (&c.base).SetWriteBuffer(bytes)
+}
+func (c *ConnTCP) SetTimeout(nsec int64) *os.Error {
+	return (&c.base).SetTimeout(nsec)
+}
+func (c *ConnTCP) SetReadTimeout(nsec int64) *os.Error {
+	return (&c.base).SetReadTimeout(nsec)
+}
+func (c *ConnTCP) SetWriteTimeout(nsec int64) *os.Error {
+	return (&c.base).SetWriteTimeout(nsec)
+}
+func (c *ConnTCP) SetLinger(sec int) *os.Error {
+	return (&c.base).SetLinger(sec)
+}
+func (c *ConnTCP) SetReuseAddr(reuseaddr bool) *os.Error {
+	return (&c.base).SetReuseAddr(reuseaddr)
+}
+func (c *ConnTCP) BindToDevice(dev string) *os.Error {
+	return (&c.base).BindToDevice(dev)
+}
+func (c *ConnTCP) SetDontRoute(dontroute bool) *os.Error {
+	return (&c.base).SetDontRoute(dontroute)
+}
+func (c *ConnTCP) SetKeepAlive(keepalive bool) *os.Error {
+	return (&c.base).SetKeepAlive(keepalive)
+}
+
+export func DialTCP(net, laddr, raddr string) (c *ConnTCP, err *os.Error) {
+	fd, e := DialInternet(net, laddr, raddr, socket.SOCK_STREAM)
+	if e != nil {
+		return nil, e
+	}
+	c = new(ConnTCP);
+	c.base.fd = os.NewFD(fd);
+	c.SetNoDelay(true)
+	return c, nil
+}
+
+
+// TODO: UDP connections
+
+
+// TODO: raw IP connections
+
+
+// TODO: raw ethernet connections
+
+
+export type Conn interface {
+	Read(b *[]byte) (n int, err *os.Error);
+	Write(b *[]byte) (n int, err *os.Error);
+	ReadFrom(b *[]byte) (n int, addr string, err *os.Error);
+	WriteTo(addr string, b *[]byte) (n int, err *os.Error);
+	Close() *os.Error;
+	SetReadBuffer(bytes int) *os.Error;
+	SetWriteBuffer(bytes int) *os.Error;
+	SetTimeout(nsec int64) *os.Error;
+	SetReadTimeout(nsec int64) *os.Error;
+	SetWriteTimeout(nsec int64) *os.Error;
+	SetLinger(sec int) *os.Error;
+	SetReuseAddr(reuseaddr bool) *os.Error;
+	SetDontRoute(dontroute bool) *os.Error;
+	SetKeepAlive(keepalive bool) *os.Error;
+	BindToDevice(dev string) *os.Error;
+}
+
+type NoConn struct { unused int }
+func (c *NoConn) Read(b *[]byte) (n int, err *os.Error) { return -1, os.EINVAL }
+func (c *NoConn) Write(b *[]byte) (n int, err *os.Error) { return -1, os.EINVAL }
+func (c *NoConn) ReadFrom(b *[]byte) (n int, addr string, err *os.Error) { return -1, "", os.EINVAL }
+func (c *NoConn) WriteTo(addr string, b *[]byte) (n int, err *os.Error) { return -1, os.EINVAL }
+func (c *NoConn) Close() *os.Error { return nil }
+func (c *NoConn) SetReadBuffer(bytes int) *os.Error { return os.EINVAL }
+func (c *NoConn) SetWriteBuffer(bytes int) *os.Error { return os.EINVAL }
+func (c *NoConn) SetTimeout(nsec int64) *os.Error { return os.EINVAL }
+func (c *NoConn) SetReadTimeout(nsec int64) *os.Error { return os.EINVAL }
+func (c *NoConn) SetWriteTimeout(nsec int64) *os.Error { return os.EINVAL }
+func (c *NoConn) SetLinger(sec int) *os.Error { return os.EINVAL }
+func (c *NoConn) SetReuseAddr(reuseaddr bool) *os.Error { return os.EINVAL }
+func (c *NoConn) SetDontRoute(dontroute bool) *os.Error { return os.EINVAL }
+func (c *NoConn) SetKeepAlive(keepalive bool) *os.Error { return os.EINVAL }
+func (c *NoConn) BindToDevice(dev string) *os.Error { return os.EINVAL }
+
+var noconn NoConn
+
+// Dial's arguments are the network, local address, and remote address.
+// Examples:
+//	Dial("tcp", "", "12.34.56.78:80")
+//	Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
+//	Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
+//
+// Eventually, we plan to allow names in addition to IP addresses,
+// but that requires writing a DNS library.
+
+export func Dial(net, laddr, raddr string) (c Conn, err *os.Error) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+		c, err := DialTCP(net, laddr, raddr)
+		if err != nil {
+			return &noconn, err
+		}
+		return c, nil
+/*
+	case "udp", "udp4", "upd6":
+		c, err := DialUDP(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, UnknownNetwork
+}
+