github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/net/udpsock_plan9.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package net
     6  
     7  import (
     8  	"github.com/x04/go/src/context"
     9  	"github.com/x04/go/src/errors"
    10  	"github.com/x04/go/src/os"
    11  	"github.com/x04/go/src/syscall"
    12  )
    13  
    14  func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
    15  	buf := make([]byte, udpHeaderSize+len(b))
    16  	m, err := c.fd.Read(buf)
    17  	if err != nil {
    18  		return 0, nil, err
    19  	}
    20  	if m < udpHeaderSize {
    21  		return 0, nil, errors.New("short read reading UDP header")
    22  	}
    23  	buf = buf[:m]
    24  
    25  	h, buf := unmarshalUDPHeader(buf)
    26  	n = copy(b, buf)
    27  	return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
    28  }
    29  
    30  func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
    31  	return 0, 0, 0, nil, syscall.EPLAN9
    32  }
    33  
    34  func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
    35  	if addr == nil {
    36  		return 0, errMissingAddress
    37  	}
    38  	h := new(udpHeader)
    39  	h.raddr = addr.IP.To16()
    40  	h.laddr = c.fd.laddr.(*UDPAddr).IP.To16()
    41  	h.ifcaddr = IPv6zero	// ignored (receive only)
    42  	h.rport = uint16(addr.Port)
    43  	h.lport = uint16(c.fd.laddr.(*UDPAddr).Port)
    44  
    45  	buf := make([]byte, udpHeaderSize+len(b))
    46  	i := copy(buf, h.Bytes())
    47  	copy(buf[i:], b)
    48  	if _, err := c.fd.Write(buf); err != nil {
    49  		return 0, err
    50  	}
    51  	return len(b), nil
    52  }
    53  
    54  func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
    55  	return 0, 0, syscall.EPLAN9
    56  }
    57  
    58  func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
    59  	fd, err := dialPlan9(ctx, sd.network, laddr, raddr)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return newUDPConn(fd), nil
    64  }
    65  
    66  const udpHeaderSize = 16*3 + 2*2
    67  
    68  type udpHeader struct {
    69  	raddr, laddr, ifcaddr	IP
    70  	rport, lport		uint16
    71  }
    72  
    73  func (h *udpHeader) Bytes() []byte {
    74  	b := make([]byte, udpHeaderSize)
    75  	i := 0
    76  	i += copy(b[i:i+16], h.raddr)
    77  	i += copy(b[i:i+16], h.laddr)
    78  	i += copy(b[i:i+16], h.ifcaddr)
    79  	b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
    80  	b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
    81  	return b
    82  }
    83  
    84  func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
    85  	h := new(udpHeader)
    86  	h.raddr, b = IP(b[:16]), b[16:]
    87  	h.laddr, b = IP(b[:16]), b[16:]
    88  	h.ifcaddr, b = IP(b[:16]), b[16:]
    89  	h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
    90  	h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
    91  	return h, b
    92  }
    93  
    94  func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
    95  	l, err := listenPlan9(ctx, sl.network, laddr)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	_, err = l.ctl.WriteString("headers")
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	fd, err := l.netFD()
   108  	return newUDPConn(fd), err
   109  }
   110  
   111  func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
   112  	// Plan 9 does not like announce command with a multicast address,
   113  	// so do not specify an IP address when listening.
   114  	l, err := listenPlan9(ctx, sl.network, &UDPAddr{IP: nil, Port: gaddr.Port, Zone: gaddr.Zone})
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	_, err = l.ctl.WriteString("headers")
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	var addrs []Addr
   123  	if ifi != nil {
   124  		addrs, err = ifi.Addrs()
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  	} else {
   129  		addrs, err = InterfaceAddrs()
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  
   135  	have4 := gaddr.IP.To4() != nil
   136  	for _, addr := range addrs {
   137  		if ipnet, ok := addr.(*IPNet); ok && (ipnet.IP.To4() != nil) == have4 {
   138  			_, err = l.ctl.WriteString("addmulti " + ipnet.IP.String() + " " + gaddr.IP.String())
   139  			if err != nil {
   140  				return nil, &OpError{Op: "addmulti", Net: "", Source: nil, Addr: ipnet, Err: err}
   141  			}
   142  		}
   143  	}
   144  	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	fd, err := l.netFD()
   149  	if err != nil {
   150  		return nil, err
   151  	}
   152  	return newUDPConn(fd), nil
   153  }