Skip to content

Commit

Permalink
Make requested TFTP transfer mode available to handlers. Resolves #2.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kale Blankenship committed Sep 16, 2016
1 parent a50016b commit 6879888
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 21 deletions.
4 changes: 2 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
type Client struct {
log *logger
net string // UDP network (ie, "udp", "udp4", "udp6")
mode transferMode // TFTP transfer mode
mode TransferMode // TFTP transfer mode
opts map[string]string // Map of TFTP options (RFC2347)

retransmit int // Per-packet retransmission limit
Expand Down Expand Up @@ -209,7 +209,7 @@ type ClientOpt func(*Client) error
// ClientMode configures the mode.
//
// Valid options are ModeNetASCII and ModeOctet. Default is ModeNetASCII.
func ClientMode(mode transferMode) ClientOpt {
func ClientMode(mode TransferMode) ClientOpt {
return func(c *Client) error {
if mode != ModeNetASCII && mode != ModeOctet {
return ErrInvalidMode
Expand Down
2 changes: 1 addition & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestNewClient(t *testing.T) {

expectedError error
expectedOpts map[string]string
expectedMode transferMode
expectedMode TransferMode
expectedRetransmit int
}{
"default": {
Expand Down
8 changes: 4 additions & 4 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var defaultOptions = map[string]string{
//
// udpNet is one of "udp", "udp4", or "udp6"
// addr is the address of the target client or server
func newConn(udpNet string, mode transferMode, addr *net.UDPAddr) (*conn, error) {
func newConn(udpNet string, mode TransferMode, addr *net.UDPAddr) (*conn, error) {
// Start listening, an empty UDPAddr will cause the system to assign a port
netConn, err := net.ListenUDP(udpNet, &net.UDPAddr{})
if err != nil {
Expand All @@ -56,7 +56,7 @@ func newConn(udpNet string, mode transferMode, addr *net.UDPAddr) (*conn, error)
return c, nil
}

func newSinglePortConn(addr *net.UDPAddr, mode transferMode, netConn *net.UDPConn, reqChan chan []byte) *conn {
func newSinglePortConn(addr *net.UDPAddr, mode TransferMode, netConn *net.UDPConn, reqChan chan []byte) *conn {
return &conn{
log: newLogger(addr.String()),
remoteAddr: addr,
Expand All @@ -74,7 +74,7 @@ func newSinglePortConn(addr *net.UDPAddr, mode transferMode, netConn *net.UDPCon
// newConnFromHost wraps newConn and looks up the target's address from a string
//
// This function is used by Client
func newConnFromHost(udpNet string, mode transferMode, host string) (*conn, error) {
func newConnFromHost(udpNet string, mode TransferMode, host string) (*conn, error) {
// Resolve server
addr, err := net.ResolveUDPAddr(udpNet, host)
if err != nil {
Expand Down Expand Up @@ -102,7 +102,7 @@ type conn struct {
blksize uint16 // Size of DATA payloads
timeout time.Duration // How long to wait before resending packets
windowsize uint16 // Number of DATA packets between ACKs
mode transferMode // octet or netascii
mode TransferMode // octet or netascii
tsize *int64 // Size of the file being sent/received

// Other, non-negotiable options
Expand Down
6 changes: 3 additions & 3 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ func TestNewConn(t *testing.T) {

cases := map[string]struct {
net string
mode transferMode
mode TransferMode
addr *net.UDPAddr

expectedAddr *net.UDPAddr
expectedMode transferMode
expectedMode TransferMode
expectedError string
}{
"success": {
Expand Down Expand Up @@ -458,7 +458,7 @@ func TestConn_sendReadRequest(t *testing.T) {

cases := map[string]struct {
timeout time.Duration
mode transferMode
mode TransferMode
connFunc func(string, *net.UDPConn, *net.UDPAddr)

expectedBuf string
Expand Down
19 changes: 10 additions & 9 deletions datagram.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,19 @@ const (
ErrCodeNoSuchUser ErrorCode = 0x7

// ModeNetASCII is the string for netascii transfer mode
ModeNetASCII transferMode = "netascii"
ModeNetASCII TransferMode = "netascii"
// ModeOctet is the string for octet/binary transfer mode
ModeOctet transferMode = "octet"
modeMail transferMode = "mail"
ModeOctet TransferMode = "octet"
modeMail TransferMode = "mail"

optBlocksize = "blksize"
optTimeout = "timeout"
optTransferSize = "tsize"
optWindowSize = "windowsize"
)

type transferMode string
// TransferMode is a TFTP transer mode
type TransferMode string

var (
errorStrings = map[ErrorCode]string{
Expand Down Expand Up @@ -164,11 +165,11 @@ func (d *datagram) writeError(code ErrorCode, msg string) {
d.writeNull()
}

func (d *datagram) writeReadReq(filename string, mode transferMode, options map[string]string) {
func (d *datagram) writeReadReq(filename string, mode TransferMode, options map[string]string) {
d.writeReq(opCodeRRQ, filename, mode, options)
}

func (d *datagram) writeWriteReq(filename string, mode transferMode, options map[string]string) {
func (d *datagram) writeWriteReq(filename string, mode TransferMode, options map[string]string) {
d.writeReq(opCodeWRQ, filename, mode, options)
}

Expand All @@ -187,7 +188,7 @@ func (d *datagram) writeOptionAck(options map[string]string) {
}

// Combines duplicate logic from RRQ and WRQ
func (d *datagram) writeReq(o opcode, filename string, mode transferMode, options map[string]string) {
func (d *datagram) writeReq(o opcode, filename string, mode TransferMode, options map[string]string) {
// This is ugly, could just set buf to 512
// or use a bytes buffer. Intend to switch to bytes buffer
// after implementing all RFCs so that perf can be compared
Expand Down Expand Up @@ -239,9 +240,9 @@ func (d *datagram) filename() string {
}

// Mode from RRQ and WRQ datagrams
func (d *datagram) mode() transferMode {
func (d *datagram) mode() TransferMode {
fields := bytes.Split(d.buf[2:], []byte{0x0})
return transferMode(fields[1])
return TransferMode(fields[1])
}

// Opcode from all datagrams
Expand Down
4 changes: 2 additions & 2 deletions datagram_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func TestDatagram(t *testing.T) {
code opcode
block uint16
filename *string
mode *transferMode
mode *TransferMode
opts options
errCode *ErrorCode
errMessage *string
Expand Down Expand Up @@ -461,7 +461,7 @@ func ptrString(s string) *string {
return &s
}

func ptrMode(s transferMode) *transferMode {
func ptrMode(s TransferMode) *TransferMode {
return &s
}

Expand Down
14 changes: 14 additions & 0 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type WriteRequest interface {
// connection. WriteError can only be called once. Read cannot
// be called after an error has been written.
WriteError(ErrorCode, string)

// TransferMode returns the TFTP transfer mode requested by the client.
TransferMode() TransferMode
}

// writeRequest implements WriteRequest.
Expand Down Expand Up @@ -80,6 +83,10 @@ func (w *writeRequest) WriteError(c ErrorCode, s string) {
w.conn.sendError(c, s)
}

func (w *writeRequest) TransferMode() TransferMode {
return w.conn.mode
}

// ReadRequest is provided to a ReadHandler's ServeTFTP method.
type ReadRequest interface {
// Addr is the network address of the client.
Expand All @@ -99,6 +106,9 @@ type ReadRequest interface {
// WriteSize sets the transfer size (tsize) value to be sent to
// the client. It must be called before any calls to Write.
WriteSize(int64)

// TransferMode returns the TFTP transfer mode requested by the client.
TransferMode() TransferMode
}

// readRequest implements ReadRequest.
Expand Down Expand Up @@ -128,6 +138,10 @@ func (w *readRequest) WriteSize(i int64) {
w.conn.tsize = &i
}

func (w *readRequest) TransferMode() TransferMode {
return w.conn.mode
}

// FileServer creates a handler for sending and reciving files on the filesystem.
func FileServer(dir string) ReadWriteHandler {
return &fileServer{path: dir, log: newLogger("fileserver")}
Expand Down
4 changes: 4 additions & 0 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type readRequestMock struct {
errCode ErrorCode
errMsg string
size *int64
tmode TransferMode
}

func (r *readRequestMock) Addr() *net.UDPAddr { return r.addr }
Expand All @@ -30,6 +31,7 @@ func (r *readRequestMock) WriteError(c ErrorCode, m string) {
r.errCode = c
r.errMsg = m
}
func (r *readRequestMock) TransferMode() TransferMode { return r.tmode }

func TestFileServer_ServeTFTP(t *testing.T) {
text := getTestData(t, "text")
Expand Down Expand Up @@ -96,6 +98,7 @@ type writeRequestMock struct {
errCode ErrorCode
errMsg string
size *int64
tmode TransferMode
}

func (r *writeRequestMock) Addr() *net.UDPAddr { return r.addr }
Expand All @@ -111,6 +114,7 @@ func (r *writeRequestMock) WriteError(c ErrorCode, m string) {
r.errCode = c
r.errMsg = m
}
func (r *writeRequestMock) TransferMode() TransferMode { return r.tmode }

func TestFileServer_ReceiveTFTP(t *testing.T) {
text := getTestData(t, "text")
Expand Down

0 comments on commit 6879888

Please sign in to comment.