github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/host/socket_unsafe.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 host 16 17 import ( 18 "unsafe" 19 20 "golang.org/x/sys/unix" 21 ) 22 23 // LINT.IfChange 24 25 // fdReadVec receives from fd to bufs. 26 // 27 // If the total length of bufs is > maxlen, fdReadVec will do a partial read 28 // and err will indicate why the message was truncated. 29 func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int64) (readLen int64, msgLen int64, controlLen uint64, controlTrunc bool, err error) { 30 flags := uintptr(unix.MSG_DONTWAIT | unix.MSG_TRUNC) 31 if peek { 32 flags |= unix.MSG_PEEK 33 } 34 35 // Always truncate the receive buffer. All socket types will truncate 36 // received messages. 37 length, iovecs, intermediate, err := buildIovec(bufs, maxlen, true) 38 if err != nil && len(iovecs) == 0 { 39 // No partial write to do, return error immediately. 40 return 0, 0, 0, false, err 41 } 42 43 var msg unix.Msghdr 44 if len(control) != 0 { 45 msg.Control = &control[0] 46 msg.Controllen = uint64(len(control)) 47 } 48 49 if len(iovecs) != 0 { 50 msg.Iov = &iovecs[0] 51 msg.Iovlen = uint64(len(iovecs)) 52 } 53 54 rawN, _, e := unix.RawSyscall(unix.SYS_RECVMSG, uintptr(fd), uintptr(unsafe.Pointer(&msg)), flags) 55 if e != 0 { 56 // N.B. prioritize the syscall error over the buildIovec error. 57 return 0, 0, 0, false, e 58 } 59 n := int64(rawN) 60 61 // Copy data back to bufs. 62 if intermediate != nil { 63 copyToMulti(bufs, intermediate) 64 } 65 66 controlTrunc = msg.Flags&unix.MSG_CTRUNC == unix.MSG_CTRUNC 67 68 if n > length { 69 return length, n, msg.Controllen, controlTrunc, nil 70 } 71 72 return n, n, msg.Controllen, controlTrunc, nil 73 } 74 75 // fdWriteVec sends from bufs to fd. 76 // 77 // If the total length of bufs is > maxlen && truncate, fdWriteVec will do a 78 // partial write and err will indicate why the message was truncated. 79 func fdWriteVec(fd int, bufs [][]byte, maxlen int64, truncate bool) (int64, int64, error) { 80 length, iovecs, intermediate, err := buildIovec(bufs, maxlen, truncate) 81 if err != nil && len(iovecs) == 0 { 82 // No partial write to do, return error immediately. 83 return 0, length, err 84 } 85 86 // Copy data to intermediate buf. 87 if intermediate != nil { 88 copyFromMulti(intermediate, bufs) 89 } 90 91 var msg unix.Msghdr 92 if len(iovecs) > 0 { 93 msg.Iov = &iovecs[0] 94 msg.Iovlen = uint64(len(iovecs)) 95 } 96 97 n, _, e := unix.RawSyscall(unix.SYS_SENDMSG, uintptr(fd), uintptr(unsafe.Pointer(&msg)), unix.MSG_DONTWAIT|unix.MSG_NOSIGNAL) 98 if e != 0 { 99 // N.B. prioritize the syscall error over the buildIovec error. 100 return 0, length, e 101 } 102 103 return int64(n), length, err 104 } 105 106 // LINT.ThenChange(../../fsimpl/host/socket_unsafe.go)