1// Copyright 2018 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
5package net
6
7import (
8	"internal/poll"
9	"io"
10)
11
12var pollSplice = poll.Splice
13
14// spliceFrom transfers data from r to c using the splice system call to minimize
15// copies from and to userspace. c must be a TCP connection.
16// Currently, spliceFrom is only enabled if r is a TCP or a stream-oriented Unix connection.
17//
18// If spliceFrom returns handled == false, it has performed no work.
19func spliceFrom(c *netFD, r io.Reader) (written int64, err error, handled bool) {
20	var remain int64 = 1<<63 - 1 // by default, copy until EOF
21	lr, ok := r.(*io.LimitedReader)
22	if ok {
23		remain, r = lr.N, lr.R
24		if remain <= 0 {
25			return 0, nil, true
26		}
27	}
28
29	var s *netFD
30	switch v := r.(type) {
31	case *TCPConn:
32		s = v.fd
33	case tcpConnWithoutWriteTo:
34		s = v.fd
35	case *UnixConn:
36		if v.fd.net != "unix" {
37			return 0, nil, false
38		}
39		s = v.fd
40	default:
41		return 0, nil, false
42	}
43
44	written, handled, err = pollSplice(&c.pfd, &s.pfd, remain)
45	if lr != nil {
46		lr.N -= written
47	}
48	return written, wrapSyscallError("splice", err), handled
49}
50
51// spliceTo transfers data from c to w using the splice system call to minimize
52// copies from and to userspace. c must be a TCP connection.
53// Currently, spliceTo is only enabled if w is a stream-oriented Unix connection.
54//
55// If spliceTo returns handled == false, it has performed no work.
56func spliceTo(w io.Writer, c *netFD) (written int64, err error, handled bool) {
57	uc, ok := w.(*UnixConn)
58	if !ok || uc.fd.net != "unix" {
59		return
60	}
61
62	written, handled, err = pollSplice(&uc.fd.pfd, &c.pfd, 1<<63-1)
63	return written, wrapSyscallError("splice", err), handled
64}
65