1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 //go:build linux || (darwin && !ios) || dragonfly || freebsd || solaris || windows
6 7 package net
8 9 import (
10 "internal/poll"
11 "io"
12 "syscall"
13 )
14 15 // sendFile copies the contents of r to c using the sendfile
16 // system call to minimize copies.
17 //
18 // if handled == true, sendFile returns the number (potentially zero) of bytes
19 // copied and any non-EOF error.
20 //
21 // if handled == false, sendFile performed no work.
22 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
23 if !supportsSendfile() {
24 return 0, nil, false
25 }
26 var remain int64 = 0 // 0 writes the entire file
27 lr, ok := r.(*io.LimitedReader)
28 if ok {
29 remain, r = lr.N, lr.R
30 if remain <= 0 {
31 return 0, nil, true
32 }
33 }
34 // r might be an *os.File or an os.fileWithoutWriteTo.
35 // Type assert to an interface rather than *os.File directly to handle the latter case.
36 f, ok := r.(syscall.Conn)
37 if !ok {
38 return 0, nil, false
39 }
40 41 sc, err := f.SyscallConn()
42 if err != nil {
43 return 0, nil, false
44 }
45 46 var werr error
47 err = sc.Read(func(fd uintptr) bool {
48 written, werr, handled = poll.SendFile(&c.pfd, fd, remain)
49 return true
50 })
51 if err == nil {
52 err = werr
53 }
54 55 if lr != nil {
56 lr.N = remain - written
57 }
58 59 return written, wrapSyscallError("sendfile", err), handled
60 }
61