diff options
author | Russ Cox <rsc@golang.org> | 2008-09-16 13:42:47 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2008-09-16 13:42:47 -0700 |
commit | 015a709e5efffab4183acf1a6d5146d99ba574cd (patch) | |
tree | 9f656df558356b50f93329d1697852b7a3feb2ef /src/lib | |
parent | 4e3a56356778e5628364e4995e1a12d93aece84e (diff) | |
download | golang-015a709e5efffab4183acf1a6d5146d99ba574cd.tar.gz |
preliminary network - just Dial for now
R=r,presotto
OCL=15393
CL=15399
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/net/Makefile | 44 | ||||
-rw-r--r-- | src/lib/net/cvt.s | 38 | ||||
-rw-r--r-- | src/lib/net/ip.go | 431 | ||||
-rw-r--r-- | src/lib/net/net.go | 483 | ||||
-rw-r--r-- | src/lib/net/socket_darwin.go | 231 | ||||
-rw-r--r-- | src/lib/net/socket_linux.go | 247 |
6 files changed, 1474 insertions, 0 deletions
diff --git a/src/lib/net/Makefile b/src/lib/net/Makefile new file mode 100644 index 000000000..5d0802173 --- /dev/null +++ b/src/lib/net/Makefile @@ -0,0 +1,44 @@ +# 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. + +O=6 +GC=$(O)g +AS=$(O)a + +NET=$(GOROOT)/pkg/net.a +SOCKET=$(GOROOT)/pkg/socket.a +IP=$(GOROOT)/pkg/ip.$O + +NETO=\ + net.$O\ + +SOCKETO=\ + cvt.$O\ + socket_$(GOOS).$O\ + +$(NET): $(NETO) + $(O)ar grc $(NET) $(NETO) + +$(NETO): $(IP) $(SOCKET) + +$(SOCKET): $(SOCKETO) + $(O)ar grc $(SOCKET) $(SOCKETO) + +$(GOROOT)/pkg/%.$O: %.$O + cp $*.$O $(GOROOT)/pkg/$*.$O + rm $*.$O + +install: nuke $(IP) $(SOCKET) $(NET) + +nuke: + rm -f *.$O *.a $(IP) $(NET) + +clean: + rm -f *.$O *.a + +%.$O: %.go + $(GC) $< + +%.$O: %.s + $(AS) $< diff --git a/src/lib/net/cvt.s b/src/lib/net/cvt.s new file mode 100644 index 000000000..920f52351 --- /dev/null +++ b/src/lib/net/cvt.s @@ -0,0 +1,38 @@ +// 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. + +// Type-unsafe casts. + +TEXT socket·SockaddrPtr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·Int32Ptr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·LingerPtr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·TimevalPtr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·SockaddrInet4ToSockaddr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·SockaddrToSockaddrInet4(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·SockaddrInet6ToSockaddr(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET +TEXT socket·SockaddrToSockaddrInet6(SB),7,$0 + MOVQ 8(SP), AX + MOVQ AX, 16(SP) + RET diff --git a/src/lib/net/ip.go b/src/lib/net/ip.go new file mode 100644 index 000000000..ddb5114c5 --- /dev/null +++ b/src/lib/net/ip.go @@ -0,0 +1,431 @@ +// 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. + +// IP address manipulations +// +// IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes. +// An IPv4 address can be converted to an IPv6 address by +// adding a canonical prefix (10 zeros, 2 0xFFs). +// This library accepts either size of byte array but always +// returns 16-byte addresses. + +package ip + +export const ( + IPv4len = 4; + IPv6len = 16 +) + +// Make the 4 bytes into an IPv4 address (in IPv6 form) +func MakeIPv4(a, b, c, d byte) *[]byte { + p := new([]byte, IPv6len) + for i := 0; i < 10; i++ { + p[i] = 0 + } + p[10] = 0xff; + p[11] = 0xff; + p[12] = a; + p[13] = b; + p[14] = c; + p[15] = d + return p +} + +// Well-known IP addresses +export var IPv4bcast, IPv4allsys, IPv4allrouter, IPv4prefix, IPallbits, IPnoaddr *[]byte + +func init() { + IPv4bcast = MakeIPv4(0xff, 0xff, 0xff, 0xff); + IPv4allsys = MakeIPv4(0xe0, 0x00, 0x00, 0x01); + IPv4allrouter = MakeIPv4(0xe0, 0x00, 0x00, 0x02); + IPv4prefix = MakeIPv4(0, 0, 0, 0); + IPallbits = new([]byte, IPv6len); + for i := 0; i < IPv6len; i++ { + IPallbits[i] = 0xff + } + IPnoaddr = new([]byte, IPv6len); // zeroed +} + +// Is p all zeros? +func IsZeros(p *[]byte) bool { + for i := 0; i < len(p); i++ { + if p[i] != 0 { + return false + } + } + return true +} + +// Is p an IPv4 address (perhaps in IPv6 form)? +// If so, return the 4-byte V4 array. +export func ToIPv4(p *[]byte) *[]byte { + if len(p) == IPv4len { + return p + } + if len(p) == IPv6len + && IsZeros(p[0:10]) + && p[10] == 0xff + && p[11] == 0xff { + return p[12:16] + } + return nil +} + +// Convert p to IPv6 form. +export func ToIPv6(p *[]byte) *[]byte { + if len(p) == IPv4len { + return MakeIPv4(p[0], p[1], p[2], p[3]) + } + if len(p) == IPv6len { + return p + } + return nil +} + +// Default route masks for IPv4. +export var ( + ClassAMask = MakeIPv4(0xff, 0, 0, 0); + ClassBMask = MakeIPv4(0xff, 0xff, 0, 0); + ClassCMask = MakeIPv4(0xff, 0xff, 0xff, 0); +) + +export func DefaultMask(p *[]byte) *[]byte { + if p = ToIPv4(p); p == nil { + return nil + } + switch true { + case p[0] < 0x80: + return ClassAMask; + case p[0] < 0xC0: + return ClassBMask; + default: + return ClassCMask; + } + return nil; // not reached +} + +// Apply mask to ip, returning new address. +export func Mask(ip *[]byte, mask *[]byte) *[]byte { + n := len(ip) + if n != len(mask) { + return nil + } + out := new([]byte, n) + for i := 0; i < n; i++ { + out[i] = ip[i] & mask[i]; + } + return out +} + +// Convert i to decimal string. +func itod(i uint) string { + if i == 0 { + return "0" + } + + // Assemble decimal in reverse order. + var b [32]byte; + bp := len(b); + for ; i > 0; i /= 10 { + bp--; + b[bp] = byte(i%10) + '0' + } + + // return string(b[bp:len(b)]) + return string((&b)[bp:len(b)]) +} + +// Convert i to hexadecimal string. +func itox(i uint) string { + if i == 0 { + return "0" + } + + // Assemble hexadecimal in reverse order. + var b [32]byte; + bp := len(b); + for ; i > 0; i /= 16 { + bp--; + b[bp] = "0123456789abcdef"[byte(i%16)] + } + + // return string(b[bp:len(b)]) + return string((&b)[bp:len(b)]) +} + +// Convert IP address to string. +export func IPToString(p *[]byte) string { + // If IPv4, use dotted notation. + if p4 := ToIPv4(p); p4 != nil { + return itod(uint(p4[0]))+"." + +itod(uint(p4[1]))+"." + +itod(uint(p4[2]))+"." + +itod(uint(p4[3])) + } + if len(p) != IPv6len { + return "?" + } + + // Find longest run of zeros. + e0 := -1; + e1 := -1 + for i := 0; i < 16; i+=2 { + j := i + for j < 16 && p[j] == 0 && p[j+1] == 0 { + j += 2 + } + if j > i && j - i > e1 - e0 { + e0 = i; + e1 = j + } + } + + // Print with possible :: in place of run of zeros + var s string; + for i := 0; i < 16; i += 2 { + if i == e0 { + s += "::"; + i = e1 + if i >= 16 { + break + } + } else if i > 0 { + s += ":" + } + s += itox((uint(p[i])<<8) | uint(p[i+1])) + } + return s +} + +// If mask is a sequence of 1 bits followed by 0 bits, +// return the number of 1 bits. +func SimpleMaskLength(mask *[]byte) int { + var i int + for i = 0; i < len(mask); i++ { + if mask[i] != 0xFF { + break + } + } + n := 8*i; + v := mask[i] + for v & 0x80 != 0 { + n++ + v <<= 1 + } + if v != 0 { + return -1 + } + for i++; i < len(mask); i++ { + if mask[i] != 0 { + return -1 + } + } + return n +} + +export func MaskToString(mask *[]byte) string { + switch len(mask) { + case 4: + n := SimpleMaskLength(mask) + if n >= 0 { + return itod(uint(n+(IPv6len-IPv4len)*8)) + } + case 16: + n := SimpleMaskLength(mask) + if n >= 0 { + return itod(uint(n)) + } + } + return IPToString(mask) +} + +// Parsing. + +// Bigger than we need, not too big to worry about overflow +const Big = 0xFFFFFF + +// Decimal to integer starting at &s[i]. +// Returns number, new offset, success. +func dtoi(s string, i int) (n int, i1 int, ok bool) { + if len(s) <= i || s[i] < '0' || s[i] > '9' { + return 0, i, false + } + n = 0; + for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ { + n = n*10 + int(s[i] - '0') + if n >= Big { + return 0, i, false + } + } + return n, i, true +} + +// Is b a hex digit? +func ishex(b byte) bool { + return '0' <= b && b <= '9' + || 'a' <= b && b <= 'f' + || 'A' <= b && b <= 'F' +} + +// Hexadecimal to integer starting at &s[i]. +// Returns number, new offset, success. +func xtoi(s string, i int) (n int, i1 int, ok bool) { + if len(s) <= i || !ishex(s[i]) { + return 0, i, false + } + + n = 0; + for ; i < len(s) && ishex(s[i]); i++ { + n *= 16 + if '0' <= s[i] && s[i] <= '9' { + n += int(s[i] - '0') + } else if 'a' <= s[i] && s[i] <= 'f' { + n += int(s[i] - 'a') + 10 + } else { + n += int(s[i] -'A') + 10 + } + if n >= Big { + return 0, i, false + } + } + return n, i, true +} + +// Parse IPv4 address (d.d.d.d). +func ParseIPv4(s string) *[]byte { + var p [IPv4len]byte + i := 0 + for j := 0; j < IPv4len; j++ { + if j > 0 { + if s[i] != '.' { + return nil + } + i++ + } + var ( + n int; + ok bool + ) + n, i, ok = dtoi(s, i) + if !ok || n > 0xFF { + return nil + } + p[j] = byte(n) + } + if i != len(s) { + return nil + } + return MakeIPv4(p[0], p[1], p[2], p[3]) +} + +// Parse IPv6 address. Many forms. +// The basic form is a sequence of eight colon-separated +// 16-bit hex numbers separated by colons, +// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef. +// Two exceptions: +// * A run of zeros can be replaced with "::". +// * The last 32 bits can be in IPv4 form. +// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4. +func ParseIPv6(s string) *[]byte { + p := new([]byte, 16); + ellipsis := -1; // position of ellipsis in p + i := 0; // index in string s + + // Might have leading ellipsis + if len(s) >= 2 && s[0] == ':' && s[1] == ':' { + ellipsis = 0; + i = 2 + } + + // Loop, parsing hex numbers followed by colon. + j := 0; +L: for j < IPv6len { + // Hex number. + n, i1, ok := xtoi(s, i) + if !ok || n >= 0xFFFF { + return nil + } + + // If followed by dot, might be in trailing IPv4. + if s[i1] == '.' { + if ellipsis < 0 && j != IPv6len - IPv4len { + // Not the right place. + return nil + } + if j+IPv4len > IPv6len { + // Not enough room. + return nil + } + p4 := ParseIPv4(s[i:len(s)]); + if p4 == nil { + return nil + } + // BUG: p[j:j+4] = p4 + p[j] = p4[12]; + p[j+1] = p4[13]; + p[j+2] = p4[14]; + p[j+3] = p4[15]; + i = len(s); + j += 4 + break + } + + // Save this 16-bit chunk. + p[j] = byte(n>>8); + p[j+1] = byte(n); + j += 2; + + // Stop at end of string. + i = i1 + if i == len(s) { + break + } + + // Otherwise must be followed by colon and more. + if s[i] != ':' && i+1 == len(s) { + return nil + } + i++ + + // Look for ellipsis. + if s[i+1] == ':' { + if ellipsis >= 0 { // already have one + return nil + } + ellipsis = j; + if i++; i == len(s) { // can be at end + break + } + } + } + + // Must have used entire string. + if i != len(s) { + return nil + } + + // If didn't parse enough, expand ellipsis. + if j < IPv6len { + if ellipsis < 0 { + return nil + } + n := IPv6len - j + for k := j; k >= ellipsis; k-- { + p[k+n] = p[k] + } + for k := ellipsis+n-1; k>=ellipsis; k-- { + p[k] = 0 + } + } + return p +} + +export func ParseIP(s string) *[]byte { + p := ParseIPv4(s) + if p != nil { + return p + } + return ParseIPv6(s) +} + diff --git a/src/lib/net/net.go b/src/lib/net/net.go new file mode 100644 index 000000000..d44f2d305 --- /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 +} + diff --git a/src/lib/net/socket_darwin.go b/src/lib/net/socket_darwin.go new file mode 100644 index 000000000..a114002ea --- /dev/null +++ b/src/lib/net/socket_darwin.go @@ -0,0 +1,231 @@ +// 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. + +// Low-level socket interface. +// Only for implementing net package. +// DO NOT USE DIRECTLY. + +package socket + +import ( + "os"; + "ip"; + "syscall" +) + +export const ( + ACCEPT = 30; + SOCKET = 97; + CONNECT = 98; + GETSOCKOPT = 118; + BIND = 104; + SETSOCKOPT = 105; + LISTEN = 106; + + AF_UNIX = 1; + AF_INET = 2; + AF_DATAKIT = 9; + AF_INET6 = 30; + + SOCK_STREAM = 1; + SOCK_DGRAM = 2; + SOCK_RAW = 3; + SOCK_RDM = 4; + SOCK_SEQPACKET = 5; + + SOL_SOCKET = 0xffff; + + SO_REUSEADDR = 0x0004; + SO_KEEPALIVE = 0x0008; + SO_DONTROUTE = 0x0010; + SO_BROADCAST = 0x0020; + SO_USELOOPBACK = 0x0040; + SO_LINGER = 0x1080; + SO_REUSEPORT = 0x0200; + SO_SNDBUF = 0x1001; + SO_RCVBUF = 0x1002; + SO_SNDTIMEO = 0x1005; + SO_RCVTIMEO = 0x1006; + SO_NOSIGPIPE = 0x1022; + + IPPROTO_TCP = 6; + IPPROTO_UDP = 17; + + TCP_NODELAY = 0x01; +) + +export type SockaddrUnix struct { + len byte; + family byte; + path [104]byte +} +export const SizeofSockaddrUnix = 106 + +export type SockaddrInet4 struct { + len byte; + family byte; + port [2]byte; + addr [4]byte; + zero [8]byte +} +export const SizeofSockaddrInet4 = 16 + +export type SockaddrInet6 struct { + len byte; + family byte; + port [2]byte; + flowinfo [4]byte; + addr [16]byte; + scopeid [4]byte; +} +export const SizeofSockaddrInet6 = 28 + +export type Sockaddr struct { + len byte; + family byte; + opaque [126]byte +} +export const SizeofSockaddr = 128 + +export type Timeval struct { + sec int32; + usec int32; +} +export type Linger struct { + yes int32; + sec int32; +} + +func SockaddrToSockaddrInet4(s *Sockaddr) *SockaddrInet4; +func SockaddrToSockaddrInet6(s *Sockaddr) *SockaddrInet6; +func SockaddrInet4ToSockaddr(s *SockaddrInet4) *Sockaddr; +func SockaddrInet6ToSockaddr(s *SockaddrInet6) *Sockaddr; +func SockaddrPtr(s *Sockaddr) int64; +func Int32Ptr(ip *int32) int64; +func TimevalPtr(tv *Timeval) int64; +func LingerPtr(l *Linger) int64; + +export func socket(domain, proto, typ int64) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(SOCKET, domain, proto, typ); + return r1, os.ErrnoToError(e) +} + +export func connect(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(CONNECT, fd, SockaddrPtr(sa), int64(sa.len)); + return r1, os.ErrnoToError(e) +} + +export func bind(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(BIND, fd, SockaddrPtr(sa), int64(sa.len)); + return r1, os.ErrnoToError(e) +} + +export func listen(fd, n int64) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(LISTEN, fd, n, 0); + return r1, os.ErrnoToError(e) +} + +export func accept(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + n := int32(sa.len); + r1, r2, e := syscall.Syscall(ACCEPT, fd, SockaddrPtr(sa), Int32Ptr(&n)); + return r1, os.ErrnoToError(e) +} + +export func setsockopt(fd, level, opt, valueptr, length int64) (ret int64, err *os.Error) { + if fd < 0 { + return -1, os.EINVAL + } + r1, r2, e := syscall.Syscall6(SETSOCKOPT, fd, level, opt, valueptr, length, 0); + return r1, os.ErrnoToError(e) +} + +export func setsockopt_int(fd, level, opt int64, value int) *os.Error { + n := int32(opt); + r1, e := setsockopt(fd, level, opt, Int32Ptr(&n), 4) + return e +} + +export func setsockopt_tv(fd, level, opt, nsec int64) *os.Error { + var tv Timeval; + nsec += 999; + tv.sec = int32(nsec/1000000000); + tv.usec = int32(nsec%1000000000); + r1, e := setsockopt(fd, level, opt, TimevalPtr(&tv), 4) + return e +} + +export func setsockopt_linger(fd, level, opt int64, sec int) *os.Error { + var l Linger; + if sec != 0 { + l.yes = 1; + l.sec = sec + } else { + l.yes = 0; + l.sec = 0 + } + r1, err := setsockopt(fd, level, opt, LingerPtr(&l), 8) + return err +} + +/* +export func getsockopt(fd, level, opt, valueptr, lenptr int64) (ret int64, errno int64) { + r1, r2, err := syscall.Syscall6(GETSOCKOPT, fd, level, opt, valueptr, lenptr, 0); + return r1, err; +} +*/ + +export func IPv4ToSockaddr(p *[]byte, port int) (sa1 *Sockaddr, err *os.Error) { + p = ip.ToIPv4(p) + if p == nil || port < 0 || port > 0xFFFF { + return nil, os.EINVAL + } + sa := new(SockaddrInet4); + sa.len = SizeofSockaddrInet4; + sa.family = AF_INET; + sa.port[0] = byte(port>>8); + sa.port[1] = byte(port); + for i := 0; i < ip.IPv4len; i++ { + sa.addr[i] = p[i] + } + return SockaddrInet4ToSockaddr(sa), nil +} + +export func IPv6ToSockaddr(p *[]byte, port int) (sa1 *Sockaddr, err *os.Error) { + p = ip.ToIPv6(p) + if p == nil || port < 0 || port > 0xFFFF { + return nil, os.EINVAL + } + sa := new(SockaddrInet6); + sa.len = SizeofSockaddrInet6; + sa.family = AF_INET6; + sa.port[0] = byte(port>>8); + sa.port[1] = byte(port); + for i := 0; i < ip.IPv6len; i++ { + sa.addr[i] = p[i] + } + return SockaddrInet6ToSockaddr(sa), nil +} + +export func SockaddrToIP(sa1 *Sockaddr) (p *[]byte, port int, err *os.Error) { + switch sa1.family { + case AF_INET: + sa := SockaddrToSockaddrInet4(sa1); + a := ip.ToIPv6(&sa.addr) + if a == nil { + return nil, 0, os.EINVAL + } + return a, int(sa.port[0])<<8 + int(sa.port[1]), nil + case AF_INET6: + sa := SockaddrToSockaddrInet6(sa1); + a := ip.ToIPv6(&sa.addr) + if a == nil { + return nil, 0, os.EINVAL + } + return a, int(sa.port[0])<<8 + int(sa.port[1]), nil + default: + return nil, 0, os.EINVAL + } + return nil, 0, nil // not reached +} + diff --git a/src/lib/net/socket_linux.go b/src/lib/net/socket_linux.go new file mode 100644 index 000000000..5dacaf58e --- /dev/null +++ b/src/lib/net/socket_linux.go @@ -0,0 +1,247 @@ +// 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. + +// Low-level socket interface. +// Only for implementing net package. +// DO NOT USE DIRECTLY. + +package socket + +import ( + "os"; + "ip"; + "syscall" +) + +export const ( + SOCKET = 41; + CONNECT = 42; + ACCEPT = 43; + SETSOCKOPT = 54; + GETSOCKOPT = 55; + BIND = 49; + LISTEN = 50; + + AF_UNIX = 1; + AF_INET = 2; + AF_INET6 = 10; + + SOCK_STREAM = 1; + SOCK_DGRAM = 2; + SOCK_RAW = 3; + SOCK_RDM = 4; + SOCK_SEQPACKET = 5; + + SOL_SOCKET = 1; + + SO_DEBUG = 1; + SO_REUSEADDR = 2; + SO_TYPE = 3; + SO_ERROR = 4; + SO_DONTROUTE = 5; + SO_BROADCAST = 6; + SO_SNDBUF = 7; + SO_RCVBUF = 8; + SO_SNDBUFFORCE = 32; + SO_RCVBUFFORCE = 33; + SO_KEEPALIVE = 9; + SO_OOBINLINE = 10; + SO_NO_CHECK = 11; + SO_PRIORITY = 12; + SO_LINGER = 13; + SO_BSDCOMPAT = 14; + SO_PASSCRED = 16; + SO_PEERCRED = 17; + SO_RCVLOWAT = 18; + SO_SNDLOWAT = 19; + SO_RCVTIMEO = 20; + SO_SNDTIMEO = 21; + SO_BINDTODEVICE = 25; + + IPPROTO_TCP = 6; + IPPROTO_UDP = 17; + + TCP_NODELAY = 0x01; +) + +export type SockaddrUnix struct { + family uint16; + path [108]byte +} +export const SizeofSockaddrUnix = 110 + +export type SockaddrInet4 struct { + family uint16; + port [2]byte; + addr [4]byte; + zero [8]byte +} +export const SizeofSockaddrInet4 = 16 + +export type SockaddrInet6 struct { + family uint16; + port [2]byte; + flowinfo [4]byte; + addr [16]byte; + scopeid [4]byte; +} +export const SizeofSockaddrInet6 = 28 + +export type Sockaddr struct { + family uint16; + opaque [126]byte +} +export const SizeofSockaddr = 128 + +export type Timeval struct { + sec int32; + usec int32; +} +export type Linger struct { + yes int32; + sec int32; +} + +func (s *Sockaddr) Len() int64 { + switch s.family { + case AF_UNIX: + return SizeofSockaddrUnix + case AF_INET: + return SizeofSockaddrInet4 + case AF_INET6: + return SizeofSockaddrInet6 + } + return 0 +} + +func SockaddrToSockaddrInet4(s *Sockaddr) *SockaddrInet4; +func SockaddrToSockaddrInet6(s *Sockaddr) *SockaddrInet6; +func SockaddrInet4ToSockaddr(s *SockaddrInet4) *Sockaddr; +func SockaddrInet6ToSockaddr(s *SockaddrInet6) *Sockaddr; +func SockaddrPtr(s *Sockaddr) int64; +func Int32Ptr(ip *int32) int64; +func TimevalPtr(tv *Timeval) int64; +func LingerPtr(l *Linger) int64; + +export func socket(domain, proto, typ int64) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(SOCKET, domain, proto, typ); + return r1, os.ErrnoToError(e) +} + +export func connect(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(CONNECT, fd, SockaddrPtr(sa), sa.Len()); + return r1, os.ErrnoToError(e) +} + +export func bind(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(BIND, fd, SockaddrPtr(sa), sa.Len()); + return r1, os.ErrnoToError(e) +} + +export func listen(fd, n int64) (ret int64, err *os.Error) { + r1, r2, e := syscall.Syscall(LISTEN, fd, n, 0); + return r1, os.ErrnoToError(e) +} + +export func accept(fd int64, sa *Sockaddr) (ret int64, err *os.Error) { + n := int32(sa.Len()); + r1, r2, e := syscall.Syscall(ACCEPT, fd, SockaddrPtr(sa), Int32Ptr(&n)); + return r1, os.ErrnoToError(e) +} + +export func setsockopt(fd, level, opt, valueptr, length int64) (ret int64, err *os.Error) { + if fd < 0 { + return -1, os.EINVAL + } + r1, r2, e := syscall.Syscall6(SETSOCKOPT, fd, level, opt, valueptr, length, 0); + return r1, os.ErrnoToError(e) +} + +export func setsockopt_int(fd, level, opt int64, value int) *os.Error { + n := int32(opt); + r1, e := setsockopt(fd, level, opt, Int32Ptr(&n), 4) + return e +} + +export func setsockopt_tv(fd, level, opt, nsec int64) *os.Error { + var tv Timeval; + nsec += 999; + tv.sec = int32(nsec/1000000000); + tv.usec = int32(nsec%1000000000); + r1, e := setsockopt(fd, level, opt, TimevalPtr(&tv), 4) + return e +} + +export func setsockopt_linger(fd, level, opt int64, sec int) *os.Error { + var l Linger; + if sec != 0 { + l.yes = 1; + l.sec = sec + } else { + l.yes = 0; + l.sec = 0 + } + r1, err := setsockopt(fd, level, opt, LingerPtr(&l), 8) + return err +} + +/* +export func getsockopt(fd, level, opt, valueptr, lenptr int64) (ret int64, errno int64) { + r1, r2, err := syscall.Syscall6(GETSOCKOPT, fd, level, opt, valueptr, lenptr, 0); + return r1, err; +} +*/ + +export func IPv4ToSockaddr(p *[]byte, port int) (sa1 *Sockaddr, err *os.Error) { + p = ip.ToIPv4(p) + if p == nil || port < 0 || port > 0xFFFF { + return nil, os.EINVAL + } + sa := new(SockaddrInet4); + sa.family = AF_INET; + sa.port[0] = byte(port>>8); + sa.port[1] = byte(port); + for i := 0; i < ip.IPv4len; i++ { + sa.addr[i] = p[i] + } + return SockaddrInet4ToSockaddr(sa), nil +} + +export func IPv6ToSockaddr(p *[]byte, port int) (sa1 *Sockaddr, err *os.Error) { + p = ip.ToIPv6(p) + if p == nil || port < 0 || port > 0xFFFF { + return nil, os.EINVAL + } + sa := new(SockaddrInet6); + sa.family = AF_INET6; + sa.port[0] = byte(port>>8); + sa.port[1] = byte(port); + for i := 0; i < ip.IPv6len; i++ { + sa.addr[i] = p[i] + } + return SockaddrInet6ToSockaddr(sa), nil +} + +export func SockaddrToIP(sa1 *Sockaddr) (p *[]byte, port int, err *os.Error) { + switch sa1.family { + case AF_INET: + sa := SockaddrToSockaddrInet4(sa1); + a := ip.ToIPv6(&sa.addr) + if a == nil { + return nil, 0, os.EINVAL + } + return a, int(sa.port[0])<<8 + int(sa.port[1]), nil + case AF_INET6: + sa := SockaddrToSockaddrInet6(sa1); + a := ip.ToIPv6(&sa.addr) + if a == nil { + return nil, 0, os.EINVAL + } + return a, int(sa.port[0])<<8 + int(sa.port[1]), nil + default: + return nil, 0, os.EINVAL + } + return nil, 0, nil // not reached +} + |