gvisor/pkg/flipcall/io.go

114 lines
3.2 KiB
Go

// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flipcall
import (
"fmt"
"io"
)
// DatagramReader implements io.Reader by reading a datagram from an Endpoint's
// packet window. Its use is optional; users that can use Endpoint.Data() more
// efficiently are advised to do so.
type DatagramReader struct {
ep *Endpoint
off uint32
end uint32
}
// Init must be called on zero-value DatagramReaders before first use.
//
// Preconditions: dataLen is 0, or was returned by a previous call to
// ep.RecvFirst() or ep.SendRecv().
func (r *DatagramReader) Init(ep *Endpoint, dataLen uint32) {
r.ep = ep
r.Reset(dataLen)
}
// Reset causes r to begin reading a new datagram of the given length from the
// associated Endpoint.
//
// Preconditions: dataLen is 0, or was returned by a previous call to the
// associated Endpoint's RecvFirst() or SendRecv() methods.
func (r *DatagramReader) Reset(dataLen uint32) {
if dataLen > r.ep.dataCap {
panic(fmt.Sprintf("invalid dataLen (%d) > ep.dataCap (%d)", dataLen, r.ep.dataCap))
}
r.off = 0
r.end = dataLen
}
// NewReader is a convenience function that returns an initialized
// DatagramReader allocated on the heap.
//
// Preconditions: dataLen was returned by a previous call to ep.RecvFirst() or
// ep.SendRecv().
func (ep *Endpoint) NewReader(dataLen uint32) *DatagramReader {
r := &DatagramReader{}
r.Init(ep, dataLen)
return r
}
// Read implements io.Reader.Read.
func (r *DatagramReader) Read(dst []byte) (int, error) {
n := copy(dst, r.ep.Data()[r.off:r.end])
r.off += uint32(n)
if r.off == r.end {
return n, io.EOF
}
return n, nil
}
// DatagramWriter implements io.Writer by writing a datagram to an Endpoint's
// packet window. Its use is optional; users that can use Endpoint.Data() more
// efficiently are advised to do so.
type DatagramWriter struct {
ep *Endpoint
off uint32
}
// Init must be called on zero-value DatagramWriters before first use.
func (w *DatagramWriter) Init(ep *Endpoint) {
w.ep = ep
}
// Reset causes w to begin writing a new datagram to the associated Endpoint.
func (w *DatagramWriter) Reset() {
w.off = 0
}
// NewWriter is a convenience function that returns an initialized
// DatagramWriter allocated on the heap.
func (ep *Endpoint) NewWriter() *DatagramWriter {
w := &DatagramWriter{}
w.Init(ep)
return w
}
// Write implements io.Writer.Write.
func (w *DatagramWriter) Write(src []byte) (int, error) {
n := copy(w.ep.Data()[w.off:w.ep.dataCap], src)
w.off += uint32(n)
if n != len(src) {
return n, fmt.Errorf("datagram would exceed maximum size of %d bytes", w.ep.dataCap)
}
return n, nil
}
// Len returns the length of the written datagram.
func (w *DatagramWriter) Len() uint32 {
return w.off
}