diff --git a/PROTOCOL.md b/PROTOCOL.md index 553150a..56292e2 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -91,9 +91,9 @@ MUST NOT be changed by a forwarding node. Hop Count specifies the number of nodes a message may pass. When creating a package, it is initialized to 0. Whenever a node forwards -a package, it MUST increment the hop limit by one. If the hop limit -BEFORE/AFTER? incrementing equals Hop Limit, the package MUST be -ignored. +a package, it MUST increment the hop limit by one. If the hop count +after incrementing equals or is greater than Hop Limit, the package +MUST NOT be forwarded. Length is the message size in bytes, including the header. diff --git a/app/src/androidTest/scala/com/nutomic/ensichat/protocol/RouterTest.scala b/app/src/androidTest/scala/com/nutomic/ensichat/protocol/RouterTest.scala index 82782c9..0b396c2 100644 --- a/app/src/androidTest/scala/com/nutomic/ensichat/protocol/RouterTest.scala +++ b/app/src/androidTest/scala/com/nutomic/ensichat/protocol/RouterTest.scala @@ -1,9 +1,9 @@ package com.nutomic.ensichat.protocol -import java.util.GregorianCalendar +import java.util.{Date, GregorianCalendar} import android.test.AndroidTestCase -import com.nutomic.ensichat.protocol.body.UserName +import com.nutomic.ensichat.protocol.body.{Text, UserName} import com.nutomic.ensichat.protocol.header.ContentHeader import junit.framework.Assert._ @@ -20,7 +20,6 @@ class RouterTest extends AndroidTestCase { var sentTo = Set[Address]() val router: Router = new Router(neighbors, (a, m) => { - assertEquals(msg, m) sentTo += a }) @@ -28,6 +27,21 @@ class RouterTest extends AndroidTestCase { assertEquals(neighbors(), sentTo) } + def testMessageSame(): Unit = { + val router: Router = new Router(neighbors, + (a, m) => { + assertEquals(msg.header.origin, m.header.origin) + assertEquals(msg.header.target, m.header.target) + assertEquals(msg.header.seqNum, m.header.seqNum) + assertEquals(msg.header.protocolType, m.header.protocolType) + assertEquals(msg.header.hopCount + 1, m.header.hopCount) + assertEquals(msg.header.hopLimit, m.header.hopLimit) + assertEquals(msg.body, m.body) + assertEquals(msg.crypto, m.crypto) + }) + router.onReceive(msg) + } + /** * Messages from different senders with the same sequence number should be forwarded. */ @@ -75,6 +89,13 @@ class RouterTest extends AndroidTestCase { test(ContentHeader.SeqNumRange.last / 2, 1) } + def testHopLimit(): Unit = Range(19, 22).foreach { i => + val msg = new Message( + new ContentHeader(AddressTest.a1, AddressTest.a2, 1, 1, 1, new Date(), i), new Text("")) + val router: Router = new Router(neighbors, (a, m) => fail()) + router.onReceive(msg) + } + private def generateMessage(sender: Address, receiver: Address, seqNum: Int): Message = { val header = new ContentHeader(sender, receiver, seqNum, UserName.Type, 5, new GregorianCalendar(2014, 6, 10).getTime) diff --git a/app/src/main/scala/com/nutomic/ensichat/protocol/Router.scala b/app/src/main/scala/com/nutomic/ensichat/protocol/Router.scala index ad4e504..27716ae 100644 --- a/app/src/main/scala/com/nutomic/ensichat/protocol/Router.scala +++ b/app/src/main/scala/com/nutomic/ensichat/protocol/Router.scala @@ -1,6 +1,6 @@ package com.nutomic.ensichat.protocol -import com.nutomic.ensichat.protocol.header.ContentHeader +import com.nutomic.ensichat.protocol.header.{MessageHeader, ContentHeader} /** * Forwards messages to all connected devices. @@ -14,12 +14,29 @@ class Router(activeConnections: () => Set[Address], send: (Address, Message) => if (messageSeen.contains(info)) return - activeConnections().foreach(a => send(a, msg)) + val updated = incHopCount(msg) + if (updated.header.hopCount >= updated.header.hopLimit) + return + + activeConnections().foreach(a => send(a, updated)) trimMessageSeen(info._1, info._2) messageSeen += info } + /** + * Returns msg with hop count increased by one. + */ + private def incHopCount(msg: Message): Message = { + val updatedHeader = msg.header match { + case ch: ContentHeader => new ContentHeader(ch.origin, ch.target, ch.seqNum, ch.contentType, + ch.messageId, ch.time, ch.hopCount + 1, ch.hopLimit) + case mh: MessageHeader => new MessageHeader(mh.protocolType, mh.origin, mh.target, mh.seqNum, + mh.hopCount + 1, mh.hopLimit) + } + new Message(updatedHeader, msg.crypto, msg.body) + } + /** * Removes old entries from [[messageSeen]]. * diff --git a/app/src/main/scala/com/nutomic/ensichat/protocol/header/ContentHeader.scala b/app/src/main/scala/com/nutomic/ensichat/protocol/header/ContentHeader.scala index 712b4e2..34755e7 100644 --- a/app/src/main/scala/com/nutomic/ensichat/protocol/header/ContentHeader.scala +++ b/app/src/main/scala/com/nutomic/ensichat/protocol/header/ContentHeader.scala @@ -45,13 +45,12 @@ case class ContentHeader(override val origin: Address, contentType: Int, messageId: Long, time: Date, - override val hopCount: Int = 0) + override val hopCount: Int = 0, + override val hopLimit: Int = AbstractHeader.DefaultHopLimit) extends AbstractHeader { override val protocolType = ContentHeader.ContentMessageType - override val hopLimit = AbstractHeader.DefaultHopLimit - /** * Writes the header to byte array. */