func (c *Conn) ReadFrame() (Frame, error) {
	if c.shutdown.IsShuttingDown() {
		return Frame{}, ErrShutdown
	}
	c.readMtx.Lock()
	defer c.readMtx.Unlock()
	f, err := c.readFrame()
	if f.Header.Type == rstFrameType {
		c.shutdown.Begin()
		return Frame{}, ErrShutdown
	}
	return f, err
}
ReadFrame reads a frame from the connection.

Due to an internal optimization (Readv, specifically), it is not guaranteed that a single call to
WriteFrame unblocks a pending ReadFrame on an otherwise idle (empty) connection.
The only way to guarantee that all previously written frames can reach the peer's layers on top
of frameconn is to send an empty frame (no payload) and to ignore empty frames on the receiving side.
package frameconn
import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"sync"
	"syscall"
	"time"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/zrepl/zrepl/rpc/dataconn/base2bufpool"
	"github.com/zrepl/zrepl/rpc/dataconn/timeoutconn"
)
type FrameHeader struct {
	Type       uint32
	PayloadLen uint32
}
func IsPublicFrameType(ft uint32) bool {
	return (0xf<<28)&ft == 0
}
const (
	rstFrameType uint32 = 1<<28 + iota
)
func assertPublicFrameType(frameType uint32) {
	if !IsPublicFrameType(frameType) {
		panic(fmt.Sprintf("frameconn: frame type %v cannot be used by consumers of this package", frameType))
	}
}
func (f *FrameHeader) Unmarshal(buf []byte) {
	if len(buf) != 8 {
		panic("frame header is 8 bytes long")
	}
	f.Type = binary.BigEndian.Uint32(buf[0:4])
	f.PayloadLen = binary.BigEndian.Uint32(buf[4:8])
}
type Conn struct {
	readMtx, writeMtx sync.Mutex
	nc                *timeoutconn.Conn
	readNextValid     bool
	readNext          FrameHeader
	nextReadErr       error
	bufPool           *base2bufpool.Pool  
	shutdown          shutdownFSM
}
func Wrap(nc *timeoutconn.Conn) *Conn {
	return &Conn{
		nc: nc,
		bufPool:       base2bufpool.New(15, 22, base2bufpool.Allocate),  
		readNext:      FrameHeader{},
		readNextValid: false,
	}
}
var ErrReadFrameLengthShort = errors.New("read frame length too short")
var ErrFixedFrameLengthMismatch = errors.New("read frame length mismatch")
type Buffer struct {
	bufpoolBuffer base2bufpool.Buffer
	payloadLen    uint32
}
func (b *Buffer) Free() {
	b.bufpoolBuffer.Free()
}
func (b *Buffer) Bytes() []byte {
	return b.bufpoolBuffer.Bytes()[0:b.payloadLen]
}
type Frame struct {
	Header FrameHeader
	Buffer Buffer
}
var ErrShutdown = fmt.Errorf("frameconn: shutting down")