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