payload_cmsg.go (2889B)
1 // Copyright 2012 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 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos 6 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos 7 8 package ipv4 9 10 import ( 11 "net" 12 13 "golang.org/x/net/internal/socket" 14 ) 15 16 // ReadFrom reads a payload of the received IPv4 datagram, from the 17 // endpoint c, copying the payload into b. It returns the number of 18 // bytes copied into b, the control message cm and the source address 19 // src of the received datagram. 20 func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) { 21 if !c.ok() { 22 return 0, nil, nil, errInvalidConn 23 } 24 c.rawOpt.RLock() 25 m := socket.Message{ 26 OOB: NewControlMessage(c.rawOpt.cflags), 27 } 28 c.rawOpt.RUnlock() 29 switch c.PacketConn.(type) { 30 case *net.UDPConn: 31 m.Buffers = [][]byte{b} 32 if err := c.RecvMsg(&m, 0); err != nil { 33 return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err} 34 } 35 case *net.IPConn: 36 h := make([]byte, HeaderLen) 37 m.Buffers = [][]byte{h, b} 38 if err := c.RecvMsg(&m, 0); err != nil { 39 return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err} 40 } 41 hdrlen := int(h[0]&0x0f) << 2 42 if hdrlen > len(h) { 43 d := hdrlen - len(h) 44 copy(b, b[d:]) 45 m.N -= d 46 } else { 47 m.N -= hdrlen 48 } 49 default: 50 return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType} 51 } 52 if m.NN > 0 { 53 if compatFreeBSD32 { 54 adjustFreeBSD32(&m) 55 } 56 cm = new(ControlMessage) 57 if err := cm.Parse(m.OOB[:m.NN]); err != nil { 58 return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err} 59 } 60 cm.Src = netAddrToIP4(m.Addr) 61 } 62 return m.N, cm, m.Addr, nil 63 } 64 65 // WriteTo writes a payload of the IPv4 datagram, to the destination 66 // address dst through the endpoint c, copying the payload from b. It 67 // returns the number of bytes written. The control message cm allows 68 // the datagram path and the outgoing interface to be specified. 69 // Currently only Darwin and Linux support this. The cm may be nil if 70 // control of the outgoing datagram is not required. 71 func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) { 72 if !c.ok() { 73 return 0, errInvalidConn 74 } 75 m := socket.Message{ 76 Buffers: [][]byte{b}, 77 OOB: cm.Marshal(), 78 Addr: dst, 79 } 80 err = c.SendMsg(&m, 0) 81 if err != nil { 82 err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err} 83 } 84 return m.N, err 85 }