2008-09-16 14:42:47 -06:00
|
|
|
// 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";
|
2008-09-26 15:11:26 -06:00
|
|
|
"net";
|
2008-11-17 13:34:03 -07:00
|
|
|
"strconv";
|
|
|
|
"syscall";
|
2008-09-16 14:42:47 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
export var (
|
2008-09-19 16:23:16 -06:00
|
|
|
BadAddress = os.NewError("malformed address");
|
|
|
|
MissingAddress = os.NewError("missing address");
|
|
|
|
UnknownNetwork = os.NewError("unknown network");
|
|
|
|
UnknownHost = os.NewError("unknown host");
|
|
|
|
UnknownPort = os.NewError("unknown port");
|
|
|
|
UnknownSocketFamily = os.NewError("unknown socket family");
|
2008-09-16 14:42:47 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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.
|
2008-10-07 13:31:31 -06:00
|
|
|
var i int;
|
2008-09-16 14:42:47 -06:00
|
|
|
for i = len(hostport)-1; i >= 0; i-- {
|
|
|
|
if hostport[i] == ':' {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i < 0 {
|
|
|
|
return "", "", BadAddress
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
host = hostport[0:i];
|
|
|
|
port = hostport[i+1:len(hostport)];
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
func xdtoi(s string) (n int, ok bool) {
|
2008-09-17 14:49:23 -06:00
|
|
|
if s == "" || s[0] < '0' || s[0] > '9' {
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
n = 0;
|
|
|
|
for i := 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
|
2008-10-07 13:31:31 -06:00
|
|
|
n = n*10 + int(s[i] - '0');
|
2008-09-17 14:49:23 -06:00
|
|
|
if n >= 1000000 { // bigger than we need
|
|
|
|
return 0, false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return n, true
|
|
|
|
}
|
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
// Convert "host:port" into IP address and port.
|
|
|
|
// For now, host and port must be numeric literals.
|
|
|
|
// Eventually, we'll have name resolution.
|
2008-09-26 15:11:26 -06:00
|
|
|
func HostPortToIP(net string, hostport string) (ip *[]byte, iport int, err *os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
var host, port string;
|
|
|
|
host, port, err = SplitHostPort(hostport);
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, err
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
// TODO: Resolve host.
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
addr := ParseIP(host);
|
2008-09-16 14:42:47 -06:00
|
|
|
if addr == nil {
|
|
|
|
return nil, 0, UnknownHost
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
// TODO: Resolve port.
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
p, ok := xdtoi(port);
|
2008-09-16 14:42:47 -06:00
|
|
|
if !ok || p < 0 || p > 0xFFFF {
|
|
|
|
return nil, 0, UnknownPort
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
return addr, p, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert socket address into "host:port".
|
2008-09-26 15:11:26 -06:00
|
|
|
func SockaddrToHostPort(sa *syscall.Sockaddr) (hostport string, err *os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
switch sa.family {
|
2008-09-26 15:11:26 -06:00
|
|
|
case syscall.AF_INET, syscall.AF_INET6:
|
2008-10-07 13:31:31 -06:00
|
|
|
addr, port, e := SockaddrToIP(sa);
|
2008-09-16 14:42:47 -06:00
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
2008-09-26 15:11:26 -06:00
|
|
|
host := IPToString(addr);
|
2008-11-17 13:34:03 -07:00
|
|
|
return JoinHostPort(host, strconv.itoa(port)), nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
default:
|
|
|
|
return "", UnknownSocketFamily
|
|
|
|
}
|
|
|
|
return "", nil // not reached
|
|
|
|
}
|
|
|
|
|
|
|
|
// Boolean to int.
|
|
|
|
func boolint(b bool) int {
|
|
|
|
if b {
|
|
|
|
return 1
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
2008-09-16 14:42:47 -06:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generic Socket creation.
|
2008-09-26 15:11:26 -06:00
|
|
|
func Socket(f, p, t int64, la, ra *syscall.Sockaddr) (fd *FD, err *os.Error) {
|
|
|
|
s, e := syscall.socket(f, p, t);
|
|
|
|
if e != 0 {
|
|
|
|
return nil, os.ErrnoToError(e)
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
|
|
|
// Allow reuse of recently-used addresses.
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.setsockopt_int(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1);
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-10-07 13:31:31 -06:00
|
|
|
var r int64;
|
2008-09-16 14:42:47 -06:00
|
|
|
if la != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
r, e = syscall.bind(s, la);
|
2008-09-26 15:11:26 -06:00
|
|
|
if e != 0 {
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.close(s);
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, os.ErrnoToError(e)
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
if ra != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
r, e = syscall.connect(s, ra);
|
2008-09-26 15:11:26 -06:00
|
|
|
if e != 0 {
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.close(s);
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, os.ErrnoToError(e)
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-10-07 13:31:31 -06:00
|
|
|
fd, err = NewFD(s);
|
2008-09-26 15:11:26 -06:00
|
|
|
if err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.close(s);
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd, nil
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Generic implementation of Conn interface; not exported.
|
|
|
|
type ConnBase struct {
|
2008-09-26 15:11:26 -06:00
|
|
|
fd *FD;
|
2008-09-16 14:42:47 -06:00
|
|
|
raddr string;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2008-10-07 13:31:31 -06:00
|
|
|
n, err = c.fd.Read(b);
|
2008-09-16 14:42:47 -06:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) Write(b *[]byte) (n int, err *os.Error) {
|
2008-10-07 13:31:31 -06:00
|
|
|
n, err = c.fd.Write(b);
|
2008-09-16 14:42:47 -06:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) ReadFrom(b *[]byte) (n int, raddr string, err *os.Error) {
|
|
|
|
if c == nil {
|
|
|
|
return -1, "", os.EINVAL
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
n, err = c.Read(b);
|
2008-09-16 14:42:47 -06:00
|
|
|
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
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
n, err = c.Write(b);
|
2008-09-16 14:42:47 -06:00
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) Close() *os.Error {
|
|
|
|
if c == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
return c.fd.Close()
|
|
|
|
}
|
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
func (c *ConnBase) SetReadBuffer(bytes int) *os.Error {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_int(c.FD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) SetWriteBuffer(bytes int) *os.Error {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_int(c.FD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) SetReadTimeout(nsec int64) *os.Error {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_tv(c.FD(), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, nsec);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) SetWriteTimeout(nsec int64) *os.Error {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_tv(c.FD(), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, nsec);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_int(c.FD(), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_int(c.FD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) SetKeepAlive(keepalive bool) *os.Error {
|
2008-09-26 15:11:26 -06:00
|
|
|
return setsockopt_int(c.FD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnBase) SetLinger(sec int) *os.Error {
|
2008-10-07 13:31:31 -06:00
|
|
|
e := syscall.setsockopt_linger(c.FD(), syscall.SOL_SOCKET, syscall.SO_LINGER, sec);
|
2008-09-26 15:11:26 -06:00
|
|
|
return os.ErrnoToError(e);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
2008-09-30 15:03:13 -06:00
|
|
|
func InternetSocket(net, laddr, raddr string, proto int64) (fd *FD, err *os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
// Parse addresses (unless they are empty).
|
2008-10-07 13:31:31 -06:00
|
|
|
var lip, rip *[]byte;
|
|
|
|
var lport, rport int;
|
|
|
|
var lerr, rerr *os.Error;
|
2008-09-17 14:49:23 -06:00
|
|
|
// BUG 6g doesn't zero var lists
|
|
|
|
lip = nil;
|
|
|
|
rip = nil;
|
|
|
|
lport = 0;
|
|
|
|
rport = 0;
|
|
|
|
lerr = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
rerr = nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
if laddr != "" {
|
2008-10-07 13:31:31 -06:00
|
|
|
lip, lport, lerr = HostPortToIP(net, laddr);
|
2008-09-16 14:42:47 -06:00
|
|
|
if lerr != nil {
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, lerr
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if raddr != "" {
|
2008-10-07 13:31:31 -06:00
|
|
|
rip, rport, rerr = HostPortToIP(net, raddr);
|
2008-09-16 14:42:47 -06:00
|
|
|
if rerr != nil {
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, rerr
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-17 14:49:23 -06:00
|
|
|
// Figure out IP version.
|
2008-09-16 14:42:47 -06:00
|
|
|
// If network has a suffix like "tcp4", obey it.
|
|
|
|
vers := 0;
|
2008-09-30 15:03:13 -06:00
|
|
|
switch net[len(net)-1] {
|
2008-09-16 14:42:47 -06:00
|
|
|
case '4':
|
2008-10-07 13:31:31 -06:00
|
|
|
vers = 4;
|
2008-09-16 14:42:47 -06:00
|
|
|
case '6':
|
2008-10-07 13:31:31 -06:00
|
|
|
vers = 6;
|
2008-09-16 14:42:47 -06:00
|
|
|
default:
|
|
|
|
// Otherwise, guess.
|
|
|
|
// If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
|
|
|
|
if PreferIPv4
|
2008-09-26 15:11:26 -06:00
|
|
|
&& (lip == nil || ToIPv4(lip) != nil)
|
|
|
|
&& (rip == nil || ToIPv4(rip) != nil) {
|
2008-09-16 14:42:47 -06:00
|
|
|
vers = 4
|
|
|
|
} else {
|
|
|
|
vers = 6
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-07 13:31:31 -06:00
|
|
|
var cvt *(addr *[]byte, port int) (sa *syscall.Sockaddr, err *os.Error);
|
|
|
|
var family int64;
|
2008-09-16 14:42:47 -06:00
|
|
|
if vers == 4 {
|
2008-09-26 15:11:26 -06:00
|
|
|
cvt = &IPv4ToSockaddr;
|
|
|
|
family = syscall.AF_INET
|
2008-09-16 14:42:47 -06:00
|
|
|
} else {
|
2008-09-26 15:11:26 -06:00
|
|
|
cvt = &IPv6ToSockaddr;
|
|
|
|
family = syscall.AF_INET6
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
var la, ra *syscall.Sockaddr;
|
2008-09-17 14:49:23 -06:00
|
|
|
// BUG
|
|
|
|
la = nil;
|
2008-10-07 13:31:31 -06:00
|
|
|
ra = nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
if lip != nil {
|
|
|
|
la, lerr = cvt(lip, lport);
|
|
|
|
if lerr != nil {
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, lerr
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if rip != nil {
|
|
|
|
ra, rerr = cvt(rip, rport);
|
|
|
|
if rerr != nil {
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, rerr
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fd, err = Socket(family, proto, 0, la, ra);
|
|
|
|
return fd, err
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TCP connections.
|
|
|
|
|
|
|
|
export type ConnTCP struct {
|
2008-12-10 16:55:59 -07:00
|
|
|
ConnBase
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ConnTCP) SetNoDelay(nodelay bool) *os.Error {
|
|
|
|
if c == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
2008-12-10 16:55:59 -07:00
|
|
|
return setsockopt_int(c.FD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay))
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
func NewConnTCP(fd *FD, raddr string) *ConnTCP {
|
2008-09-17 14:49:23 -06:00
|
|
|
c := new(ConnTCP);
|
2008-12-10 16:55:59 -07:00
|
|
|
c.fd = fd;
|
|
|
|
c.raddr = raddr;
|
2008-09-17 14:49:23 -06:00
|
|
|
c.SetNoDelay(true);
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2008-09-30 15:03:13 -06:00
|
|
|
export func DialTCP(net, laddr, raddr string) (c *ConnTCP, err *os.Error) {
|
2008-09-17 14:49:23 -06:00
|
|
|
if raddr == "" {
|
|
|
|
return nil, MissingAddress
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
fd, e := InternetSocket(net, laddr, raddr, syscall.SOCK_STREAM);
|
2008-09-16 14:42:47 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
return NewConnTCP(fd, raddr), nil
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-10 16:55:59 -07:00
|
|
|
// UDP connections.
|
|
|
|
|
|
|
|
// TODO(rsc): UDP headers mode
|
|
|
|
|
|
|
|
export type ConnUDP struct {
|
|
|
|
ConnBase
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewConnUDP(fd *FD, raddr string) *ConnUDP {
|
|
|
|
c := new(ConnUDP);
|
|
|
|
c.fd = fd;
|
|
|
|
c.raddr = raddr;
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
export 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);
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return NewConnUDP(fd, raddr), nil
|
|
|
|
}
|
2008-09-16 14:42:47 -06:00
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2008-09-30 15:03:13 -06:00
|
|
|
export func Dial(net, laddr, raddr string) (c Conn, err *os.Error) {
|
|
|
|
switch net {
|
2008-09-16 14:42:47 -06:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2008-10-07 13:31:31 -06:00
|
|
|
c, err := DialTCP(net, laddr, raddr);
|
2008-09-16 14:42:47 -06:00
|
|
|
if err != nil {
|
2008-12-10 16:55:59 -07:00
|
|
|
return nil, err
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
return c, nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
case "udp", "udp4", "upd6":
|
2008-10-07 13:31:31 -06:00
|
|
|
c, err := DialUDP(net, laddr, raddr);
|
|
|
|
return c, err;
|
2008-12-10 16:55:59 -07:00
|
|
|
/*
|
2008-09-16 14:42:47 -06:00
|
|
|
case "ether":
|
2008-10-07 13:31:31 -06:00
|
|
|
c, err := DialEther(net, laddr, raddr);
|
|
|
|
return c, err;
|
2008-09-16 14:42:47 -06:00
|
|
|
case "ipv4":
|
2008-10-07 13:31:31 -06:00
|
|
|
c, err := DialIPv4(net, laddr, raddr);
|
|
|
|
return c, err;
|
2008-09-16 14:42:47 -06:00
|
|
|
case "ipv6":
|
2008-10-07 13:31:31 -06:00
|
|
|
c, err := DialIPv6(net, laddr, raddr);
|
2008-09-16 14:42:47 -06:00
|
|
|
return c, err
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
return nil, UnknownNetwork
|
|
|
|
}
|
|
|
|
|
2008-09-17 14:49:23 -06:00
|
|
|
|
|
|
|
export type Listener interface {
|
|
|
|
Accept() (c Conn, raddr string, err *os.Error);
|
|
|
|
Close() *os.Error;
|
|
|
|
}
|
|
|
|
|
|
|
|
export type ListenerTCP struct {
|
2008-09-26 15:11:26 -06:00
|
|
|
fd *FD;
|
2008-09-17 14:49:23 -06:00
|
|
|
laddr string
|
|
|
|
}
|
|
|
|
|
2008-09-30 15:03:13 -06:00
|
|
|
export func ListenTCP(net, laddr string) (l *ListenerTCP, err *os.Error) {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd, e := InternetSocket(net, laddr, "", syscall.SOCK_STREAM);
|
2008-09-17 14:49:23 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
r, e1 := syscall.listen(fd.fd, ListenBacklog());
|
2008-09-26 15:11:26 -06:00
|
|
|
if e1 != 0 {
|
2008-10-07 13:31:31 -06:00
|
|
|
syscall.close(fd.fd);
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, os.ErrnoToError(e1)
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
l = new(ListenerTCP);
|
2008-10-07 13:31:31 -06:00
|
|
|
l.fd = fd;
|
2008-09-17 14:49:23 -06:00
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2008-09-26 15:11:26 -06:00
|
|
|
var sa syscall.Sockaddr;
|
2008-10-07 13:31:31 -06:00
|
|
|
fd, e := l.fd.Accept(&sa);
|
2008-09-17 14:49:23 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, "", e
|
|
|
|
}
|
2008-10-07 13:31:31 -06:00
|
|
|
raddr, err = SockaddrToHostPort(&sa);
|
2008-09-26 15:11:26 -06:00
|
|
|
if err != nil {
|
2008-10-07 13:31:31 -06:00
|
|
|
fd.Close();
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, "", err
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
return NewConnTCP(fd, raddr), raddr, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *ListenerTCP) Accept() (c Conn, raddr string, err *os.Error) {
|
2008-10-07 13:31:31 -06:00
|
|
|
c1, r1, e1 := l.AcceptTCP();
|
2008-09-17 14:49:23 -06:00
|
|
|
if e1 != nil {
|
2008-12-10 16:55:59 -07:00
|
|
|
return nil, "", e1
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
return c1, r1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *ListenerTCP) Close() *os.Error {
|
|
|
|
if l == nil || l.fd == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
return l.fd.Close()
|
|
|
|
}
|
|
|
|
|
2008-09-30 15:03:13 -06:00
|
|
|
export func Listen(net, laddr string) (l Listener, err *os.Error) {
|
|
|
|
switch net {
|
2008-09-17 14:49:23 -06:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2008-10-07 13:31:31 -06:00
|
|
|
l, err := ListenTCP(net, laddr);
|
2008-09-17 14:49:23 -06:00
|
|
|
if err != nil {
|
2008-12-10 16:55:59 -07:00
|
|
|
return nil, err
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
return l, nil
|
|
|
|
/*
|
|
|
|
more here
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
return nil, UnknownNetwork
|
|
|
|
}
|
2008-09-26 15:11:26 -06:00
|
|
|
|