blob: b019cbff873c32af1c06620529c67be9c7de5642 [file] [log] [blame]
// Copyright 2013 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.
// A simulated network for use within NaCl.
// The simulation is not particularly tied to NaCl,
// but other systems have real networks.
// All int64 times are UnixNanos.
package syscall
import (
"sync"
"sync/atomic"
)
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
// Really for use by package time, but we cannot import time here.
type runtimeTimer struct {
i int
when int64
period int64
f func(interface{}, uintptr) // NOTE: must not be closure
arg interface{}
seq uintptr
}
func startTimer(*runtimeTimer)
func stopTimer(*runtimeTimer) bool
type timer struct {
expired bool
q *queue
r runtimeTimer
}
func (t *timer) start(q *queue, deadline int64) {
if deadline == 0 {
return
}
t.q = q
t.r.when = deadline
t.r.f = timerExpired
t.r.arg = t
startTimer(&t.r)
}
func (t *timer) stop() {
stopTimer(&t.r)
}
func (t *timer) reset(q *queue, deadline int64) {
if t.r.f != nil {
t.stop()
}
if deadline == 0 {
return
}
if t.r.f == nil {
t.q = q
t.r.f = timerExpired
t.r.arg = t
}
t.r.when = deadline
startTimer(&t.r)
}
func timerExpired(i interface{}, seq uintptr) {
t := i.(*timer)
go func() {
t.q.Lock()
defer t.q.Unlock()
t.expired = true
t.q.canRead.Broadcast()
t.q.canWrite.Broadcast()
}()
}
// Network constants and data structures. These match the traditional values.
const (
AF_UNSPEC = iota
AF_UNIX
AF_INET
AF_INET6
)
const (
SHUT_RD = iota
SHUT_WR
SHUT_RDWR
)
const (
SOCK_STREAM = 1 + iota
SOCK_DGRAM
SOCK_RAW
SOCK_SEQPACKET
)
const (
IPPROTO_IP = 0
IPPROTO_IPV4 = 4
IPPROTO_IPV6 = 0x29
IPPROTO_TCP = 6
IPPROTO_UDP = 0x11
)
// Misc constants expected by package net but not supported.
const (
_ = iota
SOL_SOCKET
SO_TYPE
NET_RT_IFLIST
IFNAMSIZ
IFF_UP
IFF_BROADCAST
IFF_LOOPBACK
IFF_POINTOPOINT
IFF_MULTICAST
IPV6_V6ONLY
SOMAXCONN
F_DUPFD_CLOEXEC
SO_BROADCAST
SO_REUSEADDR
SO_REUSEPORT
SO_RCVBUF
SO_SNDBUF
SO_KEEPALIVE
SO_LINGER
SO_ERROR
IP_PORTRANGE
IP_PORTRANGE_DEFAULT
IP_PORTRANGE_LOW
IP_PORTRANGE_HIGH
IP_MULTICAST_IF
IP_MULTICAST_LOOP
IP_ADD_MEMBERSHIP
IPV6_PORTRANGE
IPV6_PORTRANGE_DEFAULT
IPV6_PORTRANGE_LOW
IPV6_PORTRANGE_HIGH
IPV6_MULTICAST_IF
IPV6_MULTICAST_LOOP
IPV6_JOIN_GROUP
TCP_NODELAY
TCP_KEEPINTVL
TCP_KEEPIDLE
SYS_FCNTL = 500 // unsupported
)
var SocketDisableIPv6 bool
// A Sockaddr is one of the SockaddrXxx structs.
type Sockaddr interface {
// copy returns a copy of the underlying data.
copy() Sockaddr
// key returns the value of the underlying data,
// for comparison as a map key.
key() interface{}
}
type SockaddrInet4 struct {
Port int
Addr [4]byte
}
func (sa *SockaddrInet4) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrInet4) key() interface{} { return *sa }
func isIPv4Localhost(sa Sockaddr) bool {
sa4, ok := sa.(*SockaddrInet4)
return ok && sa4.Addr == [4]byte{127, 0, 0, 1}
}
type SockaddrInet6 struct {
Port int
ZoneId uint32
Addr [16]byte
}
func (sa *SockaddrInet6) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrInet6) key() interface{} { return *sa }
type SockaddrUnix struct {
Name string
}
func (sa *SockaddrUnix) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrUnix) key() interface{} { return *sa }
type SockaddrDatalink struct {
Len uint8
Family uint8
Index uint16
Type uint8
Nlen uint8
Alen uint8
Slen uint8
Data [12]int8
}
func (sa *SockaddrDatalink) copy() Sockaddr {
sa1 := *sa
return &sa1
}
func (sa *SockaddrDatalink) key() interface{} { return *sa }
// RoutingMessage represents a routing message.
type RoutingMessage interface {
unimplemented()
}
type IPMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type IPv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type Linger struct {
Onoff int32
Linger int32
}
type ICMPv6Filter struct {
Filt [8]uint32
}
// A queue is the bookkeeping for a synchronized buffered queue.
// We do not use channels because we need to be able to handle
// writes after and during close, and because a chan byte would
// require too many send and receive operations in real use.
type queue struct {
sync.Mutex
canRead sync.Cond
canWrite sync.Cond
rtimer *timer // non-nil if in read
wtimer *timer // non-nil if in write
r int // total read index
w int // total write index
m int // index mask
closed bool
}
func (q *queue) init(size int) {
if size&(size-1) != 0 {
panic("invalid queue size - must be power of two")
}
q.canRead.L = &q.Mutex
q.canWrite.L = &q.Mutex
q.m = size - 1
}
func past(deadline int64) bool {
sec, nsec := now()
return deadline > 0 && deadline < sec*1e9+int64(nsec)
}
func (q *queue) waitRead(n int, deadline int64) (int, error) {
if past(deadline) {
return 0, EAGAIN
}
var t timer
t.start(q, deadline)
q.rtimer = &t
for q.w-q.r == 0 && !q.closed && !t.expired {
q.canRead.Wait()
}
q.rtimer = nil
t.stop()
m := q.w - q.r
if m == 0 && t.expired {
return 0, EAGAIN
}
if m > n {
m = n
q.canRead.Signal() // wake up next reader too
}
q.canWrite.Signal()
return m, nil
}
func (q *queue) waitWrite(n int, deadline int64) (int, error) {
if past(deadline) {
return 0, EAGAIN
}
var t timer
t.start(q, deadline)
q.wtimer = &t
for q.w-q.r > q.m && !q.closed && !t.expired {
q.canWrite.Wait()
}
q.wtimer = nil
t.stop()
m := q.m + 1 - (q.w - q.r)
if m == 0 && t.expired {
return 0, EAGAIN
}
if m == 0 {
return 0, EAGAIN
}
if m > n {
m = n
q.canWrite.Signal() // wake up next writer too
}
q.canRead.Signal()
return m, nil
}
func (q *queue) close() {
q.Lock()
defer q.Unlock()
q.closed = true
q.canRead.Broadcast()
q.canWrite.Broadcast()
}
// A byteq is a byte queue.
type byteq struct {
queue
data []byte
}
func newByteq() *byteq {
q := &byteq{
data: make([]byte, 4096),
}
q.init(len(q.data))
return q
}
func (q *byteq) read(b []byte, deadline int64) (int, error) {
q.Lock()
defer q.Unlock()
n, err := q.waitRead(len(b), deadline)
if err != nil {
return 0, err
}
b = b[:n]
for len(b) > 0 {
m := copy(b, q.data[q.r&q.m:])
q.r += m
b = b[m:]
}
return n, nil
}
func (q *byteq) write(b []byte, deadline int64) (n int, err error) {
q.Lock()
defer q.Unlock()
for n < len(b) {
nn, err := q.waitWrite(len(b[n:]), deadline)
if err != nil {
return n, err
}
bb := b[n : n+nn]
n += nn
for len(bb) > 0 {
m := copy(q.data[q.w&q.m:], bb)
q.w += m
bb = bb[m:]
}
}
return n, nil
}
// A msgq is a queue of messages.
type msgq struct {
queue
data []interface{}
}
func newMsgq() *msgq {
q := &msgq{
data: make([]interface{}, 32),
}
q.init(len(q.data))
return q
}
func (q *msgq) read(deadline int64) (interface{}, error) {
q.Lock()
defer q.Unlock()
n, err := q.waitRead(1, deadline)
if err != nil {
return nil, err
}
if n == 0 {
return nil, nil
}
m := q.data[q.r&q.m]
q.r++
return m, nil
}
func (q *msgq) write(m interface{}, deadline int64) error {
q.Lock()
defer q.Unlock()
_, err := q.waitWrite(1, deadline)
if err != nil {
return err
}
q.data[q.w&q.m] = m
q.w++
return nil
}
// An addr is a sequence of bytes uniquely identifying a network address.
// It is not human-readable.
type addr string
// A conn is one side of a stream-based network connection.
// That is, a stream-based network connection is a pair of cross-connected conns.
type conn struct {
rd *byteq
wr *byteq
local addr
remote addr
}
// A pktconn is one side of a packet-based network connection.
// That is, a packet-based network connection is a pair of cross-connected pktconns.
type pktconn struct {
rd *msgq
wr *msgq
local addr
remote addr
}
// A listener accepts incoming stream-based network connections.
type listener struct {
rd *msgq
local addr
}
// A netFile is an open network file.
type netFile struct {
defaultFileImpl
proto *netproto
sotype int
listener *msgq
packet *msgq
rd *byteq
wr *byteq
rddeadline int64
wrdeadline int64
addr Sockaddr
raddr Sockaddr
}
// A netAddr is a network address in the global listener map.
// All the fields must have defined == operations.
type netAddr struct {
proto *netproto
sotype int
addr interface{}
}
// net records the state of the network.
// It maps a network address to the listener on that address.
var net = struct {
sync.Mutex
listener map[netAddr]*netFile
}{
listener: make(map[netAddr]*netFile),
}
// TODO(rsc): Some day, do a better job with port allocation.
// For playground programs, incrementing is fine.
var nextport = 2
// A netproto contains protocol-specific functionality
// (one for AF_INET, one for AF_INET6 and so on).
// It is a struct instead of an interface because the
// implementation needs no state, and I expect to
// add some data fields at some point.
type netproto struct {
bind func(*netFile, Sockaddr) error
}
var netprotoAF_INET = &netproto{
bind: func(f *netFile, sa Sockaddr) error {
if sa == nil {
f.addr = &SockaddrInet4{
Port: nextport,
Addr: [4]byte{127, 0, 0, 1},
}
nextport++
return nil
}
addr, ok := sa.(*SockaddrInet4)
if !ok {
return EINVAL
}
addr = addr.copy().(*SockaddrInet4)
if addr.Port == 0 {
addr.Port = nextport
nextport++
}
f.addr = addr
return nil
},
}
var netprotos = map[int]*netproto{
AF_INET: netprotoAF_INET,
}
// These functions implement the usual BSD socket operations.
func (f *netFile) bind(sa Sockaddr) error {
if f.addr != nil {
return EISCONN
}
if err := f.proto.bind(f, sa); err != nil {
return err
}
if f.sotype == SOCK_DGRAM {
_, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
if ok {
f.addr = nil
return EADDRINUSE
}
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
f.packet = newMsgq()
}
return nil
}
func (f *netFile) listen(backlog int) error {
net.Lock()
defer net.Unlock()
if f.listener != nil {
return EINVAL
}
old, ok := net.listener[netAddr{f.proto, f.sotype, f.addr.key()}]
if ok && !old.listenerClosed() {
return EADDRINUSE
}
net.listener[netAddr{f.proto, f.sotype, f.addr.key()}] = f
f.listener = newMsgq()
return nil
}
func (f *netFile) accept() (fd int, sa Sockaddr, err error) {
msg, err := f.listener.read(f.readDeadline())
if err != nil {
return -1, nil, err
}
newf, ok := msg.(*netFile)
if !ok {
// must be eof
return -1, nil, EAGAIN
}
return newFD(newf), newf.raddr.copy(), nil
}
func (f *netFile) connect(sa Sockaddr) error {
if past(f.writeDeadline()) {
return EAGAIN
}
if f.addr == nil {
if err := f.bind(nil); err != nil {
return err
}
}
net.Lock()
if sa == nil {
net.Unlock()
return EINVAL
}
sa = sa.copy()
if f.raddr != nil {
net.Unlock()
return EISCONN
}
if f.sotype == SOCK_DGRAM {
net.Unlock()
f.raddr = sa
return nil
}
if f.listener != nil {
net.Unlock()
return EISCONN
}
l, ok := net.listener[netAddr{f.proto, f.sotype, sa.key()}]
if !ok {
// If we're dialing 127.0.0.1 but found nothing, try
// 0.0.0.0 also. (Issue 20611)
if isIPv4Localhost(sa) {
sa = &SockaddrInet4{Port: sa.(*SockaddrInet4).Port}
l, ok = net.listener[netAddr{f.proto, f.sotype, sa.key()}]
}
}
if !ok || l.listenerClosed() {
net.Unlock()
return ECONNREFUSED
}
f.raddr = sa
f.rd = newByteq()
f.wr = newByteq()
newf := &netFile{
proto: f.proto,
sotype: f.sotype,
addr: f.raddr,
raddr: f.addr,
rd: f.wr,
wr: f.rd,
}
net.Unlock()
l.listener.write(newf, f.writeDeadline())
return nil
}
func (f *netFile) read(b []byte) (int, error) {
if f.rd == nil {
if f.raddr != nil {
n, _, err := f.recvfrom(b, 0)
return n, err
}
return 0, ENOTCONN
}
return f.rd.read(b, f.readDeadline())
}
func (f *netFile) write(b []byte) (int, error) {
if f.wr == nil {
if f.raddr != nil {
err := f.sendto(b, 0, f.raddr)
var n int
if err == nil {
n = len(b)
}
return n, err
}
return 0, ENOTCONN
}
return f.wr.write(b, f.writeDeadline())
}
type pktmsg struct {
buf []byte
addr Sockaddr
}
func (f *netFile) recvfrom(p []byte, flags int) (n int, from Sockaddr, err error) {
if f.sotype != SOCK_DGRAM {
return 0, nil, EINVAL
}
if f.packet == nil {
return 0, nil, ENOTCONN
}
msg1, err := f.packet.read(f.readDeadline())
if err != nil {
return 0, nil, err
}
msg, ok := msg1.(*pktmsg)
if !ok {
return 0, nil, EAGAIN
}
return copy(p, msg.buf), msg.addr, nil
}
func (f *netFile) sendto(p []byte, flags int, to Sockaddr) error {
if f.sotype != SOCK_DGRAM {
return EINVAL
}
if f.packet == nil {
if err := f.bind(nil); err != nil {
return err
}
}
net.Lock()
if to == nil {
net.Unlock()
return EINVAL
}
to = to.copy()
l, ok := net.listener[netAddr{f.proto, f.sotype, to.key()}]
if !ok || l.packet == nil {
net.Unlock()
return ECONNREFUSED
}
net.Unlock()
msg := &pktmsg{
buf: make([]byte, len(p)),
addr: f.addr,
}
copy(msg.buf, p)
l.packet.write(msg, f.writeDeadline())
return nil
}
func (f *netFile) listenerClosed() bool {
f.listener.Lock()
defer f.listener.Unlock()
return f.listener.closed
}
func (f *netFile) close() error {
if f.listener != nil {
f.listener.close()
}
if f.packet != nil {
f.packet.close()
}
if f.rd != nil {
f.rd.close()
}
if f.wr != nil {
f.wr.close()
}
return nil
}
func fdToNetFile(fd int) (*netFile, error) {
f, err := fdToFile(fd)
if err != nil {
return nil, err
}
impl := f.impl
netf, ok := impl.(*netFile)
if !ok {
return nil, EINVAL
}
return netf, nil
}
func Socket(proto, sotype, unused int) (fd int, err error) {
p := netprotos[proto]
if p == nil {
return -1, EPROTONOSUPPORT
}
if sotype != SOCK_STREAM && sotype != SOCK_DGRAM {
return -1, ESOCKTNOSUPPORT
}
f := &netFile{
proto: p,
sotype: sotype,
}
return newFD(f), nil
}
func Bind(fd int, sa Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.bind(sa)
}
func StopIO(fd int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
f.close()
return nil
}
func Listen(fd int, backlog int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.listen(backlog)
}
func Accept(fd int) (newfd int, sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, nil, err
}
return f.accept()
}
func Getsockname(fd int) (sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return nil, err
}
if f.addr == nil {
return nil, ENOTCONN
}
return f.addr.copy(), nil
}
func Getpeername(fd int) (sa Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return nil, err
}
if f.raddr == nil {
return nil, ENOTCONN
}
return f.raddr.copy(), nil
}
func Connect(fd int, sa Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.connect(sa)
}
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, nil, err
}
return f.recvfrom(p, flags)
}
func Sendto(fd int, p []byte, flags int, to Sockaddr) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
return f.sendto(p, flags, to)
}
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn, recvflags int, from Sockaddr, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return
}
n, from, err = f.recvfrom(p, flags)
return
}
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) error {
_, err := SendmsgN(fd, p, oob, to, flags)
return err
}
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, err
}
switch f.sotype {
case SOCK_STREAM:
n, err = f.write(p)
case SOCK_DGRAM:
n = len(p)
err = f.sendto(p, flags, to)
}
if err != nil {
return 0, err
}
return n, nil
}
func GetsockoptInt(fd, level, opt int) (value int, err error) {
f, err := fdToNetFile(fd)
if err != nil {
return 0, err
}
switch {
case level == SOL_SOCKET && opt == SO_TYPE:
return f.sotype, nil
}
return 0, ENOTSUP
}
func SetsockoptInt(fd, level, opt int, value int) error {
return nil
}
func SetsockoptByte(fd, level, opt int, value byte) error {
_, err := fdToNetFile(fd)
if err != nil {
return err
}
return ENOTSUP
}
func SetsockoptLinger(fd, level, opt int, l *Linger) error {
return nil
}
func SetReadDeadline(fd int, t int64) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
atomic.StoreInt64(&f.rddeadline, t)
if bq := f.rd; bq != nil {
bq.Lock()
if timer := bq.rtimer; timer != nil {
timer.reset(&bq.queue, t)
}
bq.Unlock()
}
return nil
}
func (f *netFile) readDeadline() int64 {
return atomic.LoadInt64(&f.rddeadline)
}
func SetWriteDeadline(fd int, t int64) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
atomic.StoreInt64(&f.wrdeadline, t)
if bq := f.wr; bq != nil {
bq.Lock()
if timer := bq.wtimer; timer != nil {
timer.reset(&bq.queue, t)
}
bq.Unlock()
}
return nil
}
func (f *netFile) writeDeadline() int64 {
return atomic.LoadInt64(&f.wrdeadline)
}
func Shutdown(fd int, how int) error {
f, err := fdToNetFile(fd)
if err != nil {
return err
}
switch how {
case SHUT_RD:
f.rd.close()
case SHUT_WR:
f.wr.close()
case SHUT_RDWR:
f.rd.close()
f.wr.close()
}
return nil
}
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error { panic("SetsockoptICMPv") }
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) error { panic("SetsockoptIPMreq") }
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) error { panic("SetsockoptIPv") }
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) error { panic("SetsockoptInet") }
func SetsockoptString(fd, level, opt int, s string) error { panic("SetsockoptString") }
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) error { panic("SetsockoptTimeval") }
func Socketpair(domain, typ, proto int) (fd [2]int, err error) { panic("Socketpair") }
func SetNonblock(fd int, nonblocking bool) error { return nil }