int ProcessMessageBySection()

in OSNetworkRequirementChecker-HLApp/src/dns-helper.c [102:237]


int ProcessMessageBySection(char *buf, ssize_t len, ns_msg msg, ns_sect section,
                            ServiceInstanceDetails **instanceDetails)
{
    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: %s (%d)\n", strerror(errno), errno);
            return -1;
        }
        (*instanceDetails)->name = NULL;
        (*instanceDetails)->host = NULL;
        (*instanceDetails)->ipv4Address.s_addr = INADDR_NONE;
        (*instanceDetails)->port = 0;
        (*instanceDetails)->txtData = NULL;
        (*instanceDetails)->txtDataLength = 0;
        (*instanceDetails)->alias = NULL;
    }

    // Parse each message
    for (int i = 0; i < messageCount; ++i) {
        if (ns_parserr(&msg, section, i, &rr)) {
            Log_Debug("ERROR: ns_parserr: %s (%d)\n", strerror(errno), 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: %s (%d)\n", strerror(errno),
                              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: %s (%d)\n", strerror(errno), errno);
                    return -1;
                }
            }
            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)): %s (%d)\n", strerror(errno), 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: %s (%d)\n", strerror(errno), 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)) {
                if ((*instanceDetails)->ipv4Address.s_addr == INADDR_NONE) {
                    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;
        }
        case ns_t_cname: {
            char answerBuf[ANSWER_BUF_SIZE];
            const char *rd = ns_rr_rdata(rr);
            // Uncompress original name
            int n = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), rd, answerBuf,
                                       sizeof(answerBuf));
            if (n < 0) {
                Log_Debug(
                    "ERROR: Fail to uncompress original name from cname record. bufsize: %d, "
                    "errno: %s (%d)\n",
                    sizeof(answerBuf), strerror(errno), errno);
            }
            (*instanceDetails)->name = strdup(answerBuf);
            // Aggregate alias information
            if (!((*instanceDetails)->alias)) {
                (*instanceDetails)->alias = strdup(ns_rr_name(rr));
            } else {
                char *indent = "\n\t\t";
                char *original = (*instanceDetails)->alias;
                size_t suffixLen = strlen(ns_rr_name(rr));
                size_t originLen = strlen(original);
                size_t indentLen = strlen(indent);
                char *updated = (char *)malloc(suffixLen + originLen + indentLen + 1);
                memcpy(updated, original, originLen);
                memcpy(updated + originLen, indent, indentLen);
                memcpy(updated + originLen + indentLen, ns_rr_name(rr), suffixLen);
                updated[suffixLen + originLen + indentLen] = '\0';
                (*instanceDetails)->alias = updated;
            }
            break;
        }
        default:
            break;
        }
    }
    return 0;
}