int ProcessMessageBySection()

in DNSServiceDiscoveryUnicast/dns-sd.c [58:159]


int ProcessMessageBySection(char *buf, ssize_t len, ns_msg msg, ns_sect section,
                            ServiceInstanceDetails **instanceDetails)
{
    static char displayBuf[DISPLAY_BUF_SIZE];
    ns_rr rr;
    int messageCount = ns_msg_count(msg, section);

    if (!(*instanceDetails)) {
        // Allocate for ServiceInstanceDetails and initialize its members.
        *instanceDetails = malloc(sizeof(ServiceInstanceDetails));
        if (!(*instanceDetails)) {
            Log_Debug("ERROR: recvfrom: %d (%s)\n", errno, strerror(errno));
            return -1;
        }
        (*instanceDetails)->name = NULL;
        (*instanceDetails)->host = NULL;
        (*instanceDetails)->ipv4Address.s_addr = INADDR_NONE;
        (*instanceDetails)->port = 0;
        (*instanceDetails)->txtData = NULL;
        (*instanceDetails)->txtDataLength = 0;
    }

    // Parse each message
    for (int i = 0; i < messageCount; ++i) {
        if (ns_parserr(&msg, section, i, &rr)) {
            Log_Debug("ERROR: ns_parserr: %d (%s)\n", errno, strerror(errno));
            return -1;
        }
        switch (ns_rr_type(rr)) {
        case ns_t_ptr: {
            int compressedNameLength =
                dn_expand(buf, buf + len, ns_rr_rdata(rr), displayBuf, sizeof(displayBuf));
            if (compressedNameLength > 0 && !(*instanceDetails)->name) {
                (*instanceDetails)->name = strdup(displayBuf);
                if (!(*instanceDetails)->name) {
                    Log_Debug("ERROR: strdup for instance name failed: %d (%s)\n", errno,
                              strerror(errno));
                    return -1;
                }
            }
            break;
        }
        case ns_t_srv: {
            // Parse the SRV record and populate the port and host fields in instance details as per
            // DNS SRV record specification: https://tools.ietf.org/rfc/rfc2782.txt
            // SRV record format: Priority|  Weight |   Port  |     Target
            //                   (2 Bytes)|(2 Bytes)|(2 Bytes)|(Remaining Bytes)
            const char *data = ns_rr_rdata(rr);
            int compressedTargetDomainNameLength = dn_expand(
                buf, buf + len, data + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t),
                displayBuf, sizeof(displayBuf));
            if ((*instanceDetails)->port == 0 && compressedTargetDomainNameLength > 0 &&
                !(*instanceDetails)->host) {
                (*instanceDetails)->port =
                    (uint16_t)ns_get16(data + sizeof(uint16_t) + sizeof(uint16_t));
                (*instanceDetails)->host = strdup(displayBuf);
                if (!(*instanceDetails)->host) {
                    Log_Debug("ERROR: strdup: %d (%s)\n", errno, strerror(errno));
                    return -1;
                }
                Log_Debug("%s\n", (*instanceDetails)->host);
            }
            break;
        }
        case ns_t_txt: {
            // Populate name field in instance details if it hasn't been set
            if (!(*instanceDetails)->name) {
                (*instanceDetails)->name = strdup(ns_rr_name(rr));
                if (!(*instanceDetails)->name) {
                    Log_Debug("ERROR: strdup(ns_rr_name(rr)): %d (%s)\n", errno, strerror(errno));
                    return -1;
                }
            }

            // Get TXT record, populate txtData and txtDataLength fields in instance details
            if (!(*instanceDetails)->txtData) {
                (*instanceDetails)->txtData =
                    malloc(sizeof(unsigned char) * (size_t)(ns_rr_rdlen(rr)));
                if (!(*instanceDetails)->txtData) {
                    Log_Debug("ERROR: malloc: %d (%s)\n", errno, strerror(errno));
                    return -1;
                }
                memcpy((*instanceDetails)->txtData, ns_rr_rdata(rr), ns_rr_rdlen(rr));
                (*instanceDetails)->txtDataLength = ns_rr_rdlen(rr);
            }
            break;
        }
        case ns_t_a: {
            // Get A record (host address), populate ipv4Address field in instance details
            if (ns_rr_rdlen(rr) == sizeof((*instanceDetails)->ipv4Address)) {
                memcpy(&(*instanceDetails)->ipv4Address.s_addr, ns_rr_rdata(rr), ns_rr_rdlen(rr));
            } else {
                Log_Debug("ERROR: Invalid DNS A record length: %d\n", ns_rr_rdlen(rr));
            }
            break;
        }
        default:
            break;
        }
    }
    return 0;
}