// sendDataPacket sends the given data packet to the connected client // and waits for the correct ACK, or times out func sendDataPacket(s *Server, d *pkt.DataPacket, con *net.UDPConn) error { _, err := con.Write(d.Bytes()) if err != nil { return err } // Now wait for the ACK... maxtimeout := time.After(AckTimeout) ackch := make(chan error) // Move it to its own function go func() { ack := make([]byte, 256) for { n, _, err := con.ReadFromUDP(ack) if err != nil { ackch <- err return } pack, err := pkt.ParsePacket(ack[:n]) if err != nil { ackch <- err return } // Check packet type ackpack, ok := pack.(*pkt.AckPacket) if !ok { ackch <- pkt.ErrPacketType return } if ackpack.GetBlocknum() != d.BlockNum { s.Logger.Warning("got ack(%d) but expected ack(%d)\n", d.BlockNum, ackpack.GetBlocknum()) continue } ackch <- nil return } }() // Loop and retransmit until ack or timeout retransmit := time.After(RetransmitTime) for { select { case <-maxtimeout: return ErrTimeout case <-retransmit: s.Logger.Warning("Retransmit") _, err := con.Write(d.Bytes()) if err != nil { return err } retransmit = time.After(RetransmitTime) case err := <-ackch: return err } } }
// Serve opens up a udp socket listening on the given // address and handles incoming connections received on it func (s *Server) Serve(addr string) error { uaddr, err := net.ResolveUDPAddr("udp", addr) if err != nil { return err } uconn, err := net.ListenUDP("udp", uaddr) if err != nil { return err } for { // read in new requests buf := make([]byte, TftpMaxPacketSize) // TODO: sync.Pool n, ua, err := uconn.ReadFromUDP(buf) if err != nil { return err } s.Logger.Debug("New Connection!") buf = buf[:n] packet, err := pkt.ParsePacket(buf) if err != nil { s.Logger.Debug("Got bad packet: %s", err) continue } go s.HandleClient(ua, packet) } }
// HandleWriteRequest makes a UDP connection back to the client // and completes a TFTP Write request with them func (s *Server) HandleWriteReq(wrq *pkt.ReqPacket, addr *net.UDPAddr) error { s.Logger.Debug("Write Request: %s", wrq.Filename) // 'Our' Address listaddr, err := net.ResolveUDPAddr("udp", ":0") if err != nil { return err } // Connection directly to their open port con, err := net.DialUDP("udp", listaddr, addr) if err != nil { return err } if s.ReadOnly { errPkt := pkt.ErrorPacket{} errPkt.Value = "writing disallowed" errPkt.Code = pkt.TFTPErrAccessViolation _, err := con.Write(errPkt.Bytes()) return err } // Lol, security? What security? fi, err := s.WriteFunc(s.servdir + "/" + wrq.Filename) if err != nil { return err } // Send ACK(0) ackPkt := pkt.NewAck(0) _, err = con.Write(ackPkt.Bytes()) if err != nil { return err } curblk := uint16(1) buf := make([]byte, TftpMaxPacketSize) for { n, _, err := con.ReadFromUDP(buf) if err != nil { return err } idata, err := pkt.ParsePacket(buf[:n]) if err != nil { return err } data, ok := idata.(*pkt.DataPacket) if !ok { return ErrUnexpectedPacket } if data.BlockNum == curblk-1 { // They didnt get our ack... lets send it again ackPkt := pkt.NewAck(curblk - 1) _, err = con.Write(ackPkt.Bytes()) if err != nil { return err } continue } else if data.BlockNum != curblk { return errors.New("Received unexpected blocknum... stopping transfer.") } _, err = fi.Write(data.Data) if err != nil { return err } ackPkt := pkt.NewAck(curblk) _, err = con.Write(ackPkt.Bytes()) if err != nil { return err } if len(data.Data) < 512 { return nil } curblk++ } }