sendfile.mx raw

   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