|  | // 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 } |