Browse Source

Somewhat reasonable error-handling

main 1.0.1
Unbewohnte 3 years ago
parent
commit
c7b389efa6
  1. 2
      README.md
  2. 9
      client/client.go
  3. 131
      protocol/protocol.go
  4. 22
      server/server.go

2
README.md

@ -52,7 +52,7 @@ Thus, with a connection and a way of communication, the server will send a filei
- **VERY** slow; FIXED - [ ] - **VERY** slow; FIXED - [ ]
- **VERY** expensive on resources; FIXED - [ ] - **VERY** expensive on resources; FIXED - [ ]
- If `MAXFILEDATASIZE` is bigger than appr. 1024 - the packets on the other end will not be unmarshalled due to error ??; FIXED - [ ] - If `MAXFILEDATASIZE` is bigger than appr. 1024 - the packets on the other end will not be unmarshalled due to error ??; FIXED - [ ]
- Lack of proper error-handling; FIXED - [ ] - Lack of proper error-handling; somewhat FIXED - [x]
- Lack of information about the process of transferring (ETA, lost packets, etc.); FIXED - [ ] - 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 - [ ] - No way to verify if the transferred file is not corrupted; FIXED - [ ]
- No encryption; FIXED - [ ] - No encryption; FIXED - [ ]

9
client/client.go

@ -139,10 +139,11 @@ func (c *Client) WritePieceOfFile(filePacket protocol.Packet) error {
// Listens in an endless loop; reads incoming packages and puts them into channel // Listens in an endless loop; reads incoming packages and puts them into channel
func (c *Client) ReceivePackets() { func (c *Client) ReceivePackets() {
for { for {
incomingPacket := protocol.ReadFromConn(c.Connection) incomingPacket, err := protocol.ReadFromConn(c.Connection)
isvalid, _ := protocol.IsValidPacket(incomingPacket) if err != nil {
if !isvalid { // in current implementation there is no way to receive a working file even if only one packet is missing
continue fmt.Printf("Error reading a packet: %s\nExiting...", err)
os.Exit(-1)
} }
c.IncomingPackets <- incomingPacket c.IncomingPackets <- incomingPacket
} }

131
protocol/protocol.go

@ -34,39 +34,40 @@ type Packet struct {
} }
// converts valid packet bytes into `Packet` struct // converts valid packet bytes into `Packet` struct
func ReadPacketBytes(packetBytes []byte) Packet { func ReadPacketBytes(packetBytes []byte) (Packet, error) {
// makes sure that the packet is ALWAYS less or equal to the maximum packet size
// this allows not to use any client or server checks
//fmt.Println("READING packet: ", string(packetBytes))
var packet Packet var packet Packet
err := json.Unmarshal(packetBytes, &packet) err := json.Unmarshal(packetBytes, &packet)
if err != nil { if err != nil {
fmt.Printf("Could not unmarshal the packet: %s\n", err) return Packet{}, fmt.Errorf("could not unmarshal packet bytes: %s", err)
return Packet{}
} }
return packet return packet, nil
} }
// Converts `Packet` struct into []byte // Converts `Packet` struct into []byte
func EncodePacket(packet Packet) []byte { func EncodePacket(packet Packet) ([]byte, error) {
packetBytes, err := json.Marshal(packet) packetBytes, err := json.Marshal(packet)
if err != nil { if err != nil {
return []byte("") return nil, fmt.Errorf("could not marshal packet bytes: %s", err)
} }
return packetBytes return packetBytes, nil
} }
// Measures the packet length // Measures the packet length
func MeasurePacket(packet Packet) uint64 { func MeasurePacket(packet Packet) (uint64, error) {
packetBytes := EncodePacket(packet) packetBytes, err := EncodePacket(packet)
return uint64(len(packetBytes)) if err != nil {
return 0, fmt.Errorf("could not measure the packet: %s", err)
}
return uint64(len(packetBytes)), nil
} }
// Checks if given packet is valid, returns a boolean and an explanation message // Checks if given packet is valid, returns a boolean and an explanation message
func IsValidPacket(packet Packet) (bool, string) { func IsValidPacket(packet Packet) (bool, string) {
if MeasurePacket(packet) > uint64(MAXPACKETSIZE) { packetSize, err := MeasurePacket(packet)
if err != nil {
return false, "Measurement error"
}
if packetSize > uint64(MAXPACKETSIZE) {
return false, "Exceeded MAXPACKETSIZE" return false, "Exceeded MAXPACKETSIZE"
} }
if len(packet.FileData) > MAXFILEDATASIZE { if len(packet.FileData) > MAXFILEDATASIZE {
@ -74,7 +75,7 @@ func IsValidPacket(packet Packet) (bool, string) {
} }
if strings.TrimSpace(string(packet.Header)) == "" { if strings.TrimSpace(string(packet.Header)) == "" {
return false, "Blank header" return false, "Empty header"
} }
return true, "" return true, ""
} }
@ -87,69 +88,77 @@ func SendPacket(connection net.Conn, packet Packet) error {
return fmt.Errorf("this packet is invalid !: %v; The error: %v", packet, msg) return fmt.Errorf("this packet is invalid !: %v; The error: %v", packet, msg)
} }
packetSize := MeasurePacket(packet) packetSize, err := MeasurePacket(packet)
if err != nil {
return err
}
// write packetsize between delimeters (ie: |727|{"HEADER":"PING"...}) // write packetsize between delimeters (ie: |727|{"HEADER":"PING"...})
connection.Write([]byte(fmt.Sprintf("%s%d%s", PACKETSIZEDELIMETER, packetSize, PACKETSIZEDELIMETER))) connection.Write([]byte(fmt.Sprintf("%s%d%s", PACKETSIZEDELIMETER, packetSize, PACKETSIZEDELIMETER)))
// write an actual packet // write the packet itself
connection.Write(EncodePacket(packet)) packetBytes, err := EncodePacket(packet)
if err != nil {
return fmt.Errorf("could not send a packet: %s", err)
}
connection.Write(packetBytes)
//fmt.Println("Sending packet: ", string(EncodePacket(packet)), " Length: ", packetSize)
return nil return nil
} }
// Reads a packet from a connection by retrieving the packet length. Only once // Reads a packet from given connection.
// ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` method !!!! // ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!!
func ReadFromConn(connection net.Conn) Packet { func ReadFromConn(connection net.Conn) (Packet, error) {
var gotPacketSize bool = false var err error
var delimeterCounter int = 0 var delimeterCounter int = 0
var packetSizeStrBuffer string = ""
var packetSizeStr string = ""
var packetSize int = 0 var packetSize int = 0
for { for {
// still need to get a packetsize // reading byte-by-byte
if !gotPacketSize { buffer := make([]byte, 1)
// reading byte-by-byte connection.Read(buffer) // no fixed time limit, so no need to check for an error
buffer := make([]byte, 1)
connection.Read(buffer) // found a delimeter
if string(buffer) == PACKETSIZEDELIMETER {
// found a delimeter delimeterCounter++
if string(buffer) == PACKETSIZEDELIMETER {
delimeterCounter++
// the first delimeter is found, skipping the rest of the code
if delimeterCounter == 1 {
continue
}
}
// found the first delimeter, skip was performed, now reading an actual packetsize // the first delimeter has been found, skipping the rest of the loop
if delimeterCounter == 1 { if delimeterCounter == 1 {
packetSizeStr += string(buffer) continue
} else if delimeterCounter == 2 {
// found the last delimeter, thus already read the whole packetsize
packetSize, _ = strconv.Atoi(packetSizeStr)
gotPacketSize = true
} }
// skipping the rest of the code because we don`t know the packet size yet
continue
} }
// have a packetsize, now reading the whole packet
//fmt.Println("Got a packetsize!: ", packetSize) // found the first delimeter, skip was performed, now reading an actual packetsize
packetBuffer := make([]byte, packetSize) if delimeterCounter == 1 {
connection.Read(packetBuffer) // adding a character of the packet size to the `string buffer`; ie: | <- read, reading now -> 1 23|PACKET_HERE
packetSizeStrBuffer += string(buffer)
} else if delimeterCounter == 2 {
// found the last delimeter, thus already read the whole packetsize
// converting from string to int
packetSize, err = strconv.Atoi(packetSizeStrBuffer)
if err != nil {
return Packet{}, fmt.Errorf("could not convert packet size into integer: %s", err)
}
// packet size has been found, breaking from the loop
break
}
}
packet := ReadPacketBytes(packetBuffer) // have a packetsize, now reading the whole packet
packetBuffer := make([]byte, packetSize)
connection.Read(packetBuffer)
isvalid, _ := IsValidPacket(packet) packet, err := ReadPacketBytes(packetBuffer)
if isvalid { if err != nil {
return packet return Packet{}, err
} }
break isvalid, msg := IsValidPacket(packet)
if isvalid {
return packet, nil
} }
return Packet{} return Packet{}, fmt.Errorf("received an invalid packet. Reason: %s", msg)
} }

22
server/server.go

@ -5,6 +5,7 @@ import (
"io" "io"
"net" "net"
"net/http" "net/http"
"os"
"github.com/Unbewohnte/FTU/protocol" "github.com/Unbewohnte/FTU/protocol"
) )
@ -19,7 +20,7 @@ func GetLocalIP() (string, error) {
localAddr := conn.LocalAddr().(*net.UDPAddr) localAddr := conn.LocalAddr().(*net.UDPAddr)
return string(localAddr.IP), nil return localAddr.IP.String(), nil
} }
// gets a remote ip. Borrowed from StackOverflow, thank you, whoever I brought it from // gets a remote ip. Borrowed from StackOverflow, thank you, whoever I brought it from
@ -100,15 +101,14 @@ func (s *Server) Disconnect() {
} }
// Accepts one connection // Accepts one connection
func (s *Server) WaitForConnection() error { func (s *Server) WaitForConnection() {
connection, err := s.Listener.Accept() connection, err := s.Listener.Accept()
if err != nil { if err != nil {
return fmt.Errorf("could not accept a connection: %s", err) fmt.Printf("Could not accept a connection: %s", err)
os.Exit(-1)
} }
s.Connection = connection s.Connection = connection
fmt.Println("New connection from ", s.Connection.RemoteAddr()) fmt.Println("New connection from ", s.Connection.RemoteAddr())
return nil
} }
// Closes the listener. Used only when there is still no connection from `AcceptConnections` // Closes the listener. Used only when there is still no connection from `AcceptConnections`
@ -174,10 +174,11 @@ func (s *Server) SendPiece() error {
// Listens in an endless loop; reads incoming packages and puts them into channel // Listens in an endless loop; reads incoming packages and puts them into channel
func (s *Server) ReceivePackets() { func (s *Server) ReceivePackets() {
for { for {
incomingPacket := protocol.ReadFromConn(s.Connection) incomingPacket, err := protocol.ReadFromConn(s.Connection)
isvalid, _ := protocol.IsValidPacket(incomingPacket) if err != nil {
if !isvalid { // in current implementation there is no way to receive a working file even if only one packet is missing
continue fmt.Printf("Error reading a packet: %s\nExiting...", err)
os.Exit(-1)
} }
s.IncomingPackets <- incomingPacket s.IncomingPackets <- incomingPacket
} }
@ -226,7 +227,8 @@ func (s *Server) MainLoop() {
} }
err := s.SendPiece() err := s.SendPiece()
if err != nil { if err != nil {
fmt.Println(err) fmt.Printf("Could not send a piece of file: %s", err)
os.Exit(-1)
} }
case protocol.HeaderDisconnecting: case protocol.HeaderDisconnecting:

Loading…
Cancel
Save