...

Source file src/net/sendfile_unix_alt.go

     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 solaris
     6	
     7	package net
     8	
     9	import (
    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.
    22	func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
    23		// FreeBSD, DragonFly and Solaris 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/Solaris'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		sc, err := f.SyscallConn()
    62		if err != nil {
    63			return 0, nil, false
    64		}
    65	
    66		var werr error
    67		err = sc.Read(func(fd uintptr) bool {
    68			written, werr = poll.SendFile(&c.pfd, int(fd), pos, remain)
    69			return true
    70		})
    71		if err == nil {
    72			err = werr
    73		}
    74	
    75		if lr != nil {
    76			lr.N = remain - written
    77		}
    78	
    79		_, err1 := f.Seek(written, io.SeekCurrent)
    80		if err1 != nil && err == nil {
    81			return written, err1, written > 0
    82		}
    83	
    84		return written, wrapSyscallError("sendfile", err), written > 0
    85	}
    86	

View as plain text