/// <summary> /// Generates a list of new RREQs to send, since the original has timed out without response, but retries are still allowed. /// </summary> /// <returns>A list of Messages to send, containing RREQs.</returns> public List <Message> UpdateBufferedRreqAttempts() { var rreqRetries = new List <Message>(); //Buffered RREQ attempts also contains RREQs buffered from other destinations when received. Only update if originator=me. //RREQs not from me will not be updated, and therefore removed when they expire. var myAttempts = _bufferedRreqAttempts.FindAll(rreq => rreq.OriginatorAddress == _localAddress); foreach (var rreqAttempt in myAttempts) { //If RREQ has timed out without a response (expired) if (_time.CurrentTime > rreqAttempt.ExpirationTime) { //We still have some attempts left to try and discover a route. Detals per section 6.4 rreqAttempt.AttemptNo++; //Increase attempt number rreqAttempt.ExpirationTime = _time.GetFutureTime(Math.Pow(2, rreqAttempt.AttemptNo) * _aodvParameters.NetTraversalTime); //Binary exponentiel backoff rreqAttempt.Rreq.RouteRequestId = RoutingTable.NextRouteRequestId; //Update id on each new RREQ var msg = new Message(new Rreq(rreqAttempt.Rreq), SimulationConstants.BroadcastAddress, _localAddress, _conf.MessageTtlValue); msg.Ttl = _aodvParameters.TtlStart + (rreqAttempt.AttemptNo * _aodvParameters.TtlIncrement); //Section 6.4 if (msg.Ttl > _aodvParameters.TtlThreshold) { rreqAttempt.RetryNo++; msg.Ttl = _aodvParameters.NetDiameter; } //Routing table entry waiting for a RREP SHOULD NOT be expunged before (current_time + 2 * NET_TRAVERSAL_TIME). //Entries does not exists for initial rreqs, since they are trying to discover a route. //From section 6.4 ending. var waitingEntry = RoutingTable.GetEntry(rreqAttempt.DestinationAddress); if (waitingEntry != null) { RoutingTable.UpdateExpirationTime(rreqAttempt.DestinationAddress, _time.GetFutureTime(2 * _aodvParameters.NetTraversalTime)); } var index = _bufferedRreqAttempts.FindIndex(attempt => attempt.RouteRequestId == rreqAttempt.RouteRequestId && attempt.OriginatorAddress == rreqAttempt.OriginatorAddress); _bufferedRreqAttempts[index] = rreqAttempt; //Replace current attempt with new one rreqRetries.Add(msg); } } return(rreqRetries); }
/// <summary> /// Generates a new Message, containing a RREQ for the wanted destination. /// Implemented according to Section 6.3: Generating Route Requests (RREQ) in the RFC. /// /// Method also handles buffering of RREQ, to avoid sending a duplicate in next iteration. /// </summary> /// <param name="destination">String representation of the destination address.</param> /// <returns>A Message with the RREQ enclosed. Includes destination address set to broadcast, and TTL adjusted according to the RFC.</returns> public Message GenerateInitialRreqMessage(string destination) { //If RREQ has been sent for this destination by me, and has not yet timed out, dont send a new one if (RreqAttemptExist(destination, _localAddress) && _time.CurrentTime < GetBufferedRreqAttempt(destination, _localAddress).ExpirationTime) { _logger.WriteLine("RREQ has been sent for this destination, and has not yet timed out, so dont send a new one."); return(null); } //Else, no RREQ for this destination waiting for response, send a new one RoutingTable.IncrementSequenceNumber(); //Must be incremented before sending a RREQ, per section 6.1 and 6.3 var knownEntry = RoutingTable.GetEntry(destination); //Get stale entry if it exists var rreq = new Rreq { G = _conf.AODV_UseGratuitousRREPs, D = _conf.AODV_DestinationRespondOnlyFlag, U = knownEntry == null, //True if no current DSN is known, per section 6.3 HopCount = 0, RouteRequestId = RoutingTable.NextRouteRequestId, DestinationAddress = destination, DestinationSequenceNumber = knownEntry?.DestinationSequenceNumber ?? 0, //Known DSN and U=false, or unknown DSN=0 and U=true OriginatorAddress = _localAddress, OriginatorSequenceNumber = RoutingTable.SequenceNumber }; //Any stale routing table entry waiting for a RREP (because of the newly generated RREQ) should not be expunged before current_time + 2 * NET_TRAVERSAL_TIME if (knownEntry != null) { knownEntry.ExpirationTime = _time.GetFutureTime(2 * _aodvParameters.NetTraversalTime); } //Create Message to send RREQ in, and adjust RREQ var msg = new Message(rreq, SimulationConstants.BroadcastAddress, _localAddress, _conf.MessageTtlValue); msg.Ttl = knownEntry?.HopCount + _aodvParameters.TtlIncrement ?? _aodvParameters.TtlStart; //Per section 6.4, use last known hopcount as initial TTL + TTL_INCREMENT //Buffer RREQ ID and Originator address, pr. section 6.3 (taken from rreq) var rreqAttempt = new BufferedRreqAttempt(0, rreq, _conf.AodvConfiguration.PathDiscoveryTime); rreqAttempt.ExpirationTime = _time.GetFutureTime(_aodvParameters.PathDiscoveryTime); AddBufferedRreqAttempt(rreqAttempt); return(msg); }