func sendfile(c *net.TCPConn, f *os.File, fi os.FileInfo) { sockFile, err := c.File() if err != nil { fmt.Fprint(c, Error(fmt.Sprintf("couldn't get file sock: %x", err))) } syscall.Sendfile(int(sockFile.Fd()), int(f.Fd()), nil, int(fi.Size())) }
// sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // // if handled == true, sendFile returns the number of bytes copied and any // non-EOF error. // // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { var remain int64 = 1 << 62 // by default, copy until EOF lr, ok := r.(*io.LimitedReader) if ok { remain, r = lr.N, lr.R if remain <= 0 { return 0, nil, true } } f, ok := r.(*os.File) if !ok { return 0, nil, false } if err := c.writeLock(); err != nil { return 0, err, true } defer c.writeUnlock() dst := c.sysfd src := int(f.Fd()) for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } n, err1 := syscall.Sendfile(dst, src, nil, n) if n > 0 { written += int64(n) remain -= int64(n) } if n == 0 && err1 == nil { break } if err1 == syscall.EAGAIN { if err1 = c.pd.WaitWrite(); err1 == nil { continue } } if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which // don't implement sendfile) err = err1 break } } if lr != nil { lr.N = remain } if err != nil { err = os.NewSyscallError("sendfile", err) } return written, err, written > 0 }
// sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // // if handled == true, sendFile returns the number of bytes copied and any // non-EOF error. // // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { var remain int64 = 1 << 62 // by default, copy until EOF lr, ok := r.(*io.LimitedReader) if ok { remain, r = lr.N, lr.R if remain <= 0 { return 0, nil, true } } f, ok := r.(*os.File) if !ok { return 0, nil, false } c.wio.Lock() defer c.wio.Unlock() if err := c.incref(false); err != nil { return 0, err, true } defer c.decref() dst := c.sysfd src := int(f.Fd()) for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } n, err1 := syscall.Sendfile(dst, src, nil, n) if n > 0 { written += int64(n) remain -= int64(n) } if n == 0 && err1 == nil { break } if err1 == syscall.EAGAIN && c.wdeadline >= 0 { if err1 = pollserver.WaitWrite(c); err1 == nil { continue } } if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which // don't implement sendfile together) err = &OpError{"sendfile", c.net, c.raddr, err1} break } } if lr != nil { lr.N = remain } return written, err, written > 0 }
func doCopyFile(fin, fout fileish, fi os.FileInfo) error { size := fi.Size() var offset int64 for offset < size { // sendfile is funny; it only copies up to maxint // bytes at a time, but takes an int64 offset. count := size - offset if count > maxcp { count = maxcp } if _, err := syscall.Sendfile(int(fout.Fd()), int(fin.Fd()), &offset, int(count)); err != nil { return err } } return nil }
func sendFile(conn *net.TCPConn, fn string, offset int64) { f, err := os.Open(fn) if err != nil { fmt.Println(err.Error()) return } nf, err := conn.File() if err != nil { fmt.Println(err.Error()) return } dst := nf.Fd() for i := 0; i < 1000000; i++ { _, err = syscall.Sendfile(int(dst), int(f.Fd()), &offset, 1033) if err != nil { fmt.Println(err.Error()) break } } conn.CloseWrite() }
// sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // // if handled == true, sendFile returns the number of bytes copied and any // non-EOF error. // // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { // FreeBSD uses 0 as the "until EOF" value. If you pass in more bytes than the // file contains, it will loop back to the beginning ad nauseam until it's sent // exactly the number of bytes told to. As such, we need to know exactly how many // bytes to send. var remain int64 = 0 lr, ok := r.(*io.LimitedReader) if ok { remain, r = lr.N, lr.R if remain <= 0 { return 0, nil, true } } f, ok := r.(*os.File) if !ok { return 0, nil, false } if remain == 0 { fi, err := f.Stat() if err != nil { return 0, err, false } remain = fi.Size() } // The other quirk with FreeBSD's sendfile implementation is that it doesn't // use the current position of the file -- if you pass it offset 0, it starts // from offset 0. There's no way to tell it "start from current position", so // we have to manage that explicitly. pos, err := f.Seek(0, os.SEEK_CUR) if err != nil { return 0, err, false } if err := c.writeLock(); err != nil { return 0, err, true } defer c.writeUnlock() dst := c.sysfd src := int(f.Fd()) for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } pos1 := pos n, err1 := syscall.Sendfile(dst, src, &pos1, n) if n > 0 { pos += int64(n) written += int64(n) remain -= int64(n) } if n == 0 && err1 == nil { break } if err1 == syscall.EAGAIN { if err1 = c.pd.waitWrite(); err1 == nil { continue } } if err1 == syscall.EINTR { continue } if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which // don't implement sendfile) err = err1 break } } if lr != nil { lr.N = remain } if err != nil { err = os.NewSyscallError("sendfile", err) } return written, err, written > 0 }
// sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // // if handled == true, sendFile returns the number of bytes copied and any // non-EOF error. // // if handled == false, sendFile performed no work. func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { var remain int64 = 1 << 62 // by default, copy until EOF lr, ok := r.(*io.LimitedReader) if ok { remain, r = lr.N, lr.R if remain <= 0 { return 0, nil, true } } f, ok := r.(*os.File) if !ok { return 0, nil, false } c.wio.Lock() defer c.wio.Unlock() c.incref() defer c.decref() if c.wdeadline_delta > 0 { // This is a little odd that we're setting the timeout // for the entire file but Write has the same issue // (if one slurps the whole file into memory and // do one large Write). At least they're consistent. c.wdeadline = pollserver.Now() + c.wdeadline_delta } else { c.wdeadline = 0 } dst := c.sysfd src := f.Fd() for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } n, errno := syscall.Sendfile(dst, src, nil, n) if n > 0 { written += int64(n) remain -= int64(n) } if n == 0 && errno == 0 { break } if errno == syscall.EAGAIN && c.wdeadline >= 0 { pollserver.WaitWrite(c) continue } if errno != 0 { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which // don't implement sendfile together) err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)} break } } if lr != nil { lr.N = remain } return written, err, written > 0 }
func handle(conn net.Conn) { var rerr, werr error var wrote int buf := make([]byte, 32*1024) wrote, werr = conn.Write([]byte(headers)) if werr != nil { log.Fatal("Error writing headers", werr) } if wrote != len([]byte(headers)) { log.Fatal("Error: Wrote ", wrote, " headers bytes. Expected ", len([]byte(headers))) } outfile, ferr := conn.(*net.TCPConn).File() if ferr != nil { log.Fatal("Error getting conn fd", ferr) } outfd := int(outfile.Fd()) if outfd >= offsetsz { growOffset(outfd) } currOffset := &offset[outfd] for *currOffset < size { wrote, werr = syscall.Sendfile(outfd, srcfd, currOffset, int(size)) if werr != nil { log.Fatal("Sendfile error:", werr) } //log.Println("Sendfile wrote ", wrote) } //log.Println(outfd, ": Sendfile wrote: ", write) offset[outfd] = 0 werr = conn.(*net.TCPConn).CloseWrite() if werr != nil { log.Println("Error on CloseWrite", werr) } // Consume input for { _, rerr = conn.Read(buf) if rerr == io.EOF { break } else if rerr != nil { log.Println("Error consuming read input: ", rerr) break } } werr = outfile.Close() if werr != nil { log.Println("Error on outfile Close", werr) } werr = conn.Close() if werr != nil { log.Println("Error on Close", werr) } }