batch.go 5.47 KB
Newer Older
zhangweiwei's avatar
init  
zhangweiwei committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
// Copyright 2017 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.

// +build go1.9

package ipv4

import (
	"net"
	"runtime"

	"golang.org/x/net/internal/socket"
)

// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// PacketConn are not implemented.

// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// RawConn are not implemented.

// A Message represents an IO message.
//
//	type Message struct {
//		Buffers [][]byte
//		OOB     []byte
//		Addr    net.Addr
//		N       int
//		NN      int
//		Flags   int
//	}
//
// The Buffers fields represents a list of contiguous buffers, which
// can be used for vectored IO, for example, putting a header and a
// payload in each slice.
// When writing, the Buffers field must contain at least one byte to
// write.
// When reading, the Buffers field will always contain a byte to read.
//
// The OOB field contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
// It can be nil when not required.
//
// The Addr field specifies a destination address when writing.
// It can be nil when the underlying protocol of the endpoint uses
// connection-oriented communication.
// After a successful read, it may contain the source address on the
// received packet.
//
// The N field indicates the number of bytes read or written from/to
// Buffers.
//
// The NN field indicates the number of bytes read or written from/to
// OOB.
//
// The Flags field contains protocol-specific information on the
// received message.
type Message = socket.Message

// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
//
// Unlike the ReadFrom method, it doesn't strip the IPv4 header
// followed by option headers from the received IPv4 datagram when the
// underlying transport is net.IPConn. Each Buffers field of Message
// must be large enough to accommodate an IPv4 header and option
// headers.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
	if !c.ok() {
		return 0, errInvalidConn
	}
	switch runtime.GOOS {
	case "linux":
		n, err := c.RecvMsgs([]socket.Message(ms), flags)
		if err != nil {
			err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
		}
		return n, err
	default:
		n := 1
		err := c.RecvMsg(&ms[0], flags)
		if err != nil {
			n = 0
			err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
		}
		return n, err
	}
}

// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
	if !c.ok() {
		return 0, errInvalidConn
	}
	switch runtime.GOOS {
	case "linux":
		n, err := c.SendMsgs([]socket.Message(ms), flags)
		if err != nil {
			err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
		}
		return n, err
	default:
		n := 1
		err := c.SendMsg(&ms[0], flags)
		if err != nil {
			n = 0
			err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
		}
		return n, err
	}
}

// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
	if !c.ok() {
		return 0, errInvalidConn
	}
	switch runtime.GOOS {
	case "linux":
		n, err := c.RecvMsgs([]socket.Message(ms), flags)
		if err != nil {
			err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
		}
		return n, err
	default:
		n := 1
		err := c.RecvMsg(&ms[0], flags)
		if err != nil {
			n = 0
			err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
		}
		return n, err
	}
}

// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *packetHandler) WriteBatch(ms []Message, flags int) (int, error) {
	if !c.ok() {
		return 0, errInvalidConn
	}
	switch runtime.GOOS {
	case "linux":
		n, err := c.SendMsgs([]socket.Message(ms), flags)
		if err != nil {
			err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
		}
		return n, err
	default:
		n := 1
		err := c.SendMsg(&ms[0], flags)
		if err != nil {
			n = 0
			err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
		}
		return n, err
	}
}