/// <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);
        }