mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
111 lines
3.0 KiB
Go
111 lines
3.0 KiB
Go
// Copyright 2023 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 stack
|
|
|
|
import (
|
|
"sync"
|
|
"syscall"
|
|
|
|
"gvisor.dev/gvisor/pkg/abi/linux"
|
|
"gvisor.dev/gvisor/pkg/safemem"
|
|
"gvisor.dev/gvisor/pkg/sentry/socket/plugin/cgo"
|
|
)
|
|
|
|
type pluginStackRW struct {
|
|
handle uint32
|
|
|
|
// Represent both input and output flags.
|
|
flags uint32
|
|
|
|
// Reused as msg_control for read.
|
|
to []byte
|
|
|
|
iovs [3]syscall.Iovec
|
|
}
|
|
|
|
var pluginStackRWPool = sync.Pool{
|
|
New: func() any {
|
|
return &pluginStackRW{}
|
|
},
|
|
}
|
|
|
|
func getReadWriter(handle uint32) *pluginStackRW {
|
|
rw := pluginStackRWPool.Get().(*pluginStackRW)
|
|
rw.handle = handle
|
|
return rw
|
|
}
|
|
|
|
func putReadWriter(rw *pluginStackRW) {
|
|
*rw = pluginStackRW{}
|
|
pluginStackRWPool.Put(rw)
|
|
}
|
|
|
|
// ReadToBlocks implements safemem.Reader.ReadToBlocks.
|
|
func (rw *pluginStackRW) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
|
|
// Set MSG_DONTWAIT flag to avoid blocking in plugin stack.
|
|
flags := int(rw.flags) & ^linux.MSG_DONTWAIT
|
|
if len(rw.to) != 0 || flags != 0 {
|
|
iovs := iovecsFromBlockSeq(dsts, rw)
|
|
rc, _, lc, mflags := cgo.Recvmsg(rw.handle, iovs, nil, rw.to, int(rw.flags))
|
|
if rc >= 0 {
|
|
rw.to = rw.to[:lc]
|
|
rw.flags = uint32(mflags)
|
|
}
|
|
return translateReturn(rc)
|
|
}
|
|
|
|
var rc int64
|
|
if dsts.IsEmpty() {
|
|
rc = 0
|
|
} else if dsts.NumBlocks() == 1 {
|
|
rc = cgo.Read(rw.handle, dsts.Head().Addr(), dsts.Head().Len())
|
|
} else {
|
|
rc = cgo.Readv(rw.handle, iovecsFromBlockSeq(dsts, rw))
|
|
}
|
|
|
|
return translateReturn(rc)
|
|
}
|
|
|
|
// WriteFromBlocks implements safemem.Writer.WriteFromBlocks.
|
|
//
|
|
// Preconditions: rw.d.metadataMu must be locked.
|
|
func (rw *pluginStackRW) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) {
|
|
var rc int64
|
|
|
|
if rw.to != nil {
|
|
if srcs.IsEmpty() {
|
|
// Invoke plugin stack checking whether there is any error to report
|
|
// on target socket which sends 0-length data.
|
|
rc = cgo.Sendto(rw.handle, 0, 0, 0, rw.to)
|
|
} else if srcs.NumBlocks() == 1 {
|
|
rc = cgo.Sendto(rw.handle, srcs.Head().Addr(), srcs.Head().Len(), 0, rw.to)
|
|
} else {
|
|
iovs := iovecsFromBlockSeq(srcs, rw)
|
|
rc = cgo.Sendmsg(rw.handle, iovs, rw.to, 0)
|
|
}
|
|
} else {
|
|
if srcs.IsEmpty() {
|
|
// Invoke plugin stack checking whether there is any error to report
|
|
// on target socket which sends 0-length data.
|
|
rc = cgo.Write(rw.handle, 0, 0)
|
|
} else if srcs.NumBlocks() == 1 {
|
|
rc = cgo.Write(rw.handle, srcs.Head().Addr(), srcs.Head().Len())
|
|
} else {
|
|
rc = cgo.Writev(rw.handle, iovecsFromBlockSeq(srcs, rw))
|
|
}
|
|
}
|
|
return translateReturn(rc)
|
|
}
|