github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/socket/unix/io.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package unix
    16  
    17  import (
    18  	"github.com/SagerNet/gvisor/pkg/context"
    19  	"github.com/SagerNet/gvisor/pkg/safemem"
    20  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport"
    21  	"github.com/SagerNet/gvisor/pkg/tcpip"
    22  )
    23  
    24  // EndpointWriter implements safemem.Writer that writes to a transport.Endpoint.
    25  //
    26  // EndpointWriter is not thread-safe.
    27  type EndpointWriter struct {
    28  	Ctx context.Context
    29  
    30  	// Endpoint is the transport.Endpoint to write to.
    31  	Endpoint transport.Endpoint
    32  
    33  	// Control is the control messages to send.
    34  	Control transport.ControlMessages
    35  
    36  	// To is the endpoint to send to. May be nil.
    37  	To transport.BoundEndpoint
    38  }
    39  
    40  // WriteFromBlocks implements safemem.Writer.WriteFromBlocks.
    41  func (w *EndpointWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
    42  	return safemem.FromVecWriterFunc{func(bufs [][]byte) (int64, error) {
    43  		n, err := w.Endpoint.SendMsg(w.Ctx, bufs, w.Control, w.To)
    44  		if err != nil {
    45  			return int64(n), err.ToError()
    46  		}
    47  		return int64(n), nil
    48  	}}.WriteFromBlocks(srcs)
    49  }
    50  
    51  // EndpointReader implements safemem.Reader that reads from a
    52  // transport.Endpoint.
    53  //
    54  // EndpointReader is not thread-safe.
    55  type EndpointReader struct {
    56  	Ctx context.Context
    57  
    58  	// Endpoint is the transport.Endpoint to read from.
    59  	Endpoint transport.Endpoint
    60  
    61  	// Creds indicates if credential control messages are requested.
    62  	Creds bool
    63  
    64  	// NumRights is the number of SCM_RIGHTS FDs requested.
    65  	NumRights int
    66  
    67  	// Peek indicates that the data should not be consumed from the
    68  	// endpoint.
    69  	Peek bool
    70  
    71  	// MsgSize is the size of the message that was read from. For stream
    72  	// sockets, it is the amount read.
    73  	MsgSize int64
    74  
    75  	// From, if not nil, will be set with the address read from.
    76  	From *tcpip.FullAddress
    77  
    78  	// Control contains the received control messages.
    79  	Control transport.ControlMessages
    80  
    81  	// ControlTrunc indicates that SCM_RIGHTS FDs were discarded based on
    82  	// the value of NumRights.
    83  	ControlTrunc bool
    84  }
    85  
    86  // Truncate calls RecvMsg on the endpoint without writing to a destination.
    87  func (r *EndpointReader) Truncate() error {
    88  	// Ignore bytes read since it will always be zero.
    89  	_, ms, c, ct, err := r.Endpoint.RecvMsg(r.Ctx, [][]byte{}, r.Creds, r.NumRights, r.Peek, r.From)
    90  	r.Control = c
    91  	r.ControlTrunc = ct
    92  	r.MsgSize = ms
    93  	if err != nil {
    94  		return err.ToError()
    95  	}
    96  	return nil
    97  }
    98  
    99  // ReadToBlocks implements safemem.Reader.ReadToBlocks.
   100  func (r *EndpointReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
   101  	return safemem.FromVecReaderFunc{func(bufs [][]byte) (int64, error) {
   102  		n, ms, c, ct, err := r.Endpoint.RecvMsg(r.Ctx, bufs, r.Creds, r.NumRights, r.Peek, r.From)
   103  		r.Control = c
   104  		r.ControlTrunc = ct
   105  		r.MsgSize = ms
   106  		if err != nil {
   107  			return int64(n), err.ToError()
   108  		}
   109  		return int64(n), nil
   110  	}}.ReadToBlocks(dsts)
   111  }