batch.go raw

   1  // Copyright 2017 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 ipv4
   6  
   7  import (
   8  	"net"
   9  	"runtime"
  10  
  11  	"golang.org/x/net/internal/socket"
  12  )
  13  
  14  // BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
  15  // PacketConn are not implemented.
  16  
  17  // BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
  18  // RawConn are not implemented.
  19  
  20  // A Message represents an IO message.
  21  //
  22  //	type Message struct {
  23  //		Buffers [][]byte
  24  //		OOB     []byte
  25  //		Addr    net.Addr
  26  //		N       int
  27  //		NN      int
  28  //		Flags   int
  29  //	}
  30  //
  31  // The Buffers fields represents a list of contiguous buffers, which
  32  // can be used for vectored IO, for example, putting a header and a
  33  // payload in each slice.
  34  // When writing, the Buffers field must contain at least one byte to
  35  // write.
  36  // When reading, the Buffers field will always contain a byte to read.
  37  //
  38  // The OOB field contains protocol-specific control or miscellaneous
  39  // ancillary data known as out-of-band data.
  40  // It can be nil when not required.
  41  //
  42  // The Addr field specifies a destination address when writing.
  43  // It can be nil when the underlying protocol of the endpoint uses
  44  // connection-oriented communication.
  45  // After a successful read, it may contain the source address on the
  46  // received packet.
  47  //
  48  // The N field indicates the number of bytes read or written from/to
  49  // Buffers.
  50  //
  51  // The NN field indicates the number of bytes read or written from/to
  52  // OOB.
  53  //
  54  // The Flags field contains protocol-specific information on the
  55  // received message.
  56  type Message = socket.Message
  57  
  58  // ReadBatch reads a batch of messages.
  59  //
  60  // The provided flags is a set of platform-dependent flags, such as
  61  // syscall.MSG_PEEK.
  62  //
  63  // On a successful read it returns the number of messages received, up
  64  // to len(ms).
  65  //
  66  // On Linux, a batch read will be optimized.
  67  // On other platforms, this method will read only a single message.
  68  //
  69  // Unlike the ReadFrom method, it doesn't strip the IPv4 header
  70  // followed by option headers from the received IPv4 datagram when the
  71  // underlying transport is net.IPConn. Each Buffers field of Message
  72  // must be large enough to accommodate an IPv4 header and option
  73  // headers.
  74  func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
  75  	if !c.ok() {
  76  		return 0, errInvalidConn
  77  	}
  78  	switch runtime.GOOS {
  79  	case "linux":
  80  		n, err := c.RecvMsgs([]socket.Message(ms), flags)
  81  		if err != nil {
  82  			err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
  83  		}
  84  		return n, err
  85  	default:
  86  		n := 1
  87  		err := c.RecvMsg(&ms[0], flags)
  88  		if err != nil {
  89  			n = 0
  90  			err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
  91  		}
  92  		if compatFreeBSD32 && ms[0].NN > 0 {
  93  			adjustFreeBSD32(&ms[0])
  94  		}
  95  		return n, err
  96  	}
  97  }
  98  
  99  // WriteBatch writes a batch of messages.
 100  //
 101  // The provided flags is a set of platform-dependent flags, such as
 102  // syscall.MSG_DONTROUTE.
 103  //
 104  // It returns the number of messages written on a successful write.
 105  //
 106  // On Linux, a batch write will be optimized.
 107  // On other platforms, this method will write only a single message.
 108  func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
 109  	if !c.ok() {
 110  		return 0, errInvalidConn
 111  	}
 112  	switch runtime.GOOS {
 113  	case "linux":
 114  		n, err := c.SendMsgs([]socket.Message(ms), flags)
 115  		if err != nil {
 116  			err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
 117  		}
 118  		return n, err
 119  	default:
 120  		n := 1
 121  		err := c.SendMsg(&ms[0], flags)
 122  		if err != nil {
 123  			n = 0
 124  			err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
 125  		}
 126  		return n, err
 127  	}
 128  }
 129  
 130  // ReadBatch reads a batch of messages.
 131  //
 132  // The provided flags is a set of platform-dependent flags, such as
 133  // syscall.MSG_PEEK.
 134  //
 135  // On a successful read it returns the number of messages received, up
 136  // to len(ms).
 137  //
 138  // On Linux, a batch read will be optimized.
 139  // On other platforms, this method will read only a single message.
 140  func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
 141  	if !c.ok() {
 142  		return 0, errInvalidConn
 143  	}
 144  	switch runtime.GOOS {
 145  	case "linux":
 146  		n, err := c.RecvMsgs([]socket.Message(ms), flags)
 147  		if err != nil {
 148  			err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 149  		}
 150  		return n, err
 151  	default:
 152  		n := 1
 153  		err := c.RecvMsg(&ms[0], flags)
 154  		if err != nil {
 155  			n = 0
 156  			err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 157  		}
 158  		if compatFreeBSD32 && ms[0].NN > 0 {
 159  			adjustFreeBSD32(&ms[0])
 160  		}
 161  		return n, err
 162  	}
 163  }
 164  
 165  // WriteBatch writes a batch of messages.
 166  //
 167  // The provided flags is a set of platform-dependent flags, such as
 168  // syscall.MSG_DONTROUTE.
 169  //
 170  // It returns the number of messages written on a successful write.
 171  //
 172  // On Linux, a batch write will be optimized.
 173  // On other platforms, this method will write only a single message.
 174  func (c *packetHandler) WriteBatch(ms []Message, flags int) (int, error) {
 175  	if !c.ok() {
 176  		return 0, errInvalidConn
 177  	}
 178  	switch runtime.GOOS {
 179  	case "linux":
 180  		n, err := c.SendMsgs([]socket.Message(ms), flags)
 181  		if err != nil {
 182  			err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 183  		}
 184  		return n, err
 185  	default:
 186  		n := 1
 187  		err := c.SendMsg(&ms[0], flags)
 188  		if err != nil {
 189  			n = 0
 190  			err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
 191  		}
 192  		return n, err
 193  	}
 194  }
 195