Brad Fitzpatrick | 5194744 | 2016-03-01 22:57:46 +0000 | [diff] [blame] | 1 | // Copyright 2011 The Go Authors. All rights reserved. |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
Ian Lance Taylor | 27520cc | 2017-02-08 15:03:56 -0800 | [diff] [blame] | 5 | // +build dragonfly freebsd |
| 6 | |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 7 | package net |
| 8 | |
| 9 | import ( |
Ian Lance Taylor | 3792db5 | 2017-02-10 14:59:38 -0800 | [diff] [blame] | 10 | "internal/poll" |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 11 | "io" |
| 12 | "os" |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 13 | ) |
| 14 | |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 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. |
| 22 | func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { |
Ian Lance Taylor | 27520cc | 2017-02-08 15:03:56 -0800 | [diff] [blame] | 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. |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 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 | |
Ian Lance Taylor | 27520cc | 2017-02-08 15:03:56 -0800 | [diff] [blame] | 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. |
Brad Fitzpatrick | 381e5ee | 2016-04-13 04:35:37 +0000 | [diff] [blame] | 56 | pos, err := f.Seek(0, io.SeekCurrent) |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 57 | if err != nil { |
| 58 | return 0, err, false |
| 59 | } |
| 60 | |
Ian Lance Taylor | 3792db5 | 2017-02-10 14:59:38 -0800 | [diff] [blame] | 61 | written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain) |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 62 | |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 63 | if lr != nil { |
Ian Lance Taylor | 3792db5 | 2017-02-10 14:59:38 -0800 | [diff] [blame] | 64 | lr.N = remain - written |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 65 | } |
Ian Lance Taylor | 3792db5 | 2017-02-10 14:59:38 -0800 | [diff] [blame] | 66 | return written, wrapSyscallError("sendfile", err), written > 0 |
L Campbell | a9a8d7b | 2012-06-25 20:26:19 -0400 | [diff] [blame] | 67 | } |