예제 #1
1
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()))
}
예제 #2
0
파일: sendfile_linux.go 프로젝트: sreis/go
// 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
}
예제 #4
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
}
예제 #5
0
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()
}
예제 #6
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) {
	// 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
}
예제 #7
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
}
예제 #8
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)
	}
}