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"
2019-05-01 00:10:07 +02:00
"crypto/rand"
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"
2019-05-01 21:09:47 +02:00
"io/ioutil"
2019-04-30 05:40:42 +02:00
"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 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"
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-05-08 23:03:54 +02:00
log "github.com/schollz/logger"
2019-11-18 00:21:16 +01:00
"github.com/schollz/pake/v2"
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"
2019-11-18 00:21:16 +01:00
"github.com/tscholl2/siec"
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-05-08 23:03:54 +02:00
log . SetLevel ( "debug" )
2019-04-30 00:48:17 +02:00
}
2019-09-07 18:46:04 +02:00
// Debug toggles debug mode
2019-04-30 00:48:17 +02:00
func Debug ( debug bool ) {
2018-09-22 05:51:43 +02:00
if debug {
2019-05-08 23:03:54 +02:00
log . SetLevel ( "debug" )
2019-04-30 00:48:17 +02:00
} else {
2019-05-08 23:03:54 +02:00
log . SetLevel ( "warn" )
2019-04-30 00:48:17 +02:00
}
}
2019-09-07 18:46:04 +02:00
// Options specifies user specific options
2019-04-30 00:54:31 +02:00
type Options struct {
2019-11-18 00:32:47 +01:00
IsSender bool
SharedSecret string
Debug bool
RelayAddress string
RelayPorts [ ] string
Stdout bool
NoPrompt bool
NoMultiplexing bool
DisableLocal bool
Ask bool
2019-04-30 00:54:31 +02:00
}
2019-09-07 18:46:04 +02:00
// Client holds the state of the croc transfer
2019-04-30 00:48:17 +02:00
type Client struct {
2019-05-02 01:44:09 +02:00
Options Options
Pake * pake . Pake
2019-11-18 00:17:06 +01:00
Key [ ] byte
2019-05-02 01:44:09 +02:00
ExternalIP , ExternalIPConnected string
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-05-03 02:11:01 +02:00
SuccessfulTransfer bool
2019-04-30 00:48:17 +02:00
// send / receive information of all files
FilesToTransfer [ ] FileInfo
FilesToTransferCurrentNum int
2019-08-27 18:51:37 +02:00
FilesHasFinished map [ int ] struct { }
2019-04-30 00:48:17 +02:00
// send / receive information of current file
2019-05-03 22:51:27 +02:00
CurrentFile * os . File
CurrentFileChunkRanges [ ] int64
CurrentFileChunks [ ] int64
2019-04-30 16:29:02 +02:00
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
2019-10-08 01:20:24 +02:00
bar * progressbar . ProgressBar
spinner * spinner . Spinner
longestFilename int
firstSend bool
2019-04-30 00:48:17 +02:00
2019-09-07 16:34:05 +02:00
mutex * sync . Mutex
fread * os . File
numfinished int
quit chan bool
2019-04-30 00:48:17 +02:00
}
2019-09-07 18:46:04 +02:00
// Chunk contains information about the
// needed bytes
2019-04-30 00:48:17 +02:00
type Chunk struct {
Bytes [ ] byte ` json:"b,omitempty" `
Location int64 ` json:"l,omitempty" `
}
2019-09-07 18:46:04 +02:00
// FileInfo registers the information about the file
2019-04-30 00:48:17 +02:00
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" `
}
2019-09-07 18:46:04 +02:00
// RemoteFileRequest requests specific bytes
2019-04-30 00:48:17 +02:00
type RemoteFileRequest struct {
2019-05-03 22:51:27 +02:00
CurrentFileChunkRanges [ ] int64
2019-04-30 00:48:17 +02:00
FilesToTransferCurrentNum int
2019-10-23 23:59:47 +02:00
MachineID string
2019-04-30 00:48:17 +02:00
}
2019-09-07 18:49:08 +02:00
// SenderInfo lists the files to be transferred
2019-04-30 00:48:17 +02:00
type SenderInfo struct {
FilesToTransfer [ ] FileInfo
2019-10-23 23:59:47 +02:00
MachineID string
2019-10-24 15:58:12 +02:00
Ask bool
2019-04-30 00:48:17 +02:00
}
2019-09-07 18:49:08 +02:00
// New establishes a new connection for transferring files between two instances.
2019-04-30 00:48:17 +02:00
func New ( ops Options ) ( c * Client , err error ) {
c = new ( Client )
2019-08-27 18:51:37 +02:00
c . FilesHasFinished = make ( map [ int ] struct { } )
2019-04-30 00:48:17 +02:00
// 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
2019-04-30 00:48:17 +02:00
// initialize pake
if c . Options . IsSender {
2019-11-18 00:21:16 +01:00
c . Pake , err = pake . Init ( [ ] byte ( c . Options . SharedSecret ) , 1 , siec . SIEC255 ( ) , 1 * time . Microsecond )
2019-04-30 00:48:17 +02:00
} else {
2019-11-18 00:21:16 +01:00
c . Pake , err = pake . Init ( [ ] byte ( c . Options . SharedSecret ) , 0 , siec . SIEC255 ( ) , 1 * time . Microsecond )
2019-04-30 00:48:17 +02:00
}
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
}
2019-09-20 18:47:47 +02:00
func ( c * Client ) sendCollectFiles ( 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
}
2019-10-08 01:20:24 +02:00
if len ( fstats . Name ( ) ) > c . longestFilename {
c . longestFilename = len ( fstats . Name ( ) )
}
2019-04-30 23:39:59 +02:00
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 ] )
}
2019-10-08 01:20:24 +02:00
log . Debugf ( "longestFilename: %+v" , c . longestFilename )
2019-04-30 23:39:59 +02:00
fname := fmt . Sprintf ( "%d files" , len ( c . FilesToTransfer ) )
if len ( c . FilesToTransfer ) == 1 {
fname = fmt . Sprintf ( "'%s'" , c . FilesToTransfer [ 0 ] . Name )
}
2019-05-02 21:08:23 +02:00
fmt . Fprintf ( os . Stderr , "Sending %s (%s)\n" , fname , utils . ByteCountDecimal ( totalFilesSize ) )
2019-09-20 18:47:47 +02:00
return
}
2019-09-20 18:54:10 +02:00
func ( c * Client ) setupLocalRelay ( ) {
// 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 , strings . Join ( c . Options . RelayPorts [ 1 : ] , "," ) )
if err != nil {
panic ( err )
}
} ( port )
}
}
func ( c * Client ) broadcastOnLocalNetwork ( ) {
// look for peers first
discoveries , err := peerdiscovery . Discover ( peerdiscovery . Settings {
Limit : - 1 ,
2019-10-28 20:46:24 +01:00
Payload : [ ] byte ( "croc" + c . Options . RelayPorts [ 0 ] ) ,
2019-09-20 18:54:10 +02:00
Delay : 10 * time . Millisecond ,
TimeLimit : 30 * time . Second ,
} )
log . Debugf ( "discoveries: %+v" , discoveries )
2019-11-11 20:26:12 +01:00
if err != nil {
log . Debug ( err . Error ( ) )
2019-09-20 18:54:10 +02:00
}
}
func ( c * Client ) transferOverLocalRelay ( options TransferOptions , errchan chan <- error ) {
time . Sleep ( 500 * time . Millisecond )
log . Debug ( "establishing connection" )
var banner string
conn , banner , ipaddr , err := tcp . ConnectToTCPServer ( "localhost:" + c . Options . RelayPorts [ 0 ] , c . Options . SharedSecret )
log . Debugf ( "banner: %s" , banner )
if err != nil {
err = errors . Wrap ( err , fmt . Sprintf ( "could not connect to localhost:%s" , c . Options . RelayPorts [ 0 ] ) )
2019-09-20 19:06:26 +02:00
log . Debug ( err )
2019-09-20 19:06:50 +02:00
// not really an error because it will try to connect over the actual relay
2019-09-20 18:54:10 +02:00
return
}
log . Debugf ( "connection established: %+v" , conn )
for {
data , _ := conn . Receive ( )
if bytes . Equal ( data , [ ] byte ( "handshake" ) ) {
break
}
}
c . conn [ 0 ] = conn
log . Debug ( "exchanged header message" )
c . Options . RelayAddress = "localhost"
c . Options . RelayPorts = strings . Split ( banner , "," )
2019-11-18 00:32:47 +01:00
if c . Options . NoMultiplexing {
log . Debug ( "no multiplexing" )
c . Options . RelayPorts = [ ] string { c . Options . RelayPorts [ 0 ] }
}
2019-09-20 18:54:10 +02:00
c . ExternalIP = ipaddr
errchan <- c . transfer ( options )
}
2019-09-20 18:47:47 +02:00
// Send will send the specified file
func ( c * Client ) Send ( options TransferOptions ) ( err error ) {
err = c . sendCollectFiles ( options )
if err != nil {
return
}
2019-07-17 22:12:48 +02:00
otherRelay := ""
if c . Options . RelayAddress != models . DEFAULT_RELAY {
otherRelay = "--relay " + c . Options . RelayAddress + " "
}
fmt . Fprintf ( os . Stderr , "Code is: %s\nOn the other computer run\n\ncroc %s%s\n" , c . Options . SharedSecret , otherRelay , c . Options . SharedSecret )
2019-10-23 23:59:47 +02:00
if c . Options . Ask {
2019-11-18 16:09:39 +01:00
machid := "machineid.ID()"
2019-10-24 15:58:12 +02:00
fmt . Fprintf ( os . Stderr , "\rYour machine ID is '%s'\n" , machid )
2019-10-23 23:59:47 +02:00
}
2019-04-30 23:39:59 +02:00
// // 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 {
2019-07-17 21:04:03 +02:00
// add two things to the error channel
errchan = make ( chan error , 2 )
2019-09-20 18:54:10 +02:00
c . setupLocalRelay ( )
go c . broadcastOnLocalNetwork ( )
go c . transferOverLocalRelay ( options , errchan )
2019-04-30 23:46:27 +02:00
}
2019-04-30 21:07:30 +02:00
go func ( ) {
2019-05-10 07:02:35 +02:00
log . Debugf ( "establishing connection to %s" , c . Options . RelayAddress )
2019-05-01 01:05:19 +02:00
var banner string
2019-09-08 14:53:30 +02:00
conn , banner , ipaddr , err := tcp . ConnectToTCPServer ( c . Options . RelayAddress , c . Options . SharedSecret , 5 * time . Second )
2019-05-01 01:05:19 +02:00
log . Debugf ( "banner: %s" , banner )
2019-04-30 21:07:30 +02:00
if err != nil {
err = errors . Wrap ( err , fmt . Sprintf ( "could not connect to %s" , c . Options . RelayAddress ) )
2019-05-02 20:41:03 +02:00
log . Debug ( err )
2019-07-17 21:04:03 +02:00
errchan <- err
2019-04-30 21:07:30 +02:00
return
}
log . Debugf ( "connection established: %+v" , conn )
for {
2019-11-11 20:26:12 +01:00
data , errConn := conn . Receive ( )
if errConn != nil {
log . Debugf ( "[%+v] had error: %s" , conn , errConn . Error ( ) )
}
2019-05-03 22:51:27 +02:00
if bytes . Equal ( data , [ ] byte ( "ips?" ) ) {
// recipient wants to try to connect to local ips
var ips [ ] string
// only get local ips if the local is enabled
if ! c . Options . DisableLocal {
// get list of local ips
ips , err = utils . GetLocalIPs ( )
if err != nil {
log . Debugf ( "error getting local ips: %s" , err . Error ( ) )
}
// prepend the port that is being listened to
ips = append ( [ ] string { c . Options . RelayPorts [ 0 ] } , ips ... )
}
bips , _ := json . Marshal ( ips )
conn . Send ( bips )
2019-11-11 20:26:12 +01:00
} else if bytes . Equal ( data , [ ] byte ( "handshake" ) ) {
2019-04-30 21:07:30 +02:00
break
2019-11-11 20:26:12 +01:00
} else {
log . Debugf ( "[%+v] got weird bytes: %+v" , conn , data )
// throttle the reading
time . Sleep ( 100 * time . Millisecond )
2019-04-30 21:07:30 +02:00
}
}
c . conn [ 0 ] = conn
2019-05-01 01:39:36 +02:00
c . Options . RelayPorts = strings . Split ( banner , "," )
2019-11-18 00:32:47 +01:00
if c . Options . NoMultiplexing {
log . Debug ( "no multiplexing" )
c . Options . RelayPorts = [ ] string { c . Options . RelayPorts [ 0 ] }
}
2019-05-02 01:27:49 +02:00
c . ExternalIP = ipaddr
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-07-17 21:04:03 +02:00
err = <- errchan
if err == nil {
// return if no error
return
2019-11-17 21:59:29 +01:00
} else {
log . Debugf ( "error from errchan: %s" , err . Error ( ) )
2019-07-17 21:04:03 +02:00
}
if ! c . Options . DisableLocal {
2019-11-17 21:59:29 +01:00
if strings . Contains ( err . Error ( ) , "refusing files" ) {
errchan <- err
}
2019-07-17 21:04:03 +02:00
err = <- errchan
}
return err
2019-04-30 00:48:17 +02:00
}
// Receive will receive a file
func ( c * Client ) Receive ( ) ( err error ) {
2019-05-01 19:03:16 +02:00
fmt . Fprintf ( os . Stderr , "connecting..." )
2019-05-01 18:38:31 +02:00
// recipient will look for peers first
// and continue if it doesn't find any within 100 ms
2019-05-03 22:51:27 +02:00
usingLocal := false
2019-04-30 23:46:27 +02:00
if ! c . Options . DisableLocal {
2019-05-02 20:50:01 +02:00
log . Debug ( "attempt to discover peers" )
2019-04-30 23:46:27 +02:00
discoveries , err := peerdiscovery . Discover ( peerdiscovery . Settings {
Limit : 1 ,
Payload : [ ] byte ( "ok" ) ,
Delay : 10 * time . Millisecond ,
TimeLimit : 100 * time . Millisecond ,
} )
2019-05-01 18:38:31 +02:00
if err == nil && len ( discoveries ) > 0 {
2019-10-28 20:46:24 +01:00
for i := 0 ; i < len ( discoveries ) ; i ++ {
2019-10-28 21:13:03 +01:00
log . Debugf ( "discovery %d has payload: %+v" , i , discoveries [ i ] )
2019-10-28 20:46:24 +01:00
if ! bytes . HasPrefix ( discoveries [ i ] . Payload , [ ] byte ( "croc" ) ) {
2019-10-28 21:13:03 +01:00
log . Debug ( "skipping discovery" )
continue
2019-10-28 20:46:24 +01:00
}
log . Debug ( "switching to local" )
c . Options . RelayAddress = fmt . Sprintf ( "%s:%s" ,
discoveries [ 0 ] . Address ,
bytes . TrimPrefix ( discoveries [ 0 ] . Payload , [ ] byte ( "croc" ) ) ,
)
c . ExternalIPConnected = c . Options . RelayAddress
usingLocal = true
}
2019-05-01 18:38:31 +02:00
}
2019-04-30 23:46:27 +02:00
log . Debugf ( "discoveries: %+v" , discoveries )
log . Debug ( "establishing connection" )
}
2019-05-01 01:05:19 +02:00
var banner string
2019-05-02 01:27:49 +02:00
c . conn [ 0 ] , banner , c . ExternalIP , err = tcp . ConnectToTCPServer ( c . Options . RelayAddress , c . Options . SharedSecret )
2019-05-01 01:05:19 +02:00
log . Debugf ( "banner: %s" , banner )
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 ] )
2019-05-03 22:51:27 +02:00
if ! usingLocal && ! c . Options . DisableLocal {
// ask the sender for their local ips and port
// and try to connect to them
var data [ ] byte
c . conn [ 0 ] . Send ( [ ] byte ( "ips?" ) )
data , err = c . conn [ 0 ] . Receive ( )
if err != nil {
return
}
log . Debugf ( "ips data: %s" , data )
var ips [ ] string
json . Unmarshal ( data , & ips )
if len ( ips ) > 1 {
port := ips [ 0 ]
ips = ips [ 1 : ]
for _ , ip := range ips {
serverTry := fmt . Sprintf ( "%s:%s" , ip , port )
conn , banner2 , externalIP , errConn := tcp . ConnectToTCPServer ( serverTry , c . Options . SharedSecret , 50 * time . Millisecond )
if errConn != nil {
log . Debugf ( "could not connect to " + serverTry )
continue
}
2019-05-03 22:55:17 +02:00
log . Debugf ( "local connection established to %s" , serverTry )
2019-05-03 22:51:27 +02:00
log . Debugf ( "banner: %s" , banner2 )
// reset to the local port
banner = banner2
c . Options . RelayAddress = serverTry
c . ExternalIP = externalIP
c . conn [ 0 ] . Close ( )
c . conn [ 0 ] = nil
c . conn [ 0 ] = conn
break
}
}
}
2019-04-30 20:46:35 +02:00
c . conn [ 0 ] . Send ( [ ] byte ( "handshake" ) )
2019-05-01 01:39:36 +02:00
c . Options . RelayPorts = strings . Split ( banner , "," )
2019-11-18 00:32:47 +01:00
if c . Options . NoMultiplexing {
log . Debug ( "no multiplexing" )
c . Options . RelayPorts = [ ] string { c . Options . RelayPorts [ 0 ] }
}
2019-04-30 20:46:35 +02:00
log . Debug ( "exchanged header message" )
2019-05-02 20:44:10 +02:00
fmt . Fprintf ( os . Stderr , "\rsecuring channel..." )
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 {
2019-05-03 22:51:27 +02:00
log . Debugf ( "got error receiving: %s" , err . Error ( ) )
2019-05-01 21:09:47 +02:00
break
2019-04-30 04:50:01 +02:00
}
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-05-03 22:51:27 +02:00
log . Debugf ( "got error processing: %s" , err . Error ( ) )
2019-05-01 21:09:47 +02:00
break
2019-04-30 00:48:17 +02:00
}
2019-04-30 05:40:42 +02:00
if done {
break
}
2019-04-30 00:48:17 +02:00
}
2019-09-07 18:49:08 +02:00
// purge errors that come from successful transfer
2019-05-03 02:11:01 +02:00
if c . SuccessfulTransfer {
2019-05-03 02:12:19 +02:00
if err != nil {
log . Debugf ( "purging error: %s" , err )
}
2019-05-03 02:11:01 +02:00
err = nil
}
2019-05-01 21:09:47 +02:00
if c . Options . Stdout && ! c . Options . IsSender {
pathToFile := path . Join (
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . FolderRemote ,
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name ,
)
os . Remove ( pathToFile )
}
2019-04-30 00:48:17 +02:00
return
}
2019-09-20 18:45:42 +02:00
func ( c * Client ) processMessageFileInfo ( m message . Message ) ( done bool , err error ) {
2019-09-20 18:43:16 +02:00
var senderInfo SenderInfo
err = json . Unmarshal ( m . Bytes , & senderInfo )
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-10-08 01:20:24 +02:00
if len ( fi . Name ) > c . longestFilename {
c . longestFilename = len ( fi . Name )
}
2019-09-20 18:43:16 +02:00
}
// c.spinner.Stop()
2019-10-24 15:58:12 +02:00
if ! c . Options . NoPrompt || c . Options . Ask || senderInfo . Ask {
if c . Options . Ask || senderInfo . Ask {
2019-11-18 16:09:39 +01:00
machID := "machineid.ID()"
2019-10-23 23:59:47 +02:00
fmt . Fprintf ( os . Stderr , "\rYour machine id is '%s'.\nAccept %s (%s) from '%s'? (y/n) " , machID , fname , utils . ByteCountDecimal ( totalSize ) , senderInfo . MachineID )
} else {
fmt . Fprintf ( os . Stderr , "\rAccept %s (%s)? (y/n) " , fname , utils . ByteCountDecimal ( totalSize ) )
}
2019-09-20 18:43:16 +02:00
if strings . ToLower ( strings . TrimSpace ( utils . GetInput ( "" ) ) ) != "y" {
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "error" ,
Message : "refusing files" ,
} )
return true , fmt . Errorf ( "refused files" )
}
} else {
fmt . Fprintf ( os . Stderr , "\rReceiving %s (%s) \n" , fname , utils . ByteCountDecimal ( totalSize ) )
}
fmt . Fprintf ( os . Stderr , "\nReceiving (<-%s)\n" , c . ExternalIPConnected )
log . Debug ( c . FilesToTransfer )
c . Step2FileInfoTransfered = true
return
}
2019-09-20 18:41:58 +02:00
func ( c * Client ) procesMesssagePake ( m message . Message ) ( err error ) {
log . Debug ( "received pake payload" )
// if // c.spinner.Suffix != " performing PAKE..." {
// // c.spinner.Stop()
// // c.spinner.Suffix = " performing PAKE..."
// // c.spinner.Start()
// }
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 ( ) {
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "pake" ,
Bytes : c . Pake . Bytes ( ) ,
} )
}
if c . Pake . IsVerified ( ) {
if c . Options . IsSender {
log . Debug ( "generating salt" )
salt := make ( [ ] byte , 8 )
rand . Read ( salt )
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "salt" ,
Bytes : salt ,
Message : c . ExternalIP ,
} )
if err != nil {
return
}
}
// connects to the other ports of the server for transfer
var wg sync . WaitGroup
wg . Add ( len ( c . Options . RelayPorts ) )
for i := 0 ; i < len ( c . Options . RelayPorts ) ; i ++ {
log . Debugf ( "port: [%s]" , c . Options . RelayPorts [ i ] )
go func ( j int ) {
defer wg . Done ( )
server := fmt . Sprintf ( "%s:%s" , strings . Split ( c . Options . RelayAddress , ":" ) [ 0 ] , c . Options . RelayPorts [ j ] )
log . Debugf ( "connecting to %s" , server )
c . conn [ j + 1 ] , _ , _ , err = tcp . ConnectToTCPServer (
server ,
fmt . Sprintf ( "%s-%d" , utils . SHA256 ( c . Options . SharedSecret ) [ : 7 ] , j ) ,
)
if err != nil {
panic ( err )
}
log . Debugf ( "connected to %s" , server )
if ! c . Options . IsSender {
go c . receiveData ( j )
}
} ( i )
}
wg . Wait ( )
}
return
}
2019-09-20 18:45:42 +02:00
func ( c * Client ) processMessageSalt ( m message . Message ) ( done bool , err error ) {
log . Debug ( "received salt" )
if ! c . Options . IsSender {
log . Debug ( "sending salt back" )
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "salt" ,
Bytes : m . Bytes ,
Message : c . ExternalIP ,
} )
}
log . Debugf ( "session key is verified, generating encryption with salt: %x" , m . Bytes )
key , err := c . Pake . SessionKey ( )
if err != nil {
return true , err
}
2019-11-18 00:17:06 +01:00
c . Key , _ , err = crypt . New ( key , m . Bytes )
2019-09-20 18:45:42 +02:00
if err != nil {
return true , err
}
2019-11-18 00:17:06 +01:00
log . Debugf ( "key = %+x" , c . Key )
2019-09-20 18:45:42 +02:00
if c . ExternalIPConnected == "" {
// it can be preset by the local relay
c . ExternalIPConnected = m . Message
}
log . Debugf ( "connected as %s -> %s" , c . ExternalIP , c . ExternalIPConnected )
c . Step1ChannelSecured = true
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
2019-05-03 02:11:01 +02:00
c . SuccessfulTransfer = true
2019-04-30 05:40:42 +02:00
return
2019-04-30 00:48:17 +02:00
case "pake" :
2019-09-20 18:41:58 +02:00
err = c . procesMesssagePake ( m )
2019-05-01 00:10:07 +02:00
case "salt" :
2019-09-20 18:45:42 +02:00
done , err = c . processMessageSalt ( m )
2019-04-30 00:48:17 +02:00
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" :
2019-09-20 18:45:42 +02:00
done , err = c . processMessageFileInfo ( m )
2019-04-30 00:48:17 +02:00
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
2019-05-03 16:30:35 +02:00
c . CurrentFileChunkRanges = remoteFile . CurrentFileChunkRanges
c . CurrentFileChunks = utils . ChunkRangesToChunks ( c . CurrentFileChunkRanges )
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
2019-10-23 23:59:47 +02:00
if c . Options . Ask {
2019-10-24 15:58:12 +02:00
fmt . Fprintf ( os . Stderr , "Send to machine '%s'? (y/n) " , remoteFile . MachineID )
2019-10-23 23:59:47 +02:00
if strings . ToLower ( strings . TrimSpace ( utils . GetInput ( "" ) ) ) != "y" {
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "error" ,
Message : "refusing files" ,
} )
done = true
err = fmt . Errorf ( "refused files" )
return
}
}
2019-04-30 00:48:17 +02:00
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 {
2019-05-03 22:51:27 +02:00
log . Debugf ( "got error from processing message: %s" , err . Error ( ) )
2019-04-30 00:48:17 +02:00
return
}
err = c . updateState ( )
2019-05-03 05:47:41 +02:00
if err != nil {
2019-05-03 22:51:27 +02:00
log . Debugf ( "got error from updating state: %s" , err . Error ( ) )
2019-05-03 05:48:21 +02:00
return
2019-05-03 05:47:41 +02:00
}
2019-04-30 00:48:17 +02:00
return
}
2019-09-20 18:32:32 +02:00
func ( c * Client ) updateIfSenderChannelSecured ( ) ( err error ) {
2019-04-30 00:48:17 +02:00
if c . Options . IsSender && c . Step1ChannelSecured && ! c . Step2FileInfoTransfered {
var b [ ] byte
2019-11-18 16:09:39 +01:00
machID := "machineid.ID()"
2019-04-30 00:48:17 +02:00
b , err = json . Marshal ( SenderInfo {
FilesToTransfer : c . FilesToTransfer ,
2019-10-23 23:59:47 +02:00
MachineID : machID ,
2019-10-24 15:58:12 +02:00
Ask : c . Options . Ask ,
2019-04-30 00:48:17 +02:00
} )
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
}
2019-07-20 17:55:54 +02:00
2019-04-30 00:48:17 +02:00
c . Step2FileInfoTransfered = true
}
2019-09-20 18:32:32 +02:00
return
}
2019-09-20 18:57:18 +02:00
func ( c * Client ) recipientInitializeFile ( ) ( err error ) {
// start initiating the process to receive a new file
log . Debugf ( "working on file %d" , c . FilesToTransferCurrentNum )
// 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 )
var truncate bool // default false
c . CurrentFileChunks = [ ] int64 { }
c . CurrentFileChunkRanges = [ ] int64 { }
if errOpen == nil {
stat , _ := c . CurrentFile . Stat ( )
truncate = stat . Size ( ) != c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size
if truncate == false {
// recipient requests the file and chunks (if empty, then should receive all chunks)
// TODO: determine the missing chunks
c . CurrentFileChunkRanges = utils . MissingChunks (
pathToFile ,
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size ,
models . TCP_BUFFER_SIZE / 2 ,
)
}
} 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
}
}
return
}
2019-09-20 18:59:24 +02:00
func ( c * Client ) recipientGetFileReady ( finished bool ) ( err error ) {
if finished {
// TODO: do the last finishing stuff
log . Debug ( "finished" )
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "finished" ,
} )
if err != nil {
panic ( err )
}
c . SuccessfulTransfer = true
c . FilesHasFinished [ c . FilesToTransferCurrentNum ] = struct { } { }
}
err = c . recipientInitializeFile ( )
if err != nil {
return
}
c . TotalSent = 0
2019-11-18 16:09:39 +01:00
machID := "machineid.ID()"
2019-09-20 18:59:24 +02:00
bRequest , _ := json . Marshal ( RemoteFileRequest {
CurrentFileChunkRanges : c . CurrentFileChunkRanges ,
FilesToTransferCurrentNum : c . FilesToTransferCurrentNum ,
2019-10-23 23:59:47 +02:00
MachineID : machID ,
2019-09-20 18:59:24 +02:00
} )
log . Debug ( "converting to chunk range" )
c . CurrentFileChunks = utils . ChunkRangesToChunks ( c . CurrentFileChunkRanges )
if ! finished {
// setup the progressbar
c . setBar ( )
}
log . Debugf ( "sending recipient ready with %d chunks" , len ( c . CurrentFileChunks ) )
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : "recipientready" ,
Bytes : bRequest ,
} )
if err != nil {
return
}
c . Step3RecipientRequestFile = true
return
}
2019-09-20 19:05:29 +02:00
func ( c * Client ) createEmptyFileAndFinish ( fileInfo FileInfo , i int ) ( err error ) {
log . Debugf ( "touching file with folder / name" )
if ! utils . Exists ( fileInfo . FolderRemote ) {
err = os . MkdirAll ( fileInfo . FolderRemote , os . ModePerm )
if err != nil {
log . Error ( err )
return
}
}
emptyFile , errCreate := os . Create ( path . Join ( fileInfo . FolderRemote , fileInfo . Name ) )
if errCreate != nil {
log . Error ( errCreate )
err = errCreate
return
}
emptyFile . Close ( )
// setup the progressbar
2019-10-08 01:20:24 +02:00
description := fmt . Sprintf ( "%-*s" , c . longestFilename , c . FilesToTransfer [ i ] . Name )
2019-09-20 19:05:29 +02:00
if len ( c . FilesToTransfer ) == 1 {
description = c . FilesToTransfer [ i ] . Name
}
c . bar = progressbar . NewOptions64 ( 1 ,
progressbar . OptionOnCompletion ( func ( ) {
fmt . Fprintf ( os . Stderr , " ✔️\n" )
} ) ,
progressbar . OptionSetWidth ( 20 ) ,
progressbar . OptionSetDescription ( description ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
progressbar . OptionSetBytes64 ( 1 ) ,
progressbar . OptionSetWriter ( os . Stderr ) ,
)
c . bar . Finish ( )
return
}
2019-09-20 18:32:32 +02:00
func ( c * Client ) updateIfRecipientHasFileInfo ( ) ( err error ) {
2019-09-20 19:00:52 +02:00
if ! ( ! c . Options . IsSender && c . Step2FileInfoTransfered && ! c . Step3RecipientRequestFile ) {
return
}
// 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 _ , ok := c . FilesHasFinished [ i ] ; ok {
continue
}
log . Debugf ( "checking %+v" , fileInfo )
if i < c . FilesToTransferCurrentNum {
continue
}
fileHash , errHash := utils . HashFile ( path . Join ( fileInfo . FolderRemote , fileInfo . Name ) )
if fileInfo . Size == 0 {
2019-09-20 19:05:29 +02:00
err = c . createEmptyFileAndFinish ( fileInfo , i )
if err != nil {
2019-09-20 19:00:52 +02:00
return
2019-04-30 00:48:17 +02:00
}
2019-09-20 19:00:52 +02:00
continue
}
log . Debugf ( "%s %+x %+x %+v" , fileInfo . Name , fileHash , fileInfo . Hash , errHash )
2019-09-20 19:03:06 +02:00
if ! bytes . Equal ( fileHash , fileInfo . Hash ) {
log . Debugf ( "hashes are not equal %x != %x" , fileHash , fileInfo . Hash )
} else {
log . Debugf ( "hashes are equal %x == %x" , fileHash , fileInfo . Hash )
}
if errHash != nil {
// probably can't find, its okay
log . Debug ( errHash )
}
2019-09-20 19:00:52 +02:00
if errHash != nil || ! bytes . Equal ( fileHash , fileInfo . Hash ) {
finished = false
c . FilesToTransferCurrentNum = i
break
2019-04-30 00:48:17 +02:00
}
2019-09-20 19:00:52 +02:00
// TODO: print out something about this file already existing
2019-04-30 00:48:17 +02:00
}
2019-09-20 19:00:52 +02:00
err = c . recipientGetFileReady ( finished )
2019-09-20 18:32:32 +02:00
return
}
func ( c * Client ) updateState ( ) ( err error ) {
err = c . updateIfSenderChannelSecured ( )
if err != nil {
return
}
err = c . updateIfRecipientHasFileInfo ( )
if err != nil {
return
}
2019-04-30 00:48:17 +02:00
if c . Options . IsSender && c . Step3RecipientRequestFile && ! c . Step4FileTransfer {
2019-04-30 01:05:48 +02:00
log . Debug ( "start sending data!" )
2019-10-23 23:07:52 +02:00
2019-05-02 01:52:37 +02:00
if ! c . firstSend {
fmt . Fprintf ( os . Stderr , "\nSending (->%s)\n" , c . ExternalIPConnected )
c . firstSend = true
2019-09-07 18:49:08 +02:00
// if there are empty files, show them as already have been transferred now
2019-07-20 17:55:54 +02:00
for i := range c . FilesToTransfer {
if c . FilesToTransfer [ i ] . Size == 0 {
// setup the progressbar and takedown the progress bar for empty files
2019-10-08 01:20:24 +02:00
description := fmt . Sprintf ( "%-*s" , c . longestFilename , c . FilesToTransfer [ i ] . Name )
2019-07-20 17:55:54 +02:00
if len ( c . FilesToTransfer ) == 1 {
description = c . FilesToTransfer [ i ] . Name
}
c . bar = progressbar . NewOptions64 ( 1 ,
progressbar . OptionOnCompletion ( func ( ) {
fmt . Fprintf ( os . Stderr , " ✔️\n" )
} ) ,
progressbar . OptionSetWidth ( 20 ) ,
progressbar . OptionSetDescription ( description ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
progressbar . OptionSetBytes64 ( 1 ) ,
progressbar . OptionSetWriter ( os . Stderr ) ,
)
c . bar . Finish ( )
}
}
2019-05-02 01:52:37 +02:00
}
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-05-03 05:45:21 +02:00
log . Debug ( "beginning sending comms" )
2019-09-07 16:34:05 +02:00
pathToFile := path . Join (
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . FolderSource ,
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name ,
)
c . fread , err = os . Open ( pathToFile )
c . numfinished = 0
if err != nil {
return
}
2019-05-01 01:19:10 +02:00
for i := 0 ; i < len ( c . Options . RelayPorts ) ; i ++ {
2019-05-03 22:51:27 +02:00
log . Debugf ( "starting sending over comm %d" , i )
2019-04-30 05:40:42 +02:00
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 ( ) {
2019-10-08 01:20:24 +02:00
description := fmt . Sprintf ( "%-*s" , c . longestFilename , c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name )
2019-04-30 18:24:32 +02:00
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" )
} ) ,
2019-05-02 20:44:54 +02:00
progressbar . OptionSetWidth ( 20 ) ,
2019-04-30 18:24:32 +02:00
progressbar . OptionSetDescription ( description ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
progressbar . OptionSetBytes64 ( c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size ) ,
progressbar . OptionSetWriter ( os . Stderr ) ,
progressbar . OptionThrottle ( 100 * time . Millisecond ) ,
)
2019-05-03 05:36:49 +02:00
byteToDo := int64 ( len ( c . CurrentFileChunks ) * models . TCP_BUFFER_SIZE / 2 )
if byteToDo > 0 {
2019-05-03 22:51:27 +02:00
bytesDone := c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size - byteToDo
2019-05-03 05:44:25 +02:00
log . Debug ( byteToDo )
2019-05-03 05:36:49 +02:00
log . Debug ( c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size )
2019-05-03 05:43:39 +02:00
log . Debug ( bytesDone )
if bytesDone > 0 {
2019-05-03 22:51:27 +02:00
c . bar . Add64 ( bytesDone )
2019-05-03 05:43:39 +02:00
}
2019-05-03 05:36:49 +02:00
}
2019-04-30 18:24:32 +02:00
}
2019-04-30 05:40:42 +02:00
func ( c * Client ) receiveData ( i int ) {
2019-09-07 16:34:05 +02:00
log . Debugf ( "%d receiving data" , i )
2019-04-30 05:40:42 +02:00
for {
2019-05-01 01:39:36 +02:00
data , err := c . conn [ i + 1 ] . Receive ( )
2019-04-30 05:40:42 +02:00
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-11-18 00:17:06 +01:00
data , err = crypt . Decrypt ( data , c . Key )
2019-04-30 05:40:42 +02:00
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 ++
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 ( )
2019-05-03 02:11:01 +02:00
if c . Options . Stdout || strings . HasPrefix ( c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name , "croc-stdin" ) {
2019-05-01 21:09:47 +02:00
pathToFile := path . Join (
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . FolderRemote ,
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name ,
)
b , _ := ioutil . ReadFile ( pathToFile )
fmt . Print ( string ( b ) )
}
2019-04-30 05:40:42 +02:00
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-09-07 16:34:05 +02:00
c . numfinished ++
if c . numfinished == len ( c . Options . RelayPorts ) {
log . Debug ( "closing file" )
c . fread . Close ( )
}
2019-04-30 06:25:30 +02:00
} ( )
2019-04-30 00:48:17 +02:00
2019-09-07 16:34:05 +02:00
var readingPos int64
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-09-07 16:34:05 +02:00
// log.Debugf("%d trying to read", i)
n , errRead := c . fread . ReadAt ( data , readingPos )
// log.Debugf("%d read %d bytes", i, n)
readingPos += int64 ( n )
2019-04-30 05:40:42 +02:00
2019-05-01 01:19:10 +02:00
if math . Mod ( curi , float64 ( len ( c . Options . RelayPorts ) ) ) == 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 )
2019-11-18 00:17:06 +01:00
dataToSend , err := crypt . Encrypt (
2019-04-30 16:29:02 +02:00
compress . Compress (
append ( posByte , data [ : n ] ... ) ,
) ,
2019-11-18 00:17:06 +01:00
c . Key ,
2019-04-30 16:29:02 +02:00
)
if err != nil {
panic ( err )
}
2019-04-30 05:40:42 +02:00
2019-05-01 01:39:36 +02:00
err = c . conn [ i + 1 ] . Send ( dataToSend )
2019-04-30 16:29:02 +02:00
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-09-07 16:34:05 +02:00
if errRead != nil {
if errRead == io . EOF {
break
}
panic ( errRead )
}
}
2019-04-30 15:57:45 +02:00
return
2018-09-22 05:51:43 +02:00
}