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 }