diff --git a/Makefile b/Makefile index d6165e6fd8522bc385d1fce2ff82666a2ec884c7..6ffb05ab0cbe0c3795e6c44130f859657329a45e 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ build: update_release: GOFLAGS="" go get -u gitlab.com/elixxir/primitives@release GOFLAGS="" go get -u gitlab.com/elixxir/crypto@release - GOFLAGS="" go get -u gitlab.com/elixxir/comms@release + GOFLAGS="" go get -u gitlab.com/elixxir/comms@connectionRefactor update_master: GOFLAGS="" go get -u gitlab.com/elixxir/primitives@master diff --git a/api/client.go b/api/client.go index 8e09b41f71a745ec4ffd7b69ffe82bcd21714a98..d7c8d8621f6226edc09667526d8d96c3a308bb69 100644 --- a/api/client.go +++ b/api/client.go @@ -56,50 +56,6 @@ var noNDFErr = errors.New("Failed to get ndf from permissioning: rpc error: code //used to report the state of registration type OperationProgressCallback func(int) -// Creates a new Client using the storage mechanism provided. -// If none is provided, a default storage using OS file access -// is created -// returns a new Client object, and an error if it fails -func NewClient(s globals.Storage, locA, locB string, ndfJSON *ndf.NetworkDefinition, - callback io.ConnectionStatusCallback) (*Client, error) { - var store globals.Storage - if s == nil { - globals.Log.INFO.Printf("No storage provided," + - " initializing Client with default storage") - store = &globals.DefaultStorage{} - } else { - store = s - } - - err := store.SetLocation(locA, locB) - - if err != nil { - err = errors.New("Invalid Local Storage Location: " + err.Error()) - return nil, err - } - - cl := new(Client) - cl.storage = store - cl.commManager = io.NewCommManager(ndfJSON, callback) - cl.ndf = ndfJSON - - cl.topology = nil - - //Create the cmix group and init the registry - cmixGrp := cyclic.NewGroup( - large.NewIntFromString(cl.ndf.CMIX.Prime, 16), - large.NewIntFromString(cl.ndf.CMIX.Generator, 16)) - user.InitUserRegistry(cmixGrp) - - cl.opStatus = func(int) { - return - } - - cl.rekeyChan = make(chan struct{}, 1) - - return cl, nil -} - // Populates a text message and returns its wire representation // TODO support multi-type messages or telling if a message is too long? func FormatTextMessage(message string) []byte { @@ -175,6 +131,7 @@ func requestNdf(cl *Client) error { // Continuously polls for a new ndf after sleeping until response if gotten globals.Log.INFO.Printf("Polling for a new NDF") newNDf, err := cl.commManager.GetUpdatedNDF(cl.ndf) + if err != nil { //lets the client continue when permissioning does not provide NDFs if err.Error() == noNDFErr.Error() { @@ -193,6 +150,54 @@ func requestNdf(cl *Client) error { return nil } +// Creates a new Client using the storage mechanism provided. +// If none is provided, a default storage using OS file access +// is created +// returns a new Client object, and an error if it fails +func NewClient(s globals.Storage, locA, locB string, ndfJSON *ndf.NetworkDefinition, + callback io.ConnectionStatusCallback) (*Client, error) { + var store globals.Storage + if s == nil { + globals.Log.INFO.Printf("No storage provided," + + " initializing Client with default storage") + store = &globals.DefaultStorage{} + } else { + store = s + } + + err := store.SetLocation(locA, locB) + + if err != nil { + err = errors.New("Invalid Local Storage Location: " + err.Error()) + globals.Log.ERROR.Printf(err.Error()) + return nil, err + } + + cl := new(Client) + cl.storage = store + cl.commManager = io.NewCommManager(ndfJSON, callback) + cl.ndf = ndfJSON + //build the topology + nodeIDs := make([]*id.Node, len(cl.ndf.Nodes)) + for i, node := range cl.ndf.Nodes { + nodeIDs[i] = id.NewNodeFromBytes(node.ID) + } + + //Create the cmix group and init the registry + cmixGrp := cyclic.NewGroup( + large.NewIntFromString(cl.ndf.CMIX.Prime, 16), + large.NewIntFromString(cl.ndf.CMIX.Generator, 16)) + user.InitUserRegistry(cmixGrp) + + cl.opStatus = func(int) { + return + } + + cl.rekeyChan = make(chan struct{}, 1) + + return cl, nil +} + // DisableTLS makes the client run with TLS disabled // Must be called before Connect func (cl *Client) DisableTLS() { @@ -211,7 +216,6 @@ func (cl *Client) Connect() error { //Connect to permissioning if cl.ndf.Registration.Address != "" { isConnected, err := cl.commManager.ConnectToPermissioning() - defer cl.commManager.DisconnectFromPermissioning() if err != nil { return err @@ -266,192 +270,6 @@ func (cl *Client) SetOperationProgressCallback(rpc OperationProgressCallback) { cl.opStatus = func(i int) { go rpc(i) } } -var sessionFileError = errors.New("Session file cannot be loaded and " + - "is possibly corrupt. Please contact support@xxmessenger.io") - -// LoadSession loads the session object for the UID -func (cl *Client) Login(password string) (string, error) { - - var session user.Session - var err error - done := make(chan struct{}) - - // run session loading in a separate goroutine so if it panics it can - // be caught and an error can be returned - go func() { - defer func() { - if r := recover(); r != nil { - err = sessionFileError - done <- struct{}{} - } - }() - - session, err = user.LoadSession(cl.storage, password) - done <- struct{}{} - }() - - //wait for session file loading to complete - <-done - - if err != nil { - return "", errors.Wrap(err, "Login: Could not login") - } - - if session == nil { - return "", errors.New("Unable to load session, no error reported") - } - if session.GetRegState() < user.PermissioningComplete { - return "", errors.New("Cannot log a user in which has not " + - "completed registration ") - } - - cl.session = session - return cl.session.GetCurrentUser().Nick, nil -} - -// Logout closes the connection to the server at this time and does -// nothing with the user id. In the future this will release resources -// and safely release any sensitive memory. -// fixme: blocks forever is message reciever -func (cl *Client) Logout() error { - if cl.session == nil { - err := errors.New("Logout: Cannot Logout when you are not logged in") - return err - } - - // Stop reception runner goroutine - close(cl.session.GetQuitChan()) - - // Disconnect from the gateways - for _, gateway := range cl.ndf.Gateways { - cl.commManager.Comms.Disconnect(gateway.Address) - } - - errStore := cl.session.StoreSession() - - if errStore != nil { - err := errors.Errorf("Logout: Store Failed: %s" + - errStore.Error()) - return err - } - - errImmolate := cl.session.Immolate() - cl.session = nil - - if errImmolate != nil { - err := errors.Errorf("Logout: Immolation Failed: %s" + - errImmolate.Error()) - return err - } - - return nil -} - -// Logs in user and sets session on client object -// returns the nickname or error if login fails -func (cl *Client) StartMessageReceiver(errorCallback func(error)) error { - status := cl.commManager.GetConnectionStatus() - if status == io.Connecting || status == io.Offline { - return errors.New("ERROR: could not StartMessageReceiver - connection is either offline or connecting") - } - - // Initialize UDB and nickname "bot" stuff here - bots.InitBots(cl.session, cl.commManager, cl.topology, id.NewUserFromBytes(cl.ndf.UDB.ID)) - // Initialize Rekey listeners - rekey.InitRekey(cl.session, cl.commManager, cl.topology, cl.rekeyChan) - - pollWaitTimeMillis := 1000 * time.Millisecond - // TODO Don't start the message receiver if it's already started. - // Should be a pretty rare occurrence except perhaps for mobile. - go func() { - defer func() { - if r := recover(); r != nil { - time.Sleep(1 * time.Second) - go func() { - errorCallback(errors.Errorf(fmt.Sprintln("Message Receiver Panicked", r))) - }() - } - }() - cl.commManager.MessageReceiver(cl.session, pollWaitTimeMillis, cl.rekeyChan) - }() - - return nil -} - -// TryReconnect Attemps to to reconnect with te network. It will only cause -// an attempt if called durring a backoff timeout -func (cl *Client) TryReconnect() { - cl.commManager.TryReconnect() -} - -// Send prepares and sends a message to the cMix network -// FIXME: We need to think through the message interface part. -func (cl *Client) Send(message parse.MessageInterface) error { - status := cl.commManager.GetConnectionStatus() - if status == io.Connecting || status == io.Offline { - return errors.New("Could not Send - connection is either offline or connecting") - } - - // FIXME: There should (at least) be a version of this that takes a byte array - recipientID := message.GetRecipient() - cryptoType := message.GetCryptoType() - return cl.commManager.SendMessage(cl.session, cl.topology, recipientID, cryptoType, message.Pack()) -} - -// DisableBlockingTransmission turns off blocking transmission, for -// use with the channel bot and dummy bot -func (cl *Client) DisableBlockingTransmission() { - cl.commManager.DisableBlockingTransmission() -} - -// SetRateLimiting sets the minimum amount of time between message -// transmissions just for testing, probably to be removed in production -func (cl *Client) SetRateLimiting(limit uint32) { - cl.commManager.SetRateLimit(time.Duration(limit) * time.Millisecond) -} - -func (cl *Client) Listen(user *id.User, messageType int32, newListener switchboard.Listener) string { - listenerId := cl.session.GetSwitchboard(). - Register(user, messageType, newListener) - globals.Log.INFO.Printf("Listening now: user %v, message type %v, id %v", - user, messageType, listenerId) - return listenerId -} - -func (cl *Client) StopListening(listenerHandle string) { - cl.session.GetSwitchboard().Unregister(listenerHandle) -} - -func (cl *Client) GetSwitchboard() *switchboard.Switchboard { - return cl.session.GetSwitchboard() -} - -func (cl *Client) GetCurrentUser() *id.User { - return cl.session.GetCurrentUser().User -} - -func (cl *Client) GetKeyParams() *keyStore.KeyParams { - return cl.session.GetKeyStore().GetKeyParams() -} - -func (cl *Client) GetNetworkStatus() uint32 { - return cl.commManager.GetConnectionStatus() -} - -// Returns the local version of the client repo -func GetLocalVersion() string { - return globals.SEMVER -} - -// Returns the compatible version of client, according to permissioning -func (cl *Client) GetRemoteVersion() string { - return cl.commManager.GetRegistrationVersion() -} - -type SearchCallback interface { - Callback(userID, pubKey []byte, err error) -} - const SaltSize = 256 // RegisterWithPermissioning registers user with permissioning and returns the @@ -777,6 +595,183 @@ func (cl *Client) registerWithNode(index int, salt, registrationValidationSignat cl.session.PushNodeKey(nodeID, key) } +var sessionFileError = errors.New("Session file cannot be loaded and " + + "is possibly corrupt. Please contact support@xxmessenger.io") + +// LoadSession loads the session object for the UID +func (cl *Client) Login(password string) (string, error) { + + var session user.Session + var err error + done := make(chan struct{}) + + // run session loading in a separate goroutine so if it panics it can + // be caught and an error can be returned + go func() { + defer func() { + if r := recover(); r != nil { + globals.Log.ERROR.Println("Session file loading crashed") + err = sessionFileError + done <- struct{}{} + } + }() + + session, err = user.LoadSession(cl.storage, password) + done <- struct{}{} + }() + + //wait for session file loading to complete + <-done + + if err != nil { + return "", errors.Wrap(err, "Login: Could not login") + } + + if session == nil { + return "", errors.New("Unable to load session, no error reported") + } + if session.GetRegState() < user.PermissioningComplete { + return "", errors.New("Cannot log a user in which has not " + + "completed registration ") + } + + cl.session = session + return cl.session.GetCurrentUser().Nick, nil +} + +// Logs in user and sets session on client object +// returns the nickname or error if login fails +func (cl *Client) StartMessageReceiver() error { + status := cl.commManager.GetConnectionStatus() + if status == io.Connecting || status == io.Offline { + return errors.New("ERROR: could not StartMessageReceiver - connection is either offline or connecting") + } + + // Initialize UDB and nickname "bot" stuff here + bots.InitBots(cl.session, cl.commManager, cl.topology, id.NewUserFromBytes(cl.ndf.UDB.ID)) + // Initialize Rekey listeners + rekey.InitRekey(cl.session, cl.commManager, cl.topology, cl.rekeyChan) + + pollWaitTimeMillis := 1000 * time.Millisecond + // TODO Don't start the message receiver if it's already started. + // Should be a pretty rare occurrence except perhaps for mobile. + go cl.commManager.MessageReceiver(cl.session, pollWaitTimeMillis, cl.rekeyChan) + + return nil +} + +// TryReconnect Attemps to to reconnect with te network. It will only cause +// an attempt if called durring a backoff timeout +func (cl *Client) TryReconnect() { + cl.commManager.TryReconnect() +} + +// Send prepares and sends a message to the cMix network +// FIXME: We need to think through the message interface part. +func (cl *Client) Send(message parse.MessageInterface) error { + status := cl.commManager.GetConnectionStatus() + if status == io.Connecting || status == io.Offline { + return errors.New("Could not Send - connection is either offline or connecting") + } + + // FIXME: There should (at least) be a version of this that takes a byte array + recipientID := message.GetRecipient() + cryptoType := message.GetCryptoType() + return cl.commManager.SendMessage(cl.session, cl.topology, recipientID, cryptoType, message.Pack()) +} + +// DisableBlockingTransmission turns off blocking transmission, for +// use with the channel bot and dummy bot +func (cl *Client) DisableBlockingTransmission() { + cl.commManager.DisableBlockingTransmission() +} + +// SetRateLimiting sets the minimum amount of time between message +// transmissions just for testing, probably to be removed in production +func (cl *Client) SetRateLimiting(limit uint32) { + cl.commManager.SetRateLimit(time.Duration(limit) * time.Millisecond) +} + +func (cl *Client) Listen(user *id.User, messageType int32, newListener switchboard.Listener) string { + listenerId := cl.session.GetSwitchboard(). + Register(user, messageType, newListener) + globals.Log.INFO.Printf("Listening now: user %v, message type %v, id %v", + user, messageType, listenerId) + return listenerId +} + +func (cl *Client) StopListening(listenerHandle string) { + cl.session.GetSwitchboard().Unregister(listenerHandle) +} + +func (cl *Client) GetSwitchboard() *switchboard.Switchboard { + return cl.session.GetSwitchboard() +} + +func (cl *Client) GetCurrentUser() *id.User { + return cl.session.GetCurrentUser().User +} + +func (cl *Client) GetKeyParams() *keyStore.KeyParams { + return cl.session.GetKeyStore().GetKeyParams() +} + +func (cl *Client) GetNetworkStatus() uint32 { + return cl.commManager.GetConnectionStatus() +} + +// Logout closes the connection to the server at this time and does +// nothing with the user id. In the future this will release resources +// and safely release any sensitive memory. +// fixme: blocks forever is message reciever +func (cl *Client) Logout() error { + if cl.session == nil { + err := errors.New("Logout: Cannot Logout when you are not logged in") + globals.Log.ERROR.Printf(err.Error()) + return err + } + + // Stop reception runner goroutine + close(cl.session.GetQuitChan()) + + cl.commManager.Disconnect() + + errStore := cl.session.StoreSession() + + if errStore != nil { + err := errors.New(fmt.Sprintf("Logout: Store Failed: %s" + + errStore.Error())) + globals.Log.ERROR.Printf(err.Error()) + return err + } + + errImmolate := cl.session.Immolate() + cl.session = nil + + if errImmolate != nil { + err := errors.New(fmt.Sprintf("Logout: Immolation Failed: %s" + + errImmolate.Error())) + globals.Log.ERROR.Printf(err.Error()) + return err + } + + return nil +} + +// Returns the local version of the client repo +func GetLocalVersion() string { + return globals.SEMVER +} + +// Returns the compatible version of client, according to permissioning +func (cl *Client) GetRemoteVersion() string { + return cl.commManager.GetRegistrationVersion() +} + +type SearchCallback interface { + Callback(userID, pubKey []byte, err error) +} + // UDB Search API // Pass a callback function to extract results func (cl *Client) SearchForUser(emailAddress string, @@ -836,63 +831,6 @@ func (cl *Client) SearchForUser(emailAddress string, }() } -func (cl *Client) GetSessionData() ([]byte, error) { - return cl.session.GetSessionData() -} - -// Set the output of the -func SetLogOutput(w goio.Writer) { - globals.Log.SetLogOutput(w) -} - -// GetSession returns the session object for external access. Access at your -// own risk -func (cl *Client) GetSession() user.Session { - return cl.session -} - -// CommManager returns the comm manager object for external access. Access -// at your own risk -func (cl *Client) GetCommManager() *io.CommManager { - return cl.commManager -} - -// LoadSessionText: load the encrypted session as a string -func (cl *Client) LoadEncryptedSession() (string, error) { - encryptedSession, err := cl.GetSession().LoadEncryptedSession(cl.storage) - if err != nil { - return "", err - } - //Encode session to bas64 for useability - encodedSession := base64.StdEncoding.EncodeToString(encryptedSession) - - return encodedSession, nil -} - -//WriteToSession: Writes an arbitrary string to the session file -// Takes in a string that is base64 encoded (meant to be output of LoadEncryptedSession) -func (cl *Client) WriteToSessionFile(replacement string, store globals.Storage) error { - //This call must not occur prior to a newClient call, thus check that client has been initialized - if cl.ndf == nil || cl.topology == nil { - errMsg := errors.Errorf("Cannot write to session if client hasn't been created yet") - return errMsg - } - //Decode the base64 encoded replacement string (assumed to be encoded form LoadEncryptedSession) - decodedSession, err := base64.StdEncoding.DecodeString(replacement) - if err != nil { - errMsg := errors.Errorf("Failed to decode replacment string: %+v", err) - return errMsg - } - //Write the new session data to both locations - err = user.WriteToSession(decodedSession, store) - if err != nil { - errMsg := errors.Errorf("Failed to store session: %+v", err) - return errMsg - } - - return nil -} - type NickLookupCallback interface { Callback(nick string, err error) } @@ -991,3 +929,24 @@ func ParseMessage(message []byte) (ParsedMessage, error) { return pm, nil } + +func (cl *Client) GetSessionData() ([]byte, error) { + return cl.session.GetSessionData() +} + +// Set the output of the +func SetLogOutput(w goio.Writer) { + globals.Log.SetLogOutput(w) +} + +// GetSession returns the session object for external access. Access at your +// own risk +func (cl *Client) GetSession() user.Session { + return cl.session +} + +// CommManager returns the comm manager object for external access. Access +// at your own risk +func (cl *Client) GetCommManager() *io.CommManager { + return cl.commManager +} diff --git a/api/mockserver_test.go b/api/mockserver_test.go index 7db11a55a5bdaff2596527acb452933a684cb82e..38e83dc14163c40255064304d52005ce4cf3279f 100644 --- a/api/mockserver_test.go +++ b/api/mockserver_test.go @@ -27,8 +27,7 @@ const GWsStartPort = 7900 const PermErrorServerPort = 4000 var RegHandler = MockRegistration{} -var RegComms *registration.RegistrationComms -var NDFErrorReg = MockPerm_NDF_ErrorCase{} +var RegComms *registration.Comms const ValidRegCode = "UAV6IWD6" const InvalidRegCode = "INVALID_REG_CODE_" @@ -38,7 +37,7 @@ var RegGWHandlers [3]*TestInterface = [NumGWs]*TestInterface{ {LastReceivedMessage: pb.Slot{}}, {LastReceivedMessage: pb.Slot{}}, } -var GWComms [NumGWs]*gateway.GatewayComms +var GWComms [NumGWs]*gateway.Comms var def *ndf.NetworkDefinition var errorDef *ndf.NetworkDefinition diff --git a/api/private.go b/api/private.go index da0d5fba4378bd689e9642c5e792ee03e8baa19a..eea749ccbb0c08f75d44d2492da33378c63dd234 100644 --- a/api/private.go +++ b/api/private.go @@ -11,7 +11,6 @@ import ( "fmt" "github.com/pkg/errors" "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/io" "gitlab.com/elixxir/client/keyStore" "gitlab.com/elixxir/client/user" pb "gitlab.com/elixxir/comms/mixmessages" @@ -72,7 +71,6 @@ func (cl *Client) precannedRegister(registrationCode, nick string, func (cl *Client) sendRegistrationMessage(registrationCode string, publicKeyRSA *rsa.PublicKey) ([]byte, error) { connected, err := cl.commManager.ConnectToPermissioning() - defer cl.commManager.DisconnectFromPermissioning() if err != nil { return nil, errors.Wrap(err, "Couldn't connect to permissioning to send registration message") } @@ -81,8 +79,12 @@ func (cl *Client) sendRegistrationMessage(registrationCode string, } regValidationSignature := make([]byte, 0) // Send registration code and public key to RegistrationServer + host, ok := cl.commManager.Comms.GetHost(PermissioningAddrID) + if !ok { + return nil, errors.New("Failed to find permissioning host") + } response, err := cl.commManager.Comms. - SendRegistrationMessage(io.ConnAddr(PermissioningAddrID), + SendRegistrationMessage(host, &pb.UserRegistration{ RegistrationCode: registrationCode, ClientRSAPubKey: string(rsa.CreatePublicKeyPem(publicKeyRSA)), @@ -121,8 +123,12 @@ func (cl *Client) requestNonce(salt, regHash []byte, } // Send signed public key and salt for UserID to Server + host, ok := cl.commManager.Comms.GetHost(gwID.String()) + if !ok { + return nil, nil, errors.Errorf("Failed to find host with ID %s", gwID.String()) + } nonceResponse, err := cl.commManager.Comms. - SendRequestNonceMessage(gwID, + SendRequestNonceMessage(host, &pb.NonceRequest{ Salt: salt, ClientRSAPubKey: string(rsa.CreatePublicKeyPem(publicKeyRSA)), @@ -177,8 +183,12 @@ func (cl *Client) confirmNonce(UID, nonce []byte, Signature: sig, }, } + host, ok := cl.commManager.Comms.GetHost(gwID.String()) + if !ok { + return errors.Errorf("Failed to find host with ID %s", gwID.String()) + } confirmResponse, err := cl.commManager.Comms. - SendConfirmNonceMessage(gwID, msg) + SendConfirmNonceMessage(host, msg) if err != nil { err := errors.New(fmt.Sprintf( "confirmNonce: Unable to send signed nonce! %s", err)) diff --git a/bindings/client_test.go b/bindings/client_test.go index 96c177dce3af0448f528ecd60191e61542942c38..fc4c16d1f037fea34ec2bc3ae06cdb7effca0f47 100644 --- a/bindings/client_test.go +++ b/bindings/client_test.go @@ -37,15 +37,15 @@ const RegPort = 5000 const ValidRegCode = "UAV6IWD6" var RegHandler = api.MockRegistration{} -var RegComms *registration.RegistrationComms +var RegComms *registration.Comms -var GWComms [NumGWs]*gateway.GatewayComms +var GWComms [NumGWs]*gateway.Comms var def *ndf.NetworkDefinition //Variables ported to get mock permissioning server running var nodeId *id.Node -var permComms *registration.RegistrationComms +var permComms *registration.Comms type mockPermission struct { } @@ -133,7 +133,7 @@ func TestNewClient(t *testing.T) { t.Errorf("NewClient returned nil Client object") } for _, gw := range GWComms { - gw.Disconnect(api.PermissioningAddrID) + gw.DisconnectAll() } } @@ -163,7 +163,7 @@ func TestRegister(t *testing.T) { t.Errorf("Invalid registration number received: %v", regRes) } for _, gw := range GWComms { - gw.Disconnect(api.PermissioningAddrID) + gw.DisconnectAll() } } @@ -209,7 +209,7 @@ func TestLoginLogout(t *testing.T) { t.Errorf("Logoutfailed: %s", err3.Error()) } for _, gw := range GWComms { - gw.Disconnect(api.PermissioningAddrID) + gw.DisconnectAll() } } @@ -257,7 +257,7 @@ func TestListen(t *testing.T) { t.Error("Message not received") } for _, gw := range GWComms { - gw.Disconnect(api.PermissioningAddrID) + gw.DisconnectAll() } } diff --git a/go.mod b/go.mod index a1c87ed7b9b050bec7237aa8a250942e865ae17f..729f1da823a121ccefb0906efabcf3152baea9b1 100644 --- a/go.mod +++ b/go.mod @@ -12,13 +12,13 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.5.0 - gitlab.com/elixxir/comms v0.0.0-20191121235257-58343c70ada1 - gitlab.com/elixxir/crypto v0.0.0-20191121235352-86d305a9b253 - gitlab.com/elixxir/primitives v0.0.0-20191119224420-3776ddb853b2 - golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba - golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 // indirect - golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e // indirect - google.golang.org/genproto v0.0.0-20191115221424-83cc0476cb11 // indirect + gitlab.com/elixxir/comms v0.0.0-20191113191412-951037b1a272 + gitlab.com/elixxir/crypto v0.0.0-20191029164123-324be42ee600 + gitlab.com/elixxir/primitives v0.0.0-20191029164023-7f6b4088b191 + golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 + golang.org/x/net v0.0.0-20191112182307-2180aed22343 // indirect + golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 // indirect + google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a // indirect google.golang.org/grpc v1.25.1 // indirect - gopkg.in/yaml.v2 v2.2.7 // indirect + gopkg.in/yaml.v2 v2.2.5 // indirect ) diff --git a/go.sum b/go.sum index cb5753582a725f05ada3230498857b7b8c69174c..bfb7f71ad30392de1bfd8d8aee9a03d28cef998a 100644 --- a/go.sum +++ b/go.sum @@ -132,18 +132,14 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -gitlab.com/elixxir/comms v0.0.0-20191121235257-58343c70ada1 h1:7x/igwp+d1W20WIIxw6lcgkEtdkLalVcCZ9DMTS6Q+E= -gitlab.com/elixxir/comms v0.0.0-20191121235257-58343c70ada1/go.mod h1:X3hAF6MepjDANpPmIycDHy+dcXyyEtOZXHwlSXU7a6s= +gitlab.com/elixxir/comms v0.0.0-20191113191412-951037b1a272 h1:HLvJ4kaBVLoV+3cK7CBXT59nRpKSjpdGII/1Fc3vGas= +gitlab.com/elixxir/comms v0.0.0-20191113191412-951037b1a272/go.mod h1:X3hAF6MepjDANpPmIycDHy+dcXyyEtOZXHwlSXU7a6s= gitlab.com/elixxir/crypto v0.0.0-20191029164123-324be42ee600 h1:4oexoUT9k0H6W3i1j6T5nCPwCwEijVb/uI5yALJjAE8= gitlab.com/elixxir/crypto v0.0.0-20191029164123-324be42ee600/go.mod h1:+46Zj/NE6JEkXExYnzdvvDokPpDbA+fJsRszvrezK9k= -gitlab.com/elixxir/crypto v0.0.0-20191121235352-86d305a9b253 h1:BqgqJ0mLANRjhAFLvGAcB5AWdgAnFZhsGx0qTk5G+3Y= -gitlab.com/elixxir/crypto v0.0.0-20191121235352-86d305a9b253/go.mod h1:+46Zj/NE6JEkXExYnzdvvDokPpDbA+fJsRszvrezK9k= gitlab.com/elixxir/primitives v0.0.0-20191028233752-882c08b8f095 h1:fnRh0PUwgy0qlWM7xMdk2w5MXh7gvQ0v/xyedn2gbcY= gitlab.com/elixxir/primitives v0.0.0-20191028233752-882c08b8f095/go.mod h1:+UiRRWzNpl/WoWUuQtJSoimfXImJAJ5lrrmg0pQKY3g= gitlab.com/elixxir/primitives v0.0.0-20191029164023-7f6b4088b191 h1:pKf6JBoZb97UFb3w1h71FsvDoewL2VFfOSmIinOSTdQ= gitlab.com/elixxir/primitives v0.0.0-20191029164023-7f6b4088b191/go.mod h1:uOh4MxLDB8xGoDA2f0a/HJxgb2VFS4Pd2PC8f4m6/tU= -gitlab.com/elixxir/primitives v0.0.0-20191119224420-3776ddb853b2 h1:Rwb9XrA9WQTPqB/hUAXgbgfbLtec8QKMXI5FyIXrVvQ= -gitlab.com/elixxir/primitives v0.0.0-20191119224420-3776ddb853b2/go.mod h1:uOh4MxLDB8xGoDA2f0a/HJxgb2VFS4Pd2PC8f4m6/tU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -155,8 +151,8 @@ golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152 h1:ZC1Xn5A1nlpSmQCIva4bZ3 golang.org/x/crypto v0.0.0-20191028145041-f83a4685e152/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIoF2s4qxv0xSSS0BVZUE/ss= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= -golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4= +golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -171,8 +167,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271 h1:N66aaryRB3Ax92gH0v3hp1QYZ3zWWCCUR/j8Ifh45Ss= golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914 h1:MlY3mEfbnWGmUi4rtHOtNnnnN4UJRGSyLPx+DXA5Sq4= -golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343 h1:00ohfJ4K98s3m6BGUoBd8nyfp4Yl0GoIKvw5abItTjI= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -190,8 +186,8 @@ golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934 h1:u/E0NqCIWRDAo9WCFo6Ko49nj golang.org/x/sys v0.0.0-20191028164358-195ce5e7f934/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE= golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 h1:dHtDnRWQtSx0Hjq9kvKFpBh9uPPKfQN70NZZmvssGwk= +golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= @@ -209,8 +205,8 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 h1:UXl+Zk3jqqcbEVV7ace5lrt4YdA4tXiz3f/KbmD29Vo= google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115221424-83cc0476cb11 h1:51D++eCgOHufw5VfDE9Uzqyyc+OyQIjb9hkYy9LN5Fk= -google.golang.org/genproto v0.0.0-20191115221424-83cc0476cb11/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -230,7 +226,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/io/commManager.go b/io/commManager.go index a5016c650e59505ac293d6a37d5838c36406cba8..b7b6ca6b83f61477b4d8123f58d9473f60af3f9a 100644 --- a/io/commManager.go +++ b/io/commManager.go @@ -16,6 +16,7 @@ import ( "gitlab.com/elixxir/client/globals" "gitlab.com/elixxir/client/parse" "gitlab.com/elixxir/comms/client" + "gitlab.com/elixxir/comms/connect" "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/elixxir/primitives/id" "gitlab.com/elixxir/primitives/ndf" @@ -37,7 +38,7 @@ func (a ConnAddr) String() string { // CommManager implements the Communications interface type CommManager struct { // Comms pointer to send/recv messages - Comms *client.ClientComms + Comms *client.Comms nextId func() []byte collator *Collator @@ -85,7 +86,7 @@ func NewCommManager(ndf *ndf.NetworkDefinition, blockTransmissions: true, transmitDelay: 1000 * time.Millisecond, receivedMessages: make(map[string]struct{}), - Comms: &client.ClientComms{}, + Comms: &client.Comms{}, tryReconnect: make(chan struct{}), tls: true, ndf: ndf, @@ -95,7 +96,7 @@ func NewCommManager(ndf *ndf.NetworkDefinition, connectionStatus: &status, } - cm.Comms.ConnectionManager.SetMaxRetries(1) + //cm.Comms.ConnectionManager.SetMaxRetries(1) return cm } @@ -130,14 +131,13 @@ func (cm *CommManager) ConnectToGateways() error { globals.Log.INFO.Printf("Connecting to gateway %s at %s...", gwID.String(), gwAddr) - err = cm.Comms.ConnectToRemote(gwID, gwAddr, - gwCreds, false) - + host, err := connect.NewHost(gwAddr, gwCreds, false) if err != nil { errChan <- errors.New(fmt.Sprintf( - "Failed to connect to gateway %s at %s: %+v", + "Failed to create host for gateway %s at %s: %+v", gwID.String(), gwAddr, err)) } + cm.Comms.AddHost(gwID.String(), host) wg.Done() }() wg.Wait() @@ -165,8 +165,12 @@ func (cm *CommManager) ConnectToGateways() error { // Connects to the permissioning server, if we know about it, to get the latest // version from it func (cm *CommManager) UpdateRemoteVersion() error { + permissioningHost, ok := cm.Comms.GetHost(PermissioningAddrID) + if !ok { + return errors.Errorf("Failed to find permissioning host with id %s", PermissioningAddrID) + } registrationVersion, err := cm.Comms. - SendGetCurrentClientVersionMessage(ConnAddr(PermissioningAddrID)) + SendGetCurrentClientVersionMessage(permissioningHost) if err != nil { return errors.Wrap(err, "Couldn't get current version from permissioning") } @@ -190,8 +194,13 @@ func (cm *CommManager) GetUpdatedNDF(currentNDF *ndf.NetworkDefinition) (*ndf.Ne //Put the hash in a message msg := &mixmessages.NDFHash{Hash: ndfHash} + host, ok := cm.Comms.GetHost(PermissioningAddrID) + if !ok { + return nil, errors.New("Failed to find permissioning host") + } + //Send the hash to registration - response, err := cm.Comms.SendGetUpdatedNDF(ConnAddr(PermissioningAddrID), msg) + response, err := cm.Comms.SendGetUpdatedNDF(host, msg) if err != nil { errMsg := fmt.Sprintf("Failed to get ndf from permissioning: %v", err) return nil, errors.New(errMsg) @@ -238,18 +247,24 @@ func (cm *CommManager) CheckVersion() (bool, error) { // to permissioning is needed func (cm *CommManager) ConnectToPermissioning() (connected bool, err error) { if cm.ndf.Registration.Address != "" { + _, ok := cm.Comms.GetHost(PermissioningAddrID) + if ok { + return true, nil + } var regCert []byte if cm.ndf.Registration.TlsCertificate != "" && cm.tls { regCert = []byte(cm.ndf.Registration.TlsCertificate) } - addr := ConnAddr(PermissioningAddrID) + globals.Log.INFO.Printf("Connecting to permissioning/registration at %s...", cm.ndf.Registration.Address) - err = cm.Comms.ConnectToRemote(addr, cm.ndf.Registration.Address, regCert, false) + host, err := connect.NewHost(cm.ndf.Registration.Address, regCert, false) if err != nil { return false, errors.New(fmt.Sprintf( - "Failed connecting to permissioning: %+v", err)) + "Failed connecting to create host for permissioning: %+v", err)) } + cm.Comms.AddHost(PermissioningAddrID, host) + globals.Log.INFO.Printf( "Connected to permissioning at %v successfully!", cm.ndf.Registration.Address) @@ -263,11 +278,6 @@ func (cm *CommManager) ConnectToPermissioning() (connected bool, err error) { } } -func (cm *CommManager) DisconnectFromPermissioning() { - globals.Log.DEBUG.Printf("Disconnecting from permissioning") - cm.Comms.Disconnect(PermissioningAddrID) -} - func (cm *CommManager) Disconnect() { cm.Comms.DisconnectAll() } diff --git a/io/receive.go b/io/receive.go index 2448ec62db04372a4b7fda2a73b1150b6e57b9f2..a08573832b4e7d98b17f27a468e7ea78c3715184 100644 --- a/io/receive.go +++ b/io/receive.go @@ -84,42 +84,6 @@ func (cm *CommManager) MessageReceiver(session user.Session, delay time.Duration if strings.Contains(err.Error(), "Client has exceeded communications rate limit") { globals.Log.WARN.Printf("Rate limit excceded on gateway, pausing polling for 5 seconds") time.Sleep(5 * time.Second) - } else if !skipErrChecker(err) { - backoffCount := 0 - - // Handles disconnections - for notConnected := true; notConnected; { - - cm.Disconnect() - - block, backoffTime := cm.computeBackoff(backoffCount) - - cm.setConnectionStatus(Offline, toSeconds(backoffTime)) - - globals.Log.WARN.Printf("Disconnected, reconnecting in %s", backoffTime) - - timer := time.NewTimer(backoffTime) - - if block { - timer.Stop() - } - - select { - case <-session.GetQuitChan(): - close(session.GetQuitChan()) - return - case <-timer.C: - case <-cm.tryReconnect: - backoffCount = 0 - } - err := cm.ConnectToGateways() - - if err == nil { - notConnected = false - } - - backoffCount++ - } } } NumMessages += len(encryptedMessages) @@ -236,8 +200,11 @@ func (cm *CommManager) receiveMessagesFromGateway(session user.Session, // FIXME: dont do this over an over // Gets a list of mssages that are newer than the last one recieved - messageIDs, err := cm.Comms.SendCheckMessages(receiveGateway, - pollingMessage) + host, ok := cm.Comms.GetHost(receiveGateway.String()) + if !ok { + return nil, errors.Errorf("Could not find host with id %s", receiveGateway.String()) + } + messageIDs, err := cm.Comms.SendCheckMessages(host, pollingMessage) if err != nil { return nil, err @@ -265,8 +232,7 @@ func (cm *CommManager) receiveMessagesFromGateway(session user.Session, messageID) // We haven't seen this message before. // So, we should retrieve it from the gateway. - newMessage, err := cm.Comms.SendGetMessage( - receiveGateway, + newMessage, err := cm.Comms.SendGetMessage(host, &pb.ClientRequest{ UserID: session.GetCurrentUser().User. Bytes(), diff --git a/io/send.go b/io/send.go index 54f1d083aad4e04c8ba46209ba4e4c72ab6c16c1..88fa51beda70cf0fd73e5a255dbdb6d0e569282d 100644 --- a/io/send.go +++ b/io/send.go @@ -154,7 +154,12 @@ func (cm *CommManager) send(session user.Session, topology *circuit.Circuit, KMACs: kmacs, } - return cm.Comms.SendPutMessage(transmitGateway, msgPacket) + host, ok := cm.Comms.GetHost(transmitGateway.String()) + if !ok { + return errors.Errorf("Could not find host with ID %s", transmitGateway.String()) + } + + return cm.Comms.SendPutMessage(host, msgPacket) } func handleE2ESending(session user.Session,