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// +build dragonfly freebsd 6 7package net 8 9import ( 10 "internal/poll" 11 "io" 12 "os" 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 of bytes copied and any 19// non-EOF error. 20// 21// if handled == false, sendFile performed no work. 22func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { 23 // FreeBSD and DragonFly use 0 as the "until EOF" value. 24 // If you pass in more bytes than the file contains, it will 25 // loop back to the beginning ad nauseam until it's sent 26 // exactly the number of bytes told to. As such, we need to 27 // know exactly how many bytes to send. 28 var remain int64 = 0 29 30 lr, ok := r.(*io.LimitedReader) 31 if ok { 32 remain, r = lr.N, lr.R 33 if remain <= 0 { 34 return 0, nil, true 35 } 36 } 37 f, ok := r.(*os.File) 38 if !ok { 39 return 0, nil, false 40 } 41 42 if remain == 0 { 43 fi, err := f.Stat() 44 if err != nil { 45 return 0, err, false 46 } 47 48 remain = fi.Size() 49 } 50 51 // The other quirk with FreeBSD/DragonFly's sendfile 52 // implementation is that it doesn't use the current position 53 // of the file -- if you pass it offset 0, it starts from 54 // offset 0. There's no way to tell it "start from current 55 // position", so we have to manage that explicitly. 56 pos, err := f.Seek(0, io.SeekCurrent) 57 if err != nil { 58 return 0, err, false 59 } 60 61 written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain) 62 63 if lr != nil { 64 lr.N = remain - written 65 } 66 return written, wrapSyscallError("sendfile", err), written > 0 67} 68