From 38cff4212d3fb61efc6b742880290fdc04e6c536 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 21 Nov 2018 22:15:35 -0800 Subject: [PATCH] rename local variables acn; Add bootstrap status support to ACN/torprovider --- application/application.go | 8 +++---- application/examples/echobot/main.go | 14 +++++------ connectivity/acn.go | 5 ++++ connectivity/localProvider.go | 9 +++++++ connectivity/torProvider.go | 36 ++++++++++++++++++++++++++++ connectivity/torProvider_test.go | 18 +++++++++++--- ricochet.go | 4 ++-- ricochet_test.go | 12 +++++----- testing/integration_test.go | 12 +++++----- 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/application/application.go b/application/application.go index bbee427..859f358 100644 --- a/application/application.go +++ b/application/application.go @@ -23,15 +23,15 @@ type RicochetApplication struct { v3identity identity.Identity name string ls connectivity.ListenService - mn connectivity.ACN + acn connectivity.ACN instances []*ApplicationInstance lock sync.Mutex aif ApplicationInstanceFactory } // Init initializes the underlying RicochetApplication datastructure, making it ready for use -func (ra *RicochetApplication) Init(mn connectivity.ACN, name string, v3identity identity.Identity, af ApplicationInstanceFactory, cm ContactManagerInterface) { - ra.mn = mn +func (ra *RicochetApplication) Init(acn connectivity.ACN, name string, v3identity identity.Identity, af ApplicationInstanceFactory, cm ContactManagerInterface) { + ra.acn = acn ra.name = name ra.v3identity = v3identity ra.aif = af @@ -84,7 +84,7 @@ func (ra *RicochetApplication) HandleApplicationInstance(rai *ApplicationInstanc // Open a connection to another Ricochet peer at onionAddress. If they are unknown to use, use requestMessage (otherwise can be blank) func (ra *RicochetApplication) Open(onionAddress string, requestMessage string) (*ApplicationInstance, error) { - rc, err := goricochet.Open(ra.mn, onionAddress) + rc, err := goricochet.Open(ra.acn, onionAddress) rc.TraceLog(true) if err != nil { log.Printf("Error in application.Open(): %v\n", err) diff --git a/application/examples/echobot/main.go b/application/examples/echobot/main.go index 86c04c5..dbbd600 100644 --- a/application/examples/echobot/main.go +++ b/application/examples/echobot/main.go @@ -70,13 +70,13 @@ func main() { echobot := new(application.RicochetApplication) cpubk, cprivk, err := ed25519.GenerateKey(rand.Reader) - mn, err := connectivity.StartTor(".", "") + acn, err := connectivity.StartTor(".", "") if err != nil { log.Panicf("Unable to start Tor: %v", err) } - defer mn.Close() + defer acn.Close() - listenService, err := mn.Listen(cprivk, application.RicochetPort) + listenService, err := acn.Listen(cprivk, application.RicochetPort) if err != nil { log.Fatalf("error setting up onion service: %v", err) @@ -94,7 +94,7 @@ func main() { } }) - echobot.Init(mn, "echobot", identity.InitializeV3("echobot", &cprivk, &cpubk), af, new(application.AcceptAllContactManager)) + echobot.Init(acn, "echobot", identity.InitializeV3("echobot", &cprivk, &cpubk), af, new(application.AcceptAllContactManager)) log.Printf("echobot listening on %s", listenService.AddressFull()) go echobot.Run(listenService) @@ -106,7 +106,7 @@ func main() { //////////// //alicebot should nominally be in another package to prevent initializing it directly - alice := NewAliceBot(mn, listenService.AddressIdentity()) + alice := NewAliceBot(acn, listenService.AddressIdentity()) alice.SendMessage("be gay") alice.SendMessage("do crime") @@ -114,7 +114,7 @@ func main() { time.Sleep(time.Second * 30) } -func NewAliceBot(mn connectivity.ACN, onion string) alicebot { +func NewAliceBot(acn connectivity.ACN, onion string) alicebot { alice := alicebot{} alice.messages = make(map[uint32]string) @@ -124,7 +124,7 @@ func NewAliceBot(mn connectivity.ACN, onion string) alicebot { log.Fatalf("[alice] error generating key: %v", err) } - rc, err := goricochet.Open(mn, onion) + rc, err := goricochet.Open(acn, onion) if err != nil { log.Fatalf("[alice] error connecting to echobot: %v", err) } diff --git a/connectivity/acn.go b/connectivity/acn.go index edbd430..7be9eb4 100644 --- a/connectivity/acn.go +++ b/connectivity/acn.go @@ -21,6 +21,11 @@ type ListenService interface { // ACN is Anonymous Communication Network implementation wrapper that supports Open for new connections and Listen to accept connections type ACN interface { + // GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message + GetBootstrapStatus() (int, string) + // WaitTillBootstrapped Blocks until underlying network is bootstrapped + WaitTillBootstrapped() + // Open takes a hostname and returns a net.Conn to the derived endpoint // Open allows a client to resolve various hostnames to connections // The supported types are onions address are: diff --git a/connectivity/localProvider.go b/connectivity/localProvider.go index b1ae801..26d1039 100644 --- a/connectivity/localProvider.go +++ b/connectivity/localProvider.go @@ -29,6 +29,15 @@ func (ls *localListenService) Close() { ls.l.Close() } +// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message +func (lp *localProvider) GetBootstrapStatus() (int, string) { + return 100, "Done" +} + +// WaitTillBootstrapped Blocks until underlying network is bootstrapped +func (lp *localProvider) WaitTillBootstrapped() { +} + func (lp *localProvider) Listen(identity PrivateKey, port int) (ListenService, error) { l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%v", port)) return &localListenService{l}, err diff --git a/connectivity/torProvider.go b/connectivity/torProvider.go index e938854..d374014 100644 --- a/connectivity/torProvider.go +++ b/connectivity/torProvider.go @@ -15,6 +15,7 @@ import ( "strconv" "strings" "sync" + "time" ) const ( @@ -51,6 +52,41 @@ func (ols *onionListenService) Close() { ols.os.Close() } +// GetBootstrapStatus returns an int 0-100 on the percent the bootstrapping of the underlying network is at and an optional string message +func (tp *torProvider) GetBootstrapStatus() (int, string) { + kvs, err := tp.t.Control.GetInfo("status/bootstrap-phase") + if err != nil { + return 0, "error" + } + progress := 0 + status := "" + + if len(kvs) > 0 { + progRe := regexp.MustCompile("PROGRESS=([0-9]*)") + sumRe := regexp.MustCompile("SUMMARY=\"(.*)\"$") + + if progMatches := progRe.FindStringSubmatch(kvs[0].Val); len(progMatches) > 1 { + progress, _ = strconv.Atoi(progMatches[1]) + } + + if statusMatches := sumRe.FindStringSubmatch(kvs[0].Val); len(statusMatches) > 1 { + status = statusMatches[1] + } + } + return progress, status +} + +// WaitTillBootstrapped Blocks until underlying network is bootstrapped +func (tp *torProvider) WaitTillBootstrapped() { + for true { + progress, _ := tp.GetBootstrapStatus() + if progress == 100 { + break + } + time.Sleep(100 * time.Millisecond) + } +} + func (tp *torProvider) Listen(identity PrivateKey, port int) (ListenService, error) { tp.lock.Lock() defer tp.lock.Unlock() diff --git a/connectivity/torProvider_test.go b/connectivity/torProvider_test.go index ae53f37..c89da26 100644 --- a/connectivity/torProvider_test.go +++ b/connectivity/torProvider_test.go @@ -1,12 +1,24 @@ package connectivity -import "testing" +import ( + "fmt" + "testing" + "time" +) func TestTorProvider(t *testing.T) { - m, err := StartTor(".", "") + acn, err := StartTor(".", "") if err != nil { t.Error(err) } - m.Close() + progress := 0 + status := "" + for progress < 100 { + progress, status = acn.GetBootstrapStatus() + fmt.Printf("%v %v\n", progress, status) + time.Sleep(100) + } + + acn.Close() } diff --git a/ricochet.go b/ricochet.go index b9a4b6f..911e6d6 100644 --- a/ricochet.go +++ b/ricochet.go @@ -13,8 +13,8 @@ import ( // will be closed. This function blocks until version negotiation has completed. // The application should call Process() on the returned OpenConnection to continue // handling protocol messages. -func Open(mn connectivity.ACN, remoteHostname string) (*connection.Connection, error) { - conn, remoteHostname, err := mn.Open(remoteHostname) +func Open(acn connectivity.ACN, remoteHostname string) (*connection.Connection, error) { + conn, remoteHostname, err := acn.Open(remoteHostname) if err != nil { return nil, err diff --git a/ricochet_test.go b/ricochet_test.go index f13095a..c4c7b27 100644 --- a/ricochet_test.go +++ b/ricochet_test.go @@ -19,12 +19,12 @@ func SimpleServer() { } func TestRicochetOpen(t *testing.T) { - mn := connectivity.LocalProvider() + acn := connectivity.LocalProvider() go SimpleServer() // Wait for Server to Initialize time.Sleep(time.Second) - rc, err := Open(mn, "127.0.0.1:11000|abcdefghijklmno.onion") + rc, err := Open(acn, "127.0.0.1:11000|abcdefghijklmno.onion") if err == nil { if rc.IsInbound { t.Errorf("RicochetConnection declares itself as an Inbound connection after an Outbound attempt...that shouldn't happen") @@ -46,19 +46,19 @@ func BadServer() { } func TestRicochetOpenWithError(t *testing.T) { - mn := connectivity.LocalProvider() + acn := connectivity.LocalProvider() go BadServer() // Wait for Server to Initialize time.Sleep(time.Second) - _, err := Open(mn, "127.0.0.1:11001|abcdefghijklmno.onion") + _, err := Open(acn, "127.0.0.1:11001|abcdefghijklmno.onion") if err == nil { t.Errorf("Open should have failed because of bad version negotiation.") } } func TestRicochetOpenWithNoServer(t *testing.T) { - mn := connectivity.LocalProvider() - _, err := Open(mn, "127.0.0.1:11002|abcdefghijklmno.onion") + acn := connectivity.LocalProvider() + _, err := Open(acn, "127.0.0.1:11002|abcdefghijklmno.onion") if err == nil { t.Errorf("Open should have failed because of bad version negotiation.") } diff --git a/testing/integration_test.go b/testing/integration_test.go index cb6cad4..9457f14 100644 --- a/testing/integration_test.go +++ b/testing/integration_test.go @@ -98,7 +98,7 @@ func (bot *ChatEchoBot) ChatMessageAck(messageID uint32, accepted bool) { } func TestApplicationIntegration(t *testing.T) { - mn, err := connectivity.StartTor(".", "") + acn, err := connectivity.StartTor(".", "") if err != nil { t.Fatalf("Could not start tor: %v", err) } @@ -124,7 +124,7 @@ func TestApplicationIntegration(t *testing.T) { apubk, apk, _ := utils.GeneratePrivateKeyV3() aliceAddr := utils.GetTorV3Hostname(apubk) fmt.Println("Seting up alice's onion " + aliceAddr + "...") - al, err := mn.Listen(apk, application.RicochetPort) + al, err := acn.Listen(apk, application.RicochetPort) if err != nil { t.Fatalf("Could not setup Onion for Alice: %v", err) } @@ -137,7 +137,7 @@ func TestApplicationIntegration(t *testing.T) { return chat } }) - alice.Init(mn, "Alice", identity.InitializeV3("Alice", &apk, &apubk), af, new(application.AcceptAllContactManager)) + alice.Init(acn, "Alice", identity.InitializeV3("Alice", &apk, &apubk), af, new(application.AcceptAllContactManager)) fmt.Println("Running alice...") go alice.Run(al) @@ -149,7 +149,7 @@ func TestApplicationIntegration(t *testing.T) { } bobAddr := utils.GetTorV3Hostname(bpubk) fmt.Println("Seting up bob's onion " + bobAddr + "...") - bl, _ := mn.Listen(bpk, application.RicochetPort) + bl, _ := acn.Listen(bpk, application.RicochetPort) af.AddHandler("im.ricochet.chat", func(rai *application.ApplicationInstance) func() channels.Handler { return func() channels.Handler { chat := new(channels.ChatChannel) @@ -157,7 +157,7 @@ func TestApplicationIntegration(t *testing.T) { return chat } }) - bob.Init(mn, "Bob", identity.InitializeV3("Bob", &bpk, &bpubk), af, new(application.AcceptAllContactManager)) + bob.Init(acn, "Bob", identity.InitializeV3("Bob", &bpk, &bpubk), af, new(application.AcceptAllContactManager)) go bob.Run(bl) fmt.Println("Waiting for alice and bob hidden services to percolate...") @@ -209,7 +209,7 @@ func TestApplicationIntegration(t *testing.T) { time.Sleep(15 * time.Second) fmt.Println("Shutting down bine/tor") - mn.Close() + acn.Close() finalGoRoutines := runtime.NumGoroutine()