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 (
|
2008-09-26 15:11:26 -06:00
|
|
|
"net";
|
2009-04-16 21:52:37 -06:00
|
|
|
"os";
|
2008-11-17 13:34:03 -07:00
|
|
|
"strconv";
|
|
|
|
"syscall";
|
2008-09-16 14:42:47 -06:00
|
|
|
)
|
|
|
|
|
2009-01-20 15:40:40 -07:00
|
|
|
var (
|
2009-05-08 15:40:20 -06:00
|
|
|
BadAddress os.Error = &Error{"malformed address"};
|
|
|
|
MissingAddress os.Error = &Error{"missing address"};
|
|
|
|
UnknownNetwork os.Error = &Error{"unknown network"};
|
|
|
|
UnknownHost os.Error = &Error{"unknown host"};
|
|
|
|
UnknownSocketFamily os.Error = &Error{"unknown socket family"};
|
2008-09-16 14:42:47 -06:00
|
|
|
)
|
|
|
|
|
2009-05-07 18:36:29 -06:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// Conn is a generic network connection.
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-05-07 18:36:29 -06:00
|
|
|
// 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()
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
// 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
|
|
|
|
}
|
2009-05-07 18:36:29 -06:00
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func LookupHost(name string) (cname string, addrs []string, err os.Error)
|
2008-12-18 16:42:39 -07:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
// Split "host:port" into "host" and "port".
|
|
|
|
// Host cannot contain colons unless it is bracketed.
|
2009-04-17 01:08:24 -06:00
|
|
|
func splitHostPort(hostport string) (host, port string, err os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
// 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 ...
|
2008-12-19 16:52:21 -07:00
|
|
|
if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
|
2008-09-16 14:42:47 -06:00
|
|
|
host = host[1:len(host)-1]
|
|
|
|
} else {
|
|
|
|
// ... but if there are no brackets, no colons.
|
2009-02-15 15:18:39 -07:00
|
|
|
if byteIndex(host, ':') >= 0 {
|
2008-12-18 16:42:39 -07:00
|
|
|
return "", "", BadAddress
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return host, port, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Join "host" and "port" into "host:port".
|
|
|
|
// If host contains colons, will join into "[host]:port".
|
2009-02-15 15:18:39 -07:00
|
|
|
func joinHostPort(host, port string) string {
|
2008-09-16 14:42:47 -06:00
|
|
|
// If host has colons, have to bracket it.
|
2009-02-15 15:18:39 -07:00
|
|
|
if byteIndex(host, ':') >= 0 {
|
2008-12-18 16:42:39 -07:00
|
|
|
return "[" + host + "]:" + port
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
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.
|
2009-05-07 18:36:29 -06:00
|
|
|
func hostPortToIP(net, hostport, mode string) (ip IP, iport int, err os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
var host, port string;
|
2009-02-15 15:18:39 -07:00
|
|
|
host, port, err = splitHostPort(hostport);
|
2008-09-16 14:42:47 -06:00
|
|
|
if err != nil {
|
2008-12-19 04:05:37 -07:00
|
|
|
return nil, 0, err
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2009-05-07 18:36:29 -06:00
|
|
|
var addr IP;
|
2008-12-19 16:52:21 -07:00
|
|
|
if host == "" {
|
|
|
|
if mode == "listen" {
|
2009-05-07 18:36:29 -06:00
|
|
|
if preferIPv4 {
|
|
|
|
addr = IPv4zero;
|
|
|
|
} else {
|
|
|
|
addr = IPzero; // wildcard - listen to all
|
|
|
|
}
|
2008-12-19 16:52:21 -07:00
|
|
|
} else {
|
|
|
|
return nil, 0, MissingAddress;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-18 16:42:39 -07:00
|
|
|
// Try as an IP address.
|
2008-12-19 16:52:21 -07:00
|
|
|
if addr == nil {
|
|
|
|
addr = ParseIP(host);
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
if addr == nil {
|
2008-12-18 16:42:39 -07:00
|
|
|
// Not an IP address. Try as a DNS name.
|
|
|
|
hostname, addrs, err := LookupHost(host);
|
|
|
|
if err != nil {
|
2008-12-19 04:05:37 -07:00
|
|
|
return nil, 0, err
|
2008-12-18 16:42:39 -07:00
|
|
|
}
|
|
|
|
if len(addrs) == 0 {
|
2008-12-19 04:05:37 -07:00
|
|
|
return nil, 0, UnknownHost
|
2008-12-18 16:42:39 -07:00
|
|
|
}
|
|
|
|
addr = ParseIP(addrs[0]);
|
2008-12-19 04:05:37 -07:00
|
|
|
if addr == nil {
|
2008-12-18 16:42:39 -07:00
|
|
|
// should not happen
|
2008-12-19 04:05:37 -07:00
|
|
|
return nil, 0, BadAddress
|
2008-12-18 16:42:39 -07:00
|
|
|
}
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
p, i, ok := dtoi(port, 0);
|
2008-12-18 16:42:39 -07:00
|
|
|
if !ok || i != len(port) {
|
2009-03-05 16:48:12 -07:00
|
|
|
p, err = LookupPort(net, port);
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, err
|
2008-12-18 16:42:39 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if p < 0 || p > 0xFFFF {
|
2008-12-19 04:05:37 -07:00
|
|
|
return nil, 0, BadAddress
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
return addr, p, nil
|
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
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 "", UnknownSocketFamily
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
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;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
return nil, os.EINVAL;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
// Generic socket creation.
|
2009-06-01 23:14:39 -06:00
|
|
|
func socket(net, laddr, raddr string, f, p, t int, la, ra syscall.Sockaddr) (fd *netFD, err os.Error) {
|
2009-02-15 20:35:52 -07:00
|
|
|
// See ../syscall/exec.go for description of ForkLock.
|
|
|
|
syscall.ForkLock.RLock();
|
2009-01-16 12:36:44 -07:00
|
|
|
s, e := syscall.Socket(f, p, t);
|
2008-09-26 15:11:26 -06:00
|
|
|
if e != 0 {
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.ForkLock.RUnlock();
|
2008-09-26 15:11:26 -06:00
|
|
|
return nil, os.ErrnoToError(e)
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2009-02-15 20:35:52 -07:00
|
|
|
syscall.CloseOnExec(s);
|
|
|
|
syscall.ForkLock.RUnlock();
|
2008-09-17 14:49:23 -06:00
|
|
|
|
|
|
|
// Allow reuse of recently-used addresses.
|
2009-06-01 23:14:39 -06:00
|
|
|
syscall.SetsockoptInt(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 {
|
2009-06-01 23:14:39 -06:00
|
|
|
e = syscall.Bind(s, la);
|
2008-09-26 15:11:26 -06:00
|
|
|
if e != 0 {
|
2009-01-16 12:36:44 -07: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 {
|
2009-06-01 23:14:39 -06:00
|
|
|
e = syscall.Connect(s, ra);
|
2008-09-26 15:11:26 -06:00
|
|
|
if e != 0 {
|
2009-01-16 12:36:44 -07: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
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
fd, err = newFD(s, net, laddr, raddr);
|
2008-09-26 15:11:26 -06:00
|
|
|
if err != nil {
|
2009-01-16 12:36:44 -07: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.
|
2009-02-15 15:18:39 -07:00
|
|
|
type connBase struct {
|
|
|
|
fd *netFD;
|
2008-09-16 14:42:47 -06:00
|
|
|
raddr string;
|
|
|
|
}
|
|
|
|
|
2009-03-11 13:51:10 -06:00
|
|
|
func (c *connBase) File() *os.File {
|
2009-02-15 15:18:39 -07:00
|
|
|
if c == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2009-03-11 13:51:10 -06:00
|
|
|
return c.fd.file;
|
2009-02-15 15:18:39 -07:00
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func (c *connBase) sysFD() int {
|
2008-09-16 14:42:47 -06:00
|
|
|
if c == nil || c.fd == nil {
|
2009-02-15 15:18:39 -07:00
|
|
|
return -1;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
return c.fd.fd;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) ReadFrom(b []byte) (n int, raddr string, err os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) WriteTo(raddr string, b []byte) (n int, err os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) Close() os.Error {
|
2008-09-16 14:42:47 -06:00
|
|
|
if c == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
return c.fd.Close()
|
|
|
|
}
|
|
|
|
|
2008-09-26 15:11:26 -06:00
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func setsockoptInt(fd, level, opt int, value int) os.Error {
|
|
|
|
return os.ErrnoToError(syscall.SetsockoptInt(fd, level, opt, value));
|
2008-09-26 15:11:26 -06:00
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
|
|
|
|
var tv = syscall.NsecToTimeval(nsec);
|
|
|
|
return os.ErrnoToError(syscall.SetsockoptTimeval(fd, level, opt, &tv));
|
2008-09-26 15:11:26 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetReadBuffer(bytes int) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetWriteBuffer(bytes int) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetReadTimeout(nsec int64) os.Error {
|
2009-03-06 18:51:31 -07:00
|
|
|
c.fd.rdeadline_delta = nsec;
|
|
|
|
return nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetWriteTimeout(nsec int64) os.Error {
|
2009-03-06 18:51:31 -07:00
|
|
|
c.fd.wdeadline_delta = nsec;
|
|
|
|
return nil;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetTimeout(nsec int64) os.Error {
|
2008-09-16 14:42:47 -06:00
|
|
|
if e := c.SetReadTimeout(nsec); e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
return c.SetWriteTimeout(nsec)
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetReuseAddr(reuse bool) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) BindToDevice(dev string) os.Error {
|
2009-02-15 15:18:39 -07:00
|
|
|
// TODO(rsc): call setsockopt with null-terminated string pointer
|
2008-09-16 14:42:47 -06:00
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetDontRoute(dontroute bool) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetKeepAlive(keepalive bool) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive));
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *connBase) SetLinger(sec int) os.Error {
|
2009-06-01 23:14:39 -06:00
|
|
|
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);
|
2008-09-26 15:11:26 -06:00
|
|
|
return os.ErrnoToError(e);
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Internet sockets (TCP, UDP)
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
func internetSocket(net, laddr, raddr string, proto int, mode string) (fd *netFD, err os.Error) {
|
2008-09-16 14:42:47 -06:00
|
|
|
// Parse addresses (unless they are empty).
|
2009-03-05 16:48:12 -07:00
|
|
|
var lip, rip IP;
|
2008-10-07 13:31:31 -06:00
|
|
|
var lport, rport int;
|
2009-04-17 01:08:24 -06:00
|
|
|
var lerr, rerr os.Error;
|
2008-12-18 16:42:39 -07:00
|
|
|
|
2008-09-16 14:42:47 -06:00
|
|
|
if laddr != "" {
|
2009-02-15 15:18:39 -07:00
|
|
|
lip, lport, lerr = hostPortToIP(net, laddr, mode);
|
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 != "" {
|
2009-02-15 15:18:39 -07:00
|
|
|
rip, rport, rerr = hostPortToIP(net, raddr, mode);
|
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.
|
2009-05-07 11:31:48 -06:00
|
|
|
if preferIPv4 && (lip == nil || lip.To4() != nil) && (rip == nil || rip.To4() != nil) {
|
2008-09-16 14:42:47 -06:00
|
|
|
vers = 4
|
|
|
|
} else {
|
|
|
|
vers = 6
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
var family int;
|
2008-09-16 14:42:47 -06:00
|
|
|
if vers == 4 {
|
2008-09-26 15:11:26 -06:00
|
|
|
family = syscall.AF_INET
|
2008-09-16 14:42:47 -06:00
|
|
|
} else {
|
2008-09-26 15:11:26 -06:00
|
|
|
family = syscall.AF_INET6
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
2008-09-17 14:49:23 -06:00
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
var la, ra syscall.Sockaddr;
|
2008-12-19 04:05:37 -07:00
|
|
|
if lip != nil {
|
2009-06-01 23:14:39 -06:00
|
|
|
la, lerr = ipToSockaddr(family, lip, lport);
|
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
|
|
|
}
|
|
|
|
}
|
2008-12-19 04:05:37 -07:00
|
|
|
if rip != nil {
|
2009-06-01 23:14:39 -06:00
|
|
|
ra, rerr = ipToSockaddr(family, rip, rport);
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
fd, err = socket(net, laddr, raddr, family, proto, 0, la, ra);
|
2008-09-16 14:42:47 -06:00
|
|
|
return fd, err
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TCP connections.
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// ConnTCP is an implementation of the Conn interface
|
|
|
|
// for TCP network connections.
|
2009-01-20 15:40:40 -07:00
|
|
|
type ConnTCP struct {
|
2009-02-15 15:18:39 -07:00
|
|
|
connBase
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-04-17 01:08:24 -06:00
|
|
|
func (c *ConnTCP) SetNoDelay(nodelay bool) os.Error {
|
2008-09-16 14:42:47 -06:00
|
|
|
if c == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
return setsockoptInt(c.sysFD(), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(nodelay))
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func newConnTCP(fd *netFD, raddr string) *ConnTCP {
|
2009-01-06 16:19:02 -07: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
|
|
|
|
}
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// DialTCP is like Dial but can only connect to TCP networks
|
|
|
|
// and returns a ConnTCP structure.
|
2009-04-17 01:08:24 -06:00
|
|
|
func DialTCP(net, laddr, raddr string) (c *ConnTCP, err os.Error) {
|
2008-09-17 14:49:23 -06:00
|
|
|
if raddr == "" {
|
|
|
|
return nil, MissingAddress
|
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_STREAM, "dial");
|
2008-09-16 14:42:47 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2009-02-15 15:18:39 -07: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
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// ConnUDP is an implementation of the Conn interface
|
|
|
|
// for UDP network connections.
|
2009-01-20 15:40:40 -07:00
|
|
|
type ConnUDP struct {
|
2009-02-15 15:18:39 -07:00
|
|
|
connBase
|
2008-12-10 16:55:59 -07:00
|
|
|
}
|
|
|
|
|
2009-02-15 15:18:39 -07:00
|
|
|
func newConnUDP(fd *netFD, raddr string) *ConnUDP {
|
2009-01-06 16:19:02 -07:00
|
|
|
c := new(ConnUDP);
|
2008-12-10 16:55:59 -07:00
|
|
|
c.fd = fd;
|
|
|
|
c.raddr = raddr;
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// DialUDP is like Dial but can only connect to UDP networks
|
|
|
|
// and returns a ConnUDP structure.
|
2009-04-17 01:08:24 -06:00
|
|
|
func DialUDP(net, laddr, raddr string) (c *ConnUDP, err os.Error) {
|
2008-12-10 16:55:59 -07:00
|
|
|
if raddr == "" {
|
|
|
|
return nil, MissingAddress
|
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
fd, e := internetSocket(net, laddr, raddr, syscall.SOCK_DGRAM, "dial");
|
2008-12-10 16:55:59 -07:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2009-02-15 15:18:39 -07:00
|
|
|
return newConnUDP(fd, raddr), nil
|
2008-12-10 16:55:59 -07:00
|
|
|
}
|
2008-09-16 14:42:47 -06:00
|
|
|
|
|
|
|
|
|
|
|
// TODO: raw IP connections
|
|
|
|
|
|
|
|
// TODO: raw ethernet connections
|
|
|
|
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// Unix domain sockets
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
func unixSocket(net, laddr, raddr string, mode string) (fd *netFD, err os.Error) {
|
2009-06-01 23:14:39 -06:00
|
|
|
var proto int;
|
2009-05-13 19:03:41 -06:00
|
|
|
switch net {
|
|
|
|
default:
|
|
|
|
return nil, UnknownNetwork;
|
|
|
|
case "unix":
|
|
|
|
proto = syscall.SOCK_STREAM;
|
|
|
|
case "unix-dgram":
|
|
|
|
proto = syscall.SOCK_DGRAM;
|
|
|
|
}
|
2009-03-05 16:48:12 -07:00
|
|
|
|
2009-06-01 23:14:39 -06:00
|
|
|
var la, ra syscall.Sockaddr;
|
2009-05-13 19:03:41 -06:00
|
|
|
switch mode {
|
|
|
|
case "dial":
|
|
|
|
if laddr != "" {
|
|
|
|
return nil, BadAddress;
|
|
|
|
}
|
|
|
|
if raddr == "" {
|
|
|
|
return nil, MissingAddress;
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
ra = &syscall.SockaddrUnix{Name: raddr};
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
case "listen":
|
|
|
|
if laddr == "" {
|
|
|
|
return nil, MissingAddress;
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
la = &syscall.SockaddrUnix{Name: laddr};
|
2009-05-13 19:03:41 -06:00
|
|
|
if raddr != "" {
|
|
|
|
return nil, BadAddress;
|
|
|
|
}
|
|
|
|
}
|
2009-03-05 16:48:12 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
fd, err = socket(net, laddr, raddr, syscall.AF_UNIX, proto, 0, la, ra);
|
|
|
|
return fd, err
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// ConnUnix is an implementation of the Conn interface
|
|
|
|
// for connections to Unix domain sockets.
|
|
|
|
type ConnUnix struct {
|
|
|
|
connBase
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
func newConnUnix(fd *netFD, raddr string) *ConnUnix {
|
|
|
|
c := new(ConnUnix);
|
|
|
|
c.fd = fd;
|
|
|
|
c.raddr = raddr;
|
|
|
|
return c;
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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;
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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 {
|
|
|
|
// 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 e1 != os.ECONNREFUSED {
|
|
|
|
return nil, e;
|
|
|
|
}
|
|
|
|
syscall.Unlink(laddr);
|
|
|
|
fd1, e1 = unixSocket(net, laddr, "", "listen");
|
|
|
|
if e1 != nil {
|
|
|
|
return nil, e;
|
|
|
|
}
|
|
|
|
fd = fd1;
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
e1 := syscall.Listen(fd.fd, 8); // listenBacklog());
|
2009-05-13 19:03:41 -06:00
|
|
|
if e1 != 0 {
|
|
|
|
syscall.Close(fd.fd);
|
|
|
|
return nil, os.ErrnoToError(e1);
|
|
|
|
}
|
|
|
|
return &ListenerUnix{fd, laddr}, nil;
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
fd, e := l.fd.accept();
|
2009-05-13 19:03:41 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, "", e
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
return newConnUnix(fd, fd.raddr), raddr, nil
|
2009-05-13 19:03:41 -06:00
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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): 6g bug prevents saying
|
|
|
|
// c, raddr, err = l.AcceptUnix();
|
|
|
|
// return;
|
|
|
|
c1, r1, e1 := l.AcceptUnix();
|
|
|
|
return c1, r1, e1;
|
|
|
|
}
|
2009-03-06 18:51:31 -07:00
|
|
|
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// 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;
|
2008-09-16 14:42:47 -06:00
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// 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.
|
|
|
|
//
|
2008-09-16 14:42:47 -06:00
|
|
|
// Examples:
|
|
|
|
// Dial("tcp", "", "12.34.56.78:80")
|
2009-03-05 16:48:12 -07:00
|
|
|
// Dial("tcp", "", "google.com:80")
|
2008-09-16 14:42:47 -06:00
|
|
|
// Dial("tcp", "", "[de:ad:be:ef::ca:fe]:80")
|
|
|
|
// Dial("tcp", "127.0.0.1:123", "127.0.0.1:88")
|
2009-04-17 01:08:24 -06:00
|
|
|
func Dial(net, laddr, raddr string) (c Conn, err os.Error) {
|
2008-09-30 15:03:13 -06:00
|
|
|
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;
|
2009-05-13 19:03:41 -06:00
|
|
|
case "unix", "unix-dgram":
|
|
|
|
c, err := DialUnix(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
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// 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 {
|
2009-04-17 01:08:24 -06:00
|
|
|
Accept() (c Conn, raddr string, err os.Error);
|
|
|
|
Close() os.Error;
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// 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 {
|
2009-02-15 15:18:39 -07:00
|
|
|
fd *netFD;
|
2008-09-17 14:49:23 -06:00
|
|
|
laddr string
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// ListenTCP announces on the TCP address laddr and returns a TCP listener.
|
|
|
|
// Net must be "tcp", "tcp4", or "tcp6".
|
2009-04-17 01:08:24 -06:00
|
|
|
func ListenTCP(net, laddr string) (l *ListenerTCP, err os.Error) {
|
2009-02-15 15:18:39 -07:00
|
|
|
fd, e := internetSocket(net, laddr, "", syscall.SOCK_STREAM, "listen");
|
2008-09-17 14:49:23 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
e1 := syscall.Listen(fd.fd, listenBacklog());
|
2008-09-26 15:11:26 -06:00
|
|
|
if e1 != 0 {
|
2009-01-16 12:36:44 -07: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
|
|
|
}
|
2009-01-06 16:19:02 -07: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
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// AcceptTCP accepts the next incoming call and returns the new connection
|
|
|
|
// and the remote address.
|
2009-04-17 01:08:24 -06:00
|
|
|
func (l *ListenerTCP) AcceptTCP() (c *ConnTCP, raddr string, err os.Error) {
|
2008-09-17 14:49:23 -06:00
|
|
|
if l == nil || l.fd == nil || l.fd.fd < 0 {
|
|
|
|
return nil, "", os.EINVAL
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
fd, e := l.fd.accept();
|
2008-09-17 14:49:23 -06:00
|
|
|
if e != nil {
|
|
|
|
return nil, "", e
|
|
|
|
}
|
2009-06-01 23:14:39 -06:00
|
|
|
return newConnTCP(fd, fd.raddr), fd.raddr, nil
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
|
2009-05-13 19:03:41 -06:00
|
|
|
// Accept implements the Accept method in the Listener interface;
|
2009-03-05 16:48:12 -07:00
|
|
|
// it waits for the next call and returns a generic Conn.
|
2009-04-17 01:08:24 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// Close stops listening on the TCP address.
|
|
|
|
// Already Accepted connections are not closed.
|
2009-04-17 01:08:24 -06:00
|
|
|
func (l *ListenerTCP) Close() os.Error {
|
2008-09-17 14:49:23 -06:00
|
|
|
if l == nil || l.fd == nil {
|
|
|
|
return os.EINVAL
|
|
|
|
}
|
|
|
|
return l.fd.Close()
|
|
|
|
}
|
|
|
|
|
2009-03-05 16:48:12 -07:00
|
|
|
// Listen announces on the local network address laddr.
|
2009-05-13 19:03:41 -06:00
|
|
|
// The network string net must be "tcp", "tcp4", "tcp6",
|
|
|
|
// "unix", or "unix-dgram".
|
2009-04-17 01:08:24 -06:00
|
|
|
func Listen(net, laddr string) (l Listener, err os.Error) {
|
2008-09-30 15:03:13 -06:00
|
|
|
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 {
|
2009-05-13 19:03:41 -06:00
|
|
|
return nil, err;
|
|
|
|
}
|
|
|
|
return l, nil;
|
|
|
|
case "unix", "unix-dgram":
|
|
|
|
l, err := ListenUnix(net, laddr);
|
|
|
|
if err != nil {
|
|
|
|
return nil, err;
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
2009-05-13 19:03:41 -06:00
|
|
|
return l, nil;
|
2008-09-17 14:49:23 -06:00
|
|
|
/*
|
|
|
|
more here
|
|
|
|
*/
|
2009-03-05 16:48:12 -07:00
|
|
|
// BUG(rsc): Listen should support UDP.
|
2008-09-17 14:49:23 -06:00
|
|
|
}
|
|
|
|
return nil, UnknownNetwork
|
|
|
|
}
|
2008-09-26 15:11:26 -06:00
|
|
|
|