// 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 }