def simultaneous_challenge(self, node_ip, node_port, proto):
        """
        Used by active simultaneous nodes to attempt to initiate
        a simultaneous open to a compatible node after retrieving
        its details from bootstrapping. The function advertises
        itself as a potential candidate to the server for the
        designated node_ip. It also waits for a response from the
        node (if any) and attends any arranged fights.
        """

        parts = self.sequential_connect()
        if parts is None:
            log.debug("Sequential connect failed")
            return None
        con, mappings, predictions = parts

        # Tell server to list ourselves as a candidate for node.
        msg = "CANDIDATE %s %s %s" % (node_ip, str(proto), predictions)
        con.send_line(msg)
        reply = con.recv_line(timeout=10)
        log.debug(reply)
        if "PREDICTION SET" not in reply:
            log.debug("Prediction set failed")
            return None

        # Wait for node to accept and give us fight time.
        # FIGHT 192.168.0.1 4552 345 34235 TCP 123123123.1\
        reply = con.recv_line(timeout=10)
        log.debug(reply)
        con.s.close()
        p = "^FIGHT ([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) ((?:[0-9]+\s?)+)"
        p += " (TCP|UDP) ([0-9]+(?:[.][0-9]+)?)$"
        parts = re.findall(p, reply)
        if not len(parts):
            log.debug("Invalid parts length")
            return None
        node_ip, predictions, proto, ntp = parts[0]

        log.debug("Received fight details")
        log.debug(str(parts[0]))
        log.debug("Attending fight now")
        return self.attend_fight(mappings, node_ip, predictions, ntp)