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
}
write writes adds data to txBuf and writes data to netConn in chunks of
blksize, until the last chunk of <blksize, which signals transfer completion.
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
	}
}