1
0
mirror of https://github.com/golang/go synced 2024-10-05 14:11:22 -06:00
go/src/lib/net/net.go

654 lines
16 KiB
Go
Raw Normal View History

// 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 (
"net";
"os";
"strconv";
"syscall";
)
2009-01-20 15:40:40 -07:00
var (
BadAddress = os.NewError("malformed address");
MissingAddress = os.NewError("missing address");
UnknownNetwork = os.NewError("unknown network");
UnknownHost = os.NewError("unknown host");
UnknownSocketFamily = os.NewError("unknown socket family");
)
func LookupHost(name string) (cname string, addrs []string, err os.Error)
// 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 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 {
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.
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 []byte, iport int, err os.Error) {
var host, port string;
host, port, err = splitHostPort(hostport);
if err != nil {
return nil, 0, err
}
var addr []byte;
if host == "" {
if mode == "listen" {
addr = IPzero; // wildcard - listen to all
} else {
return nil, 0, MissingAddress;
}
}
// Try as an IP address.
if addr == nil {
addr = ParseIP(host);
}
if addr == nil {
// Not an IP address. Try as a DNS name.
hostname, addrs, err := LookupHost(host);
if err != nil {
return nil, 0, err
}
if len(addrs) == 0 {
return nil, 0, UnknownHost
}
addr = ParseIP(addrs[0]);
if addr == nil {
// should not happen
return nil, 0, BadAddress
}
}
p, i, ok := dtoi(port, 0);
if !ok || i != len(port) {
p, err = LookupPort(net, port);
if err != nil {
return nil, 0, err
}
}
if p < 0 || p > 0xFFFF {
return nil, 0, BadAddress
}
return addr, p, nil
}
// Convert socket address into "host:port".
func sockaddrToHostPort(sa *syscall.Sockaddr) (hostport string, err os.Error) {
switch sa.Family {
case syscall.AF_INET, syscall.AF_INET6:
addr, port, e := sockaddrToIP(sa);
if e != nil {
return "", e
}
host := addr.String();
return joinHostPort(host, strconv.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(net, laddr, raddr string, f, p, t int64, 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.ErrnoToError(e)
}
syscall.CloseOnExec(s);
syscall.ForkLock.RUnlock();
// Allow reuse of recently-used addresses.
syscall.Setsockopt_int(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1);
var r int64;
if la != nil {
r, e = syscall.Bind(s, la);
if e != 0 {
syscall.Close(s);
return nil, os.ErrnoToError(e)
}
}
if ra != nil {
r, e = syscall.Connect(s, ra);
if e != 0 {
syscall.Close(s);
return nil, os.ErrnoToError(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) File() *os.File {
if c == nil {
return nil
}
return c.fd.file;
}
func (c *connBase) sysFD() 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 setsockopt_int(fd, level, opt int64, value int) os.Error {
return os.ErrnoToError(syscall.Setsockopt_int(fd, level, opt, value));
}
func setsockopt_tv(fd, level, opt int64, nsec int64) os.Error {
return os.ErrnoToError(syscall.Setsockopt_tv(fd, level, opt, nsec));
}
func (c *connBase) SetReadBuffer(bytes int) os.Error {
return setsockopt_int(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes);
}
func (c *connBase) SetWriteBuffer(bytes int) os.Error {
return setsockopt_int(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 setsockopt_int(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 setsockopt_int(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute));
}
func (c *connBase) SetKeepAlive(keepalive bool) os.Error {
return setsockopt_int(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive));
}
func (c *connBase) SetLinger(sec int) os.Error {
e := syscall.Setsockopt_linger(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_LINGER, sec);
return os.ErrnoToError(e);
}
// 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.
// 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()
func internetSocket(net, laddr, raddr string, proto int64, mode string)
(fd *netFD, err os.Error)
{
// Parse addresses (unless they are empty).
var lip, rip IP;
var lport, rport int;
var lerr, rerr os.Error;
if laddr != "" {
lip, lport, lerr = hostPortToIP(net, laddr, mode);
if lerr != nil {
return nil, lerr
}
}
if raddr != "" {
rip, rport, rerr = hostPortToIP(net, raddr, mode);
if rerr != nil {
return nil, 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 || lip.To4() != nil) && (rip == nil || rip.To4() != nil) {
vers = 4
} else {
vers = 6
}
}
var cvt func(addr []byte, port int) (sa *syscall.Sockaddr, err os.Error);
var family int64;
if vers == 4 {
cvt = v4ToSockaddr;
family = syscall.AF_INET
} else {
cvt = v6ToSockaddr;
family = syscall.AF_INET6
}
var la, ra *syscall.Sockaddr;
if lip != nil {
la, lerr = cvt(lip, lport);
if lerr != nil {
return nil, lerr
}
}
if rip != nil {
ra, rerr = cvt(rip, rport);
if rerr != nil {
return nil, rerr
}
}
fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra);
return fd, err
}
// TCP connections.
2009-01-20 15:40:40 -07:00
type ConnTCP struct {
connBase
}
func (c *ConnTCP) SetNoDelay(nodelay bool) os.Error {
if c == nil {
return os.EINVAL
}
return setsockopt_int(c.sysFD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay))
}
func newConnTCP(fd *netFD, raddr string) *ConnTCP {
2009-01-06 16:19:02 -07:00
c := new(ConnTCP);
c.fd = fd;
c.raddr = raddr;
c.SetNoDelay(true);
return c
}
func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
if raddr == "" {
return nil, MissingAddress
}
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
2009-01-20 15:40:40 -07:00
type ConnUDP struct {
connBase
}
func newConnUDP(fd *netFD, raddr string) *ConnUDP {
2009-01-06 16:19:02 -07:00
c := new(ConnUDP);
c.fd = fd;
c.raddr = raddr;
return c
}
func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
if raddr == "" {
return nil, MissingAddress
}
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
// A Conn is a generic network connection.
2009-01-20 15:40:40 -07:00
type Conn interface {
// Read blocks until data is ready from the connection
// and then reads into b. It returns the number
// of bytes read, or 0 if the connection has been closed.
Read(b []byte) (n int, err os.Error);
// Write writes the data in b to the connection.
Write(b []byte) (n int, err os.Error);
// Close closes the connection.
Close() os.Error;
// For packet-based protocols such as UDP,
// ReadFrom reads the next packet from the network,
// returning the number of bytes read and the remote
// address that sent them.
ReadFrom(b []byte) (n int, addr string, err os.Error);
// For packet-based protocols such as UDP,
// WriteTo writes the byte buffer b to the network
// as a single payload, sending it to the target address.
WriteTo(addr string, b []byte) (n int, err os.Error);
// SetReadBuffer sets the size of the operating system's
// receive buffer associated with the connection.
SetReadBuffer(bytes int) os.Error;
// SetReadBuffer sets the size of the operating system's
// transmit buffer associated with the connection.
SetWriteBuffer(bytes int) os.Error;
// SetTimeout sets the read and write deadlines associated
// with the connection.
SetTimeout(nsec int64) os.Error;
// SetReadTimeout sets the time (in nanoseconds) that
// Read will wait for data before returning os.EAGAIN.
// Setting nsec == 0 (the default) disables the deadline.
SetReadTimeout(nsec int64) os.Error;
// SetWriteTimeout sets the time (in nanoseconds) that
// Write will wait to send its data before returning os.EAGAIN.
// Setting nsec == 0 (the default) disables the deadline.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
SetWriteTimeout(nsec int64) os.Error;
// SetLinger sets the behavior of Close() on a connection
// which still has data waiting to be sent or to be acknowledged.
//
// If sec < 0 (the default), Close returns immediately and
// the operating system finishes sending the data in the background.
//
// If sec == 0, Close returns immediately and the operating system
// discards any unsent or unacknowledged data.
//
// If sec > 0, Close blocks for at most sec seconds waiting for
// data to be sent and acknowledged.
SetLinger(sec int) os.Error;
// SetReuseAddr sets whether it is okay to reuse addresses
// from recent connections that were not properly closed.
SetReuseAddr(reuseaddr bool) os.Error;
// SetDontRoute sets whether outgoing messages should
// bypass the system routing tables.
SetDontRoute(dontroute bool) os.Error;
// SetKeepAlive sets whether the operating system should send
// keepalive messages on the connection.
SetKeepAlive(keepalive bool) os.Error;
// BindToDevice binds a connection to a particular network device.
BindToDevice(dev string) os.Error;
}
// Dial connects to the remote address raddr on the network net.
// If the string laddr is not empty, it is used as the local address
// for the connection.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), and "udp6" (IPv6-only).
//
// For IP networks, addresses have the form host:port. If host is
// a literal IPv6 address, it must be enclosed in square brackets.
//
// Examples:
// Dial("tcp", "", "12.34.56.78:80")
// Dial("tcp", "", "google.com:80")
// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
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 nil, 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
}
// A Listener is a generic network listener.
// Accept waits for the next connection and Close closes the connection.
2009-01-20 15:40:40 -07:00
type Listener interface {
Accept() (c Conn, raddr string, err os.Error);
Close() os.Error;
}
// ListenerTCP is a TCP network listener.
// Clients should typically use variables of type Listener
// instead of assuming TCP.
2009-01-20 15:40:40 -07:00
type ListenerTCP struct {
fd *netFD;
laddr string
}
// ListenTCP announces on the TCP address laddr and returns a TCP listener.
// Net must be "tcp", "tcp4", or "tcp6".
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
}
r, e1 := syscall.Listen(fd.fd, listenBacklog());
if e1 != 0 {
syscall.Close(fd.fd);
return nil, os.ErrnoToError(e1)
}
2009-01-06 16:19:02 -07:00
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
}
var sa syscall.Sockaddr;
fd, e := l.fd.Accept(&sa);
if e != nil {
return nil, "", e
}
raddr, err = sockaddrToHostPort(&sa);
if err != nil {
fd.Close();
return nil, "", err
}
return newConnTCP(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 *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()
}
// Listen announces on the local network address laddr.
// The network string net must be "tcp", "tcp4", or "tcp6".
func Listen(net, laddr string) (l Listener, err os.Error) {
switch net {
case "tcp", "tcp4", "tcp6":
l, err := ListenTCP(net, laddr);
if err != nil {
return nil, err
}
return l, nil
/*
more here
*/
// BUG(rsc): Listen should support UDP.
}
return nil, UnknownNetwork
}