Unbewohnte
3 years ago
13 changed files with 649 additions and 487 deletions
@ -1,51 +1,45 @@
|
||||
package node |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"testing" |
||||
) |
||||
|
||||
// Not complete
|
||||
func Test_Sendfile(t *testing.T) { |
||||
rnodeOptions := NodeOptions{ |
||||
IsSending: false, |
||||
WorkingPort: 8888, |
||||
ServerSide: &ServerSideNodeOptions{ |
||||
ServingPath: "", |
||||
Recursive: false, |
||||
}, |
||||
ClientSide: &ClientSideNodeOptions{ |
||||
ConnectionAddr: "localhost", |
||||
DownloadsFolderPath: "../testfiles/testDownload/", |
||||
}, |
||||
} |
||||
receivingNode, err := NewNode(&rnodeOptions) |
||||
if err != nil { |
||||
fmt.Printf("Error constructing a new node: %s\n", err) |
||||
os.Exit(-1) |
||||
} |
||||
// func Test_Sendfile(t *testing.T) {
|
||||
// rnodeOptions := NodeOptions{
|
||||
// IsSending: false,
|
||||
// WorkingPort: 8888,
|
||||
// ServerSide: &ServerSideNodeOptions{
|
||||
// ServingPath: "",
|
||||
// Recursive: false,
|
||||
// },
|
||||
// ClientSide: &ClientSideNodeOptions{
|
||||
// ConnectionAddr: "localhost",
|
||||
// DownloadsFolderPath: "../testfiles/testDownload/",
|
||||
// },
|
||||
// }
|
||||
// receivingNode, err := NewNode(&rnodeOptions)
|
||||
// if err != nil {
|
||||
// fmt.Printf("Error constructing a new node: %s\n", err)
|
||||
// os.Exit(-1)
|
||||
// }
|
||||
|
||||
snodeOptions := NodeOptions{ |
||||
IsSending: true, |
||||
WorkingPort: 8888, |
||||
ServerSide: &ServerSideNodeOptions{ |
||||
ServingPath: "../testfiles/testfile.txt", |
||||
Recursive: false, |
||||
}, |
||||
ClientSide: &ClientSideNodeOptions{ |
||||
ConnectionAddr: "", |
||||
DownloadsFolderPath: "", |
||||
}, |
||||
} |
||||
// snodeOptions := NodeOptions{
|
||||
// IsSending: true,
|
||||
// WorkingPort: 8888,
|
||||
// ServerSide: &ServerSideNodeOptions{
|
||||
// ServingPath: "../testfiles/testfile.txt",
|
||||
// Recursive: false,
|
||||
// },
|
||||
// ClientSide: &ClientSideNodeOptions{
|
||||
// ConnectionAddr: "",
|
||||
// DownloadsFolderPath: "",
|
||||
// },
|
||||
// }
|
||||
|
||||
sendingNode, err := NewNode(&snodeOptions) |
||||
if err != nil { |
||||
fmt.Printf("Error constructing a new node: %s\n", err) |
||||
os.Exit(-1) |
||||
} |
||||
// sendingNode, err := NewNode(&snodeOptions)
|
||||
// if err != nil {
|
||||
// fmt.Printf("Error constructing a new node: %s\n", err)
|
||||
// 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