// 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/time.go:/^type timer // Really for use by package time, but we cannot import time here. type runtimeTimer struct { tb uintptr 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() { if t.r.f == nil { return } stopTimer(&t.r) } func (t *timer) reset(q *queue, deadline int64) { 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 }