0
0
Fork 0
mirror of https://github.com/schollz/croc.git synced 2025-10-11 13:21:00 +02:00

no need to specify number of connections now

This commit is contained in:
Zack Scholl 2018-04-22 21:42:05 -07:00
parent f0ed13c392
commit 638ca9ef27
4 changed files with 124 additions and 264 deletions

122
Gopkg.lock generated
View file

@ -1,122 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/dustin/go-humanize"
packages = ["."]
revision = "02af3965c54e8cacf948b97fef38925c4120652c"
[[projects]]
name = "github.com/fatih/structs"
packages = ["."]
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
version = "v1.0"
[[projects]]
branch = "master"
name = "github.com/hashicorp/errwrap"
packages = ["."]
revision = "7554cd9344cec97297fa6649b055a8c98c2a1e55"
[[projects]]
branch = "master"
name = "github.com/hashicorp/go-multierror"
packages = ["."]
revision = "b7773ae218740a7be65057fc60b366a49b538a44"
[[projects]]
branch = "master"
name = "github.com/mars9/crypt"
packages = ["."]
revision = "65899cf653ff022fe5c7fe504b439feed9e7e0fc"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/schollz/mnemonicode"
packages = ["."]
revision = "15c9654387fad6d257aa28f9be57b9f124101955"
[[projects]]
name = "github.com/schollz/progressbar"
packages = ["."]
revision = "5441d79e9e64d6356575e1e296142ebba27949a7"
version = "v0.6.0"
[[projects]]
name = "github.com/schollz/tarinator-go"
packages = ["."]
revision = "a8626a55d48dbb55141e51226eefa15c157a65a8"
version = "v0.3.3"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "c155da19408a8799da419ed3eeb0cb5db0ad5dbc"
version = "v1.0.5"
[[projects]]
name = "github.com/urfave/cli"
packages = ["."]
revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
version = "v1.20.0"
[[projects]]
name = "github.com/yudai/gotty"
packages = ["pkg/homedir"]
revision = "a080c85cbc59226c94c6941ad8c395232d72d517"
version = "v2.0.0-alpha.3"
[[projects]]
branch = "master"
name = "github.com/yudai/hcl"
packages = [
".",
"hcl",
"json"
]
revision = "5fa2393b3552119bf33a69adb1402a1160cba23d"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = [
"pbkdf2",
"scrypt",
"ssh/terminal"
]
revision = "e73bf333ef8920dbb52ad18d4bd38ad9d9bc76d7"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = [
"unix",
"windows"
]
revision = "79b0c6888797020a994db17c8510466c72fe75d9"
[[projects]]
name = "golang.org/x/text"
packages = ["transform"]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "f8ef1cfe7bc4581e86cff48f7b1d070246e97b9d49fcf6d30a4421e5b3bfaf75"
solver-name = "gps-cdcl"
solver-version = 1

View file

@ -1,38 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/gosuri/uiprogress"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "github.com/schollz/mnemonicode"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.3"

View file

@ -17,11 +17,12 @@ import (
"time" "time"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/schollz/peerdiscovery"
"github.com/schollz/progressbar" "github.com/schollz/progressbar"
tarinator "github.com/schollz/tarinator-go" tarinator "github.com/schollz/tarinator-go"
log "github.com/cihub/seelog"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
) )
type Connection struct { type Connection struct {
@ -59,6 +60,7 @@ const (
) )
func NewConnection(config *AppConfig) (*Connection, error) { func NewConnection(config *AppConfig) (*Connection, error) {
defer log.Flush()
c := new(Connection) c := new(Connection)
c.Debug = config.Debug c.Debug = config.Debug
c.DontEncrypt = config.DontEncrypt c.DontEncrypt = config.DontEncrypt
@ -71,6 +73,13 @@ func NewConnection(config *AppConfig) (*Connection, error) {
c.rate = config.Rate c.rate = config.Rate
c.Local = config.Local c.Local = config.Local
if c.Local {
c.DontEncrypt = true
if c.Server == "cowyo.com" {
c.Server = ""
}
}
stat, _ := os.Stdin.Stat() stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 { if (stat.Mode() & os.ModeCharDevice) == 0 {
config.File = "stdin" config.File = "stdin"
@ -121,11 +130,10 @@ func NewConnection(config *AppConfig) (*Connection, error) {
c.Path = config.Path c.Path = config.Path
} }
log.SetFormatter(&log.TextFormatter{})
if c.Debug { if c.Debug {
log.SetLevel(log.DebugLevel) SetLogLevel("debug")
} else { } else {
log.SetLevel(log.WarnLevel) SetLogLevel("warn")
} }
return c, nil return c, nil
@ -133,6 +141,9 @@ func NewConnection(config *AppConfig) (*Connection, error) {
func (c *Connection) cleanup() { func (c *Connection) cleanup() {
log.Debug("cleaning") log.Debug("cleaning")
if c.Debug {
return
}
for id := 0; id <= 8; id++ { for id := 0; id <= 8; id++ {
err := os.Remove(path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id))) err := os.Remove(path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id)))
if err == nil { if err == nil {
@ -154,55 +165,66 @@ func (c *Connection) Run() error {
}() }()
defer c.cleanup() defer c.cleanup()
forceSingleThreaded := false if c.Local {
c.DontEncrypt = true
c.Code = peerdiscovery.RandStringBytesMaskImprSrc(4)
c.Yes = true
}
if c.Local && c.Server == "" {
c.Server = "localhost"
p := peerdiscovery.New(peerdiscovery.Settings{
Limit: 1,
TimeLimit: 60 * time.Second,
Delay: 500 * time.Millisecond,
Payload: []byte(c.Code),
})
if c.IsSender {
c.Server = "localhost"
p.Discover()
fmt.Println("running relay on local address " + GetLocalIP())
fmt.Println([]byte(c.Code))
} else {
discovered, err := p.Discover()
if err != nil {
return err
}
fmt.Println(discovered)
if len(discovered) == 0 {
return errors.New("could not find server")
}
c.Server = discovered[0].Address
fmt.Println(discovered[0].Payload)
c.Code = string(discovered[0].Payload)
time.Sleep(1 * time.Second)
}
}
if c.Local && c.IsSender {
relay := NewRelay(&AppConfig{
Debug: c.Debug,
})
go relay.Run()
}
log.Debug("checking code validity")
if len(c.Code) == 0 {
c.Code = GetRandomName()
log.Debug("changed code to ", c.Code)
}
c.NumberOfConnections = MAX_NUMBER_THREADS
if c.IsSender { if c.IsSender {
fsize, err := FileSize(path.Join(c.File.Path, c.File.Name)) fsize, err := FileSize(path.Join(c.File.Path, c.File.Name))
if err != nil { if err != nil {
return err return err
} }
if fsize < MAX_NUMBER_THREADS*BUFFERSIZE { if fsize < MAX_NUMBER_THREADS*BUFFERSIZE {
forceSingleThreaded = true c.NumberOfConnections = 1
log.Debug("forcing single thread") log.Debug("forcing single thread")
} }
} }
log.Debug("checking code validity")
for {
// check code
goodCode := true
m := strings.Split(c.Code, "-")
log.Debug(m)
numThreads, errParse := strconv.Atoi(m[0])
if len(m) < 2 {
goodCode = false
log.Debug("code too short")
} else if numThreads > MAX_NUMBER_THREADS || numThreads < 1 || (forceSingleThreaded && numThreads != 1) {
c.NumberOfConnections = MAX_NUMBER_THREADS
goodCode = false
log.Debug("incorrect number of threads")
} else if errParse != nil {
goodCode = false
log.Debug("problem parsing threads")
}
log.Debug(m)
log.Debug(goodCode)
if !goodCode {
if c.IsSender {
if forceSingleThreaded {
c.NumberOfConnections = 1
}
c.Code = strconv.Itoa(c.NumberOfConnections) + "-" + GetRandomName()
} else {
if len(c.Code) != 0 {
fmt.Println("Code must begin with number of threads (e.g. 3-some-code)")
}
c.Code = getInput("Enter receive code: ")
}
} else {
break
}
}
// assign number of connections
c.NumberOfConnections, _ = strconv.Atoi(strings.Split(c.Code, "-")[0])
if c.IsSender { if c.IsSender {
if c.DontEncrypt { if c.DontEncrypt {
@ -265,13 +287,8 @@ func (c *Connection) Run() error {
// runClient spawns threads for parallel uplink/downlink via TCP // runClient spawns threads for parallel uplink/downlink via TCP
func (c *Connection) runClient() error { func (c *Connection) runClient() error {
logger := log.WithFields(log.Fields{
"code": c.Code,
"sender?": c.IsSender,
})
c.HashedCode = Hash(c.Code) c.HashedCode = Hash(c.Code)
c.NumberOfConnections = MAX_NUMBER_THREADS
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(c.NumberOfConnections) wg.Add(c.NumberOfConnections)
@ -309,17 +326,17 @@ func (c *Connection) runClient() error {
defer connection.Close() defer connection.Close()
message := receiveMessage(connection) message := receiveMessage(connection)
logger.Debugf("relay says: %s", message) log.Debugf("relay says: %s", message)
if c.IsSender { if c.IsSender {
logger.Debugf("telling relay: %s", "s."+c.Code) log.Debugf("telling relay: %s", "s."+c.Code)
metaData, err := json.Marshal(c.File) metaData, err := json.Marshal(c.File)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
encryptedMetaData, salt, iv := Encrypt(metaData, c.Code) encryptedMetaData, salt, iv := Encrypt(metaData, c.Code, c.DontEncrypt)
sendMessage("s."+c.HashedCode+"."+hex.EncodeToString(encryptedMetaData)+"-"+salt+"-"+iv, connection) sendMessage("s."+c.HashedCode+"."+hex.EncodeToString(encryptedMetaData)+"-"+salt+"-"+iv, connection)
} else { } else {
logger.Debugf("telling relay: %s", "r."+c.Code) log.Debugf("telling relay: %s", "r."+c.Code)
if c.Wait { if c.Wait {
// tell server to wait for sender // tell server to wait for sender
sendMessage("r."+c.HashedCode+".0.0.0", connection) sendMessage("r."+c.HashedCode+".0.0.0", connection)
@ -329,7 +346,7 @@ func (c *Connection) runClient() error {
} }
} }
if c.IsSender { // this is a sender if c.IsSender { // this is a sender
logger.Debug("waiting for ok from relay") log.Debug("waiting for ok from relay")
message = receiveMessage(connection) message = receiveMessage(connection)
if message == "timeout" { if message == "timeout" {
responses.Lock() responses.Lock()
@ -346,14 +363,14 @@ func (c *Connection) runClient() error {
responses.gotConnectionInUse = true responses.gotConnectionInUse = true
responses.Unlock() responses.Unlock()
} else { } else {
logger.Debug("got ok from relay") log.Debug("got ok from relay")
if id == 0 { if id == 0 {
fmt.Fprintf(os.Stderr, "\nSending (->%s)..\n", message) fmt.Fprintf(os.Stderr, "\nSending (->%s)..\n", message)
} }
// wait for pipe to be made // wait for pipe to be made
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
// Write data from file // Write data from file
logger.Debug("send file") log.Debug("send file")
responses.Lock() responses.Lock()
responses.startTime = time.Now() responses.startTime = time.Now()
responses.Unlock() responses.Unlock()
@ -365,7 +382,7 @@ func (c *Connection) runClient() error {
} }
} }
} else { // this is a receiver } else { // this is a receiver
logger.Debug("waiting for meta data from sender") log.Debug("waiting for meta data from sender")
message = receiveMessage(connection) message = receiveMessage(connection)
if message == "no" { if message == "no" {
if id == 0 { if id == 0 {
@ -452,7 +469,7 @@ func (c *Connection) runClient() error {
sendMessage("not ok", connection) sendMessage("not ok", connection)
} else { } else {
sendMessage("ok", connection) sendMessage("ok", connection)
logger.Debug("receive file") log.Debug("receive file")
if id == 0 { if id == 0 {
fmt.Fprintf(os.Stderr, "\nReceiving (<-%s)..\n", sendersAddress) fmt.Fprintf(os.Stderr, "\nReceiving (<-%s)..\n", sendersAddress)
} }
@ -467,7 +484,7 @@ func (c *Connection) runClient() error {
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
} }
if err := c.receiveFile(id, connection); err != nil { if err := c.receiveFile(id, connection); err != nil {
log.Error(errors.Wrap(err, "Problem receiving the file: ")) log.Debug(errors.Wrap(err, "no file to recieve"))
} }
} }
} }
@ -475,6 +492,7 @@ func (c *Connection) runClient() error {
}(id) }(id)
} }
wg.Wait() wg.Wait()
log.Debugf("moving on")
responses.Lock() responses.Lock()
defer responses.Unlock() defer responses.Unlock()
@ -575,27 +593,31 @@ func fileAlreadyExists(s []string, f string) bool {
func (c *Connection) catFile() error { func (c *Connection) catFile() error {
// cat the file // cat the file
files := make([]string, c.NumberOfConnections) files := make([]string, c.NumberOfConnections)
for id := range files { i := 0
files[id] = path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id)) for id := 0; id < len(files); id++ {
files[i] = path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id))
if _, err := os.Stat(files[id]); os.IsNotExist(err) {
break
} }
log.Debug(files[i])
i++
}
files = files[:i]
log.Debug(files)
toRemove := !c.Debug toRemove := !c.Debug
return CatFiles(files, path.Join(c.Path, c.File.Name+".enc"), toRemove) return CatFiles(files, path.Join(c.Path, c.File.Name+".enc"), toRemove)
} }
func (c *Connection) receiveFile(id int, connection net.Conn) error { func (c *Connection) receiveFile(id int, connection net.Conn) error {
logger := log.WithFields(log.Fields{ log.Debug("waiting for chunk size from sender")
"function": "receiveFile #" + strconv.Itoa(id),
})
logger.Debug("waiting for chunk size from sender")
fileSizeBuffer := make([]byte, 10) fileSizeBuffer := make([]byte, 10)
connection.Read(fileSizeBuffer) connection.Read(fileSizeBuffer)
fileDataString := strings.Trim(string(fileSizeBuffer), ":") fileDataString := strings.Trim(string(fileSizeBuffer), ":")
fileSizeInt, _ := strconv.Atoi(fileDataString) fileSizeInt, _ := strconv.Atoi(fileDataString)
chunkSize := int64(fileSizeInt) chunkSize := int64(fileSizeInt)
logger.Debugf("chunk size: %d", chunkSize) log.Debugf("chunk size: %d", chunkSize)
if chunkSize == 0 { if chunkSize == 0 {
logger.Debug(fileSizeBuffer) log.Debug(fileSizeBuffer)
return errors.New("chunk size is empty!") return errors.New("chunk size is empty!")
} }
@ -607,16 +629,16 @@ func (c *Connection) receiveFile(id int, connection net.Conn) error {
} }
defer newFile.Close() defer newFile.Close()
logger.Debug("waiting for file") log.Debug(id, "waiting for file")
var receivedBytes int64 var receivedBytes int64
receivedFirstBytes := false receivedFirstBytes := false
for { for {
if (chunkSize - receivedBytes) < BUFFERSIZE { if (chunkSize - receivedBytes) < BUFFERSIZE {
logger.Debug("at the end") log.Debugf("%d at the end: %d < %d", id, (chunkSize - receivedBytes), BUFFERSIZE)
io.CopyN(newFile, connection, (chunkSize - receivedBytes)) io.CopyN(newFile, connection, (chunkSize - receivedBytes))
// Empty the remaining bytes that we don't need from the network buffer // Empty the remaining bytes that we don't need from the network buffer
if (receivedBytes+BUFFERSIZE)-chunkSize < BUFFERSIZE { if (receivedBytes+BUFFERSIZE)-chunkSize < BUFFERSIZE {
logger.Debug("empty remaining bytes from network buffer") log.Debug(id, "empty remaining bytes from network buffer")
connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-chunkSize)) connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-chunkSize))
} }
if !c.Debug { if !c.Debug {
@ -624,31 +646,29 @@ func (c *Connection) receiveFile(id int, connection net.Conn) error {
} }
break break
} }
io.CopyN(newFile, connection, BUFFERSIZE) written, _ := io.CopyN(newFile, connection, BUFFERSIZE)
receivedBytes += BUFFERSIZE receivedBytes += written
if !receivedFirstBytes { if !receivedFirstBytes {
receivedFirstBytes = true receivedFirstBytes = true
logger.Debug("Receieved first bytes!") log.Debug(id, "Receieved first bytes!")
} }
if !c.Debug { if !c.Debug {
c.bar.Add(BUFFERSIZE) c.bar.Add(int(written))
} }
} }
logger.Debug("received file") log.Debug(id, "received file")
return nil return nil
} }
func (c *Connection) sendFile(id int, connection net.Conn) error { func (c *Connection) sendFile(id int, connection net.Conn) error {
logger := log.WithFields(log.Fields{
"function": "sendFile #" + strconv.Itoa(id),
})
defer connection.Close() defer connection.Close()
// open encrypted file chunk // open encrypted file chunk, if it exists
logger.Debug("opening encrypted file chunk: " + c.File.Name + ".enc." + strconv.Itoa(id)) log.Debug("opening encrypted file chunk: " + c.File.Name + ".enc." + strconv.Itoa(id))
file, err := os.Open(c.File.Name + ".enc." + strconv.Itoa(id)) file, err := os.Open(c.File.Name + ".enc." + strconv.Itoa(id))
if err != nil { if err != nil {
return err log.Debug(err)
return nil
} }
defer file.Close() defer file.Close()
@ -657,38 +677,41 @@ func (c *Connection) sendFile(id int, connection net.Conn) error {
if err != nil { if err != nil {
return err return err
} }
logger.Debugf("sending chunk size: %d", fi.Size()) log.Debugf("sending chunk size: %d", fi.Size())
_, err = connection.Write([]byte(fillString(strconv.FormatInt(int64(fi.Size()), 10), 10))) _, err = connection.Write([]byte(fillString(strconv.FormatInt(int64(fi.Size()), 10), 10)))
if err != nil { if err != nil {
return errors.Wrap(err, "Problem sending chunk data: ") return errors.Wrap(err, "Problem sending chunk data: ")
} }
// rate limit the bandwidth // rate limit the bandwidth
logger.Debug("determining rate limiting") log.Debug("determining rate limiting")
bufferSizeInKilobytes := BUFFERSIZE / 1024 bufferSizeInKilobytes := BUFFERSIZE / 1024
rate := float64(c.rate) / float64(c.NumberOfConnections*bufferSizeInKilobytes) rate := float64(c.rate) / float64(c.NumberOfConnections*bufferSizeInKilobytes)
throttle := time.NewTicker(time.Second / time.Duration(rate)) throttle := time.NewTicker(time.Second / time.Duration(rate))
logger.Debugf("rate: %+v", rate) log.Debugf("rate: %+v", rate)
defer throttle.Stop() defer throttle.Stop()
// send the file // send the file
sendBuffer := make([]byte, BUFFERSIZE) sendBuffer := make([]byte, BUFFERSIZE)
totalBytesSent := 0 totalBytesSent := 0
for range throttle.C { for range throttle.C {
n, err := file.Read(sendBuffer) _, err := file.Read(sendBuffer)
connection.Write(sendBuffer) written, errWrite := connection.Write(sendBuffer)
totalBytesSent += n totalBytesSent += written
if !c.Debug { if !c.Debug {
c.bar.Add(n) c.bar.Add(int(written))
}
if errWrite != nil {
log.Error(errWrite)
} }
if err == io.EOF { if err == io.EOF {
//End of file reached, break out of for loop //End of file reached, break out of for loop
logger.Debug("EOF") log.Debug("EOF")
break break
} }
} }
logger.Debug("file is sent") log.Debug("file is sent")
logger.Debug("removing piece") log.Debug("removing piece")
if !c.Debug { if !c.Debug {
file.Close() file.Close()
err = os.Remove(c.File.Name + ".enc." + strconv.Itoa(id)) err = os.Remove(c.File.Name + ".enc." + strconv.Itoa(id))
@ -696,5 +719,13 @@ func (c *Connection) sendFile(id int, connection net.Conn) error {
if err != nil && c.File.DeleteAfterSending { if err != nil && c.File.DeleteAfterSending {
err = os.Remove(path.Join(c.File.Path, c.File.Name)) err = os.Remove(path.Join(c.File.Path, c.File.Name))
} }
// wait until client breaks connection
for range throttle.C {
_, errWrite := connection.Write([]byte("."))
if errWrite != nil {
break
}
}
return err return err
} }

11
main.go
View file

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"os" "os"
"strings" "strings"
"time"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/yudai/gotty/pkg/homedir" "github.com/yudai/gotty/pkg/homedir"
@ -100,16 +99,6 @@ func main() {
r := NewRelay(appOptions) r := NewRelay(appOptions)
r.Run() r.Run()
} else { } else {
if appOptions.Local {
fmt.Println("running relay on local address " + GetLocalIP())
appOptions.Relay = true
appOptions.Server = GetLocalIP()
appOptions.DontEncrypt = true
r := NewRelay(appOptions)
go r.Run()
appOptions.Code = "8-local"
time.Sleep(500 * time.Millisecond)
}
c, err := NewConnection(appOptions) c, err := NewConnection(appOptions)
if err != nil { if err != nil {
fmt.Printf("Error! Please submit the following error to https://github.com/schollz/croc/issues:\n\n'%s'\n\n", err.Error()) fmt.Printf("Error! Please submit the following error to https://github.com/schollz/croc/issues:\n\n'%s'\n\n", err.Error())