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