func sendFullWrite(filename string, content string) { //sends inital WRQ //waits for ack block 0,0 or times out //loop // sends data // waits for ack, or handles error, or resends // if data sent and acknowledged was last data, end ServerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:10001") checkError(err) LocalAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") checkError(err) Conn, err := net.DialUDP("udp", LocalAddr, ServerAddr) checkError(err) defer Conn.Close() /* initialize variables for tracking acknowledgements and location in content*/ index := 0 f := []byte(content) max := min(512, len(f)) data := f[index:max] block := []byte{0, 0} /*send inital WRQ*/ /*send inital WRQ*/ tftp.SendWRQ(filename, Conn) packet := make(chan []byte) defer close(packet) go getPacket(Conn, packet) select { case <-time.After(15 * time.Second): fmt.Println("WRQ from ", LocalAddr, " never acknowledged") return case r := <-packet: switch r[1] { case 4: //ACK packet recieved ackBlock, err := tftp.GetAckBlock(r) if err != nil { errCode := []byte{0, 0} errMsg := "badly formed ACK packet" tftp.SendERROR(errCode, errMsg, Conn) return } if ackBlock[1] == block[1] { break } case 5: //ERROR packet recieved _, errMsg, err := tftp.GetError(r) if err != nil { return } fmt.Println(string(errMsg), " recieved by ", LocalAddr) return } } SendLoop: for { //send Data block[1]++ tftp.SendDATA(block, data, Conn) //wait for ack LoopAck: for { select { case <-time.After(time.Second * 3): tftp.SendDATA(block, data, Conn) case <-time.After(time.Second * 15): fmt.Println("DATA packet ", string(block), " from ", LocalAddr, " never acknowledged") return case r := <-packet: switch r[1] { case 4: //ACK packet recieved ackBlock, err := tftp.GetAckBlock(r) if err != nil { errCode := []byte{0, 0} errMsg := "badly formed ACK packet" tftp.SendERROR(errCode, errMsg, Conn) return } if ackBlock[1] == block[1] { break LoopAck } case 5: //ERROR packet recieved _, errMsg, err := tftp.GetError(r) if err != nil { return } fmt.Println(string(errMsg), " recieved by ", LocalAddr) return } } } if max == len(content) { break SendLoop } //update data index += 512 max = min(index+512, len(f)) data = f[index:max] } }
func sendFullRead(filename string) (string, error) { //sends RRQ //loop: // listens for DATA with block ahead of prev ACK packet // send ACK packet for current DATA // if len(current DATA) < 512, send final ACK and close ServerAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:10001") checkError(err) LocalAddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") checkError(err) Conn, err := net.DialUDP("udp", LocalAddr, ServerAddr) checkError(err) defer Conn.Close() temp := []byte{} tftp.SendRRQ(filename, Conn) prev_block := []byte{0, 0} packet := make(chan []byte) defer close(packet) go getPacket(Conn, packet) Read: for { select { case r := <-packet: switch r[1] { case 3: //DATA packet recieved block, data, err := tftp.GetData(r) if err != nil { return "", err } if block[1] == prev_block[1]+1 { tftp.SendACK(block, Conn) prev_block[1] = block[1] temp = append(temp, data...) if len(data) < 512 { break Read } } else if block[1] != 0 { tftp.SendACK(prev_block, Conn) } // else the RRQ itself failed somehow case 5: //ERROR packet recieved _, errMsg, err := tftp.GetError(r) if err != nil { return "", err } fmt.Println(string(errMsg), " recieved by ", LocalAddr) return "", errors.New(string(errMsg)) } case <-time.After(1 * time.Second): tftp.SendACK(prev_block, Conn) case <-time.After(15 * time.Second): fmt.Println("A read request by ", LocalAddr, " timed out") return "", errors.New("rrq timed out") } } return string(temp), nil }