Unbewohnte
3 years ago
13 changed files with 649 additions and 487 deletions
@ -1,51 +1,45 @@ |
|||||||
package node |
package node |
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"os" |
|
||||||
"testing" |
|
||||||
) |
|
||||||
|
|
||||||
// Not complete
|
// Not complete
|
||||||
func Test_Sendfile(t *testing.T) { |
// func Test_Sendfile(t *testing.T) {
|
||||||
rnodeOptions := NodeOptions{ |
// rnodeOptions := NodeOptions{
|
||||||
IsSending: false, |
// IsSending: false,
|
||||||
WorkingPort: 8888, |
// WorkingPort: 8888,
|
||||||
ServerSide: &ServerSideNodeOptions{ |
// ServerSide: &ServerSideNodeOptions{
|
||||||
ServingPath: "", |
// ServingPath: "",
|
||||||
Recursive: false, |
// Recursive: false,
|
||||||
}, |
// },
|
||||||
ClientSide: &ClientSideNodeOptions{ |
// ClientSide: &ClientSideNodeOptions{
|
||||||
ConnectionAddr: "localhost", |
// ConnectionAddr: "localhost",
|
||||||
DownloadsFolderPath: "../testfiles/testDownload/", |
// DownloadsFolderPath: "../testfiles/testDownload/",
|
||||||
}, |
// },
|
||||||
} |
// }
|
||||||
receivingNode, err := NewNode(&rnodeOptions) |
// receivingNode, err := NewNode(&rnodeOptions)
|
||||||
if err != nil { |
// if err != nil {
|
||||||
fmt.Printf("Error constructing a new node: %s\n", err) |
// fmt.Printf("Error constructing a new node: %s\n", err)
|
||||||
os.Exit(-1) |
// os.Exit(-1)
|
||||||
} |
// }
|
||||||
|
|
||||||
snodeOptions := NodeOptions{ |
// snodeOptions := NodeOptions{
|
||||||
IsSending: true, |
// IsSending: true,
|
||||||
WorkingPort: 8888, |
// WorkingPort: 8888,
|
||||||
ServerSide: &ServerSideNodeOptions{ |
// ServerSide: &ServerSideNodeOptions{
|
||||||
ServingPath: "../testfiles/testfile.txt", |
// ServingPath: "../testfiles/testfile.txt",
|
||||||
Recursive: false, |
// Recursive: false,
|
||||||
}, |
// },
|
||||||
ClientSide: &ClientSideNodeOptions{ |
// ClientSide: &ClientSideNodeOptions{
|
||||||
ConnectionAddr: "", |
// ConnectionAddr: "",
|
||||||
DownloadsFolderPath: "", |
// DownloadsFolderPath: "",
|
||||||
}, |
// },
|
||||||
} |
// }
|
||||||
|
|
||||||
sendingNode, err := NewNode(&snodeOptions) |
// sendingNode, err := NewNode(&snodeOptions)
|
||||||
if err != nil { |
// if err != nil {
|
||||||
fmt.Printf("Error constructing a new node: %s\n", err) |
// fmt.Printf("Error constructing a new node: %s\n", err)
|
||||||
os.Exit(-1) |
// os.Exit(-1)
|
||||||
} |
// }
|
||||||
|
|
||||||
go receivingNode.Start() |
// go receivingNode.Start()
|
||||||
|
|
||||||
sendingNode.Start() |
// sendingNode.Start()
|
||||||
} |
// }
|
||||||
|
@ -1,122 +0,0 @@ |
|||||||
// node-specific packets and packet handling
|
|
||||||
package node |
|
||||||
|
|
||||||
import ( |
|
||||||
"bytes" |
|
||||||
"encoding/binary" |
|
||||||
"fmt" |
|
||||||
"net" |
|
||||||
|
|
||||||
"github.com/Unbewohnte/ftu/fsys" |
|
||||||
"github.com/Unbewohnte/ftu/protocol" |
|
||||||
) |
|
||||||
|
|
||||||
// sends an encryption key to the other side
|
|
||||||
func sendEncryptionKey(connection net.Conn, encrKey []byte) error { |
|
||||||
encrKeyPacketBuffer := new(bytes.Buffer) |
|
||||||
|
|
||||||
encrKeyLength := uint64(len(encrKey)) |
|
||||||
|
|
||||||
err := binary.Write(encrKeyPacketBuffer, binary.BigEndian, &encrKeyLength) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
encrKeyPacketBuffer.Write(encrKey) |
|
||||||
|
|
||||||
err = protocol.SendPacket(connection, protocol.Packet{ |
|
||||||
Header: protocol.HeaderEncryptionKey, |
|
||||||
Body: encrKeyPacketBuffer.Bytes(), |
|
||||||
}) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
var ErrorNotConnected error = fmt.Errorf("not connected") |
|
||||||
|
|
||||||
// Reads packets from connection in an endless loop, sends them to the channel, if encrKey is not nil -
|
|
||||||
// decrypts packet`s body beforehand
|
|
||||||
func receivePackets(connection net.Conn, packetPipe chan *protocol.Packet) error { |
|
||||||
for { |
|
||||||
if connection == nil { |
|
||||||
return ErrorNotConnected |
|
||||||
} |
|
||||||
|
|
||||||
packetBytes, err := protocol.ReadFromConn(connection) |
|
||||||
if err != nil { |
|
||||||
close(packetPipe) |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
incomingPacket, err := protocol.BytesToPacket(packetBytes) |
|
||||||
if err != nil { |
|
||||||
close(packetPipe) |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
packetPipe <- incomingPacket |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// decodes packet with the header FILE into the fsys.File struct. If encrKey is not nil -
|
|
||||||
// filepacket`s body will be decrypted beforehand
|
|
||||||
func decodeFilePacket(filePacket *protocol.Packet) (*fsys.File, error) { |
|
||||||
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum
|
|
||||||
|
|
||||||
// retrieve data from packet body
|
|
||||||
|
|
||||||
// id
|
|
||||||
packetReader := bytes.NewBuffer(filePacket.Body) |
|
||||||
|
|
||||||
var fileID uint64 |
|
||||||
err := binary.Read(packetReader, binary.BigEndian, &fileID) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
|
|
||||||
// filename
|
|
||||||
var filenameLength uint64 |
|
||||||
err = binary.Read(packetReader, binary.BigEndian, &filenameLength) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
|
|
||||||
filenameBytes := make([]byte, filenameLength) |
|
||||||
_, err = packetReader.Read(filenameBytes) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
|
|
||||||
filename := string(filenameBytes) |
|
||||||
|
|
||||||
// filesize
|
|
||||||
var filesize uint64 |
|
||||||
err = binary.Read(packetReader, binary.BigEndian, &filesize) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
|
|
||||||
// checksum
|
|
||||||
var checksumLength uint64 |
|
||||||
err = binary.Read(packetReader, binary.BigEndian, &checksumLength) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
checksumBytes := make([]byte, checksumLength) |
|
||||||
_, err = packetReader.Read(checksumBytes) |
|
||||||
if err != nil { |
|
||||||
panic(err) |
|
||||||
} |
|
||||||
checksum := string(checksumBytes) |
|
||||||
|
|
||||||
return &fsys.File{ |
|
||||||
ID: fileID, |
|
||||||
Name: filename, |
|
||||||
Size: filesize, |
|
||||||
Checksum: checksum, |
|
||||||
Handler: nil, |
|
||||||
}, nil |
|
||||||
} |
|
@ -1,209 +0,0 @@ |
|||||||
package node |
|
||||||
|
|
||||||
import ( |
|
||||||
"bytes" |
|
||||||
"encoding/binary" |
|
||||||
"fmt" |
|
||||||
"io" |
|
||||||
"net" |
|
||||||
"os" |
|
||||||
|
|
||||||
"github.com/Unbewohnte/ftu/checksum" |
|
||||||
"github.com/Unbewohnte/ftu/fsys" |
|
||||||
"github.com/Unbewohnte/ftu/protocol" |
|
||||||
) |
|
||||||
|
|
||||||
// sends a notification about the file to the other side. If encrKey is not nil - encrypts packet`s body
|
|
||||||
func sendFilePacket(connection net.Conn, file *fsys.File, encrKey []byte) error { |
|
||||||
if connection == nil { |
|
||||||
return ErrorNotConnected |
|
||||||
} |
|
||||||
|
|
||||||
err := file.Open() |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)(checksum)
|
|
||||||
|
|
||||||
// send file packet with file description
|
|
||||||
filePacket := protocol.Packet{ |
|
||||||
Header: protocol.HeaderFile, |
|
||||||
} |
|
||||||
fPacketBodyBuff := new(bytes.Buffer) |
|
||||||
|
|
||||||
// file id
|
|
||||||
binary.Write(fPacketBodyBuff, binary.BigEndian, &file.ID) |
|
||||||
|
|
||||||
// filename
|
|
||||||
filenameLen := uint64(len([]byte(file.Name))) |
|
||||||
binary.Write(fPacketBodyBuff, binary.BigEndian, &filenameLen) |
|
||||||
fPacketBodyBuff.Write([]byte(file.Name)) |
|
||||||
|
|
||||||
// size
|
|
||||||
binary.Write(fPacketBodyBuff, binary.BigEndian, &file.Size) |
|
||||||
|
|
||||||
// checksum
|
|
||||||
fileChecksum, err := checksum.GetPartialCheckSum(file.Handler) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
checksumLen := uint64(len([]byte(fileChecksum))) |
|
||||||
binary.Write(fPacketBodyBuff, binary.BigEndian, &checksumLen) |
|
||||||
fPacketBodyBuff.Write([]byte(fileChecksum)) |
|
||||||
|
|
||||||
filePacket.Body = fPacketBodyBuff.Bytes() |
|
||||||
|
|
||||||
if encrKey != nil { |
|
||||||
// if the key is given - encrypt ready-to-go packet
|
|
||||||
err = filePacket.EncryptBody(encrKey) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// and send it
|
|
||||||
err = protocol.SendPacket(connection, filePacket) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// we do not check for packet size because there is no way that it`ll exceed current
|
|
||||||
// maximum of 128 KiB
|
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
// sends a notification about the directory. If encrkey != nil - encrypts
|
|
||||||
// packet`s body
|
|
||||||
func sendDirectoryPacket(connection net.Conn, dir *fsys.Directory, encrKey []byte) error { |
|
||||||
if connection == nil { |
|
||||||
return ErrorNotConnected |
|
||||||
} |
|
||||||
|
|
||||||
dirPacket := protocol.Packet{ |
|
||||||
Header: protocol.HeaderDirectory, |
|
||||||
} |
|
||||||
|
|
||||||
// DIRECTORY~(dirname size in binary)(dirname)(dirsize)(checksumLengthInBinary)(checksum)
|
|
||||||
|
|
||||||
dirPacketBuffer := new(bytes.Buffer) |
|
||||||
|
|
||||||
// dirname
|
|
||||||
dirnameLength := uint64(len(dir.Name)) |
|
||||||
err := binary.Write(dirPacketBuffer, binary.BigEndian, &dirnameLength) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
dirPacketBuffer.Write([]byte(dir.Name)) |
|
||||||
|
|
||||||
// dirsize
|
|
||||||
err = binary.Write(dirPacketBuffer, binary.BigEndian, dir.Size) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// checksum
|
|
||||||
checksumLength := uint64(len(dir.Checksum)) |
|
||||||
err = binary.Write(dirPacketBuffer, binary.BigEndian, &checksumLength) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
dirPacketBuffer.Write([]byte(dir.Checksum)) |
|
||||||
|
|
||||||
dirPacket.Body = dirPacketBuffer.Bytes() |
|
||||||
|
|
||||||
if encrKey != nil { |
|
||||||
// if the key is given - encrypt ready-to-go packet
|
|
||||||
err = dirPacket.EncryptBody(encrKey) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// and send it
|
|
||||||
err = protocol.SendPacket(connection, dirPacket) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// we do not check for packet size because there is no way that it`ll exceed current
|
|
||||||
// maximum of 128 KiB
|
|
||||||
return nil |
|
||||||
} |
|
||||||
|
|
||||||
var ErrorSentAll error = fmt.Errorf("sent the whole file") |
|
||||||
|
|
||||||
// sends a piece of file to the connection; The next calls will send
|
|
||||||
// another piece util the file has been fully sent. If encrKey is not nil - encrypts each packet with
|
|
||||||
// this key
|
|
||||||
func sendPiece(file *fsys.File, connection net.Conn, encrKey []byte) error { |
|
||||||
if file.Handler == nil { |
|
||||||
fHandler, err := os.Open(file.Path) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
file.Handler = fHandler |
|
||||||
} |
|
||||||
|
|
||||||
if file.SentBytes == 0 { |
|
||||||
file.Handler.Seek(0, io.SeekStart) |
|
||||||
} |
|
||||||
|
|
||||||
if file.Size == file.SentBytes { |
|
||||||
return ErrorSentAll |
|
||||||
} |
|
||||||
|
|
||||||
fileBytesPacket := protocol.Packet{ |
|
||||||
Header: protocol.HeaderFileBytes, |
|
||||||
} |
|
||||||
|
|
||||||
packetBodyBuff := new(bytes.Buffer) |
|
||||||
|
|
||||||
// write file ID first
|
|
||||||
err := binary.Write(packetBodyBuff, binary.BigEndian, &file.ID) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
// fill the remaining space of packet with the contents of a file
|
|
||||||
canSendBytes := uint64(protocol.MAXPACKETSIZE) - fileBytesPacket.Size() - uint64(packetBodyBuff.Len()) |
|
||||||
|
|
||||||
if encrKey != nil { |
|
||||||
// account for padding
|
|
||||||
canSendBytes -= 32 |
|
||||||
} |
|
||||||
|
|
||||||
if (file.Size - file.SentBytes) < canSendBytes { |
|
||||||
canSendBytes = (file.Size - file.SentBytes) |
|
||||||
} |
|
||||||
|
|
||||||
fileBytes := make([]byte, canSendBytes) |
|
||||||
|
|
||||||
read, err := file.Handler.ReadAt(fileBytes, int64(file.SentBytes)) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
packetBodyBuff.Write(fileBytes) |
|
||||||
|
|
||||||
fileBytesPacket.Body = packetBodyBuff.Bytes() |
|
||||||
|
|
||||||
if encrKey != nil { |
|
||||||
err = fileBytesPacket.EncryptBody(encrKey) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// send it to the other side
|
|
||||||
err = protocol.SendPacket(connection, fileBytesPacket) |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
|
|
||||||
file.SentBytes += uint64(read) |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
@ -0,0 +1,84 @@ |
|||||||
|
// Methods to construct various packets defined in a protocol
|
||||||
|
package protocol |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/binary" |
||||||
|
|
||||||
|
"github.com/Unbewohnte/ftu/checksum" |
||||||
|
"github.com/Unbewohnte/ftu/fsys" |
||||||
|
) |
||||||
|
|
||||||
|
// constructs a ready to send FILE packet
|
||||||
|
func CreateFilePacket(file *fsys.File) (*Packet, error) { |
||||||
|
err := file.Open() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
defer file.Handler.Close() |
||||||
|
|
||||||
|
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)(checksum)
|
||||||
|
|
||||||
|
filePacket := Packet{ |
||||||
|
Header: HeaderFile, |
||||||
|
} |
||||||
|
fPacketBodyBuff := new(bytes.Buffer) |
||||||
|
|
||||||
|
// file id
|
||||||
|
binary.Write(fPacketBodyBuff, binary.BigEndian, &file.ID) |
||||||
|
|
||||||
|
// filename
|
||||||
|
filenameLen := uint64(len([]byte(file.Name))) |
||||||
|
binary.Write(fPacketBodyBuff, binary.BigEndian, &filenameLen) |
||||||
|
fPacketBodyBuff.Write([]byte(file.Name)) |
||||||
|
|
||||||
|
// size
|
||||||
|
binary.Write(fPacketBodyBuff, binary.BigEndian, &file.Size) |
||||||
|
|
||||||
|
// checksum
|
||||||
|
fileChecksum, err := checksum.GetPartialCheckSum(file.Handler) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
checksumLen := uint64(len([]byte(fileChecksum))) |
||||||
|
binary.Write(fPacketBodyBuff, binary.BigEndian, &checksumLen) |
||||||
|
fPacketBodyBuff.Write([]byte(fileChecksum)) |
||||||
|
|
||||||
|
filePacket.Body = fPacketBodyBuff.Bytes() |
||||||
|
|
||||||
|
// we do not check for packet size because there is no way that it`ll exceed current
|
||||||
|
// maximum of 128 KiB
|
||||||
|
return &filePacket, nil |
||||||
|
} |
||||||
|
|
||||||
|
// constructs a ready to send DIRECTORY packet
|
||||||
|
func CreateDirectoryPacket(dir *fsys.Directory) (*Packet, error) { |
||||||
|
dirPacket := Packet{ |
||||||
|
Header: HeaderDirectory, |
||||||
|
} |
||||||
|
|
||||||
|
// DIRECTORY~(dirname size in binary)(dirname)(dirsize)(checksumLengthInBinary)(checksum)
|
||||||
|
|
||||||
|
dirPacketBuffer := new(bytes.Buffer) |
||||||
|
|
||||||
|
// dirname
|
||||||
|
dirnameLength := uint64(len(dir.Name)) |
||||||
|
err := binary.Write(dirPacketBuffer, binary.BigEndian, &dirnameLength) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
dirPacketBuffer.Write([]byte(dir.Name)) |
||||||
|
|
||||||
|
// dirsize
|
||||||
|
err = binary.Write(dirPacketBuffer, binary.BigEndian, dir.Size) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
dirPacket.Body = dirPacketBuffer.Bytes() |
||||||
|
|
||||||
|
// we do not check for packet size because there is no way that it`ll exceed current
|
||||||
|
// maximum of 128 KiB
|
||||||
|
return &dirPacket, nil |
||||||
|
} |
@ -0,0 +1,154 @@ |
|||||||
|
// Methods to decode read from connection packets defined in protocol
|
||||||
|
package protocol |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/binary" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/Unbewohnte/ftu/fsys" |
||||||
|
) |
||||||
|
|
||||||
|
var ErrorWrongPacket error = fmt.Errorf("wrong type of packet header") |
||||||
|
|
||||||
|
// decodes packet with the header FILE into the fsys.File struct
|
||||||
|
func DecodeFilePacket(filePacket *Packet) (*fsys.File, error) { |
||||||
|
if filePacket.Header != HeaderFile { |
||||||
|
return nil, ErrorWrongPacket |
||||||
|
} |
||||||
|
// FILE~(idInBinary)(filenameLengthInBinary)(filename)(filesize)(checksumLengthInBinary)checksum
|
||||||
|
|
||||||
|
// retrieve data from packet body
|
||||||
|
|
||||||
|
// id
|
||||||
|
packetReader := bytes.NewBuffer(filePacket.Body) |
||||||
|
|
||||||
|
var fileID uint64 |
||||||
|
err := binary.Read(packetReader, binary.BigEndian, &fileID) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// filename
|
||||||
|
var filenameLength uint64 |
||||||
|
err = binary.Read(packetReader, binary.BigEndian, &filenameLength) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
filenameBytes := make([]byte, filenameLength) |
||||||
|
_, err = packetReader.Read(filenameBytes) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
filename := string(filenameBytes) |
||||||
|
|
||||||
|
// filesize
|
||||||
|
var filesize uint64 |
||||||
|
err = binary.Read(packetReader, binary.BigEndian, &filesize) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// checksum
|
||||||
|
var checksumLength uint64 |
||||||
|
err = binary.Read(packetReader, binary.BigEndian, &checksumLength) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
checksumBytes := make([]byte, checksumLength) |
||||||
|
_, err = packetReader.Read(checksumBytes) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
checksum := string(checksumBytes) |
||||||
|
|
||||||
|
return &fsys.File{ |
||||||
|
ID: fileID, |
||||||
|
Name: filename, |
||||||
|
Size: filesize, |
||||||
|
Checksum: checksum, |
||||||
|
Handler: nil, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// decodes DIRECTORY packet into fsys.Directory struct
|
||||||
|
func DecodeDirectoryPacket(dirPacket *Packet) (*fsys.Directory, error) { |
||||||
|
if dirPacket.Header != HeaderDirectory { |
||||||
|
return nil, ErrorWrongPacket |
||||||
|
} |
||||||
|
|
||||||
|
// DIRECTORY~(dirname size in binary)(dirname)(dirsize)
|
||||||
|
|
||||||
|
packetReader := bytes.NewReader(dirPacket.Body) |
||||||
|
|
||||||
|
// name
|
||||||
|
var dirNameSize uint64 |
||||||
|
err := binary.Read(packetReader, binary.BigEndian, &dirNameSize) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
dirName := make([]byte, dirNameSize) |
||||||
|
_, err = packetReader.Read(dirName) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// size
|
||||||
|
var dirSize uint64 |
||||||
|
err = binary.Read(packetReader, binary.BigEndian, &dirSize) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
dir := fsys.Directory{ |
||||||
|
Name: string(dirName), |
||||||
|
Size: dirSize, |
||||||
|
} |
||||||
|
|
||||||
|
return &dir, nil |
||||||
|
} |
||||||
|
|
||||||
|
// decodes TRANSFERINFO packet into either fsys.File or fsys.Directory struct.
|
||||||
|
// decodeTransferPacket cannot return 2 nils or both non-nils as 2 first return values in case
|
||||||
|
// of a successfull decoding
|
||||||
|
func DecodeTransferPacket(transferPacket *Packet) (*fsys.File, *fsys.Directory, error) { |
||||||
|
if transferPacket.Header != HeaderTransferOffer { |
||||||
|
return nil, nil, ErrorWrongPacket |
||||||
|
} |
||||||
|
|
||||||
|
var file *fsys.File = nil |
||||||
|
var dir *fsys.Directory = nil |
||||||
|
var err error |
||||||
|
|
||||||
|
// determine if it`s a file or a directory
|
||||||
|
switch string(transferPacket.Body[0]) { |
||||||
|
case FILECODE: |
||||||
|
filePacket := Packet{ |
||||||
|
Header: HeaderFile, |
||||||
|
Body: transferPacket.Body[1:], |
||||||
|
} |
||||||
|
|
||||||
|
file, err = DecodeFilePacket(&filePacket) |
||||||
|
if err != nil { |
||||||
|
return nil, nil, err |
||||||
|
} |
||||||
|
|
||||||
|
case DIRCODE: |
||||||
|
dirPacket := Packet{ |
||||||
|
Header: HeaderDirectory, |
||||||
|
Body: transferPacket.Body[1:], |
||||||
|
} |
||||||
|
|
||||||
|
dir, err = DecodeDirectoryPacket(&dirPacket) |
||||||
|
if err != nil { |
||||||
|
return nil, nil, err |
||||||
|
} |
||||||
|
|
||||||
|
default: |
||||||
|
return nil, nil, ErrorInvalidPacket |
||||||
|
} |
||||||
|
|
||||||
|
return file, dir, nil |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
// Methods allowing to receive and preprocess packets from connection
|
||||||
|
package protocol |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/binary" |
||||||
|
"fmt" |
||||||
|
"net" |
||||||
|
) |
||||||
|
|
||||||
|
// Reads a packet from given connection, returns its bytes.
|
||||||
|
// ASSUMING THAT THE PACKETS ARE SENT BY `SendPacket` function !!!!
|
||||||
|
func ReadFromConn(connection net.Conn) ([]byte, error) { |
||||||
|
var packetSize uint64 |
||||||
|
err := binary.Read(connection, binary.BigEndian, &packetSize) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// have a packetsize, now reading the whole packet
|
||||||
|
packetBuffer := new(bytes.Buffer) |
||||||
|
|
||||||
|
// splitting a big-sized packet into chunks and constructing it from pieces
|
||||||
|
left := packetSize |
||||||
|
for { |
||||||
|
if left == 0 { |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
buff := make([]byte, 8192) |
||||||
|
if left < uint64(len(buff)) { |
||||||
|
buff = make([]byte, left) |
||||||
|
} |
||||||
|
|
||||||
|
read, _ := connection.Read(buff) |
||||||
|
left -= uint64(read) |
||||||
|
|
||||||
|
packetBuffer.Write(buff[:read]) |
||||||
|
} |
||||||
|
|
||||||
|
// fmt.Printf("[RECV] read from connection: %s; length: %d\n", packetBuffer.Bytes()[:30], packetBuffer.Len())
|
||||||
|
|
||||||
|
return packetBuffer.Bytes(), nil |
||||||
|
} |
||||||
|
|
||||||
|
var ErrorNotConnected error = fmt.Errorf("not connected") |
||||||
|
|
||||||
|
// Reads packets from connection in an endless loop, sends them to the channel
|
||||||
|
func ReceivePackets(connection net.Conn, packetPipe chan *Packet) error { |
||||||
|
for { |
||||||
|
if connection == nil { |
||||||
|
return ErrorNotConnected |
||||||
|
} |
||||||
|
|
||||||
|
packetBytes, err := ReadFromConn(connection) |
||||||
|
if err != nil { |
||||||
|
close(packetPipe) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
incomingPacket, err := BytesToPacket(packetBytes) |
||||||
|
if err != nil { |
||||||
|
close(packetPipe) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
packetPipe <- incomingPacket |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,189 @@ |
|||||||
|
// Methonds to send packets in various ways defined in protocol
|
||||||
|
package protocol |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/binary" |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"net" |
||||||
|
|
||||||
|
"github.com/Unbewohnte/ftu/encryption" |
||||||
|
"github.com/Unbewohnte/ftu/fsys" |
||||||
|
) |
||||||
|
|
||||||
|
// Sends given packet to connection.
|
||||||
|
// ALL packets MUST be sent by this method
|
||||||
|
func SendPacket(connection net.Conn, packet Packet) error { |
||||||
|
packetBytes, err := packet.ToBytes() |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// fmt.Printf("[SEND] packet %+s; len: %d\n", packetBytes[:30], len(packetBytes))
|
||||||
|
|
||||||
|
// write the result (ie: (packetsize)(header)~(bodybytes))
|
||||||
|
connection.Write(packetBytes) |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// sends an encryption key to the other side
|
||||||
|
func SendEncryptionKey(connection net.Conn, encrKey []byte) error { |
||||||
|
encrKeyPacketBuffer := new(bytes.Buffer) |
||||||
|
|
||||||
|
encrKeyLength := uint64(len(encrKey)) |
||||||
|
|
||||||
|
err := binary.Write(encrKeyPacketBuffer, binary.BigEndian, &encrKeyLength) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
encrKeyPacketBuffer.Write(encrKey) |
||||||
|
|
||||||
|
err = SendPacket(connection, Packet{ |
||||||
|
Header: HeaderEncryptionKey, |
||||||
|
Body: encrKeyPacketBuffer.Bytes(), |
||||||
|
}) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// sends a TRANSFEROFFER packet to connection with information about either file or directory.
|
||||||
|
// If file is the only thing that the sender is going to send - leave dir arg as nil, the same
|
||||||
|
// applies if directory is the only thing that the sender is going to send - leave file as nil.
|
||||||
|
// sendTransferOffer PANICS if both file and dir are present or nil. If encrKey != nil - encrypts
|
||||||
|
// constructed packet
|
||||||
|
func SendTransferOffer(connection net.Conn, file *fsys.File, dir *fsys.Directory, encrKey []byte) error { |
||||||
|
if file == nil && dir == nil { |
||||||
|
panic("either file or dir must be specified") |
||||||
|
} else if file != nil && dir != nil { |
||||||
|
panic("only one either file or dir must be specified") |
||||||
|
} |
||||||
|
|
||||||
|
transferOfferPacket := Packet{ |
||||||
|
Header: HeaderTransferOffer, |
||||||
|
} |
||||||
|
|
||||||
|
if file != nil { |
||||||
|
filePacket, err := CreateFilePacket(file) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
transferOfferBody := append([]byte(FILECODE), filePacket.Body...) |
||||||
|
|
||||||
|
// if encrKey is present - encrypt
|
||||||
|
if encrKey != nil { |
||||||
|
encryptedBody, err := encryption.Encrypt(encrKey, transferOfferBody) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
transferOfferBody = encryptedBody |
||||||
|
} |
||||||
|
|
||||||
|
transferOfferPacket.Body = transferOfferBody |
||||||
|
|
||||||
|
} else if dir != nil { |
||||||
|
dirPacket, err := CreateDirectoryPacket(dir) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
transferOfferBody := append([]byte(DIRCODE), dirPacket.Body...) |
||||||
|
// if encrKey is present - encrypt
|
||||||
|
if encrKey != nil { |
||||||
|
encryptedBody, err := encryption.Encrypt(encrKey, transferOfferBody) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
transferOfferBody = encryptedBody |
||||||
|
} |
||||||
|
|
||||||
|
transferOfferPacket.Body = transferOfferBody |
||||||
|
} |
||||||
|
|
||||||
|
// send packet
|
||||||
|
err := SendPacket(connection, transferOfferPacket) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
var ErrorSentAll error = fmt.Errorf("sent the whole file") |
||||||
|
|
||||||
|
// sends a piece of file to the connection; The next calls will send
|
||||||
|
// another piece util the file has been fully sent. If encrKey is not nil - encrypts each packet with
|
||||||
|
// this key
|
||||||
|
func SendPiece(file *fsys.File, connection net.Conn, encrKey []byte) error { |
||||||
|
err := file.Open() |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
defer file.Handler.Close() |
||||||
|
|
||||||
|
if file.SentBytes == 0 { |
||||||
|
file.Handler.Seek(0, io.SeekStart) |
||||||
|
} |
||||||
|
|
||||||
|
if file.Size == file.SentBytes { |
||||||
|
return ErrorSentAll |
||||||
|
} |
||||||
|
|
||||||
|
fileBytesPacket := Packet{ |
||||||
|
Header: HeaderFileBytes, |
||||||
|
} |
||||||
|
|
||||||
|
packetBodyBuff := new(bytes.Buffer) |
||||||
|
|
||||||
|
// write file ID first
|
||||||
|
err = binary.Write(packetBodyBuff, binary.BigEndian, &file.ID) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// fill the remaining space of packet with the contents of a file
|
||||||
|
canSendBytes := uint64(MAXPACKETSIZE) - fileBytesPacket.Size() - uint64(packetBodyBuff.Len()) |
||||||
|
|
||||||
|
if encrKey != nil { |
||||||
|
// account for padding
|
||||||
|
canSendBytes -= 32 |
||||||
|
} |
||||||
|
|
||||||
|
if (file.Size - file.SentBytes) < canSendBytes { |
||||||
|
canSendBytes = (file.Size - file.SentBytes) |
||||||
|
} |
||||||
|
|
||||||
|
fileBytes := make([]byte, canSendBytes) |
||||||
|
|
||||||
|
read, err := file.Handler.ReadAt(fileBytes, int64(file.SentBytes)) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
packetBodyBuff.Write(fileBytes) |
||||||
|
|
||||||
|
fileBytesPacket.Body = packetBodyBuff.Bytes() |
||||||
|
|
||||||
|
if encrKey != nil { |
||||||
|
err = fileBytesPacket.EncryptBody(encrKey) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// send it to the other side
|
||||||
|
err = SendPacket(connection, fileBytesPacket) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
file.SentBytes += uint64(read) |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
Loading…
Reference in new issue