gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/lisafs/communicator.go (about)

     1  // Copyright 2021 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 lisafs
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"golang.org/x/sys/unix"
    21  	"gvisor.dev/gvisor/pkg/log"
    22  )
    23  
    24  // Communicator is a server side utility which represents exactly how the
    25  // server is communicating with the client.
    26  type Communicator interface {
    27  	fmt.Stringer
    28  
    29  	// PayloadBuf returns a slice to the payload section of its internal buffer
    30  	// where the message can be marshalled. The handlers should use this to
    31  	// populate the payload buffer with the message.
    32  	//
    33  	// The payload buffer contents *should* be preserved across calls with
    34  	// different sizes. Note that this is not a guarantee, because a compromised
    35  	// owner of a "shared" payload buffer can tamper with its contents anytime,
    36  	// even when it's not its turn to do so.
    37  	PayloadBuf(size uint32) []byte
    38  
    39  	// SndRcvMessage sends message m. The caller must have populated PayloadBuf()
    40  	// with payloadLen bytes. The caller expects to receive wantFDs FDs.
    41  	// Any received FDs must be accessible via ReleaseFDs(). It returns the
    42  	// response message along with the response payload length.
    43  	SndRcvMessage(m MID, payloadLen uint32, wantFDs uint8) (MID, uint32, error)
    44  
    45  	// DonateFD attempts to make fd non-blocking and starts tracking it. The next
    46  	// call to ReleaseFDs will include fd in the order it was added. Communicator
    47  	// takes ownership of fd. Server side should call this.
    48  	DonateFD(fd int)
    49  
    50  	// Track starts tracking fd. The next call to ReleaseFDs will include fd in
    51  	// the order it was added. Communicator takes ownership of fd. Client side
    52  	// should use this for accumulating received FDs.
    53  	TrackFD(fd int)
    54  
    55  	// ReleaseFDs returns the accumulated FDs and stops tracking them. The
    56  	// ownership of the FDs is transferred to the caller.
    57  	ReleaseFDs() []int
    58  }
    59  
    60  // fdTracker is a partial implementation of Communicator. It can be embedded in
    61  // Communicator implementations to keep track of FD donations.
    62  type fdTracker struct {
    63  	fds []int
    64  }
    65  
    66  // DonateFD implements Communicator.DonateFD.
    67  func (d *fdTracker) DonateFD(fd int) {
    68  	// Try to make the FD non-blocking.
    69  	if err := unix.SetNonblock(fd, true); err != nil && err != unix.EBADF {
    70  		// This may fail if fd was opened with O_PATH, because fcntl(F_SETFL) fails
    71  		// with EBADF on O_PATH FDs.
    72  		log.Warningf("DonateFD: unix.SetNonblock() failed on FD %d: %v", fd, err)
    73  	}
    74  	d.TrackFD(fd)
    75  }
    76  
    77  // TrackFD implements Communicator.TrackFD.
    78  func (d *fdTracker) TrackFD(fd int) {
    79  	d.fds = append(d.fds, fd)
    80  }
    81  
    82  // ReleaseFDs implements Communicator.ReleaseFDs.
    83  func (d *fdTracker) ReleaseFDs() []int {
    84  	ret := d.fds
    85  	d.fds = d.fds[:0]
    86  	return ret
    87  }