func (c *conn) remoteError() error {
	c.err = &errRemoteError{dg: c.rx.String()}
	return c.err
}
remoteError formats the error in rx, sets err and returns the error.
package tftp  
import (
	"bytes"
	"errors"
	"io"
	"net"
	"strconv"
	"time"
	"pack.ag/tftp/netascii"
)
const (
	defaultPort       = "69"
	defaultMode       = ModeOctet
	defaultUDPNet     = "udp"
	defaultTimeout    = time.Second
	defaultBlksize    = 512
	defaultWindowsize = 1
	defaultRetransmit = 10
)
var defaultOptions = map[string]string{
	optTransferSize: "0",  
}
func newConn(udpNet string, mode TransferMode, addr *net.UDPAddr) (*conn, error) {
	netConn, err := net.ListenUDP(udpNet, &net.UDPAddr{})
	if err != nil {
		return nil, wrapError(err, "network listen failed")
	}
	c := &conn{
		log:        newLogger(addr.String()),
		remoteAddr: addr,
		netConn:    netConn,
		blksize:    defaultBlksize,
		timeout:    defaultTimeout,
		windowsize: defaultWindowsize,
		retransmit: defaultRetransmit,
		mode:       mode,
	}
	c.rx.buf = make([]byte, 4+defaultBlksize)  
	return c, nil
}
func newSinglePortConn(addr *net.UDPAddr, mode TransferMode, netConn *net.UDPConn, reqChan chan []byte) *conn {
	return &conn{
		log:        newLogger(addr.String()),
		remoteAddr: addr,
		blksize:    defaultBlksize,
		timeout:    defaultTimeout,
		windowsize: defaultWindowsize,
		retransmit: defaultRetransmit,
		mode:       mode,
		buf:        make([]byte, 4+defaultBlksize),  
		reqChan:    reqChan,
		netConn:    netConn,
	}
}
func newConnFromHost(udpNet string, mode TransferMode, host string) (*conn, error) {
	addr, err := net.ResolveUDPAddr(udpNet, host)
	if err != nil {
		return nil, wrapError(err, "address resolve failed")
	}
	return newConn(udpNet, mode, addr)
}
type conn struct {
	log        *logger
	netConn    *net.UDPConn  
	remoteAddr net.Addr      
	reqChan chan []byte
	timer   *time.Timer
	isClient bool  
	isSender bool  
	blksize    uint16         
	timeout    time.Duration  
	windowsize uint16         
	mode       TransferMode   
	tsize      *int64         
	retransmit int  
	optionsParsed bool    
	window        uint16  
	block         uint16  
	catchup       bool    
	p             []byte  
	n             int     
	tries         int     
	err           error   
	closing       bool    
	done          bool    
	buf   []byte        
	txBuf *ringBuffer   
	rxBuf bytes.Buffer  
	tx datagram  
	rx datagram  
	reader io.Reader
	writer io.Writer
}
func (c *conn) sendWriteRequest(filename string, opts map[string]string) error {
	c.isSender = true
	c.tx.writeWriteReq(filename, c.mode, opts)
	for state := c.sendRequest; state != nil; {
		state = state()
	}
	return c.err
}
func (c *conn) sendReadRequest(filename string, opts map[string]string) error {
	c.tx.writeReadReq(filename, c.mode, opts)
	for state := c.sendRequest; state != nil; {
		state = state()
	}
	return c.err
}
func (c *conn) sendRequest() stateType {
	c.isClient = true
	if err := c.writeToNet(); err != nil {
		c.err = wrapError(err, "writing request to network")
		return nil
	}
	return c.receiveResponse
}
func (c *conn) receiveResponse() stateType {
	if c.tries >= c.retransmit {
		c.err = wrapError(c.err, "receiving request response")
		return nil
	}
	c.tries++
	addr, err := c.readFromNet()
	if err != nil {
		c.log.debug("error getting %s response from %v", c.tx.opcode(), c.remoteAddr)
		c.err = err
		return c.receiveResponse
	}
	if err := c.rx.validate(); err != nil {
		c.log.debug("error validating response from %v: %v", c.remoteAddr, err)
		c.err = wrapError(err, "validating request response")
		return nil
	}
	if c.reqChan == nil {
		c.remoteAddr = addr
	}
	c.log.trace("Received response from %v: %v", addr, c.rx)
	c.tries = 0
	if c.isSender {
		return c.handleWRQResponse
	}
	return c.handleRRQResponse
}
func (c *conn) handleWRQResponse() stateType {
	switch c.rx.opcode() {
	case opCodeOACK, opCodeACK:
		return c.writeSetup
	case opCodeERROR:
		c.err = wrapError(c.remoteError(), "WRQ OACK response")
		return nil
	default:
		c.err = wrapError(&errUnexpectedDatagram{dg: c.rx.String()}, "WRQ OACK response")
		return nil
	}
}
func (c *conn) handleRRQResponse() stateType {
	switch c.rx.opcode() {
	case opCodeOACK:
		return c.readSetup
	case opCodeDATA:
		n, err := c.rxBuf.Write(c.rx.data())
		if err != nil {
			c.err = wrapError(err, "writing RRQ response data")
			return nil
		}
		c.block = c.rx.block()
		if uint16(n) < c.blksize {
			c.done = true
		}
		return c.readSetup
	case opCodeERROR:
		c.err = wrapError(c.remoteError(), "RRQ OACK response")
		return nil
	default:
		c.err = wrapError(&errUnexpectedDatagram{dg: c.rx.String()}, "RRQ OACK response")
		return nil
	}
}
func (c *conn) Write(p []byte) (int, error) {
	if c.err != nil {
		return 0, wrapError(c.err, "checking conn err before Write")
	}
	c.p = p
	for state := c.startWrite; state != nil; {
		state = state()
	}
	return c.n, wrapError(c.err, "writing")
}
type stateType func() stateType
func (c *conn) startWrite() stateType {
	if !c.optionsParsed {
		return c.writeSetup
	}
	return c.write
}
func (c *conn) writeSetup() stateType {
	c.isSender = true
	ackOpts, err := c.parseOptions()
	if err != nil {
		return c.error(err, "parsing options")
	}
	if len(c.buf) != int(c.blksize) {
		c.buf = make([]byte, c.blksize)
	}
	c.txBuf = newRingBuffer(int(c.windowsize), int(c.blksize))
	c.writer = c.txBuf
	if c.mode == ModeNetASCII {
		c.writer = netascii.NewWriter(c.writer)
	}
	if c.isClient {
		return nil
	}
	if len(ackOpts) == 0 {
		return c.write
	}
	return c.sendOACK(ackOpts)
}
func (c *conn) sendOACK(o options) stateType {
	return func() stateType {
		c.log.trace("Sending OACK to %s\n", c.remoteAddr)
		c.tx.writeOptionAck(o)
		if err := c.writeToNet(); err != nil {
			return c.error(err, "writing OACK")
		}
		return c.getAck
	}
}
func (c *conn) error(err error, desc string) stateType {
	return func() stateType {
		c.err = wrapError(err, desc)
		return nil
	}
}
func (c *conn) write() stateType {
	read, err := c.writer.Write(c.p)
	if err != nil {
		c.n, c.err = read, wrapError(err, "writing data to txBuf before write")
		return nil
	}
	c.n = read
	return c.writeData
}
func (c *conn) writeData() stateType {
	if c.closing && c.done {
		return nil
	}
	if c.txBuf.Len() < int(c.blksize) && !c.closing {
		return nil
	}
	c.block++
	n, err := c.txBuf.Read(c.buf)
	if err != nil && err != io.EOF {
		c.err = wrapError(err, "reading data from txBuf before writing to network")
		return nil
	}
	c.tx.writeData(c.block, c.buf[:n])
	c.log.trace("Sending block %d with %d bytes to %s\n", c.block, n, c.remoteAddr)
	err = c.writeToNet()
	if err != nil {
		c.err = wrapError(err, "writing data to network")
		return nil
	}
	c.window++
	if uint16(n) < c.blksize {
		c.done = true
		return c.getAck
	}
	if c.window < c.windowsize {
		return c.writeData
	}
	c.window = 0
	return c.getAck
}
func (c *conn) Read(p []byte) (int, error) {
	c.n = 0
	if c.err != nil {
		return 0, wrapError(c.err, "checking conn error before Read")
	}
	c.p = p
	for state := c.startRead; state != nil; {
		state = state()
	}
	return c.n, c.err
}
func (c *conn) startRead() stateType {
	if !c.optionsParsed {
		return c.readSetup
	}
	return c.read
}
func (c *conn) readSetup() stateType {
	c.reader = &c.rxBuf
	if c.mode == ModeNetASCII {
		c.reader = netascii.NewReader(c.reader)
	}
	ackOpts, err := c.parseOptions()
	if err != nil {
		c.err = wrapError(err, "read setup")
		return nil
	}
	if needed := int(c.blksize + 4); len(c.rx.buf) != needed {
		c.rx.buf = make([]byte, needed)
	}
	if len(ackOpts) == 0 || c.isClient {
		c.log.trace("Sending ACK to %s\n", c.remoteAddr)
		c.tx.writeAck(c.block)
	} else {
		c.log.trace("Sending OACK to %s\n", c.remoteAddr)
		c.tx.writeOptionAck(ackOpts)
	}
	err = c.writeToNet()
	if err != nil {
		c.err = err
		return nil
	}
	if c.isClient {
		return nil
	}
	return c.read
}
func (c *conn) read() stateType {
	if c.rxBuf.Len() >= len(c.p) || c.done {
		n, err := c.reader.Read(c.p)
		c.n = n
		if err != nil && err != io.EOF {  
			c.err = wrapError(err, "reading from rxBuf after read")
		}
		if c.done && c.rxBuf.Len() == 0 {
			c.err = io.EOF
		}
		return nil
	}
	return c.readData
}
func (c *conn) readData() stateType {
	if c.tries >= c.retransmit {
		c.log.debug("Max retries exceeded")
		c.sendError(ErrCodeNotDefined, "max retries reached")
		c.err = wrapError(ErrMaxRetries, "reading data")
		return nil
	}
	c.tries++
	c.log.trace("Waiting for DATA from %s\n", c.remoteAddr)
	_, err := c.readFromNet()
	if err != nil {
		c.log.debug("error receiving block %d: %v", c.block+1, err)
		c.log.trace("Resending ACK for %d\n", c.block)
		if err := c.sendAck(c.block); err != nil {
			c.log.debug("resending ACK %v", err)
		}
		c.window = 0
		return c.readData
	}
	if err := c.rx.validate(); err != nil {
		c.err = wrapError(err, "validating read data")
		return nil
	}
	switch op := c.rx.opcode(); op {
	case opCodeDATA:
	case opCodeERROR:
		c.err = wrapError(c.remoteError(), "reading data")
		return nil
	default:
		c.err = wrapError(&errUnexpectedDatagram{dg: c.rx.String()}, "read data response")
		return nil
	}
	c.log.trace("Received block %d\n", c.rx.block())
	c.tries = 0
	return c.ackData
}
func (c *conn) ackData() stateType {
	switch diff := c.rx.block() - c.block; {
	case diff == 1:
		c.log.trace("ackData diff: %d, current block: %d, rx block %d", diff, c.block, c.rx.block())
		c.block++
		c.window++
		c.catchup = false
	case diff == 0:
		c.log.trace("ackData diff: %d, current block: %d, rx block %d", diff, c.block, c.rx.block())
		return c.read
	case diff > c.windowsize:
		c.log.trace("ackData diff: %d, current block: %d, rx block %d", diff, c.block, c.rx.block())
		return c.read
	case diff <= c.windowsize:
		c.log.trace("ackData diff: %d, current block: %d, rx block %d", diff, c.block, c.rx.block())
		if c.catchup {
			return c.read
		}
		c.log.debug("Missing blocks between %d and %d. Resetting to block %d", c.block, c.rx.block(), c.block)
		if err := c.sendAck(c.block); err != nil {
			c.err = wrapError(err, "sending missed block(s) ACK")
			return nil
		}
		c.window = 0
		c.catchup = true
		return c.read
	}
	n, err := c.rxBuf.Write(c.rx.data())
	if err != nil {
		c.err = wrapError(err, "writing to rxBuf after read")
		return nil
	}
	if n < int(c.blksize) {
		c.done = true
	}
	if c.window < c.windowsize && n >= int(c.blksize) {
		return c.read
	}
	c.log.trace("window %d, windowsize: %d, offset: %d, blksize: %d", c.window, c.windowsize, c.rx.offset, c.blksize)
	c.window = 0
	c.log.trace("Window %d reached, sending ACK for %d\n", c.windowsize, c.block)
	if err := c.sendAck(c.block); err != nil {
		c.err = wrapError(err, "sending DATA ACK")
		return nil
	}
	return c.read
}
func (c *conn) Close() error {
	c.log.debug("Closing connection to %s\n", c.remoteAddr)
	if c.reqChan == nil {
		defer func() {
			err := c.netConn.Close()
			if err != nil {
				c.log.debug("error closing network connection:", err)
			}
			if c.err == nil {
				c.err = err
			}
		}()
	}
	if c.err != nil && c.err != io.EOF {
		return wrapError(c.err, "checking conn err before Close")
	}
	if flusher, ok := c.writer.(interface {
		Flush() error
	}); ok {
		c.log.trace("flushing writer")
		if err := flusher.Flush(); err != nil {
			return wrapError(err, "flushing writer")
		}
	}
	if c.txBuf != nil {
		c.closing = true
		c.Write([]byte{})
	}
	if c.err == io.EOF {
		return nil
	}
	return c.err
}
func (c *conn) parseOptions() (options, error) {
	ackOpts := make(map[string]string)
	for opt, val := range c.rx.options() {
		switch opt {
		case optBlocksize:
			size, err := strconv.ParseUint(val, 10, 16)
			if err != nil {
				return nil, &errParsingOption{option: opt, value: val}
			}
			c.blksize = uint16(size)
			ackOpts[opt] = val
		case optTimeout:
			seconds, err := strconv.ParseUint(val, 10, 8)
			if err != nil {
				return nil, &errParsingOption{option: opt, value: val}
			}
			c.timeout = time.Second * time.Duration(seconds)
			ackOpts[opt] = val
		case optTransferSize:
			tsize, err := strconv.ParseInt(val, 10, 64)
			if err != nil {
				return nil, &errParsingOption{option: opt, value: val}
			}
			if c.isSender && c.tsize != nil {
				ackOpts[opt] = strconv.FormatInt(*c.tsize, 10)
				continue
			}
			c.tsize = &tsize
		case optWindowSize:
			size, err := strconv.ParseUint(val, 10, 16)
			if err != nil {
				return nil, &errParsingOption{option: opt, value: val}
			}
			c.windowsize = uint16(size)
			ackOpts[opt] = val
		}
	}
	c.optionsParsed = true
	return ackOpts, nil
}
func (c *conn) sendError(code ErrorCode, msg string) {
	c.log.debug("Sending error code %s to %s: %s\n", code, c.remoteAddr, msg)
	if len(msg) > int((c.blksize - 1)) {  
		c.log.debug("error message is larger than blksize, truncating")
		msg = msg[:c.blksize-1]
	}
	c.tx.writeError(code, msg)
	if err := c.writeToNet(); err != nil {
		c.log.debug("sending ERROR: %v", err)
	}
}
func (c *conn) sendAck(block uint16) error {
	c.tx.writeAck(block)
	c.log.trace("Sending ACK for %d to %s\n", block, c.remoteAddr)
	return wrapError(c.writeToNet(), "sending ACK")
}
func (c *conn) getAck() stateType {
	c.tries++
	if c.tries > c.retransmit {
		c.log.debug("Max retries exceeded")
		c.sendError(ErrCodeNotDefined, "max retries reached")
		c.err = wrapError(ErrMaxRetries, "reading ack")
		return nil
	}
	c.log.trace("Waiting for ACK from %s\n", c.remoteAddr)
	sAddr, err := c.readFromNet()
	if err != nil {
		c.log.trace("Error waiting for ACK: %v", err)
		c.err = wrapError(err, "waiting for ACK")
		return c.getAck
	}
	if c.reqChan == nil && sAddr.String() != c.remoteAddr.String() {
		c.log.err("Received unexpected datagram from %v, expected %v\n", sAddr, c.remoteAddr)
		go func() {
			var err datagram
			err.writeError(ErrCodeUnknownTransferID, "Unexpected TID")
			_, _ = c.netConn.WriteTo(err.bytes(), sAddr)
		}()
		return c.getAck  
	}
	if err := c.rx.validate(); err != nil {
		c.err = wrapError(err, "ACK validation failed")
		return nil
	}
	switch op := c.rx.opcode(); op {
	case opCodeACK:
		c.log.trace("Got ACK for block %d\n", c.rx.block())
	case opCodeERROR:
		c.err = wrapError(c.remoteError(), "error receiving ACK")
		return nil
	default:
		c.err = wrapError(&errUnexpectedDatagram{c.rx.String()}, "error receiving ACK")
		return nil
	}
	if rxBlock := c.rx.block(); rxBlock != c.block {
		if rxBlock > c.block {
			c.log.debug("Received ACK > current block, ignoring.")
			return c.getAck
		}
		c.log.debug("Expected ACK for block %d, got %d. Resetting to block %d.", c.block, rxBlock, rxBlock)
		c.txBuf.UnreadSlots(int(c.block - rxBlock))
		c.block = rxBlock
		c.window = 0
		c.done = false
	}
	c.tries = 0
	if c.tx.opcode() == opCodeOACK {  
		return c.write
	}
	return c.writeData
}