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 }