This repository has been archived on 2025-10-15. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Uftp/client.go

163 lines
3.0 KiB
Go

package main
import (
"encoding/hex"
"fmt"
"net"
"os"
"sort"
"time"
)
func GetFile(path string) {
request := NewRequest(path)
udpAddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:13374")
// udpAddr, err := net.ResolveUDPAddr("udp", "192.168.2.145:13374")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Dial to the address with UDP
conn, err := net.DialUDP("udp", nil, udpAddr)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
_, err = conn.Write(request.ToBytes())
if err != nil {
panic(err)
}
bytes := make([]byte, PacketSize)
file, err := os.Create("out/" + hex.EncodeToString(request.sid[:]) + ".recv")
if err != nil {
panic(err)
}
_, _, err = conn.ReadFrom(bytes)
if err != nil {
panic(err)
}
pck := PacketFromBytes(bytes)
if pck.flag != PTE {
panic("Header flag was supposed to be PTE")
}
size, err := pck.GetUint32Payload()
if err != nil {
panic(err)
}
file.Truncate(int64(size))
ackPck := NewAck(&pck)
conn.Write(ackPck.ToBytes())
recvPackets := make([]uint32, 0)
var endPacket Packet
for {
_, _, err = conn.ReadFrom(bytes)
if err != nil {
panic(err)
}
pck := PacketFromBytes(bytes)
if pck.flag == End {
endPacket = pck
break
}
recvPackets = append(recvPackets, pck.sync)
offset := (int64(pck.sync) - int64(ackPck.sync+1)) * (PacketSize - int64(HeaderSize))
fmt.Printf("Sync: %v, Offset: %v\n", pck.sync, offset)
_, err = file.WriteAt(pck.data, offset)
if err != nil {
panic(err)
}
}
sort.Slice(recvPackets, func(i, j int) bool {
pckI := recvPackets[i]
pckJ := recvPackets[j]
return pckI < pckJ
})
lostPackets := make([]uint32, 0)
for i := ackPck.sync + 1; i < endPacket.sync; i++ {
if b, _ := contains(recvPackets, i); !b {
lostPackets = append(lostPackets, i)
}
}
for _, i := range lostPackets {
fmt.Println(i)
}
lastPacket := ackPck
for {
if len(lostPackets) == 0 {
break
}
for _, sync := range lostPackets {
fmt.Printf("Request resend for %v\n", sync)
resend := NewResend(uint32(sync), lastPacket)
conn.Write(resend.ToBytes())
lastPacket = resend
conn.SetReadDeadline(time.Now().Add(10 * time.Second))
_, _, err = conn.ReadFrom(bytes)
if err != nil {
if e, ok := err.(net.Error); !ok || !e.Timeout() {
// If it's not a timeout, log the error as usual
panic(err)
}
continue
}
pck := PacketFromBytes(bytes)
offset := (int64(pck.sync) - int64(ackPck.sync+1)) * (PacketSize - int64(HeaderSize))
// fmt.Printf("Sync: %v, Offset: %v\n", pck.sync, offset)
_, err = file.WriteAt(pck.data, offset)
if err != nil {
panic(err)
}
_, index := contains(lostPackets, pck.sync)
fmt.Printf("Removing sync %v from LostPackets\n", pck.sync)
lostPackets = remove(lostPackets, index)
}
}
ack := NewAck(&endPacket)
conn.Write(ack.ToBytes())
}
func remove(s []uint32, i int) []uint32 {
s[i] = s[len(s)-1]
return s[:len(s)-1]
}
func contains(s []uint32, e uint32) (bool, int) {
for i, a := range s {
if a == e {
return true, i
}
}
return false, 0
}