diff --git a/README.md b/README.md index bd28450..6a08095 100644 --- a/README.md +++ b/README.md @@ -49,15 +49,14 @@ Thus, with a connection and a way of communication, the sender will send some pa --- ## Known issues|problems|lack of features|reasons why it`s bad -- **VERY** slow; somewhat FIXED - [x], now **a little** faster than before +- **VERY** slow; somewhat FIXED - [x], now **faster** than before - **VERY** expensive on resources; somewhat FIXED - [x], no more **json manipulations**, only **raw bytes**`s wizardry ! -- If `MAXFILEDATASIZE` is bigger than appr. 1024 - the packets on the other end will not be unmarshalled due to error ??; FIXED - [x], unnecessary, wrong, deprecated, **destroyed !!!** (But now present in the other form, unfortunately) +- If `MAXFILEDATASIZE` is bigger than appr. 1024 - the packets on the other end will not be unmarshalled due to error ??; FIXED - [x], unnecessary, wrong, deprecated, **destroyed !!!** - Lack of proper error-handling; somewhat FIXED - [x] - Lack of information about the process of transferring (ETA, lost packets, etc.); FIXED - [ ] - No way to verify if the transferred file is not corrupted; FIXED via checksum- [x] - No encryption; FIXED - [ ] - Messy and hard to follow code && file structure; partially FIXED (protocol is looking fairly good rn) - [ X ] -- Lack of downloads` management; FIXED - [ ] - No way to stop the download/upload and resume it later or even during the next connection; FIXED - [ ] - No tests; FIXED - [ ] diff --git a/protocol/constants.go b/protocol/constants.go index 76e357f..98f736d 100644 --- a/protocol/constants.go +++ b/protocol/constants.go @@ -4,10 +4,7 @@ package protocol // MAXPACKETSIZE. // How many bytes can contain one packet (header + body) at maximum // (packets with size bigger than MAXPACKETSIZE are invalid and will not be sent) -const MAXPACKETSIZE uint = 1024 // the same problem as in the previous versions: if the packet is big enough - the conn.Read() -// will result in some sort of error where it does not read the intended amount of bytes (less, in fact), -// which is strange, but I guess that -// I just do something wrong in my code +const MAXPACKETSIZE uint = 10240 // 10 kilobytes // PACKETSIZEDELIMETER. // Character that delimits one and the other sides of the next incoming packet. diff --git a/protocol/packet.go b/protocol/packet.go index 4d867c0..a766ce2 100644 --- a/protocol/packet.go +++ b/protocol/packet.go @@ -118,10 +118,25 @@ func ReadFromConn(connection net.Conn) (Packet, error) { } // have a packetsize, now reading the whole packet - packetBuff := make([]byte, packetSize) - connection.Read(packetBuff) + packetBytes := new(bytes.Buffer) + + left := packetSize + for { + if left == 0 { + break + } + buff := make([]byte, 1024) + if left < len(buff) { + buff = make([]byte, left) + } + + r, _ := connection.Read(buff) + left -= r + + packetBytes.Write(buff[:r]) + } - packet := BytesToPacket(packetBuff) + packet := BytesToPacket(packetBytes.Bytes()) return packet, nil } diff --git a/receiver/file.go b/receiver/file.go index 825b03a..2226f7e 100644 --- a/receiver/file.go +++ b/receiver/file.go @@ -1,6 +1,11 @@ package receiver -import "github.com/Unbewohnte/FTU/checksum" +import ( + "fmt" + "os" + + "github.com/Unbewohnte/FTU/checksum" +) // Receiver`s file struct. Used internally by receiver type File struct { @@ -8,3 +13,18 @@ type File struct { Filesize uint64 CheckSum checksum.CheckSum } + +// Goes through all files in the downloads directory and compares their +// names with the name of the file that is about to be downloaded +func (r *Receiver) CheckIfFileAlreadyExists() (bool, error) { + contents, err := os.ReadDir(r.DownloadsFolder) + if err != nil { + return false, fmt.Errorf("could not get contents of the downloads` directory: %s", err) + } + for _, file := range contents { + if file.Name() == r.FileToDownload.Filename { + return true, nil + } + } + return false, nil +} diff --git a/receiver/receiver.go b/receiver/receiver.go index 09aab96..4b237f8 100644 --- a/receiver/receiver.go +++ b/receiver/receiver.go @@ -7,6 +7,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "github.com/Unbewohnte/FTU/checksum" "github.com/Unbewohnte/FTU/protocol" @@ -118,10 +119,35 @@ func (r *Receiver) HandleFileOffer() error { } // accept the file + // check if the file with the same name is present + doesExist, err := r.CheckIfFileAlreadyExists() + if err != nil { + return fmt.Errorf("could not check if the file with the same name alredy exists: %s", err) + } + + if doesExist { + fmt.Printf(` + | Looks like that there is a file with the same name in your downloads directory, do you want to overwrite it ? [Y/N]: `) + + fmt.Scanln(&input) + input = strings.TrimSpace(input) + input = strings.ToLower(input) + + if input == "y" { + err = os.Remove(filepath.Join(r.DownloadsFolder, r.FileToDownload.Filename)) + if err != nil { + return fmt.Errorf("could not remove the file: %s", err) + } + } else { + // user did not agree to overwrite, adding checksum to the name + r.FileToDownload.Filename = fmt.Sprint(time.Now().Unix()) + r.FileToDownload.Filename + } + } + acceptancePacket := protocol.Packet{ Header: protocol.HeaderAccept, } - err := protocol.SendPacket(r.Connection, acceptancePacket) + err = protocol.SendPacket(r.Connection, acceptancePacket) if err != nil { return fmt.Errorf("could not send an acceptance packet: %s", err) } @@ -180,7 +206,11 @@ func (r *Receiver) MainLoop() { readyPacket := protocol.Packet{ Header: protocol.HeaderReady, } - protocol.SendPacket(r.Connection, readyPacket) + err := protocol.SendPacket(r.Connection, readyPacket) + if err != nil { + fmt.Printf("Could not send the packet: %s\nExiting...", err) + r.Stop() + } r.ReadyToReceive = false } @@ -216,12 +246,23 @@ func (r *Receiver) MainLoop() { case protocol.HeaderDone: if r.FileToDownload.Filename != "" && r.FileToDownload.Filesize != 0 && r.FileToDownload.CheckSum != [32]byte{} { - r.HandleFileOffer() + err := r.HandleFileOffer() + if err != nil { + fmt.Printf("Could not handle a file download confirmation: %s\nExiting...", err) + r.Stop() + } r.ReadyToReceive = true + } else { + fmt.Println("Not enough data about the file was sent. Exiting...") + r.Stop() } case protocol.HeaderFileBytes: - r.WritePieceOfFile(incomingPacket) + err := r.WritePieceOfFile(incomingPacket) + if err != nil { + fmt.Printf("Could not write a piece of file: %s\nExiting...", err) + r.Stop() + } r.ReadyToReceive = true case protocol.HeaderDisconnecting: diff --git a/sender/ip.go b/sender/ip.go new file mode 100644 index 0000000..6060f3a --- /dev/null +++ b/sender/ip.go @@ -0,0 +1,35 @@ +package sender + +import ( + "fmt" + "io" + "net" + "net/http" +) + +// gets a local ip. Borrowed from StackOverflow, thank you, whoever I brought it from +func GetLocalIP() (string, error) { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + return "", err + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP.String(), nil +} + +// gets a remote ip. Borrowed from StackOverflow, thank you, whoever I brought it from +func GetRemoteIP() (string, error) { + resp, err := http.Get("https://api.ipify.org?format=text") + if err != nil { + return "", fmt.Errorf("could not make a request to get your remote IP: %s", err) + } + defer resp.Body.Close() + ip, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("could not read a response: %s", err) + } + return string(ip), nil +} diff --git a/sender/sender.go b/sender/sender.go index ab644f7..4da9c5d 100644 --- a/sender/sender.go +++ b/sender/sender.go @@ -2,9 +2,7 @@ package sender import ( "fmt" - "io" "net" - "net/http" "os" "strconv" @@ -12,33 +10,6 @@ import ( "github.com/Unbewohnte/FTU/protocol" ) -// gets a local ip. Borrowed from StackOverflow, thank you, whoever I brought it from -func GetLocalIP() (string, error) { - conn, err := net.Dial("udp", "8.8.8.8:80") - if err != nil { - return "", err - } - defer conn.Close() - - localAddr := conn.LocalAddr().(*net.UDPAddr) - - return localAddr.IP.String(), nil -} - -// gets a remote ip. Borrowed from StackOverflow, thank you, whoever I brought it from -func GetRemoteIP() (string, error) { - resp, err := http.Get("https://api.ipify.org?format=text") - if err != nil { - return "", fmt.Errorf("could not make a request to get your remote IP: %s", err) - } - defer resp.Body.Close() - ip, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("could not read a response: %s", err) - } - return string(ip), nil -} - // The main sender struct type Sender struct { Port int