int dns_transaction_go(DnsTransaction *t) {
        usec_t ts;
        int r;
        char key_str[DNS_RESOURCE_KEY_STRING_MAX];

        assert(t);

        /* Returns > 0 if the transaction is now pending, returns 0 if could be processed immediately and has finished
         * now. */

        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);

        r = dns_transaction_prepare(t, ts);
        if (r <= 0)
                return r;

        log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.",
                  t->id,
                  dns_resource_key_to_string(t->key, key_str, sizeof key_str),
                  dns_protocol_to_string(t->scope->protocol),
                  t->scope->link ? t->scope->link->name : "*",
                  af_to_name_short(t->scope->family));

        if (!t->initial_jitter_scheduled &&
            IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
                usec_t jitter, accuracy;

                /* RFC 4795 Section 2.7 suggests all queries should be
                 * delayed by a random time from 0 to JITTER_INTERVAL. */

                t->initial_jitter_scheduled = true;

                random_bytes(&jitter, sizeof(jitter));

                switch (t->scope->protocol) {

                case DNS_PROTOCOL_LLMNR:
                        jitter %= LLMNR_JITTER_INTERVAL_USEC;
                        accuracy = LLMNR_JITTER_INTERVAL_USEC;
                        break;

                case DNS_PROTOCOL_MDNS:
                        jitter %= MDNS_JITTER_RANGE_USEC;
                        jitter += MDNS_JITTER_MIN_USEC;
                        accuracy = MDNS_JITTER_RANGE_USEC;
                        break;
                default:
                        assert_not_reached("bad protocol");
                }

                r = sd_event_add_time(
                                t->scope->manager->event,
                                &t->timeout_event_source,
                                clock_boottime_or_monotonic(),
                                ts + jitter, accuracy,
                                on_transaction_timeout, t);
                if (r < 0)
                        return r;

                (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

                t->n_attempts = 0;
                t->next_attempt_after = ts;
                t->state = DNS_TRANSACTION_PENDING;

                log_debug("Delaying %s transaction for " USEC_FMT "us.", dns_protocol_to_string(t->scope->protocol), jitter);
                return 0;
        }

        /* Otherwise, we need to ask the network */
        r = dns_transaction_make_packet(t);
        if (r < 0)
                return r;

        if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
            (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 ||
             dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) {

                /* RFC 4795, Section 2.4. says reverse lookups shall
                 * always be made via TCP on LLMNR */
                r = dns_transaction_emit_tcp(t);
        } else {
                /* Try via UDP, and if that fails due to large size or lack of
                 * support try via TCP */
                r = dns_transaction_emit_udp(t);
                if (r == -EMSGSIZE)
                        log_debug("Sending query via TCP since it is too large.");
                else if (r == -EAGAIN)
                        log_debug("Sending query via TCP since UDP isn't supported.");
                if (IN_SET(r, -EMSGSIZE, -EAGAIN))
                        r = dns_transaction_emit_tcp(t);
        }

        if (r == -ESRCH) {
                /* No servers to send this to? */
                dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
                return 0;
        }
        if (r == -EOPNOTSUPP) {
                /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC  */
                dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED);
                return 0;
        }
        if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(-r)) {
                /* On LLMNR, if we cannot connect to a host via TCP when doing reverse lookups. This means we cannot
                 * answer this request with this protocol. */
                dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND);
                return 0;
        }
        if (r < 0) {
                if (t->scope->protocol != DNS_PROTOCOL_DNS)
                        return r;

                /* Couldn't send? Try immediately again, with a new server */
                dns_scope_next_dns_server(t->scope);

                return dns_transaction_go(t);
        }

        ts += transaction_get_resend_timeout(t);

        r = sd_event_add_time(
                        t->scope->manager->event,
                        &t->timeout_event_source,
                        clock_boottime_or_monotonic(),
                        ts, 0,
                        on_transaction_timeout, t);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

        t->state = DNS_TRANSACTION_PENDING;
        t->next_attempt_after = ts;

        return 1;
}
int dns_transaction_go(DnsTransaction *t) {
        usec_t ts;
        int r;
        char key_str[DNS_RESOURCE_KEY_STRING_MAX];

        assert(t);

         

        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);

        r = dns_transaction_prepare(t, ts);
        if (r <= 0)
                return r;

        log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.",
                  t->id,
                  dns_resource_key_to_string(t->key, key_str, sizeof key_str),
                  dns_protocol_to_string(t->scope->protocol),
                  t->scope->link ? t->scope->link->name : "*",
                  af_to_name_short(t->scope->family));

        if (!t->initial_jitter_scheduled &&
            IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
                usec_t jitter, accuracy;

                 

                t->initial_jitter_scheduled = true;

                random_bytes(&jitter, sizeof(jitter));

                switch (t->scope->protocol) {

                case DNS_PROTOCOL_LLMNR:
                        jitter %= LLMNR_JITTER_INTERVAL_USEC;
                        accuracy = LLMNR_JITTER_INTERVAL_USEC;
                        break;

                case DNS_PROTOCOL_MDNS:
                        jitter %= MDNS_JITTER_RANGE_USEC;
                        jitter += MDNS_JITTER_MIN_USEC;
                        accuracy = MDNS_JITTER_RANGE_USEC;
                        break;
                default:
                        assert_not_reached("bad protocol");
                }

                r = sd_event_add_time(
                                t->scope->manager->event,
                                &t->timeout_event_source,
                                clock_boottime_or_monotonic(),
                                ts + jitter, accuracy,
                                on_transaction_timeout, t);
                if (r < 0)
                        return r;

                (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

                t->n_attempts = 0;
                t->next_attempt_after = ts;
                t->state = DNS_TRANSACTION_PENDING;

                log_debug("Delaying %s transaction for " USEC_FMT "us.", dns_protocol_to_string(t->scope->protocol), jitter);
                return 0;
        }

         
        r = dns_transaction_make_packet(t);
        if (r < 0)
                return r;

        if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
            (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 ||
             dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) {

                 
                r = dns_transaction_emit_tcp(t);
        } else {
                 
                r = dns_transaction_emit_udp(t);
                if (r == -EMSGSIZE)
                        log_debug("Sending query via TCP since it is too large.");
                else if (r == -EAGAIN)
                        log_debug("Sending query via TCP since UDP isn't supported.");
                if (IN_SET(r, -EMSGSIZE, -EAGAIN))
                        r = dns_transaction_emit_tcp(t);
        }

        if (r == -ESRCH) {
                 
                dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
                return 0;
        }
        if (r == -EOPNOTSUPP) {
                 
                dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED);
                return 0;
        }
        if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(-r)) {
                 
                dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND);
                return 0;
        }
        if (r < 0) {
                if (t->scope->protocol != DNS_PROTOCOL_DNS)
                        return r;

                 
                dns_scope_next_dns_server(t->scope);

                return dns_transaction_go(t);
        }

        ts += transaction_get_resend_timeout(t);

        r = sd_event_add_time(
                        t->scope->manager->event,
                        &t->timeout_event_source,
                        clock_boottime_or_monotonic(),
                        ts, 0,
                        on_transaction_timeout, t);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

        t->state = DNS_TRANSACTION_PENDING;
        t->next_attempt_after = ts;

        return 1;
}