diff --git a/api/send.go b/api/send.go index 5ef62966daf88579091196898ce4e661583696e3..28b8435425b8941290581342ee54838a8de27eda 100644 --- a/api/send.go +++ b/api/send.go @@ -16,6 +16,7 @@ import ( "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" + "time" ) //This holds all functions to send messages over the network @@ -24,7 +25,7 @@ import ( // the provided msgType. Returns the list of rounds in which parts of // the message were sent or an error if it fails. func (c *Client) SendE2E(m message.Send, param params.E2E) ([]id.Round, - e2e.MessageID, error) { + e2e.MessageID, time.Time, error) { jww.INFO.Printf("SendE2E(%s, %d. %v)", m.Recipient, m.MessageType, m.Payload) return c.network.SendE2E(m, param, nil) diff --git a/api/utilsInterfaces_test.go b/api/utilsInterfaces_test.go index ad97286b779237335a1e9b14f2606266d97ad3cf..e421ffdc9aa20bd5c8ce89b1a7dea24432e7f9d9 100644 --- a/api/utilsInterfaces_test.go +++ b/api/utilsInterfaces_test.go @@ -20,6 +20,7 @@ import ( "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" + "time" ) // Mock comm struct which returns no historical round data @@ -94,9 +95,9 @@ func (t *testNetworkManagerGeneric) CheckGarbledMessages() { return } func (t *testNetworkManagerGeneric) SendE2E(message.Send, params.E2E, *stoppable.Single) ( - []id.Round, cE2e.MessageID, error) { + []id.Round, cE2e.MessageID, time.Time, error) { rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)} - return rounds, cE2e.MessageID{}, nil + return rounds, cE2e.MessageID{}, time.Time{}, nil } func (t *testNetworkManagerGeneric) SendUnsafe(m message.Send, p params.Unsafe) ([]id.Round, error) { diff --git a/bindings/message.go b/bindings/message.go index 44526fa2e3756868e1b895452d1484f1ff4366fa..680d9caf778d8d8ceb700b0a3d3ad2b8b6b20d4b 100644 --- a/bindings/message.go +++ b/bindings/message.go @@ -40,7 +40,7 @@ func (m *Message) GetMessageType() int { // GetTimestampMS returns the message's timestamp in milliseconds func (m *Message) GetTimestampMS() int64 { ts := m.r.Timestamp.UnixNano() - ts = (ts + 999999) / 1000000 + ts = (ts + 500000) / 1000000 return ts } diff --git a/bindings/send.go b/bindings/send.go index 586100d051b0f4f0248b235630111476b87b930f..cef9c99500772b54012dcf07f6b4d3aaea5628a8 100644 --- a/bindings/send.go +++ b/bindings/send.go @@ -15,6 +15,7 @@ import ( "gitlab.com/elixxir/client/interfaces/params" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/xx_network/primitives/id" + "time" ) // SendCMIX sends a "raw" CMIX message payload to the provided @@ -163,7 +164,7 @@ func (c *Client) SendE2E(recipient, payload []byte, messageType int, parameters MessageType: message.Type(messageType), } - rids, mid, err := c.api.SendE2E(m, p) + rids, mid, ts, err := c.api.SendE2E(m, p) if err != nil { return nil, errors.New(fmt.Sprintf("Failed SendE2E: %+v", err)) } @@ -171,6 +172,7 @@ func (c *Client) SendE2E(recipient, payload []byte, messageType int, parameters sr := SendReport{ rl: &RoundList{list: rids}, mid: mid, + ts: ts, } return &sr, nil @@ -180,6 +182,7 @@ func (c *Client) SendE2E(recipient, payload []byte, messageType int, parameters type SendReport struct { rl *RoundList mid e2e.MessageID + ts time.Time } type SendReportDisk struct { @@ -195,6 +198,18 @@ func (sr *SendReport) GetMessageID() []byte { return sr.mid[:] } +// GetTimestampMS returns the message's timestamp in milliseconds +func (sr *SendReport) GetTimestampMS() int64 { + ts := sr.ts.UnixNano() + ts = (ts + 500000) / 1000000 + return ts +} + +// GetTimestampNano returns the message's timestamp in nanoseconds +func (sr *SendReport) GetTimestampNano() int64 { + return sr.ts.UnixNano() +} + func (sr *SendReport) Marshal() ([]byte, error) { srd := SendReportDisk{ List: sr.rl.list, diff --git a/cmd/root.go b/cmd/root.go index 9ebdc637ac86440f250319c0db384eb16632fda3..41cd73e10c7b68e224776771c31e8cfb1323fbe7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -198,7 +198,7 @@ var rootCmd = &cobra.Command{ paramsUnsafe) roundTimeout = paramsUnsafe.Timeout } else { - roundIDs, _, err = client.SendE2E(msg, + roundIDs, _, _, err = client.SendE2E(msg, paramsE2E) roundTimeout = paramsE2E.Timeout } diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go index 3e4cc39f2995dbe870b4caa771cbd3a075c77eb7..70c5501ec7c6492a1b33f5a5309b2602c38ad06e 100644 --- a/groupChat/sendRequests.go +++ b/groupChat/sendRequests.go @@ -110,7 +110,7 @@ func (m Manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, error MessageType: message.GroupCreationRequest, } - rounds, _, err := m.net.SendE2E(sendMsg, params.GetDefaultE2E(), nil) + rounds, _, _, err := m.net.SendE2E(sendMsg, params.GetDefaultE2E(), nil) if err != nil { return nil, errors.Errorf(sendE2eErr, memberID, err) } diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go index bdf58edfa1a3e2070c2d6144411463a6740c97a0..4997976c643c3d90de630309daee335c503c63b0 100644 --- a/groupChat/utils_test.go +++ b/groupChat/utils_test.go @@ -36,6 +36,7 @@ import ( "math/rand" "sync" "testing" + "time" ) // newTestManager creates a new Manager for testing. @@ -240,20 +241,20 @@ func (tnm *testNetworkManager) GetE2eMsg(i int) message.Send { return tnm.e2eMessages[i] } -func (tnm *testNetworkManager) SendE2E(msg message.Send, _ params.E2E, _ *stoppable.Single) ([]id.Round, e2e.MessageID, error) { +func (tnm *testNetworkManager) SendE2E(msg message.Send, _ params.E2E, _ *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) { tnm.Lock() defer tnm.Unlock() tnm.errSkip++ if tnm.sendErr == 1 { - return nil, e2e.MessageID{}, errors.New("SendE2E error") + return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") } else if tnm.sendErr == 2 && tnm.errSkip%2 == 0 { - return nil, e2e.MessageID{}, errors.New("SendE2E error") + return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") } tnm.e2eMessages = append(tnm.e2eMessages, msg) - return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, nil + return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, time.Time{}, nil } func (tnm *testNetworkManager) SendUnsafe(message.Send, params.Unsafe) ([]id.Round, error) { diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index c3bc9f49d6994012f0f2cbc58ed0016b62180f59..3e40b9baea140a99fb615362ec50ee02c6a09f5d 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -17,11 +17,12 @@ import ( "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" + "time" ) type NetworkManager interface { // The stoppable can be nil. - SendE2E(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, error) + SendE2E(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) SendUnsafe(m message.Send, p params.Unsafe) ([]id.Round, error) SendCMIX(message format.Message, recipient *id.ID, p params.CMIX) (id.Round, ephemeral.Id, error) SendManyCMIX(messages map[id.ID]format.Message, p params.CMIX) (id.Round, []ephemeral.Id, error) @@ -50,4 +51,4 @@ type NetworkManager interface { } //for use in key exchange which needs to be callable inside of network -type SendE2E func(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, error) +type SendE2E func(m message.Send, p params.E2E, stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) diff --git a/keyExchange/rekey.go b/keyExchange/rekey.go index f4caacd2586bd7a8c0c8c296ba7f8ae19377db4f..5acc9ba71f383b5e8ae15966421ecd227ed7f6e7 100644 --- a/keyExchange/rekey.go +++ b/keyExchange/rekey.go @@ -104,7 +104,7 @@ func negotiate(instance *network.Instance, sendE2E interfaces.SendE2E, e2eParams := params.GetDefaultE2E() e2eParams.Type = params.KeyExchange - rounds, _, err := sendE2E(m, e2eParams, stop) + rounds, _, _, err := sendE2E(m, e2eParams, stop) // If the send fails, returns the error so it can be handled. The caller // should ensure the calling session is in a state where the Rekey will // be triggered next time a key is used diff --git a/keyExchange/trigger.go b/keyExchange/trigger.go index c88d068fe8d1463ea4c2b5408dd9b18c4030e488..e25da821f9a3485969608bd320a7f22534622255 100644 --- a/keyExchange/trigger.go +++ b/keyExchange/trigger.go @@ -127,7 +127,7 @@ func handleTrigger(sess *storage.Session, net interfaces.NetworkManager, // send fails sess.GetCriticalMessages().AddProcessing(m, e2eParams) - rounds, _, err := net.SendE2E(m, e2eParams, stop) + rounds, _, _, err := net.SendE2E(m, e2eParams, stop) if err != nil { return err } diff --git a/keyExchange/utils_test.go b/keyExchange/utils_test.go index cb0518466f10c4737fcc2376ce38ddfaeb318225..d844f16b46bf90b026d6ede34b743432939e03c2 100644 --- a/keyExchange/utils_test.go +++ b/keyExchange/utils_test.go @@ -31,6 +31,7 @@ import ( "gitlab.com/xx_network/primitives/ndf" "gitlab.com/xx_network/primitives/netTime" "testing" + "time" ) // Generate partner ID for two people, used for smoke tests @@ -67,9 +68,9 @@ func (t *testNetworkManagerGeneric) CheckGarbledMessages() { } func (t *testNetworkManagerGeneric) SendE2E(message.Send, params.E2E, *stoppable.Single) ( - []id.Round, cE2e.MessageID, error) { + []id.Round, cE2e.MessageID, time.Time, error) { rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)} - return rounds, cE2e.MessageID{}, nil + return rounds, cE2e.MessageID{}, time.Time{}, nil } @@ -169,7 +170,7 @@ func (t *testNetworkManagerFullExchange) CheckGarbledMessages() { // Intended for alice to send to bob. Trigger's Bob's confirmation, chaining the operation // together func (t *testNetworkManagerFullExchange) SendE2E(message.Send, params.E2E, *stoppable.Single) ( - []id.Round, cE2e.MessageID, error) { + []id.Round, cE2e.MessageID, time.Time, error) { rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)} alicePrivKey := aliceSession.E2e().GetDHPrivateKey() @@ -193,7 +194,7 @@ func (t *testNetworkManagerFullExchange) SendE2E(message.Send, params.E2E, *stop bobSwitchboard.Speak(confirmMessage) - return rounds, cE2e.MessageID{}, nil + return rounds, cE2e.MessageID{}, time.Time{}, nil } func (t *testNetworkManagerFullExchange) SendUnsafe(m message.Send, p params.Unsafe) ([]id.Round, error) { diff --git a/network/ephemeral/testutil.go b/network/ephemeral/testutil.go index 3b443dfe3a85f8c85e92dd235b190e00171df3ef..c5cbd8b7c03861888392f9a4b8077b0cf49fb72d 100644 --- a/network/ephemeral/testutil.go +++ b/network/ephemeral/testutil.go @@ -10,6 +10,7 @@ package ephemeral import ( "gitlab.com/elixxir/client/network/gateway" "testing" + "time" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" @@ -34,7 +35,7 @@ type testNetworkManager struct { } func (t *testNetworkManager) SendE2E(m message.Send, _ params.E2E, _ *stoppable.Single) ([]id.Round, - e2e.MessageID, error) { + e2e.MessageID, time.Time, error) { rounds := []id.Round{ id.Round(0), id.Round(1), @@ -43,7 +44,7 @@ func (t *testNetworkManager) SendE2E(m message.Send, _ params.E2E, _ *stoppable. t.msg = m - return rounds, e2e.MessageID{}, nil + return rounds, e2e.MessageID{}, time.Time{}, nil } func (t *testNetworkManager) SendUnsafe(m message.Send, _ params.Unsafe) ([]id.Round, error) { diff --git a/network/message/critical.go b/network/message/critical.go index 84b88da602ac8fb87a1562d25ab8a52c6f1c23ed..9c5b6bff7c824a925c969459ddb683e38a1faa1d 100644 --- a/network/message/critical.go +++ b/network/message/critical.go @@ -54,7 +54,7 @@ func (m *Manager) criticalMessages(stop *stoppable.Single) { jww.INFO.Printf("Resending critical message to %s ", msg.Recipient) //send the message - rounds, _, err := m.SendE2E(msg, param, stop) + rounds, _, _, err := m.SendE2E(msg, param, stop) //if the message fail to send, notify the buffer so it can be handled //in the future and exit if err != nil { diff --git a/network/message/sendE2E.go b/network/message/sendE2E.go index 7b468ad1a30c818396d631b4b9f85b5945dd88ab..e26dcb6de4ee21a8a72bcebf2dbf7ea26220453d 100644 --- a/network/message/sendE2E.go +++ b/network/message/sendE2E.go @@ -23,9 +23,9 @@ import ( ) func (m *Manager) SendE2E(msg message.Send, param params.E2E, - stop *stoppable.Single) ([]id.Round, e2e.MessageID, error) { + stop *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) { if msg.MessageType == message.Raw { - return nil, e2e.MessageID{}, errors.Errorf("Raw (%d) is a reserved "+ + return nil, e2e.MessageID{}, time.Time{}, errors.Errorf("Raw (%d) is a reserved "+ "message type", msg.MessageType) } //timestamp the message @@ -35,7 +35,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E, partitions, internalMsgId, err := m.partitioner.Partition(msg.Recipient, msg.MessageType, ts, msg.Payload) if err != nil { - return nil, e2e.MessageID{}, errors.WithMessage(err, "failed to send unsafe message") + return nil, e2e.MessageID{}, time.Time{}, errors.WithMessage(err, "failed to send unsafe message") } //encrypt then send the partitions over cmix @@ -45,7 +45,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E, // get the key manager for the partner partner, err := m.Session.E2e().GetPartner(msg.Recipient) if err != nil { - return nil, e2e.MessageID{}, errors.WithMessagef(err, + return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err, "Could not send End to End encrypted "+ "message, no relationship found with %s", msg.Recipient) } @@ -83,7 +83,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E, key, err = partner.GetKeyForSending(param.Type) } if err != nil { - return nil, e2e.MessageID{}, errors.WithMessagef(err, + return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err, "Failed to get key for end to end encryption") } @@ -113,7 +113,7 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E, if numFail > 0 { jww.INFO.Printf("Failed to E2E send %d/%d to %s", numFail, len(partitions), msg.Recipient) - return nil, e2e.MessageID{}, errors.Errorf("Failed to E2E send %v/%v sub payloads:"+ + return nil, e2e.MessageID{}, time.Time{}, errors.Errorf("Failed to E2E send %v/%v sub payloads:"+ " %s", numFail, len(partitions), errRtn) } else { jww.INFO.Printf("Successfully E2E sent %d/%d to %s", @@ -122,5 +122,5 @@ func (m *Manager) SendE2E(msg message.Send, param params.E2E, //return the rounds if everything send successfully msgID := e2e.NewMessageID(partner.GetSendRelationshipFingerprint(), internalMsgId) - return roundIds, msgID, nil + return roundIds, msgID, ts, nil } diff --git a/network/send.go b/network/send.go index d54e478c7c705f4995c451b1e302e5ae77d292f7..8fff3ac152e65a55822d6e824aba7f7f6d4f09eb 100644 --- a/network/send.go +++ b/network/send.go @@ -17,6 +17,7 @@ import ( "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" + "time" ) // SendCMIX sends a "raw" CMIX message payload to the provided @@ -63,10 +64,10 @@ func (m *manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round, // the provided msgType. Returns the list of rounds in which parts of // the message were sent or an error if it fails. func (m *manager) SendE2E(msg message.Send, e2eP params.E2E, stop *stoppable.Single) ( - []id.Round, e2e.MessageID, error) { + []id.Round, e2e.MessageID, time.Time, error) { if !m.Health.IsHealthy() { - return nil, e2e.MessageID{}, errors.New("Cannot send e2e " + + return nil, e2e.MessageID{}, time.Time{}, errors.New("Cannot send e2e " + "message when the network is not healthy") } diff --git a/single/manager_test.go b/single/manager_test.go index 1a62edf8405d450a82688e05a1e7b04af3f5ef06..a787e7462870d0f3cda30a5a31b3a89a92c3a1f3 100644 --- a/single/manager_test.go +++ b/single/manager_test.go @@ -283,8 +283,8 @@ func (tnm *testNetworkManager) GetMsg(i int) format.Message { return tnm.msgs[i] } -func (tnm *testNetworkManager) SendE2E(message.Send, params.E2E, *stoppable.Single) ([]id.Round, e2e.MessageID, error) { - return nil, e2e.MessageID{}, nil +func (tnm *testNetworkManager) SendE2E(message.Send, params.E2E, *stoppable.Single) ([]id.Round, e2e.MessageID, time.Time, error) { + return nil, e2e.MessageID{}, time.Time{}, nil } func (tnm *testNetworkManager) SendUnsafe(_ message.Send, _ params.Unsafe) ([]id.Round, error) {