def pingWithRetransmit(self, pn, tries, later, ack_key=None):

        dcall_discard(pn, 'sendPing_dcall')
        pn.ping_reqs.clear()

        def cb(tries):
            pn.sendPing_dcall = None

            # Send the ping
            self.sendPing(pn, True)

            # While tries is positive, use 1 second intervals.
            # When it hits zero, trigger a timeout.  As it goes negative,
            # pings get progressively more spaced out.

            if tries > 0:
                when = 1.0
            else:
                tries = max(tries, -7)
                when = 2.0 ** -tries  # max of 128 sec

            # Tweak the delay
            when *= random.uniform(0.9, 1.1)

            # Schedule retransmit
            pn.sendPing_dcall = reactor.callLater(when, cb, tries-1)

            # Just failed now
            if tries == 0:

                if self.main.osm.syncd and pn.got_ack:
                    # Note that we had to set sendPing_dcall before this.
                    self.handleNodeFailure(pn.ipp)

                pn.got_ack = False

                # If this was an inbound node, forget it.
                pn.inbound = False

                if pn.outbound:
                    # An outbound link just failed.  Go find another one.
                    self.scheduleMakeNewLinks()
                else:
                    # Neither side wants this link.  Clean up.
                    self.cancelInactiveLink(pn)

        if later:
            when = 5.0
        else:
            # Send first ping
            self.sendPing(pn, True, ack_key)
            tries -= 1
            when = 1.0

        # Schedule retransmit(s)
        when *= random.uniform(0.9, 1.1)
        pn.sendPing_dcall = reactor.callLater(when, cb, tries)

        # Leave a flag value in the dcall so we can test whether this
        # ping can be made a bit sooner
        if later:
            pn.sendPing_dcall.ping_is_shortable = True