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"
"math"
2019-11-21 23:58:48 +01:00
"net"
2019-04-30 00:48:17 +02:00
"os"
"path"
"path/filepath"
2020-09-21 15:02:13 +02:00
"strconv"
2019-04-30 00:48:17 +02:00
"strings"
"sync"
2018-09-22 05:51:43 +02:00
"time"
2022-02-21 19:16:27 +01:00
2021-10-19 02:46:54 +02:00
"golang.org/x/time/rate"
2018-09-22 05:51:43 +02:00
2019-10-23 23:59:47 +02:00
"github.com/denisbrodbeck/machineid"
2023-09-23 03:15:27 +02:00
ignore "github.com/sabhiram/go-gitignore"
2020-08-23 01:05:00 +02:00
log "github.com/schollz/logger"
2021-04-17 18:42:11 +02:00
"github.com/schollz/pake/v3"
2020-08-23 01:05:00 +02:00
"github.com/schollz/peerdiscovery"
"github.com/schollz/progressbar/v3"
2021-04-17 19:33:38 +02:00
"github.com/schollz/croc/v9/src/comm"
"github.com/schollz/croc/v9/src/compress"
"github.com/schollz/croc/v9/src/crypt"
"github.com/schollz/croc/v9/src/message"
"github.com/schollz/croc/v9/src/models"
"github.com/schollz/croc/v9/src/tcp"
"github.com/schollz/croc/v9/src/utils"
2018-09-22 05:51:43 +02:00
)
2018-09-22 05:17:57 +02:00
2021-10-01 23:24:28 +02:00
var (
ipRequest = [ ] byte ( "ips?" )
handshakeRequest = [ ] byte ( "handshake" )
)
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 16:53:57 +01:00
IsSender bool
SharedSecret string
Debug bool
RelayAddress string
2020-08-27 18:40:41 +02:00
RelayAddress6 string
2019-11-18 16:53:57 +01:00
RelayPorts [ ] string
2019-11-18 17:16:19 +01:00
RelayPassword string
2019-11-18 16:53:57 +01:00
Stdout bool
NoPrompt bool
NoMultiplexing bool
DisableLocal bool
2020-10-21 19:23:12 +02:00
OnlyLocal bool
2021-01-10 14:14:10 +01:00
IgnoreStdin bool
2019-11-18 16:53:57 +01:00
Ask bool
2020-09-03 02:24:32 +02:00
SendingText bool
2020-09-04 00:09:23 +02:00
NoCompress bool
2020-12-17 16:37:48 +01:00
IP string
2021-04-17 00:14:21 +02:00
Overwrite bool
2021-04-17 18:01:58 +02:00
Curve string
2021-04-21 00:32:05 +02:00
HashAlgorithm string
2021-10-19 02:46:54 +02:00
ThrottleUpload string
2022-07-06 15:18:19 +02:00
ZipFolder bool
2023-01-08 17:11:55 +01:00
TestFlag bool
2023-09-23 03:15:27 +02:00
GitIgnore 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 16:53:57 +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
2022-02-21 19:16:27 +01:00
Step2FileInfoTransferred bool
2019-04-30 00:48:17 +02:00
Step3RecipientRequestFile bool
2022-04-09 00:38:22 +02:00
Step4FileTransferred 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
2022-04-09 00:38:22 +02:00
EmptyFoldersToTransfer [ ] FileInfo
2022-04-13 01:03:21 +02:00
TotalNumberOfContents int
2022-04-09 00:38:22 +02:00
TotalNumberFolders int
2019-04-30 00:48:17 +02:00
FilesToTransferCurrentNum int
2019-08-27 18:51:37 +02:00
FilesHasFinished map [ int ] struct { }
2023-09-23 03:15:27 +02:00
TotalFilesIgnored int
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
2021-04-18 05:07:50 +02:00
CurrentFileIsClosed bool
2021-04-18 05:27:51 +02:00
LastFolder string
2019-05-03 22:51:27 +02:00
2022-02-21 19:16:27 +01:00
TotalSent int64
2021-11-17 19:20:32 +01:00
TotalChunksTransferred int
2022-02-21 19:16:27 +01:00
chunkMap map [ uint64 ] struct { }
limiter * rate . Limiter
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
longestFilename int
firstSend bool
2019-04-30 00:48:17 +02:00
2022-02-21 19:16:27 +01:00
mutex * sync . Mutex
fread * os . File
numfinished int
quit chan bool
finishedNum int
2021-11-17 19:20:32 +01:00
numberOfTransferredFiles int
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 {
2022-02-21 19:16:27 +01:00
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" `
Symlink string ` json:"sy,omitempty" `
Mode os . FileMode ` json:"md,omitempty" `
2022-07-06 15:18:19 +02:00
TempFile bool ` json:"tf,omitempty" `
2023-09-23 03:15:27 +02:00
IsIgnored bool ` json:"ig,omitempty" `
2019-04-30 00:48:17 +02:00
}
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 {
2022-04-09 00:38:22 +02:00
FilesToTransfer [ ] FileInfo
EmptyFoldersToTransfer [ ] FileInfo
TotalNumberFolders int
MachineID string
Ask bool
SendingText bool
NoCompress bool
HashAlgorithm string
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 )
2021-04-16 17:13:43 +02:00
if len ( c . Options . SharedSecret ) < 6 {
2020-03-06 16:05:04 +01:00
err = fmt . Errorf ( "code is too short" )
return
}
2019-04-30 20:46:35 +02:00
c . conn = make ( [ ] * comm . Comm , 16 )
2019-04-30 04:50:01 +02:00
2021-10-19 13:10:43 +02:00
// initialize throttler
if len ( c . Options . ThrottleUpload ) > 1 && c . Options . IsSender {
2021-10-19 02:46:54 +02:00
upload := c . Options . ThrottleUpload [ : len ( c . Options . ThrottleUpload ) - 1 ]
2022-12-05 20:21:04 +01:00
var uploadLimit int64
uploadLimit , err = strconv . ParseInt ( upload , 10 , 64 )
2021-10-19 02:46:54 +02:00
if err != nil {
panic ( "Could not parse given Upload Limit" )
}
minBurstSize := models . TCP_BUFFER_SIZE
var rt rate . Limit
switch unit := string ( c . Options . ThrottleUpload [ len ( c . Options . ThrottleUpload ) - 1 : ] ) ; unit {
case "g" , "G" :
2022-02-21 19:16:27 +01:00
uploadLimit = uploadLimit * 1024 * 1024 * 1024
2021-10-19 02:46:54 +02:00
case "m" , "M" :
2022-02-21 19:16:27 +01:00
uploadLimit = uploadLimit * 1024 * 1024
2021-10-19 02:46:54 +02:00
case "k" , "K" :
2022-02-21 19:16:27 +01:00
uploadLimit = uploadLimit * 1024
2021-10-19 13:10:43 +02:00
default :
uploadLimit , err = strconv . ParseInt ( c . Options . ThrottleUpload , 10 , 64 )
if err != nil {
panic ( "Could not parse given Upload Limit" )
}
2021-10-19 02:46:54 +02:00
}
2022-08-05 14:41:18 +02:00
// Somehow 4* is necessary
2022-02-21 19:16:27 +01:00
rt = rate . Every ( time . Second / ( 4 * time . Duration ( uploadLimit ) ) )
if int ( uploadLimit ) > minBurstSize {
2021-10-19 02:46:54 +02:00
minBurstSize = int ( uploadLimit )
}
c . limiter = rate . NewLimiter ( rt , minBurstSize )
log . Debugf ( "Throttling Upload to %#v" , c . limiter . Limit ( ) )
}
2021-04-17 18:01:58 +02:00
// initialize pake for recipient
if ! c . Options . IsSender {
c . Pake , err = pake . InitCurve ( [ ] byte ( c . Options . SharedSecret [ 5 : ] ) , 0 , c . Options . Curve )
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
}
2022-04-09 00:38:22 +02:00
func isEmptyFolder ( folderPath string ) ( bool , error ) {
f , err := os . Open ( folderPath )
if err != nil {
return false , err
}
defer f . Close ( )
_ , err = f . Readdirnames ( 1 )
if err == io . EOF {
return true , nil
}
return false , nil
}
2023-09-23 03:15:27 +02:00
// helper function to walk each subfolder and parses against an ignore file.
// returns a hashmap Key: Absolute filepath, Value: boolean (true=ignore)
func gitWalk ( dir string , gitObj * ignore . GitIgnore , files map [ string ] bool ) {
var ignoredDir bool
var current string
err := filepath . Walk ( dir , func ( path string , info os . FileInfo , err error ) error {
if err != nil {
return err
}
if isChild ( current , path ) && ignoredDir {
files [ path ] = true
return nil
}
if info . IsDir ( ) && filepath . Base ( path ) == filepath . Base ( dir ) {
ignoredDir = false // Skip applying ignore rules for root directory
return nil
}
if gitObj . MatchesPath ( info . Name ( ) ) {
files [ path ] = true
ignoredDir = true
current = path
return nil
} else {
files [ path ] = false
ignoredDir = false
return nil
}
} )
if err != nil {
log . Errorf ( "filepath error" )
}
}
func isChild ( parentPath , childPath string ) bool {
relPath , err := filepath . Rel ( parentPath , childPath )
if err != nil {
return false
}
return ! strings . HasPrefix ( relPath , ".." )
}
2023-03-27 17:13:09 +02:00
// This function retrieves the important file information
2022-08-05 14:41:18 +02:00
// for every file that will be transferred
2023-09-23 03:15:27 +02:00
func GetFilesInfo ( fnames [ ] string , zipfolder bool , ignoreGit bool ) ( filesInfo [ ] FileInfo , emptyFolders [ ] FileInfo , totalNumberFolders int , err error ) {
2022-10-23 00:18:16 +02:00
// fnames: the relative/absolute paths of files/folders that will be transferred
2022-04-09 00:38:22 +02:00
totalNumberFolders = 0
2022-02-21 19:16:27 +01:00
var paths [ ] string
for _ , fname := range fnames {
// Support wildcard
if strings . Contains ( fname , "*" ) {
matches , errGlob := filepath . Glob ( fname )
if errGlob != nil {
err = errGlob
return
}
paths = append ( paths , matches ... )
continue
} else {
paths = append ( paths , fname )
}
}
2023-09-23 03:15:27 +02:00
var ignoredPaths = make ( map [ string ] bool )
if ignoreGit {
wd , wdErr := os . Stat ( ".gitignore" )
if wdErr == nil {
gitIgnore , gitErr := ignore . CompileIgnoreFile ( wd . Name ( ) )
if gitErr == nil {
for _ , path := range paths {
abs , absErr := filepath . Abs ( path )
if absErr != nil {
err = absErr
return
}
if gitIgnore . MatchesPath ( path ) {
ignoredPaths [ abs ] = true
}
}
}
}
for _ , path := range paths {
abs , absErr := filepath . Abs ( path )
if absErr != nil {
err = absErr
return
}
file , fileErr := os . Stat ( path )
if fileErr == nil && file . IsDir ( ) {
_ , subErr := os . Stat ( filepath . Join ( path , ".gitignore" ) )
if subErr == nil {
gitObj , gitObjErr := ignore . CompileIgnoreFile ( filepath . Join ( path , ".gitignore" ) )
if gitObjErr != nil {
err = gitObjErr
return
}
gitWalk ( abs , gitObj , ignoredPaths )
}
}
}
}
2022-12-06 00:24:47 +01:00
for _ , fpath := range paths {
stat , errStat := os . Lstat ( fpath )
2022-02-21 19:16:27 +01:00
if errStat != nil {
err = errStat
return
}
2022-12-06 00:24:47 +01:00
absPath , errAbs := filepath . Abs ( fpath )
2022-02-21 19:16:27 +01:00
if errAbs != nil {
err = errAbs
return
}
2022-07-06 15:18:19 +02:00
if stat . IsDir ( ) && zipfolder {
2022-12-06 00:24:47 +01:00
if fpath [ len ( fpath ) - 1 : ] != "/" {
fpath += "/"
2022-07-07 15:26:37 +02:00
}
2022-12-06 00:24:47 +01:00
fpath = filepath . Dir ( fpath )
dest := filepath . Base ( fpath ) + ".zip"
utils . ZipDirectory ( dest , fpath )
2022-07-06 15:18:19 +02:00
stat , errStat = os . Lstat ( dest )
if errStat != nil {
err = errStat
return
}
absPath , errAbs = filepath . Abs ( dest )
if errAbs != nil {
err = errAbs
return
}
2023-09-23 03:15:27 +02:00
fInfo := FileInfo {
2022-07-06 15:18:19 +02:00
Name : stat . Name ( ) ,
FolderRemote : "./" ,
FolderSource : filepath . Dir ( absPath ) ,
Size : stat . Size ( ) ,
ModTime : stat . ModTime ( ) ,
Mode : stat . Mode ( ) ,
TempFile : true ,
2023-09-23 03:15:27 +02:00
IsIgnored : ignoredPaths [ absPath ] ,
}
if fInfo . IsIgnored {
continue
}
filesInfo = append ( filesInfo , fInfo )
2022-07-06 15:18:19 +02:00
continue
}
2022-02-21 19:16:27 +01:00
if stat . IsDir ( ) {
err = filepath . Walk ( absPath ,
func ( pathName string , info os . FileInfo , err error ) error {
if err != nil {
return err
}
2022-04-09 00:38:22 +02:00
remoteFolder := strings . TrimPrefix ( filepath . Dir ( pathName ) ,
filepath . Dir ( absPath ) + string ( os . PathSeparator ) )
2022-02-21 19:16:27 +01:00
if ! info . IsDir ( ) {
2023-09-23 03:15:27 +02:00
fInfo := FileInfo {
2022-02-21 20:50:24 +01:00
Name : info . Name ( ) ,
2022-12-05 20:21:04 +01:00
FolderRemote : strings . ReplaceAll ( remoteFolder , string ( os . PathSeparator ) , "/" ) + "/" ,
2022-02-21 19:16:27 +01:00
FolderSource : filepath . Dir ( pathName ) ,
Size : info . Size ( ) ,
ModTime : info . ModTime ( ) ,
Mode : info . Mode ( ) ,
2022-07-06 15:18:19 +02:00
TempFile : false ,
2023-09-23 03:15:27 +02:00
IsIgnored : ignoredPaths [ pathName ] ,
}
if fInfo . IsIgnored && ignoreGit {
return nil
} else {
filesInfo = append ( filesInfo , fInfo )
}
2022-04-09 00:38:22 +02:00
} else {
2023-09-23 03:15:27 +02:00
if ignoredPaths [ pathName ] {
return filepath . SkipDir
}
2022-04-09 00:38:22 +02:00
isEmptyFolder , _ := isEmptyFolder ( pathName )
2023-09-23 03:15:27 +02:00
totalNumberFolders ++
2022-04-09 00:38:22 +02:00
if isEmptyFolder {
emptyFolders = append ( emptyFolders , FileInfo {
2022-04-10 23:00:47 +02:00
// Name: info.Name(),
2022-12-05 20:21:04 +01:00
FolderRemote : strings . ReplaceAll ( strings . TrimPrefix ( pathName ,
filepath . Dir ( absPath ) + string ( os . PathSeparator ) ) , string ( os . PathSeparator ) , "/" ) + "/" ,
2022-04-09 00:38:22 +02:00
} )
}
2022-02-21 19:16:27 +01:00
}
return nil
} )
if err != nil {
return
}
2022-07-06 15:18:19 +02:00
2022-02-21 19:16:27 +01:00
} else {
2023-09-23 03:15:27 +02:00
fInfo := FileInfo {
2022-02-21 19:16:27 +01:00
Name : stat . Name ( ) ,
FolderRemote : "./" ,
FolderSource : filepath . Dir ( absPath ) ,
Size : stat . Size ( ) ,
ModTime : stat . ModTime ( ) ,
Mode : stat . Mode ( ) ,
2022-07-06 15:18:19 +02:00
TempFile : false ,
2023-09-23 03:15:27 +02:00
IsIgnored : ignoredPaths [ absPath ] ,
}
if fInfo . IsIgnored && ignoreGit {
continue
} else {
filesInfo = append ( filesInfo , fInfo )
}
2022-02-21 19:16:27 +01:00
}
}
return
}
2022-02-21 19:41:19 +01:00
func ( c * Client ) sendCollectFiles ( filesInfo [ ] FileInfo ) ( err error ) {
c . FilesToTransfer = filesInfo
2019-04-30 23:39:59 +02:00
totalFilesSize := int64 ( 0 )
2022-02-21 19:41:19 +01:00
for i , fileInfo := range c . FilesToTransfer {
2019-04-30 23:39:59 +02:00
var fullPath string
2022-02-21 19:41:19 +01:00
fullPath = fileInfo . FolderSource + string ( os . PathSeparator ) + fileInfo . Name
2019-04-30 23:39:59 +02:00
fullPath = filepath . Clean ( fullPath )
2022-02-21 19:41:19 +01:00
if len ( fileInfo . Name ) > c . longestFilename {
c . longestFilename = len ( fileInfo . Name )
2019-04-30 23:39:59 +02:00
}
2022-02-21 19:41:19 +01:00
if fileInfo . Mode & os . ModeSymlink != 0 {
log . Debugf ( "%s is symlink" , fileInfo . Name )
c . FilesToTransfer [ i ] . Symlink , err = os . Readlink ( fullPath )
2020-09-03 23:49:08 +02:00
if err != nil {
log . Debugf ( "error getting symlink: %s" , err . Error ( ) )
}
log . Debugf ( "%+v" , c . FilesToTransfer [ i ] )
}
2022-02-21 19:41:19 +01:00
2021-04-21 00:48:13 +02:00
if c . Options . HashAlgorithm == "" {
c . Options . HashAlgorithm = "xxhash"
}
2022-02-21 19:41:19 +01:00
2021-04-21 00:32:05 +02:00
c . FilesToTransfer [ i ] . Hash , err = utils . HashFile ( fullPath , c . Options . HashAlgorithm )
2021-04-21 00:44:28 +02:00
log . Debugf ( "hashed %s to %x using %s" , fullPath , c . FilesToTransfer [ i ] . Hash , c . Options . HashAlgorithm )
2022-02-21 19:41:19 +01:00
totalFilesSize += fileInfo . Size
2019-04-30 23:39:59 +02:00
if err != nil {
return
}
log . Debugf ( "file %d info: %+v" , i , c . FilesToTransfer [ i ] )
2021-06-21 20:11:44 +02:00
fmt . Fprintf ( os . Stderr , "\r " )
fmt . Fprintf ( os . Stderr , "\rSending %d files (%s)" , i , utils . ByteCountDecimal ( totalFilesSize ) )
2019-04-30 23:39:59 +02:00
}
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 ) )
2022-04-10 23:00:47 +02:00
folderName := fmt . Sprintf ( "%d folders" , c . TotalNumberFolders )
2019-04-30 23:39:59 +02:00
if len ( c . FilesToTransfer ) == 1 {
fname = fmt . Sprintf ( "'%s'" , c . FilesToTransfer [ 0 ] . Name )
}
2020-09-06 02:23:07 +02:00
if strings . HasPrefix ( fname , "'croc-stdin-" ) {
fname = "'stdin'"
if c . Options . SendingText {
fname = "'text'"
}
}
2021-06-21 20:11:44 +02:00
fmt . Fprintf ( os . Stderr , "\r " )
2022-05-19 01:53:28 +02:00
if c . TotalNumberFolders > 0 {
fmt . Fprintf ( os . Stderr , "\rSending %s and %s (%s)\n" , fname , folderName , utils . ByteCountDecimal ( totalFilesSize ) )
} else {
fmt . Fprintf ( os . Stderr , "\rSending %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
2020-09-21 15:02:13 +02:00
firstPort , _ := strconv . Atoi ( c . Options . RelayPorts [ 0 ] )
2023-03-20 17:16:07 +01:00
openPorts := utils . FindOpenPorts ( "127.0.0.1" , firstPort , len ( c . Options . RelayPorts ) )
2020-09-21 15:02:13 +02:00
if len ( openPorts ) < len ( c . Options . RelayPorts ) {
panic ( "not enough open ports to run local relay" )
}
for i , port := range openPorts {
c . Options . RelayPorts [ i ] = fmt . Sprint ( port )
}
2019-09-20 18:54:10 +02:00
for _ , port := range c . Options . RelayPorts {
go func ( portStr string ) {
debugString := "warn"
if c . Options . Debug {
debugString = "debug"
}
2023-03-20 17:16:07 +01:00
err := tcp . Run ( debugString , "127.0.0.1" , portStr , c . Options . RelayPassword , strings . Join ( c . Options . RelayPorts [ 1 : ] , "," ) )
2019-09-20 18:54:10 +02:00
if err != nil {
panic ( err )
}
} ( port )
}
}
2020-08-26 23:42:49 +02:00
func ( c * Client ) broadcastOnLocalNetwork ( useipv6 bool ) {
2022-02-20 16:40:50 +01:00
var timeLimit time . Duration
2022-12-05 20:21:04 +01:00
// if we don't use an external relay, the broadcast messages need to be sent continuously
2022-02-20 16:40:50 +01:00
if c . Options . OnlyLocal {
timeLimit = - 1 * time . Second
} else {
timeLimit = 30 * time . Second
}
2019-09-20 18:54:10 +02:00
// look for peers first
2020-08-26 23:42:49 +02:00
settings := peerdiscovery . Settings {
2019-09-20 18:54:10 +02:00
Limit : - 1 ,
2019-10-28 20:46:24 +01:00
Payload : [ ] byte ( "croc" + c . Options . RelayPorts [ 0 ] ) ,
2020-10-13 22:47:43 +02:00
Delay : 20 * time . Millisecond ,
2022-02-20 16:40:50 +01:00
TimeLimit : timeLimit ,
2020-08-26 23:42:49 +02:00
}
if useipv6 {
settings . IPVersion = peerdiscovery . IPv6
}
discoveries , err := peerdiscovery . Discover ( settings )
2019-09-20 18:54:10 +02:00
log . Debugf ( "discoveries: %+v" , discoveries )
2019-11-11 20:26:12 +01:00
if err != nil {
2020-08-23 01:05:00 +02:00
log . Debug ( err )
2019-09-20 18:54:10 +02:00
}
}
2022-02-21 19:41:19 +01:00
func ( c * Client ) transferOverLocalRelay ( errchan chan <- error ) {
2019-09-20 18:54:10 +02:00
time . Sleep ( 500 * time . Millisecond )
log . Debug ( "establishing connection" )
var banner string
2023-03-20 17:16:07 +01:00
conn , banner , ipaddr , err := tcp . ConnectToTCPServer ( "127.0.0.1:" + c . Options . RelayPorts [ 0 ] , c . Options . RelayPassword , c . Options . SharedSecret [ : 3 ] )
2019-09-20 18:54:10 +02:00
log . Debugf ( "banner: %s" , banner )
if err != nil {
2023-03-20 17:16:07 +01:00
err = fmt . Errorf ( "could not connect to 127.0.0.1:%s: %w" , c . Options . RelayPorts [ 0 ] , err )
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
}
2019-11-18 22:09:17 +01:00
log . Debugf ( "local connection established: %+v" , conn )
2019-09-20 18:54:10 +02:00
for {
data , _ := conn . Receive ( )
2021-10-01 23:24:28 +02:00
if bytes . Equal ( data , handshakeRequest ) {
2019-09-20 18:54:10 +02:00
break
2019-11-18 22:15:41 +01:00
} else if bytes . Equal ( data , [ ] byte { 1 } ) {
log . Debug ( "got ping" )
2019-11-18 22:09:17 +01:00
} else {
log . Debugf ( "instead of handshake got: %s" , data )
2019-09-20 18:54:10 +02:00
}
}
c . conn [ 0 ] = conn
log . Debug ( "exchanged header message" )
2023-03-20 17:16:07 +01:00
c . Options . RelayAddress = "127.0.0.1"
2019-09-20 18:54:10 +02:00
c . Options . RelayPorts = strings . Split ( banner , "," )
2019-11-18 16:53:57 +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
2022-02-21 19:41:19 +01:00
errchan <- c . transfer ( )
2019-09-20 18:54:10 +02:00
}
2019-09-20 18:47:47 +02:00
// Send will send the specified file
2022-04-09 00:38:22 +02:00
func ( c * Client ) Send ( filesInfo [ ] FileInfo , emptyFoldersToTransfer [ ] FileInfo , totalNumberFolders int ) ( err error ) {
c . EmptyFoldersToTransfer = emptyFoldersToTransfer
c . TotalNumberFolders = totalNumberFolders
2022-04-13 01:03:21 +02:00
c . TotalNumberOfContents = len ( filesInfo )
2022-04-10 23:00:47 +02:00
err = c . sendCollectFiles ( filesInfo )
2019-09-20 18:47:47 +02:00
if err != nil {
return
}
2020-10-22 09:06:54 +02:00
flags := & strings . Builder { }
2019-07-17 22:12:48 +02:00
if c . Options . RelayAddress != models . DEFAULT_RELAY {
2020-10-22 09:06:54 +02:00
flags . WriteString ( "--relay " + c . Options . RelayAddress + " " )
2019-07-17 22:12:48 +02:00
}
2020-10-22 08:37:32 +02:00
if c . Options . RelayPassword != models . DEFAULT_PASSPHRASE {
2020-10-22 09:06:54 +02:00
flags . WriteString ( "--pass " + c . Options . RelayPassword + " " )
2020-10-22 08:37:32 +02:00
}
2020-10-22 09:06:54 +02:00
fmt . Fprintf ( os . Stderr , "Code is: %[1]s\nOn the other computer run\n\ncroc %[2]s%[1]s\n" , c . Options . SharedSecret , flags . String ( ) )
2019-10-23 23:59:47 +02:00
if c . Options . Ask {
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 ( )
2020-10-19 20:02:48 +02:00
// broadcast on ipv4
2020-08-26 23:42:49 +02:00
go c . broadcastOnLocalNetwork ( false )
2020-10-21 17:17:39 +02:00
// broadcast on ipv6
go c . broadcastOnLocalNetwork ( true )
2022-02-21 19:41:19 +01:00
go c . transferOverLocalRelay ( errchan )
2019-04-30 23:46:27 +02:00
}
2019-04-30 21:07:30 +02:00
2020-10-21 19:23:12 +02:00
if ! c . Options . OnlyLocal {
go func ( ) {
var ipaddr , banner string
var conn * comm . Comm
durations := [ ] time . Duration { 100 * time . Millisecond , 5 * time . Second }
for i , address := range [ ] string { c . Options . RelayAddress6 , c . Options . RelayAddress } {
if address == "" {
continue
}
host , port , _ := net . SplitHostPort ( address )
log . Debugf ( "host: '%s', port: '%s'" , host , port )
// Default port to :9009
if port == "" {
host = address
2021-10-01 23:24:28 +02:00
port = models . DEFAULT_PORT
2020-10-21 19:23:12 +02:00
}
log . Debugf ( "got host '%v' and port '%v'" , host , port )
address = net . JoinHostPort ( host , port )
log . Debugf ( "trying connection to %s" , address )
conn , banner , ipaddr , err = tcp . ConnectToTCPServer ( address , c . Options . RelayPassword , c . Options . SharedSecret [ : 3 ] , durations [ i ] )
if err == nil {
c . Options . RelayAddress = address
break
}
log . Debugf ( "could not establish '%s'" , address )
2020-08-27 18:40:41 +02:00
}
2020-10-21 19:23:12 +02:00
if conn == nil && err == nil {
err = fmt . Errorf ( "could not connect" )
2020-08-27 18:40:41 +02:00
}
2020-10-21 19:23:12 +02:00
if err != nil {
err = fmt . Errorf ( "could not connect to %s: %w" , c . Options . RelayAddress , err )
log . Debug ( err )
errchan <- err
return
2019-11-11 20:26:12 +01:00
}
2020-10-21 19:23:12 +02:00
log . Debugf ( "banner: %s" , banner )
log . Debugf ( "connection established: %+v" , conn )
for {
log . Debug ( "waiting for bytes" )
data , errConn := conn . Receive ( )
if errConn != nil {
log . Debugf ( "[%+v] had error: %s" , conn , errConn . Error ( ) )
2019-05-03 22:51:27 +02:00
}
2021-10-01 23:24:28 +02:00
if bytes . Equal ( data , ipRequest ) {
2020-10-21 19:23:12 +02:00
// 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: %v" , err )
}
// prepend the port that is being listened to
ips = append ( [ ] string { c . Options . RelayPorts [ 0 ] } , ips ... )
}
bips , _ := json . Marshal ( ips )
2022-12-05 20:21:04 +01:00
if err = conn . Send ( bips ) ; err != nil {
2020-10-21 19:23:12 +02:00
log . Errorf ( "error sending: %v" , err )
}
2021-10-01 23:24:28 +02:00
} else if bytes . Equal ( data , handshakeRequest ) {
2020-10-21 19:23:12 +02:00
break
} else if bytes . Equal ( data , [ ] byte { 1 } ) {
log . Debug ( "got ping" )
continue
} else {
log . Debugf ( "[%+v] got weird bytes: %+v" , conn , data )
// throttle the reading
errchan <- fmt . Errorf ( "gracefully refusing using the public relay" )
return
2020-08-23 01:05:00 +02:00
}
2019-04-30 21:07:30 +02:00
}
2020-10-21 19:23:12 +02:00
c . conn [ 0 ] = conn
c . Options . RelayPorts = strings . Split ( banner , "," )
if c . Options . NoMultiplexing {
log . Debug ( "no multiplexing" )
c . Options . RelayPorts = [ ] string { c . Options . RelayPorts [ 0 ] }
}
c . ExternalIP = ipaddr
log . Debug ( "exchanged header message" )
2022-02-21 19:41:19 +01:00
errchan <- c . transfer ( )
2020-10-21 19:23:12 +02:00
} ( )
}
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 {
2020-08-23 01:05:00 +02:00
log . Debugf ( "error from errchan: %v" , err )
2020-09-03 21:45:40 +02:00
if strings . Contains ( err . Error ( ) , "could not secure channel" ) {
return err
}
2019-07-17 21:04:03 +02:00
}
if ! c . Options . DisableLocal {
2019-11-18 23:26:01 +01:00
if strings . Contains ( err . Error ( ) , "refusing files" ) || strings . Contains ( err . Error ( ) , "EOF" ) || strings . Contains ( err . Error ( ) , "bad password" ) {
2019-11-17 21:59:29 +01:00
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
2020-12-17 16:37:48 +01:00
isIPset := false
if c . Options . OnlyLocal || c . Options . IP != "" {
2020-10-21 19:23:12 +02:00
c . Options . RelayAddress = ""
c . Options . RelayAddress6 = ""
}
2020-12-17 16:37:48 +01:00
if c . Options . IP != "" {
// check ip version
if strings . Count ( c . Options . IP , ":" ) >= 2 {
log . Debug ( "assume ipv6" )
c . Options . RelayAddress6 = c . Options . IP
}
if strings . Contains ( c . Options . IP , "." ) {
log . Debug ( "assume ipv4" )
c . Options . RelayAddress = c . Options . IP
}
isIPset = true
}
if ! c . Options . DisableLocal && ! isIPset {
2019-05-02 20:50:01 +02:00
log . Debug ( "attempt to discover peers" )
2020-08-26 23:42:49 +02:00
var discoveries [ ] peerdiscovery . Discovered
var wgDiscovery sync . WaitGroup
var dmux sync . Mutex
wgDiscovery . Add ( 2 )
go func ( ) {
defer wgDiscovery . Done ( )
ipv4discoveries , err1 := peerdiscovery . Discover ( peerdiscovery . Settings {
Limit : 1 ,
Payload : [ ] byte ( "ok" ) ,
2020-10-13 22:47:43 +02:00
Delay : 20 * time . Millisecond ,
2020-08-26 23:56:57 +02:00
TimeLimit : 200 * time . Millisecond ,
2020-08-26 23:42:49 +02:00
} )
if err1 == nil && len ( ipv4discoveries ) > 0 {
dmux . Lock ( )
err = err1
2020-10-22 18:53:27 +02:00
discoveries = append ( discoveries , ipv4discoveries ... )
2020-08-26 23:42:49 +02:00
dmux . Unlock ( )
}
} ( )
go func ( ) {
defer wgDiscovery . Done ( )
ipv6discoveries , err1 := peerdiscovery . Discover ( peerdiscovery . Settings {
Limit : 1 ,
Payload : [ ] byte ( "ok" ) ,
2020-10-13 22:47:43 +02:00
Delay : 20 * time . Millisecond ,
2020-08-26 23:56:57 +02:00
TimeLimit : 200 * time . Millisecond ,
2020-08-26 23:42:49 +02:00
IPVersion : peerdiscovery . IPv6 ,
} )
if err1 == nil && len ( ipv6discoveries ) > 0 {
dmux . Lock ( )
err = err1
2020-10-22 18:53:27 +02:00
discoveries = append ( discoveries , ipv6discoveries ... )
2020-08-26 23:42:49 +02:00
dmux . Unlock ( )
}
} ( )
wgDiscovery . Wait ( )
2019-05-01 18:38:31 +02:00
if err == nil && len ( discoveries ) > 0 {
2020-10-22 18:53:27 +02:00
log . Debugf ( "all discoveries: %+v" , discoveries )
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" )
2021-10-02 20:55:43 +02:00
portToUse := string ( bytes . TrimPrefix ( discoveries [ i ] . Payload , [ ] byte ( "croc" ) ) )
2020-07-15 19:47:56 +02:00
if portToUse == "" {
2021-10-01 23:24:28 +02:00
portToUse = models . DEFAULT_PORT
2020-07-15 19:47:56 +02:00
}
2021-10-02 20:55:43 +02:00
address := net . JoinHostPort ( discoveries [ i ] . Address , portToUse )
errPing := tcp . PingServer ( address )
if errPing == nil {
2021-11-17 19:20:32 +01:00
log . Debugf ( "successfully pinged '%s'" , address )
2020-10-22 19:11:11 +02:00
c . Options . RelayAddress = address
c . ExternalIPConnected = c . Options . RelayAddress
c . Options . RelayAddress6 = ""
usingLocal = true
break
2021-10-02 20:55:43 +02:00
} else {
log . Debugf ( "could not ping: %+v" , errPing )
2020-10-22 19:11:11 +02:00
}
2019-10-28 20:46:24 +01:00
}
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
2021-05-12 16:04:10 +02:00
durations := [ ] time . Duration { 200 * time . Millisecond , 5 * time . Second }
2020-10-21 19:23:12 +02:00
err = fmt . Errorf ( "found no addresses to connect" )
2020-08-27 18:40:41 +02:00
for i , address := range [ ] string { c . Options . RelayAddress6 , c . Options . RelayAddress } {
if address == "" {
continue
}
2020-09-02 18:46:31 +02:00
var host , port string
2020-09-03 18:53:14 +02:00
host , port , _ = net . SplitHostPort ( address )
2020-08-27 18:40:41 +02:00
// Default port to :9009
if port == "" {
2020-09-03 18:53:14 +02:00
host = address
2021-10-01 23:24:28 +02:00
port = models . DEFAULT_PORT
2020-08-27 18:40:41 +02:00
}
log . Debugf ( "got host '%v' and port '%v'" , host , port )
address = net . JoinHostPort ( host , port )
log . Debugf ( "trying connection to %s" , address )
c . conn [ 0 ] , banner , c . ExternalIP , err = tcp . ConnectToTCPServer ( address , c . Options . RelayPassword , c . Options . SharedSecret [ : 3 ] , durations [ i ] )
if err == nil {
c . Options . RelayAddress = address
break
}
log . Debugf ( "could not establish '%s'" , address )
}
2019-04-30 20:46:35 +02:00
if err != nil {
2020-08-23 01:05:00 +02:00
err = fmt . Errorf ( "could not connect to %s: %w" , c . Options . RelayAddress , err )
log . Debug ( err )
2019-04-30 20:46:35 +02:00
return
}
2019-11-18 22:09:17 +01:00
log . Debugf ( "receiver connection established: %+v" , c . conn [ 0 ] )
2020-09-02 18:46:31 +02:00
log . Debugf ( "banner: %s" , banner )
2019-05-03 22:51:27 +02:00
2023-01-08 17:11:55 +01:00
if c . Options . TestFlag {
log . Debugf ( "TEST FLAG ENABLED, TESTING LOCAL IPS" )
}
if c . Options . TestFlag || ( ! usingLocal && ! c . Options . DisableLocal && ! isIPset ) {
2019-05-03 22:51:27 +02:00
// ask the sender for their local ips and port
// and try to connect to them
2019-11-18 22:09:17 +01:00
log . Debug ( "sending ips?" )
2019-05-03 22:51:27 +02:00
var data [ ] byte
2022-12-05 20:21:04 +01:00
if err = c . conn [ 0 ] . Send ( ipRequest ) ; err != nil {
2020-08-23 01:05:00 +02:00
log . Errorf ( "ips send error: %v" , err )
}
2019-05-03 22:51:27 +02:00
data , err = c . conn [ 0 ] . Receive ( )
if err != nil {
return
}
log . Debugf ( "ips data: %s" , data )
var ips [ ] string
2022-12-05 20:21:04 +01:00
if err = json . Unmarshal ( data , & ips ) ; err != nil {
2020-09-13 21:15:05 +02:00
log . Debugf ( "ips unmarshal error: %v" , err )
2020-08-23 01:05:00 +02:00
}
2019-05-03 22:51:27 +02:00
if len ( ips ) > 1 {
port := ips [ 0 ]
ips = ips [ 1 : ]
for _ , ip := range ips {
2019-11-21 23:58:48 +01:00
ipv4Addr , ipv4Net , errNet := net . ParseCIDR ( fmt . Sprintf ( "%s/24" , ip ) )
log . Debugf ( "ipv4Add4: %+v, ipv4Net: %+v, err: %+v" , ipv4Addr , ipv4Net , errNet )
localIps , _ := utils . GetLocalIPs ( )
haveLocalIP := false
for _ , localIP := range localIps {
localIPparsed := net . ParseIP ( localIP )
2023-01-08 17:11:55 +01:00
log . Debugf ( "localIP: %+v, localIPparsed: %+v" , localIP , localIPparsed )
2019-11-21 23:58:48 +01:00
if ipv4Net . Contains ( localIPparsed ) {
haveLocalIP = true
2023-01-08 17:11:55 +01:00
log . Debugf ( "ip: %+v is a local IP" , ip )
2019-11-21 23:58:48 +01:00
break
}
}
if ! haveLocalIP {
log . Debugf ( "%s is not a local IP, skipping" , ip )
continue
}
2022-05-16 22:04:55 +02:00
serverTry := net . JoinHostPort ( ip , port )
2021-10-02 20:55:43 +02:00
conn , banner2 , externalIP , errConn := tcp . ConnectToTCPServer ( serverTry , c . Options . RelayPassword , c . Options . SharedSecret [ : 3 ] , 500 * time . Millisecond )
2019-05-03 22:51:27 +02:00
if errConn != nil {
2021-10-02 20:55:43 +02:00
log . Debug ( errConn )
2019-05-03 22:51:27 +02:00
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
}
}
}
2022-12-05 20:21:04 +01:00
if err = c . conn [ 0 ] . Send ( handshakeRequest ) ; err != nil {
2020-08-23 01:05:00 +02:00
log . Errorf ( "handshake send error: %v" , err )
}
2019-05-01 01:39:36 +02:00
c . Options . RelayPorts = strings . Split ( banner , "," )
2019-11-18 16:53:57 +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..." )
2022-02-21 19:41:19 +01:00
err = c . transfer ( )
2021-04-17 00:12:11 +02:00
if err == nil {
2022-04-09 00:38:22 +02:00
if c . numberOfTransferredFiles + len ( c . EmptyFoldersToTransfer ) == 0 {
2021-04-17 02:17:32 +02:00
fmt . Fprintf ( os . Stderr , "\rNo files transferred." )
2021-04-17 00:12:11 +02:00
}
}
return
2019-04-30 00:48:17 +02:00
}
2022-02-21 19:41:19 +01:00
func ( c * Client ) transfer ( ) ( 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 {
2021-10-01 23:24:28 +02:00
Type : message . TypePAKE ,
2021-04-17 18:01:58 +02:00
Bytes : c . Pake . Bytes ( ) ,
Bytes2 : [ ] byte ( c . Options . Curve ) ,
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 {
2020-08-23 01:05:00 +02:00
log . Debugf ( "got error receiving: %v" , err )
2020-03-06 16:12:08 +01:00
if ! c . Step1ChannelSecured {
err = fmt . Errorf ( "could not secure channel" )
}
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 {
2020-08-23 01:05:00 +02:00
log . Debugf ( "got error processing: %v" , err )
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
}
2022-07-06 15:18:19 +02:00
if c . Options . IsSender && c . SuccessfulTransfer {
for _ , file := range c . FilesToTransfer {
if file . TempFile {
fmt . Println ( "Removing " + file . Name )
os . Remove ( file . Name )
}
}
}
2019-05-01 21:09:47 +02:00
2022-07-06 20:36:11 +02:00
if c . SuccessfulTransfer && ! c . Options . IsSender {
for _ , file := range c . FilesToTransfer {
if file . TempFile {
utils . UnzipDirectory ( "." , file . Name )
os . Remove ( file . Name )
log . Debugf ( "Removing %s\n" , file . Name )
}
}
}
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 ,
)
2020-09-03 02:24:32 +02:00
log . Debugf ( "pathToFile: %s" , pathToFile )
// close if not closed already
2021-04-18 05:07:50 +02:00
if ! c . CurrentFileIsClosed {
c . CurrentFile . Close ( )
c . CurrentFileIsClosed = true
}
2022-12-05 20:21:04 +01:00
if err = os . Remove ( pathToFile ) ; err != nil {
2020-08-23 01:05:00 +02:00
log . Warnf ( "error removing %s: %v" , pathToFile , err )
}
2020-09-03 02:35:36 +02:00
fmt . Print ( "\n" )
2019-05-01 21:09:47 +02:00
}
2020-09-03 21:45:40 +02:00
if err != nil && strings . Contains ( err . Error ( ) , "pake not successful" ) {
log . Debugf ( "pake error: %s" , err . Error ( ) )
err = fmt . Errorf ( "password mismatch" )
}
2020-09-13 21:15:05 +02:00
if err != nil && strings . Contains ( err . Error ( ) , "unexpected end of JSON input" ) {
log . Debugf ( "error: %s" , err . Error ( ) )
err = fmt . Errorf ( "room not ready" )
}
2019-04-30 00:48:17 +02:00
return
}
2022-04-13 01:03:21 +02:00
func ( c * Client ) createEmptyFolder ( i int ) ( err error ) {
err = os . MkdirAll ( c . EmptyFoldersToTransfer [ i ] . FolderRemote , os . ModePerm )
if err != nil {
return
}
fmt . Fprintf ( os . Stderr , "%s\n" , c . EmptyFoldersToTransfer [ i ] . FolderRemote )
c . bar = progressbar . NewOptions64 ( 1 ,
progressbar . OptionOnCompletion ( func ( ) {
c . fmtPrintUpdate ( )
} ) ,
progressbar . OptionSetWidth ( 20 ) ,
progressbar . OptionSetDescription ( " " ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
progressbar . OptionShowBytes ( true ) ,
progressbar . OptionShowCount ( ) ,
progressbar . OptionSetWriter ( os . Stderr ) ,
progressbar . OptionSetVisibility ( ! c . Options . SendingText ) ,
)
c . bar . Finish ( )
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 {
2020-09-13 21:15:05 +02:00
log . Debug ( err )
2019-09-20 18:43:16 +02:00
return
}
2020-09-03 02:24:32 +02:00
c . Options . SendingText = senderInfo . SendingText
2020-09-04 00:09:23 +02:00
c . Options . NoCompress = senderInfo . NoCompress
2021-04-21 00:32:05 +02:00
c . Options . HashAlgorithm = senderInfo . HashAlgorithm
2022-04-09 00:38:22 +02:00
c . EmptyFoldersToTransfer = senderInfo . EmptyFoldersToTransfer
c . TotalNumberFolders = senderInfo . TotalNumberFolders
2022-04-13 01:03:21 +02:00
c . FilesToTransfer = senderInfo . FilesToTransfer
c . TotalNumberOfContents = 0
if c . FilesToTransfer != nil {
c . TotalNumberOfContents += len ( c . FilesToTransfer )
}
if c . EmptyFoldersToTransfer != nil {
c . TotalNumberOfContents += len ( c . EmptyFoldersToTransfer )
}
2021-04-21 00:32:05 +02:00
if c . Options . HashAlgorithm == "" {
2021-06-21 16:34:28 +02:00
c . Options . HashAlgorithm = "xxhash"
2021-04-21 00:32:05 +02:00
}
log . Debugf ( "using hash algorithm: %s" , c . Options . HashAlgorithm )
2020-09-04 00:09:23 +02:00
if c . Options . NoCompress {
log . Debug ( "disabling compression" )
}
2020-09-03 02:24:32 +02:00
if c . Options . SendingText {
c . Options . Stdout = true
}
2022-04-13 01:03:21 +02:00
2019-09-20 18:43:16 +02:00
fname := fmt . Sprintf ( "%d files" , len ( c . FilesToTransfer ) )
2022-04-09 00:38:22 +02:00
folderName := fmt . Sprintf ( "%d folders" , c . TotalNumberFolders )
2019-09-20 18:43:16 +02:00
if len ( c . FilesToTransfer ) == 1 {
fname = fmt . Sprintf ( "'%s'" , c . FilesToTransfer [ 0 ] . Name )
}
totalSize := int64 ( 0 )
2020-09-06 02:23:07 +02:00
for i , fi := range c . FilesToTransfer {
2019-09-20 18:43:16 +02:00
totalSize += fi . Size
2019-10-08 01:20:24 +02:00
if len ( fi . Name ) > c . longestFilename {
c . longestFilename = len ( fi . Name )
}
2022-02-03 18:39:37 +01:00
if strings . HasPrefix ( fi . Name , "croc-stdin-" ) && c . Options . SendingText {
2020-09-06 02:23:07 +02:00
c . FilesToTransfer [ i ] . Name , err = utils . RandomFileName ( )
if err != nil {
return
}
}
2019-09-20 18:43:16 +02:00
}
// c.spinner.Stop()
2021-05-07 19:21:24 +02:00
action := "Accept"
2021-05-01 21:27:44 +02:00
if c . Options . SendingText {
action = "Display"
fname = "text message"
2020-09-06 02:23:07 +02:00
}
2019-10-24 15:58:12 +02:00
if ! c . Options . NoPrompt || c . Options . Ask || senderInfo . Ask {
if c . Options . Ask || senderInfo . Ask {
2019-10-23 23:59:47 +02:00
machID , _ := machineid . ID ( )
2021-06-10 14:12:05 +02:00
fmt . Fprintf ( os . Stderr , "\rYour machine id is '%s'.\n%s %s (%s) from '%s'? (Y/n) " , machID , action , fname , utils . ByteCountDecimal ( totalSize ) , senderInfo . MachineID )
2019-10-23 23:59:47 +02:00
} else {
2022-05-19 01:57:00 +02:00
if c . TotalNumberFolders > 0 {
fmt . Fprintf ( os . Stderr , "\r%s %s and %s (%s)? (Y/n) " , action , fname , folderName , utils . ByteCountDecimal ( totalSize ) )
} else {
fmt . Fprintf ( os . Stderr , "\r%s %s (%s)? (Y/n) " , action , fname , utils . ByteCountDecimal ( totalSize ) )
}
2019-10-23 23:59:47 +02:00
}
2021-06-10 14:12:05 +02:00
choice := strings . ToLower ( utils . GetInput ( "" ) )
if choice != "" && choice != "y" && choice != "yes" {
2019-09-20 18:43:16 +02:00
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypeError ,
2019-09-20 18:43:16 +02:00
Message : "refusing files" ,
} )
2021-03-10 01:55:42 +01:00
if err != nil {
return false , err
}
2019-09-20 18:43:16 +02:00
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 )
2022-04-09 00:38:22 +02:00
for i := 0 ; i < len ( c . EmptyFoldersToTransfer ) ; i += 1 {
2022-04-13 01:03:21 +02:00
_ , errExists := os . Stat ( c . EmptyFoldersToTransfer [ i ] . FolderRemote )
if os . IsNotExist ( errExists ) {
err = c . createEmptyFolder ( i )
if err != nil {
return
}
} else {
isEmpty , _ := isEmptyFolder ( c . EmptyFoldersToTransfer [ i ] . FolderRemote )
if ! isEmpty {
log . Debug ( "asking to overwrite" )
prompt := fmt . Sprintf ( "\n%s already has some content in it. \nDo you want" +
" to overwrite it with an empty folder? (y/N) " , c . EmptyFoldersToTransfer [ i ] . FolderRemote )
choice := strings . ToLower ( utils . GetInput ( prompt ) )
if choice == "y" || choice == "yes" {
err = c . createEmptyFolder ( i )
if err != nil {
return
}
}
}
2022-04-09 00:38:22 +02:00
}
}
2022-04-10 23:00:47 +02:00
2022-08-05 14:41:18 +02:00
// if no files are to be transferred, then we can end the file transfer process
2022-04-09 00:38:22 +02:00
if c . FilesToTransfer == nil {
c . SuccessfulTransfer = true
c . Step3RecipientRequestFile = true
c . Step4FileTransferred = true
errStopTransfer := message . Send ( c . conn [ 0 ] , c . Key , message . Message {
Type : message . TypeFinished ,
} )
if errStopTransfer != nil {
err = errStopTransfer
}
}
2019-09-20 18:43:16 +02:00
log . Debug ( c . FilesToTransfer )
2021-11-17 19:20:32 +01:00
c . Step2FileInfoTransferred = true
2019-09-20 18:43:16 +02:00
return
}
2021-04-16 23:25:57 +02:00
func ( c * Client ) processMessagePake ( m message . Message ) ( err error ) {
2019-09-20 18:41:58 +02:00
log . Debug ( "received pake payload" )
2021-04-16 23:01:48 +02:00
2021-04-16 23:25:57 +02:00
var salt [ ] byte
2021-04-16 23:01:48 +02:00
if c . Options . IsSender {
2021-04-17 18:01:58 +02:00
// initialize curve based on the recipient's choice
log . Debugf ( "using curve %s" , string ( m . Bytes2 ) )
c . Pake , err = pake . InitCurve ( [ ] byte ( c . Options . SharedSecret [ 5 : ] ) , 1 , string ( m . Bytes2 ) )
if err != nil {
log . Error ( err )
return
}
// update the pake
err = c . Pake . Update ( m . Bytes )
if err != nil {
return
}
// generate salt and send it back to recipient
2021-04-16 23:01:48 +02:00
log . Debug ( "generating salt" )
2021-04-16 23:25:57 +02:00
salt = make ( [ ] byte , 8 )
2021-04-16 23:01:48 +02:00
if _ , rerr := rand . Read ( salt ) ; err != nil {
log . Errorf ( "can't generate random numbers: %v" , rerr )
return
}
2021-04-16 23:25:57 +02:00
log . Debug ( "sender sending pake+salt" )
2021-04-16 23:01:48 +02:00
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypePAKE ,
2021-04-16 23:25:57 +02:00
Bytes : c . Pake . Bytes ( ) ,
Bytes2 : salt ,
2021-04-16 23:01:48 +02:00
} )
2021-04-16 23:25:57 +02:00
} else {
2021-04-17 18:01:58 +02:00
err = c . Pake . Update ( m . Bytes )
if err != nil {
return
}
2021-04-16 23:25:57 +02:00
salt = m . Bytes2
}
// generate key
key , err := c . Pake . SessionKey ( )
if err != nil {
return err
2021-04-16 23:01:48 +02:00
}
2021-04-16 23:25:57 +02:00
c . Key , _ , err = crypt . New ( key , salt )
if err != nil {
return err
}
log . Debugf ( "generated key = %+x with salt %x" , c . Key , salt )
2019-09-20 18:41:58 +02:00
2021-04-16 23:01:48 +02:00
// 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 ( )
var host string
2023-03-20 17:16:07 +01:00
if c . Options . RelayAddress == "127.0.0.1" {
2021-04-16 23:01:48 +02:00
host = c . Options . RelayAddress
} else {
host , _ , err = net . SplitHostPort ( c . Options . RelayAddress )
2019-09-20 18:41:58 +02:00
if err != nil {
2021-04-16 23:01:48 +02:00
log . Errorf ( "bad relay address %s" , c . Options . RelayAddress )
return
2019-09-20 18:41:58 +02:00
}
2021-04-16 23:01:48 +02:00
}
server := net . JoinHostPort ( host , c . Options . RelayPorts [ j ] )
log . Debugf ( "connecting to %s" , server )
c . conn [ j + 1 ] , _ , _ , err = tcp . ConnectToTCPServer (
server ,
c . Options . RelayPassword ,
fmt . Sprintf ( "%s-%d" , utils . SHA256 ( c . Options . SharedSecret [ : 5 ] ) [ : 6 ] , j ) ,
)
if err != nil {
panic ( err )
}
log . Debugf ( "connected to %s" , server )
if ! c . Options . IsSender {
go c . receiveData ( j )
}
} ( i )
2019-09-20 18:41:58 +02:00
}
2021-04-16 23:01:48 +02:00
wg . Wait ( )
2019-09-20 18:41:58 +02:00
2021-04-16 23:25:57 +02:00
if ! c . Options . IsSender {
2020-02-28 21:58:46 +01:00
log . Debug ( "sending external IP" )
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypeExternalIP ,
2020-03-31 22:33:27 +02:00
Message : c . ExternalIP ,
Bytes : m . Bytes ,
2020-02-28 21:58:46 +01:00
} )
}
return
}
func ( c * Client ) processExternalIP ( m message . Message ) ( done bool , err error ) {
2020-03-31 22:42:52 +02:00
log . Debugf ( "received external IP: %+v" , m )
2021-04-17 00:12:11 +02:00
if c . Options . IsSender {
2020-02-28 21:58:46 +01:00
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypeExternalIP ,
2020-02-28 21:58:46 +01:00
Message : c . ExternalIP ,
} )
if err != nil {
return true , err
}
}
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 {
2020-08-23 01:05:00 +02:00
err = fmt . Errorf ( "problem with decoding: %w" , err )
log . Debug ( err )
2019-04-30 04:50:01 +02:00
return
}
2021-04-17 02:15:51 +02:00
// only "pake" messages should be unencrypted
// if a non-"pake" message is received unencrypted something
// is weird
2021-10-01 23:24:28 +02:00
if m . Type != message . TypePAKE && c . Key == nil {
2021-04-17 02:15:51 +02:00
err = fmt . Errorf ( "unencrypted communication rejected" )
done = true
return
}
2019-04-30 00:48:17 +02:00
switch m . Type {
2021-10-01 23:24:28 +02:00
case message . TypeFinished :
2019-04-30 05:40:42 +02:00
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypeFinished ,
2019-04-30 05:40:42 +02:00
} )
done = true
2019-05-03 02:11:01 +02:00
c . SuccessfulTransfer = true
2019-04-30 05:40:42 +02:00
return
2021-10-01 23:24:28 +02:00
case message . TypePAKE :
2021-04-16 23:25:57 +02:00
err = c . processMessagePake ( m )
2020-03-06 16:12:08 +01:00
if err != nil {
2020-08-23 01:05:00 +02:00
err = fmt . Errorf ( "pake not successful: %w" , err )
log . Debug ( err )
2020-03-06 16:12:08 +01:00
}
2021-10-01 23:24:28 +02:00
case message . TypeExternalIP :
2020-02-28 21:58:46 +01:00
done , err = c . processExternalIP ( m )
2021-10-01 23:24:28 +02:00
case message . TypeError :
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
2021-10-01 23:24:28 +02:00
case message . TypeFileInfo :
2019-09-20 18:45:42 +02:00
done , err = c . processMessageFileInfo ( m )
2021-10-01 23:24:28 +02:00
case message . TypeRecipientReady :
2019-04-30 00:48:17 +02:00
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 )
2020-03-18 04:06:50 +01:00
c . mutex . Lock ( )
2019-04-30 16:29:02 +02:00
c . chunkMap = make ( map [ uint64 ] struct { } )
for _ , chunk := range c . CurrentFileChunks {
c . chunkMap [ uint64 ( chunk ) ] = struct { } { }
}
2020-03-18 04:06:50 +01:00
c . mutex . Unlock ( )
2019-04-30 00:48:17 +02:00
c . Step3RecipientRequestFile = true
2019-10-23 23:59:47 +02:00
if c . Options . Ask {
2021-06-10 14:12:05 +02:00
fmt . Fprintf ( os . Stderr , "Send to machine '%s'? (Y/n) " , remoteFile . MachineID )
choice := strings . ToLower ( utils . GetInput ( "" ) )
if choice != "" && choice != "y" && choice != "yes" {
2019-10-23 23:59:47 +02:00
err = message . Send ( c . conn [ 0 ] , c . Key , message . Message {
2021-10-01 23:24:28 +02:00
Type : message . TypeError ,
2019-10-23 23:59:47 +02:00
Message : "refusing files" ,
} )
done = true
return
}
}
2021-10-01 23:24:28 +02:00
case message . TypeCloseSender :
2019-04-30 18:43:52 +02:00
c . bar . Finish ( )
2019-04-30 00:48:17 +02:00
log . Debug ( "close-sender received..." )
2022-04-09 00:38:22 +02:00
c . Step4FileTransferred = false
2019-04-30 00:48:17 +02:00
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 {
2021-10-01 23:24:28 +02:00
Type : message . TypeCloseRecipient ,
2019-04-30 04:50:01 +02:00
} )
2021-10-01 23:24:28 +02:00
case message . TypeCloseRecipient :
2022-04-09 00:38:22 +02:00
c . Step4FileTransferred = false
2019-04-30 00:48:17 +02:00
c . Step3RecipientRequestFile = false
}
if err != nil {
2020-08-23 01:05:00 +02:00
log . Debugf ( "got error from processing message: %v" , err )
2019-04-30 00:48:17 +02:00
return
}
err = c . updateState ( )
2019-05-03 05:47:41 +02:00
if err != nil {
2020-08-23 01:05:00 +02:00
log . Debugf ( "got error from updating state: %v" , err )
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 ) {
2021-11-17 19:20:32 +01:00
if c . Options . IsSender && c . Step1ChannelSecured && ! c . Step2FileInfoTransferred {
2019-04-30 00:48:17 +02:00
var b [ ] byte
2019-10-23 23:59:47 +02:00
machID , _ := machineid . ID ( )
2019-04-30 00:48:17 +02:00
b , err = json . Marshal ( SenderInfo {
2022-04-09 00:38:22 +02:00
FilesToTransfer : c . FilesToTransfer ,
EmptyFoldersToTransfer : c . EmptyFoldersToTransfer ,
MachineID : machID ,
Ask : c . Options . Ask ,
TotalNumberFolders : c . TotalNumberFolders ,
SendingText : c . Options . SendingText ,
NoCompress : c . Options . NoCompress ,
HashAlgorithm : c . Options . HashAlgorithm ,
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 {
2021-10-01 23:24:28 +02:00
Type : message . TypeFileInfo ,
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
2021-11-17 19:20:32 +01:00
c . Step2FileInfoTransferred = true
2019-04-30 00:48:17 +02:00
}
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 )
2020-08-26 18:55:59 +02:00
folderForFileBase := filepath . Base ( folderForFile )
if folderForFileBase != "." && folderForFileBase != "" {
if err := os . MkdirAll ( folderForFile , os . ModePerm ) ; err != nil {
log . Errorf ( "can't create %s: %v" , folderForFile , err )
}
2020-08-23 01:05:00 +02:00
}
2019-09-20 18:57:18 +02:00
var errOpen error
c . CurrentFile , errOpen = os . OpenFile (
pathToFile ,
2022-12-05 20:21:04 +01:00
os . O_WRONLY , 0 o666 )
2019-09-20 18:57:18 +02:00
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
2022-04-10 23:00:47 +02:00
if ! truncate {
2019-09-20 18:57:18 +02:00
// 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 {
2020-08-23 01:05:00 +02:00
errOpen = fmt . Errorf ( "could not create %s: %w" , pathToFile , errOpen )
2019-09-20 18:57:18 +02:00
log . Error ( errOpen )
return errOpen
}
2023-02-10 10:18:44 +01:00
errChmod := os . Chmod ( pathToFile , c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Mode . Perm ( ) )
if errChmod != nil {
log . Error ( errChmod )
}
2019-09-20 18:57:18 +02:00
truncate = true
}
if truncate {
err := c . CurrentFile . Truncate ( c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size )
if err != nil {
2020-08-23 01:05:00 +02:00
err = fmt . Errorf ( "could not truncate %s: %w" , pathToFile , err )
2019-09-20 18:57:18 +02:00
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 {
2021-10-01 23:24:28 +02:00
Type : message . TypeFinished ,
2019-09-20 18:59:24 +02:00
} )
if err != nil {
panic ( err )
}
c . SuccessfulTransfer = true
c . FilesHasFinished [ c . FilesToTransferCurrentNum ] = struct { } { }
}
err = c . recipientInitializeFile ( )
if err != nil {
return
}
c . TotalSent = 0
2021-04-18 05:07:50 +02:00
c . CurrentFileIsClosed = false
2019-10-23 23:59:47 +02: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 {
2021-10-01 23:24:28 +02:00
Type : message . TypeRecipientReady ,
2019-09-20 18:59:24 +02:00
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
}
}
2020-09-03 23:57:09 +02:00
pathToFile := path . Join ( fileInfo . FolderRemote , fileInfo . Name )
if fileInfo . Symlink != "" {
log . Debug ( "creating symlink" )
2021-03-05 18:00:15 +01:00
// remove symlink if it exists
if _ , errExists := os . Lstat ( pathToFile ) ; errExists == nil {
os . Remove ( pathToFile )
}
2020-09-03 23:57:09 +02:00
err = os . Symlink ( fileInfo . Symlink , pathToFile )
if err != nil {
return
}
} else {
emptyFile , errCreate := os . Create ( pathToFile )
if errCreate != nil {
log . Error ( errCreate )
err = errCreate
return
}
emptyFile . Close ( )
2019-09-20 19:05:29 +02:00
}
// 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 {
2022-04-10 23:00:47 +02:00
description = c . FilesToTransfer [ i ] . Name
// description = ""
2021-04-18 05:27:51 +02:00
} else {
description = " " + description
2019-09-20 19:05:29 +02:00
}
c . bar = progressbar . NewOptions64 ( 1 ,
progressbar . OptionOnCompletion ( func ( ) {
2020-10-23 02:03:46 +02:00
c . fmtPrintUpdate ( )
2019-09-20 19:05:29 +02:00
} ) ,
progressbar . OptionSetWidth ( 20 ) ,
progressbar . OptionSetDescription ( description ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
2020-03-31 22:33:27 +02:00
progressbar . OptionShowBytes ( true ) ,
2020-05-01 15:59:09 +02:00
progressbar . OptionShowCount ( ) ,
2019-09-20 19:05:29 +02:00
progressbar . OptionSetWriter ( os . Stderr ) ,
2020-09-03 02:33:53 +02:00
progressbar . OptionSetVisibility ( ! c . Options . SendingText ) ,
2019-09-20 19:05:29 +02:00
)
c . bar . Finish ( )
return
}
2019-09-20 18:32:32 +02:00
func ( c * Client ) updateIfRecipientHasFileInfo ( ) ( err error ) {
2022-12-05 20:21:04 +01:00
if c . Options . IsSender || ! c . Step2FileInfoTransferred || c . Step3RecipientRequestFile {
2019-09-20 19:00:52 +02:00
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
}
if i < c . FilesToTransferCurrentNum {
continue
}
2021-04-21 00:36:46 +02:00
log . Debugf ( "checking %+v" , fileInfo )
2021-04-20 18:08:02 +02:00
recipientFileInfo , errRecipientFile := os . Lstat ( path . Join ( fileInfo . FolderRemote , fileInfo . Name ) )
var errHash error
var fileHash [ ] byte
if errRecipientFile == nil && recipientFileInfo . Size ( ) == fileInfo . Size {
// the file exists, but is same size, so hash it
2021-04-21 00:32:05 +02:00
fileHash , errHash = utils . HashFile ( path . Join ( fileInfo . FolderRemote , fileInfo . Name ) , c . Options . HashAlgorithm )
2021-04-20 18:08:02 +02:00
}
2020-09-03 23:57:09 +02:00
if fileInfo . Size == 0 || fileInfo . Symlink != "" {
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
2021-04-17 02:15:51 +02:00
} else {
2021-11-17 19:20:32 +01:00
c . numberOfTransferredFiles ++
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 ) {
2021-04-21 00:44:28 +02:00
log . Debugf ( "hashed %s to %x using %s" , fileInfo . Name , fileHash , c . Options . HashAlgorithm )
2019-09-20 19:03:06 +02:00
log . Debugf ( "hashes are not equal %x != %x" , fileHash , fileInfo . Hash )
2022-02-23 16:57:40 +01:00
if errHash == nil && ! c . Options . Overwrite && errRecipientFile == nil && ! strings . HasPrefix ( fileInfo . Name , "croc-stdin-" ) && ! c . Options . SendingText {
2021-06-15 23:53:16 +02:00
missingChunks := utils . ChunkRangesToChunks ( utils . MissingChunks (
path . Join ( fileInfo . FolderRemote , fileInfo . Name ) ,
fileInfo . Size ,
models . TCP_BUFFER_SIZE / 2 ,
) )
percentDone := 100 - float64 ( len ( missingChunks ) * models . TCP_BUFFER_SIZE / 2 ) / float64 ( fileInfo . Size ) * 100
2021-04-18 05:07:50 +02:00
log . Debug ( "asking to overwrite" )
2021-06-10 14:12:05 +02:00
prompt := fmt . Sprintf ( "\nOverwrite '%s'? (y/N) " , path . Join ( fileInfo . FolderRemote , fileInfo . Name ) )
2021-06-15 23:53:16 +02:00
if percentDone < 99 {
prompt = fmt . Sprintf ( "\nResume '%s' (%2.1f%%)? (y/N) " , path . Join ( fileInfo . FolderRemote , fileInfo . Name ) , percentDone )
}
2021-06-10 14:12:05 +02:00
choice := strings . ToLower ( utils . GetInput ( prompt ) )
if choice != "y" && choice != "yes" {
2021-04-17 02:15:51 +02:00
fmt . Fprintf ( os . Stderr , "skipping '%s'" , path . Join ( fileInfo . FolderRemote , fileInfo . Name ) )
2021-04-17 00:12:11 +02:00
continue
2021-04-17 02:15:51 +02:00
}
2021-04-17 00:12:11 +02:00
}
2019-09-20 19:03:06 +02:00
} 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
2021-11-17 19:20:32 +01:00
c . numberOfTransferredFiles ++
2021-04-18 05:27:51 +02:00
newFolder , _ := filepath . Split ( fileInfo . FolderRemote )
2022-02-23 16:57:40 +01:00
if newFolder != c . LastFolder && len ( c . FilesToTransfer ) > 0 && ! c . Options . SendingText && newFolder != "./" {
2021-04-18 05:27:51 +02:00
fmt . Fprintf ( os . Stderr , "\r%s\n" , newFolder )
}
c . LastFolder = newFolder
2019-09-20 19:00:52 +02:00
break
2019-04-30 00:48:17 +02:00
}
}
2022-04-09 00:38:22 +02:00
c . recipientGetFileReady ( finished )
2019-09-20 18:32:32 +02:00
return
}
2020-10-23 02:03:46 +02:00
func ( c * Client ) fmtPrintUpdate ( ) {
c . finishedNum ++
2022-04-13 01:03:21 +02:00
if c . TotalNumberOfContents > 1 {
fmt . Fprintf ( os . Stderr , " %d/%d\n" , c . finishedNum , c . TotalNumberOfContents )
2021-03-15 19:50:30 +01:00
} else {
fmt . Fprintf ( os . Stderr , "\n" )
2020-10-23 02:03:46 +02:00
}
}
2019-09-20 18:32:32 +02:00
func ( c * Client ) updateState ( ) ( err error ) {
err = c . updateIfSenderChannelSecured ( )
if err != nil {
return
}
err = c . updateIfRecipientHasFileInfo ( )
if err != nil {
return
}
2022-04-09 00:38:22 +02:00
if c . Options . IsSender && c . Step3RecipientRequestFile && ! c . Step4FileTransferred {
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 {
2022-04-10 23:00:47 +02:00
description = c . FilesToTransfer [ i ] . Name
// description = ""
2019-07-20 17:55:54 +02:00
}
c . bar = progressbar . NewOptions64 ( 1 ,
progressbar . OptionOnCompletion ( func ( ) {
2020-10-23 02:03:46 +02:00
c . fmtPrintUpdate ( )
2019-07-20 17:55:54 +02:00
} ) ,
progressbar . OptionSetWidth ( 20 ) ,
progressbar . OptionSetDescription ( description ) ,
progressbar . OptionSetRenderBlankState ( true ) ,
2020-03-31 22:33:27 +02:00
progressbar . OptionShowBytes ( true ) ,
2020-05-01 15:59:09 +02:00
progressbar . OptionShowCount ( ) ,
2019-07-20 17:55:54 +02:00
progressbar . OptionSetWriter ( os . Stderr ) ,
2020-09-03 02:33:53 +02:00
progressbar . OptionSetVisibility ( ! c . Options . SendingText ) ,
2019-07-20 17:55:54 +02:00
)
c . bar . Finish ( )
}
}
2019-05-02 01:52:37 +02:00
}
2022-04-09 00:38:22 +02:00
c . Step4FileTransferred = 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
2021-04-18 05:07:50 +02:00
c . CurrentFileIsClosed = false
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 )
2022-04-10 23:00:47 +02:00
folder , _ := filepath . Split ( c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . FolderRemote )
2022-04-13 01:03:21 +02:00
if folder == "./" {
2022-04-10 23:00:47 +02:00
description = c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name
2022-04-13 01:03:21 +02:00
} else if ! c . Options . IsSender {
2021-04-18 05:27:51 +02:00
description = " " + description
2019-04-30 18:24:32 +02:00
}
c . bar = progressbar . NewOptions64 (
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size ,
progressbar . OptionOnCompletion ( func ( ) {
2020-10-23 02:03:46 +02:00
c . fmtPrintUpdate ( )
2019-04-30 18:24:32 +02:00
} ) ,
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 ) ,
2020-03-31 22:33:27 +02:00
progressbar . OptionShowBytes ( true ) ,
2020-05-01 15:59:09 +02:00
progressbar . OptionShowCount ( ) ,
2019-04-30 18:24:32 +02:00
progressbar . OptionSetWriter ( os . Stderr ) ,
progressbar . OptionThrottle ( 100 * time . Millisecond ) ,
2020-09-03 02:33:53 +02:00
progressbar . OptionSetVisibility ( ! c . Options . SendingText ) ,
2019-04-30 18:24:32 +02:00
)
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-11-18 22:09:17 +01:00
if bytes . Equal ( data , [ ] byte { 1 } ) {
log . Debug ( "got ping" )
continue
}
2019-04-30 15:57:45 +02:00
2023-10-05 17:30:56 +02:00
// data, err = crypt.Decrypt(data, c.Key)
// if err != nil {
// panic(err)
// }
2020-09-04 00:09:23 +02:00
if ! c . Options . NoCompress {
data = compress . Decompress ( data )
}
2019-04-30 05:40:42 +02:00
// 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
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 : ] ) )
2021-11-17 19:20:32 +01:00
c . TotalChunksTransferred ++
// log.Debug(len(c.CurrentFileChunks), c.TotalChunksTransferred, c.TotalSent, c.FilesToTransfer[c.FilesToTransferCurrentNum].Size)
2021-08-06 18:48:26 +02:00
2021-11-17 19:20:32 +01:00
if ! c . CurrentFileIsClosed && ( c . TotalChunksTransferred == len ( c . CurrentFileChunks ) || c . TotalSent == c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Size ) {
2021-04-18 05:07:50 +02:00
c . CurrentFileIsClosed = true
2019-04-30 05:40:42 +02:00
log . Debug ( "finished receiving!" )
2022-12-05 20:21:04 +01:00
if err = c . CurrentFile . Close ( ) ; err != nil {
2021-04-18 05:07:50 +02:00
log . Debugf ( "error closing %s: %v" , c . CurrentFile . Name ( ) , err )
2022-04-10 23:00:47 +02:00
} else {
log . Debugf ( "Successful closing %s" , c . CurrentFile . Name ( ) )
2020-08-23 01:05:00 +02:00
}
2020-09-06 02:23:07 +02:00
if c . Options . Stdout || c . Options . SendingText {
2019-05-01 21:09:47 +02:00
pathToFile := path . Join (
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . FolderRemote ,
c . FilesToTransfer [ c . FilesToTransferCurrentNum ] . Name ,
)
2021-11-17 04:25:52 +01:00
b , _ := os . ReadFile ( pathToFile )
2019-05-01 21:09:47 +02:00
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 {
2021-10-01 23:24:28 +02:00
Type : message . TypeCloseSender ,
2019-04-30 05:40:42 +02:00
} )
if err != nil {
panic ( err )
}
}
2021-08-06 18:48:26 +02:00
c . mutex . Unlock ( )
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" )
2020-08-23 01:05:00 +02:00
if err := c . fread . Close ( ) ; err != nil {
log . Errorf ( "error closing file: %v" , err )
}
2019-09-07 16:34:05 +02:00
}
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 )
2022-02-21 20:50:24 +01:00
if c . limiter != nil {
2021-10-19 02:46:54 +02:00
r := c . limiter . ReserveN ( time . Now ( ) , n )
log . Debugf ( "Limiting Upload for %d" , r . Delay ( ) )
time . Sleep ( r . Delay ( ) )
}
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 )
2020-09-04 00:09:23 +02:00
var err error
var dataToSend [ ] byte
if c . Options . NoCompress {
2023-10-05 17:30:56 +02:00
dataToSend = append ( posByte , data [ : n ] ... )
2020-09-04 00:09:23 +02:00
} else {
dataToSend , err = crypt . Encrypt (
compress . Compress (
append ( posByte , data [ : n ] ... ) ,
) ,
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)
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 )
}
}
2018-09-22 05:51:43 +02:00
}