github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/host/socket_iovec.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 "golang.org/x/sys/unix" 19 "github.com/SagerNet/gvisor/pkg/errors/linuxerr" 20 "github.com/SagerNet/gvisor/pkg/sentry/hostfd" 21 ) 22 23 // LINT.IfChange 24 25 // copyToMulti copies as many bytes from src to dst as possible. 26 func copyToMulti(dst [][]byte, src []byte) { 27 for _, d := range dst { 28 done := copy(d, src) 29 src = src[done:] 30 if len(src) == 0 { 31 break 32 } 33 } 34 } 35 36 // copyFromMulti copies as many bytes from src to dst as possible. 37 func copyFromMulti(dst []byte, src [][]byte) { 38 for _, s := range src { 39 done := copy(dst, s) 40 dst = dst[done:] 41 if len(dst) == 0 { 42 break 43 } 44 } 45 } 46 47 // buildIovec builds an iovec slice from the given []byte slice. 48 // 49 // If truncate, truncate bufs > maxlen. Otherwise, immediately return an error. 50 // 51 // If length < the total length of bufs, err indicates why, even when returning 52 // a truncated iovec. 53 // 54 // If intermediate != nil, iovecs references intermediate rather than bufs and 55 // the caller must copy to/from bufs as necessary. 56 func buildIovec(bufs [][]byte, maxlen int64, truncate bool) (length int64, iovecs []unix.Iovec, intermediate []byte, err error) { 57 var iovsRequired int 58 for _, b := range bufs { 59 length += int64(len(b)) 60 if len(b) > 0 { 61 iovsRequired++ 62 } 63 } 64 65 stopLen := length 66 if length > maxlen { 67 if truncate { 68 stopLen = maxlen 69 err = linuxerr.EAGAIN 70 } else { 71 return 0, nil, nil, linuxerr.EMSGSIZE 72 } 73 } 74 75 if iovsRequired > hostfd.MaxSendRecvMsgIov { 76 // The kernel will reject our call if we pass this many iovs. 77 // Use a single intermediate buffer instead. 78 b := make([]byte, stopLen) 79 80 return stopLen, []unix.Iovec{{ 81 Base: &b[0], 82 Len: uint64(stopLen), 83 }}, b, err 84 } 85 86 var total int64 87 iovecs = make([]unix.Iovec, 0, iovsRequired) 88 for i := range bufs { 89 l := len(bufs[i]) 90 if l == 0 { 91 continue 92 } 93 94 stop := int64(l) 95 if total+stop > stopLen { 96 stop = stopLen - total 97 } 98 99 iovecs = append(iovecs, unix.Iovec{ 100 Base: &bufs[i][0], 101 Len: uint64(stop), 102 }) 103 104 total += stop 105 if total >= stopLen { 106 break 107 } 108 } 109 110 return total, iovecs, nil, err 111 } 112 113 // LINT.ThenChange(../../fsimpl/host/socket_iovec.go)