func (c *Conn) SetDeadline(t time.Time) error {
	return c.SetReadDeadline(t)
}
SetDeadline sets the read and write deadlines associated
with the connection. It is equivalent to calling both
SetReadDeadline and SetWriteDeadline.

A deadline is an absolute time after which I/O operations
fail with a timeout (see type Error) instead of
blocking. The deadline applies to all future I/O, not just
the immediately following call to Read or Write.

An idle timeout can be implemented by repeatedly extending
the deadline after successful Read or Write calls.

A zero value for t means I/O operations will not time out.
package kex2
import (
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"errors"
	"io"
	"net"
	"sync"
	"time"
	"github.com/keybase/go-codec/codec"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/net/context"
)
type DeviceID [16]byte
type SessionID [32]byte
const SecretLen = 32
type Secret [SecretLen]byte
type Seqno uint32
func (d DeviceID) Eq(d2 DeviceID) bool {
	return hmac.Equal(d[:], d2[:])
}
func (s SessionID) Eq(s2 SessionID) bool {
	return hmac.Equal(s[:], s2[:])
}
type MessageRouter interface {
	Post(I SessionID, sender DeviceID, seqno Seqno, msg []byte) error
	Get(I SessionID, receiver DeviceID, seqno Seqno, poll time.Duration) (msg [][]byte, err error)
}
type Conn struct {
	router    MessageRouter
	secret    Secret
	sessionID SessionID
	deviceID  DeviceID
	readMutex    sync.Mutex
	readSeqno    Seqno
	readDeadline time.Time
	readTimeout  time.Duration
	bufferedMsgs [][]byte
	writeMutex sync.Mutex
	writeSeqno Seqno
	pollLoopRunningMutex sync.Mutex
	pollLoopRunning      bool
	errMutex sync.Mutex
	readErr  error
	writeErr error
	closed   bool
	ctx context.Context
}
const sessionIDText = "Kex v2 Session ID"
func NewConn(ctx context.Context, r MessageRouter, s Secret, d DeviceID, readTimeout time.Duration) (con net.Conn, err error) {
	mac := hmac.New(sha256.New, []byte(s[:]))
	mac.Write([]byte(sessionIDText))
	tmp := mac.Sum(nil)
	var sessionID SessionID
	copy(sessionID[:], tmp)
	ret := &Conn{
		router:      r,
		secret:      s,
		sessionID:   sessionID,
		deviceID:    d,
		readSeqno:   0,
		readTimeout: readTimeout,
		writeSeqno:  0,
		ctx:         ctx,
	}
	return ret, nil
}
type timedoutError struct{}
func (t timedoutError) Error() string { return "operation timed out" }
func (t timedoutError) Temporary() bool { return true }
func (t timedoutError) Timeout() bool { return true }
var ErrTimedOut net.Error = timedoutError{}
var ErrUnimplemented = errors.New("unimplemented")
var ErrBadMetadata = errors.New("bad metadata")
var ErrDecryption = errors.New("decryption failed")
var ErrNotEnoughRandomness = errors.New("not enough random data")
var ErrBadPacketSequence = errors.New("packets arrived out-of-order")
var ErrWrongSession = errors.New("got message for wrong Session ID")
var ErrSelfRecieve = errors.New("got message back that we sent")
var ErrAgain = errors.New("no data were ready to read")
var ErrBadSecret = errors.New("bad secret")
var ErrHelloTimeout = errors.New("hello timeout")
func (c *Conn) setReadError(e error) error {
	c.errMutex.Lock()
	c.readErr = e
	c.errMutex.Unlock()
	return e
}
func (c *Conn) setWriteError(e error) error {
	c.errMutex.Lock()
	c.writeErr = e
	c.errMutex.Unlock()
	return e
}
func (c *Conn) getErrorForWrite() error {
	var err error
	c.errMutex.Lock()
	if c.readErr != nil && c.readErr != io.EOF {
		err = c.readErr
	} else if c.writeErr != nil {
		err = c.writeErr
	}
	c.errMutex.Unlock()
	return err
}
func (c *Conn) setClosed() {
	c.errMutex.Lock()
	c.closed = true
	c.errMutex.Unlock()
}
func (c *Conn) getClosed() bool {
	c.errMutex.Lock()
	ret := c.closed
	c.errMutex.Unlock()
	return ret
}
func (c *Conn) getErrorForRead() error {
	var err error
	c.errMutex.Lock()
	if c.readErr != nil {
		err = c.readErr
	} else if c.writeErr != nil && c.writeErr != io.EOF {
		err = c.writeErr
	}
	c.errMutex.Unlock()
	return err
}
func (c *Conn) setPollLoopRunning(b bool) {
	c.pollLoopRunningMutex.Lock()
	c.pollLoopRunning = b
	c.pollLoopRunningMutex.Unlock()
}
func (c *Conn) getPollLoopRunning() bool {
	c.pollLoopRunningMutex.Lock()
	ret := c.pollLoopRunning
	c.pollLoopRunningMutex.Unlock()
	return ret
}
type outerMsg struct {
	_struct   bool      `codec:",toarray"`
	SenderID  DeviceID  `codec:"senderID"`
	SessionID SessionID `codec:"sessionID"`
	Seqno     Seqno     `codec:"seqno"`
	Nonce     [24]byte  `codec:"nonce"`
	Payload   []byte    `codec:"payload"`
}
type innerMsg struct {
	_struct   bool      `codec:",toarray"`
	SenderID  DeviceID  `codec:"senderID"`
	SessionID SessionID `codec:"sessionID"`
	Seqno     Seqno     `codec:"seqno"`
	Payload   []byte    `codec:"payload"`
}
func (c *Conn) decryptIncomingMessage(msg []byte) (int, error) {
	var err error
	mh := codec.MsgpackHandle{WriteExt: true}
	dec := codec.NewDecoderBytes(msg, &mh)
	var om outerMsg
	err = dec.Decode(&om)
	if err != nil {
		return 0, err
	}
	var plaintext []byte
	var ok bool
	plaintext, ok = secretbox.Open(plaintext, om.Payload, &om.Nonce, (*[32]byte)(&c.secret))
	if !ok {
		return 0, ErrDecryption
	}
	dec = codec.NewDecoderBytes(plaintext, &mh)
	var im innerMsg
	err = dec.Decode(&im)
	if err != nil {
		return 0, err
	}
	if !om.SenderID.Eq(im.SenderID) || !om.SessionID.Eq(im.SessionID) || om.Seqno != im.Seqno {
		return 0, ErrBadMetadata
	}
	if !im.SessionID.Eq(c.sessionID) {
		return 0, ErrWrongSession
	}
	if im.SenderID.Eq(c.deviceID) {
		return 0, ErrSelfRecieve
	}
	if im.Seqno != c.readSeqno+1 {
		return 0, ErrBadPacketSequence
	}
	c.readSeqno = im.Seqno
	c.bufferedMsgs = append(c.bufferedMsgs, im.Payload)
	return len(im.Payload), nil
}
func (c *Conn) decryptIncomingMessages(msgs [][]byte) (int, error) {
	var ret int
	for _, msg := range msgs {
		n, e := c.decryptIncomingMessage(msg)
		if e != nil {
			return ret, e
		}
		ret += n
	}
	return ret, nil
}
func (c *Conn) readBufferedMsgsIntoBytes(out []byte) (int, error) {
	p := 0
	if len(c.bufferedMsgs) == 0 {
		return 0, nil
	}
	if len(c.bufferedMsgs[0]) == 0 {
		return 0, io.EOF
	}
	for p < len(out) {
		rem := len(out) - p
		if len(c.bufferedMsgs) > 0 {
			front := c.bufferedMsgs[0]
			n := len(front)
			if n == 0 {
				var err error
				if p == 0 {
					err = io.EOF
				}
				return p, err
			}
			if rem < n {
				n = rem
				copy(out[p:(p+n)], front[0:n])
				front = front[n:]
				if len(front) == 0 {
					c.bufferedMsgs = c.bufferedMsgs[1:]
				} else {
					c.bufferedMsgs[0] = front
				}
			} else {
				copy(out[p:(p+n)], front[:])
				c.bufferedMsgs = c.bufferedMsgs[1:]
			}
			p += n
		} else {
			break
		}
	}
	return p, nil
}
func (c *Conn) pollLoop(poll time.Duration) (msgs [][]byte, err error) {
	var totalWaitTime time.Duration
	c.setPollLoopRunning(true)
	defer c.setPollLoopRunning(false)
	start := time.Now()
	for {
		newPoll := poll - totalWaitTime
		msgs, err = c.router.Get(c.sessionID, c.deviceID, c.readSeqno+1, newPoll)
		totalWaitTime = time.Since(start)
		if err != nil || len(msgs) > 0 || totalWaitTime >= poll || c.getClosed() {
			return
		}
		select {
		case <-c.ctx.Done():
			return nil, ErrCanceled
		default:
		}
	}
}
func (c *Conn) Read(out []byte) (n int, err error) {
	c.readMutex.Lock()
	defer c.readMutex.Unlock()
	if err = c.getErrorForRead(); err != nil {
		return 0, err
	}
	if n, err = c.readBufferedMsgsIntoBytes(out); err != nil {
		return 0, c.setReadError(err)
	}
	if n > 0 {
		return n, nil
	}
	var poll time.Duration
	if !c.readDeadline.IsZero() {
		poll = c.readDeadline.Sub(time.Now())
		if poll.Nanoseconds() < 0 {
			return 0, c.setReadError(ErrTimedOut)
		}
	} else {
		poll = c.readTimeout
	}
	var msgs [][]byte
	msgs, err = c.pollLoop(poll)
	if err != nil {
		return 0, c.setReadError(err)
	}
	if _, err = c.decryptIncomingMessages(msgs); err != nil {
		return 0, c.setReadError(err)
	}
	if n, err = c.readBufferedMsgsIntoBytes(out); err != nil {
		return 0, c.setReadError(err)
	}
	if n == 0 {
		switch {
		case c.getClosed():
			err = io.EOF
		case poll > 0:
			err = ErrTimedOut
		default:
			err = ErrAgain
		}
	}
	return n, err
}
func (c *Conn) encryptOutgoingMessage(seqno Seqno, buf []byte) (ret []byte, err error) {
	var nonce [24]byte
	var n int
	if n, err = rand.Read(nonce[:]); err != nil {
		return nil, err
	} else if n != 24 {
		return nil, ErrNotEnoughRandomness
	}
	im := innerMsg{
		SenderID:  c.deviceID,
		SessionID: c.sessionID,
		Seqno:     seqno,
		Payload:   buf,
	}
	mh := codec.MsgpackHandle{WriteExt: true}
	var imPacked []byte
	enc := codec.NewEncoderBytes(&imPacked, &mh)
	if err = enc.Encode(im); err != nil {
		return nil, err
	}
	ciphertext := secretbox.Seal(nil, imPacked, &nonce, (*[32]byte)(&c.secret))
	om := outerMsg{
		SenderID:  c.deviceID,
		SessionID: c.sessionID,
		Seqno:     seqno,
		Nonce:     nonce,
		Payload:   ciphertext,
	}
	enc = codec.NewEncoderBytes(&ret, &mh)
	if err = enc.Encode(om); err != nil {
		return nil, err
	}
	return ret, nil
}
func (c *Conn) nextWriteSeqno() Seqno {
	c.writeSeqno++
	return c.writeSeqno
}
func (c *Conn) Write(buf []byte) (n int, err error) {
	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()
	if len(buf) == 0 {
		return 0, nil
	}
	return c.writeWithLock(buf)
}
func (c *Conn) writeWithLock(buf []byte) (n int, err error) {
	var ctext []byte
	if err = c.getErrorForWrite(); err != nil {
		return 0, err
	}
	seqno := c.nextWriteSeqno()
	ctext, err = c.encryptOutgoingMessage(seqno, buf)
	if err != nil {
		return 0, c.setWriteError(err)
	}
	if err = c.router.Post(c.sessionID, c.deviceID, seqno, ctext); err != nil {
		return 0, c.setWriteError(err)
	}
	return len(ctext), nil
}
func (c *Conn) Close() error {
	c.writeMutex.Lock()
	defer c.writeMutex.Unlock()
	c.setClosed()
	if _, err := c.writeWithLock([]byte{}); err != nil {
		return err
	}
	c.setWriteError(io.EOF)
	return nil
}
func (c *Conn) LocalAddr() (addr net.Addr) {
	return
}
func (c *Conn) RemoteAddr() (addr net.Addr) {
	return
}