Define tcpip.Payloader in terms of io.Reader

Fixes #1509.

PiperOrigin-RevId: 353295589
This commit is contained in:
Tamir Duberstein
2021-01-22 12:26:09 -08:00
committed by gVisor bot
parent 527ef5fc03
commit 6c0e1d9cfe
30 changed files with 372 additions and 373 deletions
+1 -1
View File
@@ -69,7 +69,7 @@ func (t *Task) BlockWithTimeout(C chan struct{}, haveTimeout bool, timeout time.
// syserror.ErrInterrupted if t is interrupted.
//
// Preconditions: The caller must be running on the task goroutine.
func (t *Task) BlockWithDeadline(C chan struct{}, haveDeadline bool, deadline ktime.Time) error {
func (t *Task) BlockWithDeadline(C <-chan struct{}, haveDeadline bool, deadline ktime.Time) error {
if !haveDeadline {
return t.block(C, nil)
}
-1
View File
@@ -41,7 +41,6 @@ go_library(
"//pkg/syserr",
"//pkg/syserror",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
"//pkg/tcpip/network/ipv4",
"//pkg/tcpip/network/ipv6",
+57 -121
View File
@@ -19,7 +19,7 @@
// be used to expose certain endpoints to the sentry while leaving others out,
// for example, TCP endpoints and Unix-domain endpoints.
//
// Lock ordering: netstack => mm: ioSequencePayload copies user memory inside
// Lock ordering: netstack => mm: ioSequenceReadWriter copies user memory inside
// tcpip.Endpoint.Write(). Netstack is allowed to (and does) hold locks during
// this operation.
package netstack
@@ -55,7 +55,6 @@ import (
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
@@ -440,45 +439,10 @@ func (s *SocketOperations) WriteTo(ctx context.Context, _ *fs.File, dst io.Write
return int64(res.Count), nil
}
// ioSequencePayload implements tcpip.Payload.
//
// t copies user memory bytes on demand based on the requested size.
type ioSequencePayload struct {
ctx context.Context
src usermem.IOSequence
}
// FullPayload implements tcpip.Payloader.FullPayload
func (i *ioSequencePayload) FullPayload() ([]byte, *tcpip.Error) {
return i.Payload(int(i.src.NumBytes()))
}
// Payload implements tcpip.Payloader.Payload.
func (i *ioSequencePayload) Payload(size int) ([]byte, *tcpip.Error) {
if max := int(i.src.NumBytes()); size > max {
size = max
}
v := buffer.NewView(size)
if _, err := i.src.CopyIn(i.ctx, v); err != nil {
// EOF can be returned only if src is a file and this means it
// is in a splice syscall and the error has to be ignored.
if err == io.EOF {
return v, nil
}
return nil, tcpip.ErrBadAddress
}
return v, nil
}
// DropFirst drops the first n bytes from underlying src.
func (i *ioSequencePayload) DropFirst(n int) {
i.src = i.src.DropFirst(int(n))
}
// Write implements fs.FileOperations.Write.
func (s *SocketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IOSequence, _ int64) (int64, error) {
f := &ioSequencePayload{ctx: ctx, src: src}
n, err := s.Endpoint.Write(f, tcpip.WriteOptions{})
r := src.Reader(ctx)
n, err := s.Endpoint.Write(r, tcpip.WriteOptions{})
if err == tcpip.ErrWouldBlock {
return 0, syserror.ErrWouldBlock
}
@@ -486,69 +450,40 @@ func (s *SocketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IO
return 0, syserr.TranslateNetstackError(err).ToError()
}
if int64(n) < src.NumBytes() {
return int64(n), syserror.ErrWouldBlock
if n < src.NumBytes() {
return n, syserror.ErrWouldBlock
}
return int64(n), nil
return n, nil
}
// readerPayload implements tcpip.Payloader.
//
// It allocates a view and reads from a reader on-demand, based on available
// capacity in the endpoint.
type readerPayload struct {
ctx context.Context
r io.Reader
count int64
err error
var _ tcpip.Payloader = (*limitedPayloader)(nil)
type limitedPayloader struct {
io.LimitedReader
}
// FullPayload implements tcpip.Payloader.FullPayload.
func (r *readerPayload) FullPayload() ([]byte, *tcpip.Error) {
return r.Payload(int(r.count))
}
// Payload implements tcpip.Payloader.Payload.
func (r *readerPayload) Payload(size int) ([]byte, *tcpip.Error) {
if size > int(r.count) {
size = int(r.count)
}
v := buffer.NewView(size)
n, err := r.r.Read(v)
if n > 0 {
// We ignore the error here. It may re-occur on subsequent
// reads, but for now we can enqueue some amount of data.
r.count -= int64(n)
return v[:n], nil
}
if err == syserror.ErrWouldBlock {
return nil, tcpip.ErrWouldBlock
} else if err != nil {
r.err = err // Save for propation.
return nil, tcpip.ErrBadAddress
}
// There is no data and no error. Return an error, which will propagate
// r.err, which will be nil. This is the desired result: (0, nil).
return nil, tcpip.ErrBadAddress
func (l limitedPayloader) Len() int {
return int(l.N)
}
// ReadFrom implements fs.FileOperations.ReadFrom.
func (s *SocketOperations) ReadFrom(ctx context.Context, _ *fs.File, r io.Reader, count int64) (int64, error) {
f := &readerPayload{ctx: ctx, r: r, count: count}
n, err := s.Endpoint.Write(f, tcpip.WriteOptions{
f := limitedPayloader{
LimitedReader: io.LimitedReader{
R: r,
N: count,
},
}
n, err := s.Endpoint.Write(&f, tcpip.WriteOptions{
// Reads may be destructive but should be very fast,
// so we can't release the lock while copying data.
Atomic: true,
})
if err == tcpip.ErrWouldBlock {
return n, syserror.ErrWouldBlock
} else if err != nil {
return int64(n), f.err // Propagate error.
if err == tcpip.ErrBadBuffer {
err = nil
}
return int64(n), nil
return n, syserr.TranslateNetstackError(err).ToError()
}
// Readiness returns a mask of ready events for socket s.
@@ -2836,45 +2771,46 @@ func (s *socketOpsCommon) SendMsg(t *kernel.Task, src usermem.IOSequence, to []b
EndOfRecord: flags&linux.MSG_EOR != 0,
}
v := &ioSequencePayload{t, src}
n, err := s.Endpoint.Write(v, opts)
dontWait := flags&linux.MSG_DONTWAIT != 0
if err == nil && (n >= v.src.NumBytes() || dontWait) {
// Complete write.
return int(n), nil
}
if err != nil && (err != tcpip.ErrWouldBlock || dontWait) {
return int(n), syserr.TranslateNetstackError(err)
}
// We'll have to block. Register for notification and keep trying to
// send all the data.
e, ch := waiter.NewChannelEntry(nil)
s.EventRegister(&e, waiter.EventOut)
defer s.EventUnregister(&e)
v.DropFirst(int(n))
total := n
r := src.Reader(t)
var (
total int64
entry waiter.Entry
ch <-chan struct{}
)
for {
n, err = s.Endpoint.Write(v, opts)
v.DropFirst(int(n))
n, err := s.Endpoint.Write(r, opts)
total += n
if err != nil && err != tcpip.ErrWouldBlock && total == 0 {
return 0, syserr.TranslateNetstackError(err)
if flags&linux.MSG_DONTWAIT != 0 {
return int(total), syserr.TranslateNetstackError(err)
}
if err == nil && v.src.NumBytes() == 0 || err != nil && err != tcpip.ErrWouldBlock {
return int(total), nil
}
if err := t.BlockWithDeadline(ch, haveDeadline, deadline); err != nil {
if err == syserror.ETIMEDOUT {
return int(total), syserr.ErrTryAgain
switch err {
case nil:
if total == src.NumBytes() {
break
}
// handleIOError will consume errors from t.Block if needed.
return int(total), syserr.FromError(err)
fallthrough
case tcpip.ErrWouldBlock:
if ch == nil {
// We'll have to block. Register for notification and keep trying to
// send all the data.
entry, ch = waiter.NewChannelEntry(nil)
s.EventRegister(&entry, waiter.EventOut)
defer s.EventUnregister(&entry)
} else {
// Don't wait immediately after registration in case more data
// became available between when we last checked and when we setup
// the notification.
if err := t.BlockWithDeadline(ch, haveDeadline, deadline); err != nil {
if err == syserror.ETIMEDOUT {
return int(total), syserr.ErrTryAgain
}
// handleIOError will consume errors from t.Block if needed.
return int(total), syserr.FromError(err)
}
}
continue
}
return int(total), syserr.TranslateNetstackError(err)
}
}
+5 -5
View File
@@ -128,8 +128,8 @@ func (s *SocketVFS2) Write(ctx context.Context, src usermem.IOSequence, opts vfs
return 0, syserror.EOPNOTSUPP
}
f := &ioSequencePayload{ctx: ctx, src: src}
n, err := s.Endpoint.Write(f, tcpip.WriteOptions{})
r := src.Reader(ctx)
n, err := s.Endpoint.Write(r, tcpip.WriteOptions{})
if err == tcpip.ErrWouldBlock {
return 0, syserror.ErrWouldBlock
}
@@ -137,11 +137,11 @@ func (s *SocketVFS2) Write(ctx context.Context, src usermem.IOSequence, opts vfs
return 0, syserr.TranslateNetstackError(err).ToError()
}
if int64(n) < src.NumBytes() {
return int64(n), syserror.ErrWouldBlock
if n < src.NumBytes() {
return n, syserror.ErrWouldBlock
}
return int64(n), nil
return n, nil
}
// Accept implements the linux syscall accept(2) for sockets backed by
+30 -35
View File
@@ -16,6 +16,7 @@
package gonet
import (
"bytes"
"context"
"errors"
"io"
@@ -354,8 +355,6 @@ func (c *TCPConn) Write(b []byte) (int, error) {
default:
}
v := buffer.NewViewFromBytes(b)
// We must handle two soft failure conditions simultaneously:
// 1. Write may write nothing and return tcpip.ErrWouldBlock.
// If this happens, we need to register for notifications if we have
@@ -368,22 +367,23 @@ func (c *TCPConn) Write(b []byte) (int, error) {
// There is no guarantee that all of the condition #1s will occur before
// all of the condition #2s or visa-versa.
var (
err *tcpip.Error
nbytes int
reg bool
notifyCh chan struct{}
r bytes.Reader
nbytes int
entry waiter.Entry
ch <-chan struct{}
)
for nbytes < len(b) && (err == tcpip.ErrWouldBlock || err == nil) {
if err == tcpip.ErrWouldBlock {
if !reg {
// Only register once.
reg = true
for nbytes != len(b) {
r.Reset(b[nbytes:])
n, err := c.ep.Write(&r, tcpip.WriteOptions{})
nbytes += int(n)
switch err {
case nil:
case tcpip.ErrWouldBlock:
if ch == nil {
entry, ch = waiter.NewChannelEntry(nil)
// Create wait queue entry that notifies a channel.
var waitEntry waiter.Entry
waitEntry, notifyCh = waiter.NewChannelEntry(nil)
c.wq.EventRegister(&waitEntry, waiter.EventOut)
defer c.wq.EventUnregister(&waitEntry)
c.wq.EventRegister(&entry, waiter.EventOut)
defer c.wq.EventUnregister(&entry)
} else {
// Don't wait immediately after registration in case more data
// became available between when we last checked and when we setup
@@ -391,22 +391,15 @@ func (c *TCPConn) Write(b []byte) (int, error) {
select {
case <-deadline:
return nbytes, c.newOpError("write", &timeoutError{})
case <-notifyCh:
case <-ch:
continue
}
}
default:
return nbytes, c.newOpError("write", errors.New(err.String()))
}
var n int64
n, err = c.ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{})
nbytes += int(n)
v.TrimFront(int(n))
}
if err == nil {
return nbytes, nil
}
return nbytes, c.newOpError("write", errors.New(err.String()))
return nbytes, nil
}
// Close implements net.Conn.Close.
@@ -644,16 +637,18 @@ func (c *UDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
}
// If we're being called by Write, there is no addr
wopts := tcpip.WriteOptions{}
writeOptions := tcpip.WriteOptions{}
if addr != nil {
ua := addr.(*net.UDPAddr)
wopts.To = &tcpip.FullAddress{Addr: tcpip.Address(ua.IP), Port: uint16(ua.Port)}
writeOptions.To = &tcpip.FullAddress{
Addr: tcpip.Address(ua.IP),
Port: uint16(ua.Port),
}
}
v := buffer.NewView(len(b))
copy(v, b)
n, err := c.ep.Write(tcpip.SlicePayload(v), wopts)
var r bytes.Reader
r.Reset(b)
n, err := c.ep.Write(&r, writeOptions)
if err == tcpip.ErrWouldBlock {
// Create wait queue entry that notifies a channel.
waitEntry, notifyCh := waiter.NewChannelEntry(nil)
@@ -666,7 +661,7 @@ func (c *UDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
case <-notifyCh:
}
n, err = c.ep.Write(tcpip.SlicePayload(v), wopts)
n, err = c.ep.Write(&r, writeOptions)
if err != tcpip.ErrWouldBlock {
break
}
+7 -3
View File
@@ -15,6 +15,7 @@
package ipv6
import (
"bytes"
"context"
"net"
"reflect"
@@ -638,7 +639,6 @@ func TestLinkResolution(t *testing.T) {
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6EchoMinimumSize))
pkt.SetType(header.ICMPv6EchoRequest)
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
payload := tcpip.SlicePayload(hdr.View())
// We can't send our payload directly over the route because that
// doesn't provoke NDP discovery.
@@ -648,8 +648,12 @@ func TestLinkResolution(t *testing.T) {
t.Fatalf("NewEndpoint(_) = (_, %s), want = (_, nil)", err)
}
if _, err := ep.Write(payload, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: nicID, Addr: lladdr1}}); err != nil {
t.Fatalf("ep.Write(_): %s", err)
{
var r bytes.Reader
r.Reset(hdr.View())
if _, err := ep.Write(&r, tcpip.WriteOptions{To: &tcpip.FullAddress{NIC: nicID, Addr: lladdr1}}); err != nil {
t.Fatalf("ep.Write(_): %s", err)
}
}
for _, args := range []routeArgs{
{src: c.linkEP0, dst: c.linkEP1, typ: header.ICMPv6NeighborSolicit, remoteLinkAddr: header.EthernetAddressFromMulticastIPv6Address(header.SolicitedNodeAddr(lladdr1))},
-1
View File
@@ -8,7 +8,6 @@ go_binary(
visibility = ["//:sandbox"],
deps = [
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/header",
"//pkg/tcpip/link/fdbased",
"//pkg/tcpip/link/rawfile",
+13 -17
View File
@@ -41,7 +41,7 @@
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"math/rand"
@@ -51,7 +51,6 @@ import (
"time"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
@@ -71,24 +70,21 @@ func writer(ch chan struct{}, ep tcpip.Endpoint) {
close(ch)
}()
r := bufio.NewReader(os.Stdin)
for {
v := buffer.NewView(1024)
n, err := r.Read(v)
if err != nil {
return
}
v.CapLength(n)
for len(v) > 0 {
n, err := ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{})
if err != nil {
fmt.Println("Write failed:", err)
return
var b bytes.Buffer
if err := func() error {
for {
if _, err := b.ReadFrom(os.Stdin); err != nil {
return fmt.Errorf("b.ReadFrom failed: %w", err)
}
v.TrimFront(int(n))
for b.Len() != 0 {
if _, err := ep.Write(&b, tcpip.WriteOptions{Atomic: true}); err != nil {
return fmt.Errorf("ep.Write failed: %s", err)
}
}
}
}(); err != nil {
fmt.Println(err)
}
}
+4 -1
View File
@@ -20,6 +20,7 @@
package main
import (
"bytes"
"flag"
"io"
"log"
@@ -58,7 +59,9 @@ func (e *tcpipError) Error() string {
}
func (e *endpointWriter) Write(p []byte) (int, error) {
n, err := e.ep.Write(tcpip.SlicePayload(p), tcpip.WriteOptions{})
var r bytes.Reader
r.Reset(p)
n, err := e.ep.Write(&r, tcpip.WriteOptions{})
if err != nil {
return int(n), &tcpipError{
inner: err,
+9 -5
View File
@@ -15,6 +15,7 @@
package stack_test
import (
"bytes"
"io"
"testing"
@@ -95,10 +96,11 @@ func (f *fakeTransportEndpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions
return 0, tcpip.ErrNoRoute
}
v, err := p.FullPayload()
if err != nil {
return 0, err
v := make([]byte, p.Len())
if _, err := io.ReadFull(p, v); err != nil {
return 0, tcpip.ErrBadBuffer
}
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(f.route.MaxHeaderLength()) + fakeTransHeaderLen,
Data: buffer.View(v).ToVectorisedView(),
@@ -520,8 +522,10 @@ func TestTransportSend(t *testing.T) {
}
// Create buffer that will hold the payload.
view := buffer.NewView(30)
if _, err := ep.Write(tcpip.SlicePayload(view), tcpip.WriteOptions{}); err != nil {
b := make([]byte, 30)
var r bytes.Reader
r.Reset(b)
if _, err := ep.Write(&r, tcpip.WriteOptions{}); err != nil {
t.Fatalf("write failed: %v", err)
}
+7 -21
View File
@@ -29,6 +29,7 @@
package tcpip
import (
"bytes"
"errors"
"fmt"
"io"
@@ -471,30 +472,15 @@ type FullAddress struct {
// This interface allows the endpoint to request the amount of data it needs
// based on internal buffers without exposing them.
type Payloader interface {
// FullPayload returns all available bytes.
FullPayload() ([]byte, *Error)
io.Reader
// Payload returns a slice containing at most size bytes.
Payload(size int) ([]byte, *Error)
// Len returns the number of bytes of the unread portion of the
// Reader.
Len() int
}
// SlicePayload implements Payloader for slices.
//
// This is typically used for tests.
type SlicePayload []byte
// FullPayload implements Payloader.FullPayload.
func (s SlicePayload) FullPayload() ([]byte, *Error) {
return s, nil
}
// Payload implements Payloader.Payload.
func (s SlicePayload) Payload(size int) ([]byte, *Error) {
if size > len(s) {
size = len(s)
}
return s[:size], nil
}
var _ Payloader = (*bytes.Buffer)(nil)
var _ Payloader = (*bytes.Reader)(nil)
var _ io.Writer = (*SliceWriter)(nil)
+4 -3
View File
@@ -436,9 +436,10 @@ func TestForwarding(t *testing.T) {
write := func(ep tcpip.Endpoint, data []byte) {
t.Helper()
dataPayload := tcpip.SlicePayload(data)
var r bytes.Reader
r.Reset(data)
var wOpts tcpip.WriteOptions
n, err := ep.Write(dataPayload, wOpts)
n, err := ep.Write(&r, wOpts)
if err != nil {
t.Fatalf("ep.Write(_, %#v): %s", wOpts, err)
}
@@ -486,7 +487,7 @@ func TestForwarding(t *testing.T) {
read(serverCH, serverEP, data, clientAddr)
data = tcpip.SlicePayload([]byte{5, 6, 7, 8, 9, 10, 11, 12})
data = []byte{5, 6, 7, 8, 9, 10, 11, 12}
write(serverEP, data)
read(epsAndAddrs.clientReadableCH, epsAndAddrs.clientEP, data, serverAddr)
})
@@ -209,8 +209,10 @@ func TestPing(t *testing.T) {
defer ep.Close()
icmpBuf := test.icmpBuf(t)
var r bytes.Reader
r.Reset(icmpBuf)
wOpts := tcpip.WriteOptions{To: &tcpip.FullAddress{Addr: test.remoteAddr}}
if n, err := ep.Write(tcpip.SlicePayload(icmpBuf), wOpts); err != nil {
if n, err := ep.Write(&r, wOpts); err != nil {
t.Fatalf("ep.Write(_, _): %s", err)
} else if want := int64(len(icmpBuf)); n != want {
t.Fatalf("got ep.Write(_, _) = (%d, _), want = (%d, _)", n, want)
@@ -360,9 +362,11 @@ func TestTCPLinkResolutionFailure(t *testing.T) {
// Wait for an error due to link resolution failing, or the endpoint to be
// writable.
<-ch
var r bytes.Reader
r.Reset([]byte{0})
var wOpts tcpip.WriteOptions
if n, err := clientEP.Write(tcpip.SlicePayload(nil), wOpts); err != test.expectedWriteErr {
t.Errorf("got clientEP.Write(nil, %#v) = (%d, %s), want = (_, %s)", wOpts, n, err, test.expectedWriteErr)
if n, err := clientEP.Write(&r, wOpts); err != test.expectedWriteErr {
t.Errorf("got clientEP.Write(_, %#v) = (%d, %s), want = (_, %s)", wOpts, n, err, test.expectedWriteErr)
}
if test.expectedWriteErr == nil {
+3 -1
View File
@@ -232,7 +232,9 @@ func TestLoopbackAcceptAllInSubnetUDP(t *testing.T) {
Port: localPort,
},
}
n, err := sep.Write(tcpip.SlicePayload(data), wopts)
var r bytes.Reader
r.Reset(data)
n, err := sep.Write(&r, wopts)
if err != nil {
t.Fatalf("sep.Write(_, _): %s", err)
}
@@ -586,8 +586,10 @@ func TestReuseAddrAndBroadcast(t *testing.T) {
Port: localPort,
},
}
data := tcpip.SlicePayload([]byte{byte(i), 2, 3, 4})
if n, err := wep.ep.Write(data, writeOpts); err != nil {
data := []byte{byte(i), 2, 3, 4}
var r bytes.Reader
r.Reset(data)
if n, err := wep.ep.Write(&r, writeOpts); err != nil {
t.Fatalf("eps[%d].Write(_, _): %s", i, err)
} else if want := int64(len(data)); n != want {
t.Fatalf("got eps[%d].Write(_, _) = (%d, nil), want = (%d, nil)", i, n, want)
+12 -6
View File
@@ -194,9 +194,11 @@ func TestLocalPing(t *testing.T) {
return
}
payload := tcpip.SlicePayload(test.icmpBuf(t))
payload := test.icmpBuf(t)
var r bytes.Reader
r.Reset(payload)
var wOpts tcpip.WriteOptions
if n, err := ep.Write(payload, wOpts); err != nil {
if n, err := ep.Write(&r, wOpts); err != nil {
t.Fatalf("ep.Write(%#v, %#v): %s", payload, wOpts, err)
} else if n != int64(len(payload)) {
t.Fatalf("got ep.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", payload, wOpts, n, len(payload))
@@ -329,12 +331,14 @@ func TestLocalUDP(t *testing.T) {
Port: 80,
}
clientPayload := tcpip.SlicePayload([]byte{1, 2, 3, 4})
clientPayload := []byte{1, 2, 3, 4}
{
var r bytes.Reader
r.Reset(clientPayload)
wOpts := tcpip.WriteOptions{
To: &serverAddr,
}
if n, err := client.Write(clientPayload, wOpts); err != subTest.expectedWriteErr {
if n, err := client.Write(&r, wOpts); err != subTest.expectedWriteErr {
t.Fatalf("got client.Write(%#v, %#v) = (%d, %s), want = (_, %s)", clientPayload, wOpts, n, err, subTest.expectedWriteErr)
} else if subTest.expectedWriteErr != nil {
// Nothing else to test if we expected not to be able to send the
@@ -376,12 +380,14 @@ func TestLocalUDP(t *testing.T) {
}
}
serverPayload := tcpip.SlicePayload([]byte{1, 2, 3, 4})
serverPayload := []byte{1, 2, 3, 4}
{
var r bytes.Reader
r.Reset(serverPayload)
wOpts := tcpip.WriteOptions{
To: &clientAddr,
}
if n, err := server.Write(serverPayload, wOpts); err != nil {
if n, err := server.Write(&r, wOpts); err != nil {
t.Fatalf("server.Write(%#v, %#v): %s", serverPayload, wOpts, err)
} else if n != int64(len(serverPayload)) {
t.Fatalf("got server.Write(%#v, %#v) = (%d, nil), want = (%d, nil)", serverPayload, wOpts, n, len(serverPayload))
+4 -3
View File
@@ -313,11 +313,12 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tc
route = r
}
v, err := p.FullPayload()
if err != nil {
return 0, err
v := make([]byte, p.Len())
if _, err := io.ReadFull(p, v); err != nil {
return 0, tcpip.ErrBadBuffer
}
var err *tcpip.Error
switch e.NetProto {
case header.IPv4ProtocolNumber:
err = send4(route, e.ID.LocalPort, v, e.ttl, e.owner)
+1 -1
View File
@@ -207,7 +207,7 @@ func (ep *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResul
return res, nil
}
func (*endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tcpip.Error) {
func (*endpoint) Write(tcpip.Payloader, tcpip.WriteOptions) (int64, *tcpip.Error) {
// TODO(gvisor.dev/issue/173): Implement.
return 0, tcpip.ErrInvalidOptionValue
}
+3 -3
View File
@@ -280,9 +280,9 @@ func (e *endpoint) write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, *tc
return 0, tcpip.ErrInvalidEndpointState
}
payloadBytes, err := p.FullPayload()
if err != nil {
return 0, err
payloadBytes := make([]byte, p.Len())
if _, err := io.ReadFull(p, payloadBytes); err != nil {
return 0, tcpip.ErrBadBuffer
}
// If this is an unassociated socket and callee provided a nonzero
-1
View File
@@ -99,7 +99,6 @@ go_test(
"//pkg/rand",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/checker",
"//pkg/tcpip/header",
"//pkg/tcpip/link/loopback",

Some files were not shown because too many files have changed in this diff Show More