croc/src/croc/croc.go

768 lines
19 KiB
Go
Raw Normal View History

2018-09-22 05:17:57 +02:00
package croc
2018-09-22 05:51:43 +02:00
import (
2019-04-30 00:48:17 +02:00
"bytes"
"crypto/elliptic"
2019-04-30 05:40:42 +02:00
"encoding/binary"
2019-04-30 00:48:17 +02:00
"encoding/json"
"fmt"
2019-04-30 05:40:42 +02:00
"io"
"math"
2019-04-30 00:48:17 +02:00
"os"
"path"
"path/filepath"
"strings"
"sync"
2018-09-22 05:51:43 +02:00
"time"
2019-04-30 00:54:31 +02:00
log "github.com/cihub/seelog"
2019-04-30 00:48:17 +02:00
"github.com/denisbrodbeck/machineid"
2019-04-30 04:50:01 +02:00
"github.com/pkg/errors"
2019-04-30 00:54:31 +02:00
"github.com/schollz/croc/v6/src/comm"
2019-04-30 05:40:42 +02:00
"github.com/schollz/croc/v6/src/compress"
2019-04-30 00:54:31 +02:00
"github.com/schollz/croc/v6/src/crypt"
"github.com/schollz/croc/v6/src/logger"
2019-04-30 04:50:01 +02:00
"github.com/schollz/croc/v6/src/message"
2019-04-30 15:57:45 +02:00
"github.com/schollz/croc/v6/src/models"
2019-04-30 04:50:01 +02:00
"github.com/schollz/croc/v6/src/tcp"
2019-04-30 00:54:31 +02:00
"github.com/schollz/croc/v6/src/utils"
2019-04-30 00:48:17 +02:00
"github.com/schollz/pake"
2019-04-30 19:19:03 +02:00
"github.com/schollz/peerdiscovery"
2018-10-17 19:20:09 +02:00
"github.com/schollz/progressbar/v2"
2019-04-30 00:48:17 +02:00
"github.com/schollz/spinner"
2018-09-22 05:51:43 +02:00
)
2018-09-22 05:17:57 +02:00
2018-09-25 21:33:51 +02:00
func init() {
2019-04-30 00:54:31 +02:00
logger.SetLogLevel("debug")
2019-04-30 00:48:17 +02:00
}
func Debug(debug bool) {
2018-09-22 05:51:43 +02:00
if debug {
2019-04-30 00:54:31 +02:00
logger.SetLogLevel("debug")
2019-04-30 00:48:17 +02:00
} else {
2019-04-30 00:54:31 +02:00
logger.SetLogLevel("warn")
2019-04-30 00:48:17 +02:00
}
}
2019-04-30 00:54:31 +02:00
type Options struct {
IsSender bool
SharedSecret string
Debug bool
2019-04-30 04:50:01 +02:00
RelayAddress string
RelayPorts []string
2019-04-30 00:54:31 +02:00
Stdout bool
NoPrompt bool
2019-04-30 23:46:27 +02:00
DisableLocal bool
2019-04-30 00:54:31 +02:00
}
2019-04-30 00:48:17 +02:00
type Client struct {
Options Options
Pake *pake.Pake
2019-04-30 04:50:01 +02:00
Key crypt.Encryption
2019-04-30 00:48:17 +02:00
// steps involved in forming relationship
Step1ChannelSecured bool
Step2FileInfoTransfered bool
Step3RecipientRequestFile bool
Step4FileTransfer bool
2019-04-30 00:54:31 +02:00
Step5CloseChannels bool
2019-04-30 00:48:17 +02:00
// send / receive information of all files
FilesToTransfer []FileInfo
FilesToTransferCurrentNum int
// send / receive information of current file
2019-04-30 16:29:02 +02:00
CurrentFile *os.File
CurrentFileChunks []int64
TotalSent int64
TotalChunksTransfered int
chunkMap map[uint64]struct{}
2019-04-30 00:48:17 +02:00
2019-04-30 04:50:01 +02:00
// tcp connections
conn []*comm.Comm
2019-04-30 00:48:17 +02:00
bar *progressbar.ProgressBar
spinner *spinner.Spinner
machineID string
mutex *sync.Mutex
quit chan bool
}
type Chunk struct {
Bytes []byte `json:"b,omitempty"`
Location int64 `json:"l,omitempty"`
}
type FileInfo struct {
Name string `json:"n,omitempty"`
FolderRemote string `json:"fr,omitempty"`
FolderSource string `json:"fs,omitempty"`
Hash []byte `json:"h,omitempty"`
Size int64 `json:"s,omitempty"`
ModTime time.Time `json:"m,omitempty"`
IsCompressed bool `json:"c,omitempty"`
IsEncrypted bool `json:"e,omitempty"`
}
type RemoteFileRequest struct {
CurrentFileChunks []int64
FilesToTransferCurrentNum int
}
type SenderInfo struct {
MachineID string
FilesToTransfer []FileInfo
}
// New establishes a new connection for transfering files between two instances.
func New(ops Options) (c *Client, err error) {
c = new(Client)
// setup basic info
c.Options = ops
Debug(c.Options.Debug)
log.Debugf("options: %+v", c.Options)
2019-04-30 20:46:35 +02:00
c.conn = make([]*comm.Comm, 16)
2019-04-30 04:50:01 +02:00
// use default key (no encryption, until PAKE succeeds)
c.Key, err = crypt.New(nil, nil)
if err != nil {
return
}
2019-04-30 00:48:17 +02:00
// initialize pake
if c.Options.IsSender {
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 1, elliptic.P521(), 1*time.Microsecond)
} else {
c.Pake, err = pake.Init([]byte(c.Options.SharedSecret), 0, elliptic.P521(), 1*time.Microsecond)
}
if err != nil {
return
}
c.mutex = &sync.Mutex{}
return
}
2019-04-30 04:50:01 +02:00
// TransferOptions for sending
2019-04-30 00:48:17 +02:00
type TransferOptions struct {
PathToFiles []string
KeepPathInRemote bool
}
// Send will send the specified file
func (c *Client) Send(options TransferOptions) (err error) {
2019-04-30 23:39:59 +02:00
c.FilesToTransfer = make([]FileInfo, len(options.PathToFiles))
totalFilesSize := int64(0)
for i, pathToFile := range options.PathToFiles {
var fstats os.FileInfo
var fullPath string
fullPath, err = filepath.Abs(pathToFile)
if err != nil {
return
}
fullPath = filepath.Clean(fullPath)
var folderName string
folderName, _ = filepath.Split(fullPath)
fstats, err = os.Stat(fullPath)
if err != nil {
return
}
c.FilesToTransfer[i] = FileInfo{
Name: fstats.Name(),
FolderRemote: ".",
FolderSource: folderName,
Size: fstats.Size(),
ModTime: fstats.ModTime(),
}
c.FilesToTransfer[i].Hash, err = utils.HashFile(fullPath)
totalFilesSize += fstats.Size()
if err != nil {
return
}
if options.KeepPathInRemote {
var curFolder string
curFolder, err = os.Getwd()
if err != nil {
return
}
curFolder, err = filepath.Abs(curFolder)
if err != nil {
return
}
if !strings.HasPrefix(folderName, curFolder) {
err = fmt.Errorf("remote directory must be relative to current")
return
}
c.FilesToTransfer[i].FolderRemote = strings.TrimPrefix(folderName, curFolder)
c.FilesToTransfer[i].FolderRemote = filepath.ToSlash(c.FilesToTransfer[i].FolderRemote)
c.FilesToTransfer[i].FolderRemote = strings.TrimPrefix(c.FilesToTransfer[i].FolderRemote, "/")
if c.FilesToTransfer[i].FolderRemote == "" {
c.FilesToTransfer[i].FolderRemote = "."
}
}
log.Debugf("file %d info: %+v", i, c.FilesToTransfer[i])
}
fname := fmt.Sprintf("%d files", len(c.FilesToTransfer))
if len(c.FilesToTransfer) == 1 {
fname = fmt.Sprintf("'%s'", c.FilesToTransfer[0].Name)
}
machID, macIDerr := machineid.ID()
if macIDerr != nil {
log.Error(macIDerr)
return
}
if len(machID) > 6 {
machID = machID[:6]
}
c.machineID = machID
fmt.Fprintf(os.Stderr, "Sending %s (%s) from your machine, '%s'\n", fname, utils.ByteCountDecimal(totalFilesSize), machID)
fmt.Fprintf(os.Stderr, "Code is: %s\nOn the other computer run\n\ncroc %s\n", c.Options.SharedSecret, c.Options.SharedSecret)
// // c.spinner.Suffix = " waiting for recipient..."
// c.spinner.Start()
// create channel for quitting
2019-04-30 20:55:18 +02:00
// connect to the relay for messaging
errchan := make(chan error, 1)
2019-04-30 23:46:27 +02:00
if !c.Options.DisableLocal {
// setup the relay locally
for _, port := range c.Options.RelayPorts {
go func(portStr string) {
debugString := "warn"
if c.Options.Debug {
debugString = "debug"
}
err = tcp.Run(debugString, portStr)
if err != nil {
panic(err)
}
}(port)
}
// look for peers first
go func() {
discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{
Limit: 1,
Payload: []byte("9009"),
Delay: 10 * time.Millisecond,
TimeLimit: 30 * time.Second,
})
log.Debugf("discoveries: %+v", discoveries)
if err == nil && len(discoveries) > 0 {
log.Debug("using local server")
2019-04-30 23:39:59 +02:00
}
2019-04-30 23:46:27 +02:00
}()
go func() {
time.Sleep(500 * time.Millisecond)
log.Debug("establishing connection")
conn, err := tcp.ConnectToTCPServer("localhost:"+c.Options.RelayPorts[0], c.Options.SharedSecret)
2019-04-30 21:07:30 +02:00
if err != nil {
2019-04-30 23:46:27 +02:00
err = errors.Wrap(err, fmt.Sprintf("could not connect to %s", c.Options.RelayAddress))
return
2019-04-30 21:07:30 +02:00
}
2019-04-30 23:46:27 +02:00
log.Debugf("connection established: %+v", conn)
for {
data, _ := conn.Receive()
if bytes.Equal(data, []byte("handshake")) {
break
}
2019-04-30 21:07:30 +02:00
}
2019-04-30 23:46:27 +02:00
c.conn[0] = conn
log.Debug("exchanged header message")
c.Options.RelayAddress = "localhost"
errchan <- c.transfer(options)
}()
}
2019-04-30 21:07:30 +02:00
go func() {
log.Debug("establishing connection")
conn, err := tcp.ConnectToTCPServer(c.Options.RelayAddress+":"+c.Options.RelayPorts[0], c.Options.SharedSecret)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("could not connect to %s", c.Options.RelayAddress))
return
}
log.Debugf("connection established: %+v", conn)
for {
data, _ := conn.Receive()
if bytes.Equal(data, []byte("handshake")) {
break
}
}
c.conn[0] = conn
2019-04-30 20:46:35 +02:00
log.Debug("exchanged header message")
errchan <- c.transfer(options)
}()
2019-04-30 19:39:45 +02:00
2019-04-30 20:46:35 +02:00
return <-errchan
2019-04-30 00:48:17 +02:00
}
// Receive will receive a file
func (c *Client) Receive() (err error) {
2019-04-30 19:23:53 +02:00
// look for peers first
2019-04-30 23:46:27 +02:00
if !c.Options.DisableLocal {
discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{
Limit: 1,
Payload: []byte("ok"),
Delay: 10 * time.Millisecond,
TimeLimit: 100 * time.Millisecond,
})
_ = err
log.Debugf("discoveries: %+v", discoveries)
log.Debug("establishing connection")
}
2019-04-30 20:49:51 +02:00
c.conn[0], err = tcp.ConnectToTCPServer(c.Options.RelayAddress+":"+c.Options.RelayPorts[0], c.Options.SharedSecret)
2019-04-30 20:46:35 +02:00
if err != nil {
err = errors.Wrap(err, fmt.Sprintf("could not connect to %s", c.Options.RelayAddress))
return
}
log.Debugf("connection established: %+v", c.conn[0])
c.conn[0].Send([]byte("handshake"))
log.Debug("exchanged header message")
2019-04-30 00:48:17 +02:00
return c.transfer(TransferOptions{})
}
func (c *Client) transfer(options TransferOptions) (err error) {
2019-04-30 04:50:01 +02:00
// connect to the server
2019-04-30 00:48:17 +02:00
// quit with c.quit <- true
c.quit = make(chan bool)
// if recipient, initialize with sending pake information
2019-04-30 01:05:48 +02:00
log.Debug("ready")
2019-04-30 00:48:17 +02:00
if !c.Options.IsSender && !c.Step1ChannelSecured {
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "pake",
Bytes: c.Pake.Bytes(),
2019-04-30 04:50:01 +02:00
})
2019-04-30 00:48:17 +02:00
if err != nil {
return
}
}
// listen for incoming messages and process them
for {
2019-04-30 04:50:01 +02:00
var data []byte
2019-04-30 05:40:42 +02:00
var done bool
2019-04-30 04:50:01 +02:00
data, err = c.conn[0].Receive()
if err != nil {
return
}
2019-04-30 05:40:42 +02:00
done, err = c.processMessage(data)
2019-04-30 04:50:01 +02:00
if err != nil {
2019-04-30 00:48:17 +02:00
return
}
2019-04-30 05:40:42 +02:00
if done {
break
}
2019-04-30 00:48:17 +02:00
}
return
}
2019-04-30 05:40:42 +02:00
func (c *Client) processMessage(payload []byte) (done bool, err error) {
2019-04-30 04:50:01 +02:00
m, err := message.Decode(c.Key, payload)
if err != nil {
return
}
2019-04-30 00:48:17 +02:00
switch m.Type {
2019-04-30 05:40:42 +02:00
case "finished":
err = message.Send(c.conn[0], c.Key, message.Message{
Type: "finished",
})
done = true
return
2019-04-30 00:48:17 +02:00
case "pake":
2019-04-30 04:50:01 +02:00
// if // c.spinner.Suffix != " performing PAKE..." {
// // c.spinner.Stop()
// // c.spinner.Suffix = " performing PAKE..."
// // c.spinner.Start()
// }
2019-04-30 00:48:17 +02:00
notVerified := !c.Pake.IsVerified()
err = c.Pake.Update(m.Bytes)
if err != nil {
return
}
if (notVerified && c.Pake.IsVerified() && !c.Options.IsSender) || !c.Pake.IsVerified() {
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "pake",
Bytes: c.Pake.Bytes(),
2019-04-30 04:50:01 +02:00
})
2019-04-30 00:48:17 +02:00
}
if c.Pake.IsVerified() {
2019-04-30 04:50:01 +02:00
log.Debug("session key is verified, generating encryption")
key, err := c.Pake.SessionKey()
if err != nil {
2019-04-30 05:40:42 +02:00
return true, err
2019-04-30 04:50:01 +02:00
}
c.Key, err = crypt.New(key, []byte(c.Options.SharedSecret))
if err != nil {
2019-04-30 05:40:42 +02:00
return true, err
}
// connects to the other ports of the server for transfer
2019-04-30 16:07:23 +02:00
var wg sync.WaitGroup
wg.Add(len(c.Options.RelayPorts) - 1)
2019-04-30 05:40:42 +02:00
for i := 1; i < len(c.Options.RelayPorts); i++ {
2019-04-30 16:07:23 +02:00
go func(j int) {
defer wg.Done()
c.conn[j], err = tcp.ConnectToTCPServer(
fmt.Sprintf("%s:%s", c.Options.RelayAddress, c.Options.RelayPorts[j]),
fmt.Sprintf("%s-%d", utils.SHA256(c.Options.SharedSecret)[:7], j),
)
if err != nil {
panic(err)
}
if !c.Options.IsSender {
go c.receiveData(j)
}
}(i)
2019-04-30 04:50:01 +02:00
}
2019-04-30 16:07:23 +02:00
wg.Wait()
2019-04-30 00:48:17 +02:00
c.Step1ChannelSecured = true
}
case "error":
2019-04-30 04:50:01 +02:00
// c.spinner.Stop()
2019-04-30 00:48:17 +02:00
fmt.Print("\r")
err = fmt.Errorf("peer error: %s", m.Message)
2019-04-30 05:40:42 +02:00
return true, err
2019-04-30 00:48:17 +02:00
case "fileinfo":
var senderInfo SenderInfo
2019-04-30 04:50:01 +02:00
err = json.Unmarshal(m.Bytes, &senderInfo)
2019-04-30 00:48:17 +02:00
if err != nil {
log.Error(err)
return
}
c.FilesToTransfer = senderInfo.FilesToTransfer
fname := fmt.Sprintf("%d files", len(c.FilesToTransfer))
if len(c.FilesToTransfer) == 1 {
fname = fmt.Sprintf("'%s'", c.FilesToTransfer[0].Name)
}
totalSize := int64(0)
for _, fi := range c.FilesToTransfer {
totalSize += fi.Size
}
2019-04-30 04:50:01 +02:00
// c.spinner.Stop()
2019-04-30 00:48:17 +02:00
if !c.Options.NoPrompt {
fmt.Fprintf(os.Stderr, "\rAccept %s (%s) from machine '%s'? (y/n) ", fname, utils.ByteCountDecimal(totalSize), senderInfo.MachineID)
if strings.ToLower(strings.TrimSpace(utils.GetInput(""))) != "y" {
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "error",
Message: "refusing files",
2019-04-30 04:50:01 +02:00
})
2019-04-30 05:40:42 +02:00
return true, fmt.Errorf("refused files")
2019-04-30 00:48:17 +02:00
}
} else {
fmt.Fprintf(os.Stderr, "\rReceiving %s (%s) from machine '%s'\n", fname, utils.ByteCountDecimal(totalSize), senderInfo.MachineID)
}
2019-04-30 01:05:48 +02:00
log.Debug(c.FilesToTransfer)
2019-04-30 00:48:17 +02:00
c.Step2FileInfoTransfered = true
case "recipientready":
var remoteFile RemoteFileRequest
2019-04-30 04:50:01 +02:00
err = json.Unmarshal(m.Bytes, &remoteFile)
2019-04-30 00:48:17 +02:00
if err != nil {
return
}
c.FilesToTransferCurrentNum = remoteFile.FilesToTransferCurrentNum
c.CurrentFileChunks = remoteFile.CurrentFileChunks
2019-04-30 16:29:02 +02:00
log.Debugf("current file chunks: %+v", c.CurrentFileChunks)
c.chunkMap = make(map[uint64]struct{})
for _, chunk := range c.CurrentFileChunks {
c.chunkMap[uint64(chunk)] = struct{}{}
}
2019-04-30 00:48:17 +02:00
c.Step3RecipientRequestFile = true
case "close-sender":
2019-04-30 18:43:52 +02:00
c.bar.Finish()
2019-04-30 00:48:17 +02:00
log.Debug("close-sender received...")
c.Step4FileTransfer = false
c.Step3RecipientRequestFile = false
log.Debug("sending close-recipient")
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "close-recipient",
2019-04-30 04:50:01 +02:00
})
2019-04-30 00:48:17 +02:00
case "close-recipient":
c.Step4FileTransfer = false
c.Step3RecipientRequestFile = false
}
if err != nil {
return
}
err = c.updateState()
return
}
func (c *Client) updateState() (err error) {
if c.Options.IsSender && c.Step1ChannelSecured && !c.Step2FileInfoTransfered {
var b []byte
b, err = json.Marshal(SenderInfo{
MachineID: c.machineID,
FilesToTransfer: c.FilesToTransfer,
})
if err != nil {
log.Error(err)
return
}
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "fileinfo",
2019-04-30 04:50:01 +02:00
Bytes: b,
})
2019-04-30 00:48:17 +02:00
if err != nil {
return
}
c.Step2FileInfoTransfered = true
}
if !c.Options.IsSender && c.Step2FileInfoTransfered && !c.Step3RecipientRequestFile {
// find the next file to transfer and send that number
// if the files are the same size, then look for missing chunks
finished := true
for i, fileInfo := range c.FilesToTransfer {
if i < c.FilesToTransferCurrentNum {
continue
}
fileHash, errHash := utils.HashFile(path.Join(fileInfo.FolderRemote, fileInfo.Name))
if errHash != nil || !bytes.Equal(fileHash, fileInfo.Hash) {
if !bytes.Equal(fileHash, fileInfo.Hash) {
log.Debugf("hashes are not equal %x != %x", fileHash, fileInfo.Hash)
}
finished = false
c.FilesToTransferCurrentNum = i
break
}
// TODO: print out something about this file already existing
}
if finished {
// TODO: do the last finishing stuff
log.Debug("finished")
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "finished",
2019-04-30 04:50:01 +02:00
})
2019-04-30 00:48:17 +02:00
if err != nil {
panic(err)
}
}
// start initiating the process to receive a new file
log.Debugf("working on file %d", c.FilesToTransferCurrentNum)
2019-04-30 05:40:42 +02:00
// recipient sets the file
pathToFile := path.Join(
c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderRemote,
c.FilesToTransfer[c.FilesToTransferCurrentNum].Name,
)
folderForFile, _ := filepath.Split(pathToFile)
os.MkdirAll(folderForFile, os.ModePerm)
var errOpen error
c.CurrentFile, errOpen = os.OpenFile(
pathToFile,
os.O_WRONLY, 0666)
truncate := false
2019-04-30 16:47:05 +02:00
c.CurrentFileChunks = []int64{}
2019-04-30 05:40:42 +02:00
if errOpen == nil {
stat, _ := c.CurrentFile.Stat()
truncate = stat.Size() != c.FilesToTransfer[c.FilesToTransferCurrentNum].Size
2019-04-30 16:47:05 +02:00
if truncate == false {
// recipient requests the file and chunks (if empty, then should receive all chunks)
// TODO: determine the missing chunks
c.CurrentFileChunks = utils.MissingChunks(
pathToFile,
c.FilesToTransfer[c.FilesToTransferCurrentNum].Size,
models.TCP_BUFFER_SIZE/2,
)
}
2019-04-30 05:40:42 +02:00
} else {
c.CurrentFile, errOpen = os.Create(pathToFile)
if errOpen != nil {
errOpen = errors.Wrap(errOpen, "could not create "+pathToFile)
log.Error(errOpen)
return errOpen
}
truncate = true
}
if truncate {
err := c.CurrentFile.Truncate(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size)
if err != nil {
err = errors.Wrap(err, "could not truncate "+pathToFile)
log.Error(err)
return err
}
}
// setup the progressbar
2019-04-30 18:24:32 +02:00
c.setBar()
2019-04-30 06:25:30 +02:00
c.TotalSent = 0
2019-04-30 00:48:17 +02:00
bRequest, _ := json.Marshal(RemoteFileRequest{
CurrentFileChunks: c.CurrentFileChunks,
FilesToTransferCurrentNum: c.FilesToTransferCurrentNum,
})
2019-04-30 04:50:01 +02:00
err = message.Send(c.conn[0], c.Key, message.Message{
2019-04-30 00:48:17 +02:00
Type: "recipientready",
2019-04-30 04:50:01 +02:00
Bytes: bRequest,
})
2019-04-30 00:48:17 +02:00
if err != nil {
return
}
c.Step3RecipientRequestFile = true
}
if c.Options.IsSender && c.Step3RecipientRequestFile && !c.Step4FileTransfer {
2019-04-30 01:05:48 +02:00
log.Debug("start sending data!")
2019-04-30 00:48:17 +02:00
c.Step4FileTransfer = true
2019-04-30 05:40:42 +02:00
// setup the progressbar
2019-04-30 18:24:32 +02:00
c.setBar()
2019-04-30 06:25:30 +02:00
c.TotalSent = 0
2019-04-30 05:40:42 +02:00
for i := 1; i < len(c.Options.RelayPorts); i++ {
go c.sendData(i)
}
2019-04-30 00:48:17 +02:00
}
return
}
2019-04-30 18:24:32 +02:00
func (c *Client) setBar() {
description := fmt.Sprintf("%28s", c.FilesToTransfer[c.FilesToTransferCurrentNum].Name)
if len(c.FilesToTransfer) == 1 {
description = c.FilesToTransfer[c.FilesToTransferCurrentNum].Name
}
c.bar = progressbar.NewOptions64(
c.FilesToTransfer[c.FilesToTransferCurrentNum].Size,
progressbar.OptionOnCompletion(func() {
fmt.Fprintf(os.Stderr, " ✔️\n")
}),
progressbar.OptionSetWidth(8),
progressbar.OptionSetDescription(description),
progressbar.OptionSetRenderBlankState(true),
progressbar.OptionSetBytes64(c.FilesToTransfer[c.FilesToTransferCurrentNum].Size),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionThrottle(100*time.Millisecond),
)
c.bar.Add(len(c.CurrentFileChunks) * models.TCP_BUFFER_SIZE / 2)
}
2019-04-30 05:40:42 +02:00
func (c *Client) receiveData(i int) {
for {
2019-04-30 15:57:45 +02:00
log.Debug("waiting for data")
2019-04-30 05:40:42 +02:00
data, err := c.conn[i].Receive()
if err != nil {
2019-04-30 17:58:09 +02:00
break
2019-04-30 05:40:42 +02:00
}
2019-04-30 15:57:45 +02:00
2019-04-30 05:40:42 +02:00
data, err = c.Key.Decrypt(data)
if err != nil {
panic(err)
}
data = compress.Decompress(data)
// get position
var position uint64
rbuf := bytes.NewReader(data[:8])
err = binary.Read(rbuf, binary.LittleEndian, &position)
if err != nil {
2019-04-30 17:58:09 +02:00
panic(err)
2019-04-30 05:40:42 +02:00
}
positionInt64 := int64(position)
c.mutex.Lock()
2019-04-30 06:25:30 +02:00
_, err = c.CurrentFile.WriteAt(data[8:], positionInt64)
2019-04-30 05:40:42 +02:00
c.mutex.Unlock()
if err != nil {
panic(err)
}
2019-04-30 06:25:30 +02:00
c.bar.Add(len(data[8:]))
c.TotalSent += int64(len(data[8:]))
2019-04-30 16:29:02 +02:00
c.TotalChunksTransfered++
2019-04-30 15:57:45 +02:00
log.Debugf("block: %+v", positionInt64)
2019-04-30 16:29:02 +02:00
if c.TotalChunksTransfered == len(c.CurrentFileChunks) || c.TotalSent == c.FilesToTransfer[c.FilesToTransferCurrentNum].Size {
2019-04-30 05:40:42 +02:00
log.Debug("finished receiving!")
c.CurrentFile.Close()
log.Debug("sending close-sender")
err = message.Send(c.conn[0], c.Key, message.Message{
Type: "close-sender",
})
if err != nil {
panic(err)
}
}
2019-04-30 00:48:17 +02:00
}
2019-04-30 05:40:42 +02:00
return
2019-04-30 00:48:17 +02:00
}
2019-04-30 05:40:42 +02:00
func (c *Client) sendData(i int) {
2019-04-30 06:25:30 +02:00
defer func() {
log.Debugf("finished with %d", i)
}()
2019-04-30 05:40:42 +02:00
pathToFile := path.Join(
c.FilesToTransfer[c.FilesToTransferCurrentNum].FolderSource,
c.FilesToTransfer[c.FilesToTransferCurrentNum].Name,
)
log.Debugf("opening %s to read", pathToFile)
f, err := os.Open(pathToFile)
2019-04-30 00:48:17 +02:00
if err != nil {
2019-04-30 05:40:42 +02:00
panic(err)
2019-04-30 00:48:17 +02:00
}
2019-04-30 05:40:42 +02:00
defer f.Close()
2019-04-30 00:48:17 +02:00
2019-04-30 05:40:42 +02:00
pos := uint64(0)
curi := float64(0)
for {
// Read file
2019-04-30 15:57:45 +02:00
data := make([]byte, models.TCP_BUFFER_SIZE/2)
2019-04-30 05:40:42 +02:00
n, err := f.Read(data)
if err != nil {
if err == io.EOF {
2019-04-30 15:57:45 +02:00
break
2019-04-30 05:40:42 +02:00
}
panic(err)
}
if math.Mod(curi, float64(len(c.Options.RelayPorts)-1))+1 == float64(i) {
2019-04-30 16:29:02 +02:00
// check to see if this is a chunk that the recipient wants
usableChunk := true
c.mutex.Lock()
if len(c.chunkMap) != 0 {
if _, ok := c.chunkMap[pos]; !ok {
usableChunk = false
} else {
delete(c.chunkMap, pos)
}
2019-04-30 05:40:42 +02:00
}
2019-04-30 16:29:02 +02:00
c.mutex.Unlock()
if usableChunk {
2019-04-30 16:51:48 +02:00
// log.Debugf("sending chunk %d", pos)
2019-04-30 16:29:02 +02:00
posByte := make([]byte, 8)
binary.LittleEndian.PutUint64(posByte, pos)
dataToSend, err := c.Key.Encrypt(
compress.Compress(
append(posByte, data[:n]...),
),
)
if err != nil {
panic(err)
}
2019-04-30 05:40:42 +02:00
2019-04-30 16:29:02 +02:00
err = c.conn[i].Send(dataToSend)
if err != nil {
panic(err)
}
c.bar.Add(n)
c.TotalSent += int64(n)
// time.Sleep(100 * time.Millisecond)
} else {
2019-04-30 16:51:48 +02:00
// log.Debugf("skipping chunk %d", pos)
2019-04-30 05:40:42 +02:00
}
}
curi++
pos += uint64(n)
}
2019-04-30 15:57:45 +02:00
time.Sleep(10 * time.Second)
return
2018-09-22 05:51:43 +02:00
}