예제 #1
0
int
mdns_serve(struct mdns_ctx *ctx, mdns_stop_func stop, void *p_cookie)
{
        int r;
        struct mdns_svc *svc;
        struct mdns_hdr qhdr = {0};
        struct rr_entry *question;

        if (setsockopt(ctx->sock, SOL_SOCKET, SO_RCVTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
                return (MDNS_NETERR);
        if (setsockopt(ctx->sock, SOL_SOCKET, SO_SNDTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
                return (MDNS_NETERR);

        for (; stop(p_cookie) == false;) {
                r = mdns_recv(ctx, &qhdr, &question);
                if (r == MDNS_NETERR)
                        continue;
                if (qhdr.num_qn == 0)
                        goto again;

                for (svc = ctx->services; svc; svc = svc->next) {
                        if (!strrcmp(question->name, svc->name) && question->type == svc->type) {
                                svc->callback(svc->p_cookie, r, question);
                                goto again;
                        }
                }
again:
                mdns_free(question);
        }
        return (0);
}
예제 #2
0
int
mdns_recv(const struct mdns_ctx *ctx, struct mdns_hdr *hdr, struct rr_entry **entries)
{
        uint8_t buf[MDNS_PKT_MAXSZ];
        size_t num_entry, n;
        ssize_t length;
        struct rr_entry *entry;

        *entries = NULL;
        if ((length = recv(ctx->sock, (char *) buf, sizeof(buf), 0)) < 0)
                return (MDNS_NETERR);

        const uint8_t *ptr = mdns_read_header(buf, length, hdr);

        num_entry = hdr->num_qn + hdr->num_ans_rr + hdr->num_add_rr;
        for (size_t i = 0; i < num_entry; ++i) {
                entry = calloc(1, sizeof(struct rr_entry));
                if (!entry)
                        goto err;
                ptr = rr_read(ptr, &n, buf, entry, (hdr->flags & FLAG_QR) > 0);
                if (!ptr) {
                        errno = ENOSPC;
                        goto err;
                }
                entry->next = *entries;
                *entries = entry;
        }
        if (*entries == NULL) {
                return (MDNS_STDERR);
        }
        return (0);
err:
        mdns_free(*entries);
        return (MDNS_STDERR);
}
예제 #3
0
int
mdns_listen(const struct mdns_ctx *ctx, const char *name, enum rr_type type, unsigned int interval,
    mdns_stop_func stop, mdns_callback callback, void *p_cookie)
{
        int r;
        time_t t1, t2;
        struct mdns_hdr hdr = {0};
        struct rr_entry qn = {0};

        hdr.num_qn  = 1;
        qn.name     = (char *)name;
        qn.type     = type;
        qn.rr_class = RR_IN;

        if (setsockopt(ctx->sock, SOL_SOCKET, SO_RCVTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
                return (MDNS_NETERR);
        if (setsockopt(ctx->sock, SOL_SOCKET, SO_SNDTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
                return (MDNS_NETERR);

        if ((r = mdns_send(ctx, &hdr, &qn)) < 0) // send a first probe request
                callback(p_cookie, r, NULL);
        for (t1 = t2 = time(NULL); stop(p_cookie) == false; t2 = time(NULL)) {
                struct mdns_hdr ahdr = {0};
                struct rr_entry *entries;

                if (difftime(t2, t1) >= (double) interval) {
                        if ((r = mdns_send(ctx, &hdr, &qn)) < 0) {
                                callback(p_cookie, r, NULL);
                                continue;
                        }
                        t1 = t2;
                }
                r = mdns_recv(ctx, &ahdr, &entries);
                if (r == MDNS_NETERR && os_wouldblock())
                        continue;

                if (ahdr.num_ans_rr + ahdr.num_add_rr == 0)
                        continue;

                for (struct rr_entry *entry = entries; entry; entry = entry->next) {
                        if (!strrcmp(entry->name, name)) {
                                callback(p_cookie, r, entries);
                                break;
                        }
                }
                mdns_free(entries);
        }
        return (0);
}
예제 #4
0
int
mdns_listen(const struct mdns_ctx *ctx, const char *const names[],
            unsigned int nb_names, enum rr_type type, unsigned int interval,
            mdns_stop_func stop, mdns_callback callback, void *p_cookie)
{
        int r;
        time_t t1, t2;
        struct mdns_hdr hdr = {0};
        struct rr_entry *qns = malloc(nb_names * sizeof(struct rr_entry));
        if (qns == NULL)
            return (MDNS_STDERR);
        memset(qns, 0, nb_names * sizeof(struct rr_entry));

        hdr.num_qn = nb_names;
        for (unsigned int i = 0; i < nb_names; ++i)
        {
                qns[i].name     = (char *)names[i];
                qns[i].type     = type;
                qns[i].rr_class = RR_IN;
                if (i + 1 < nb_names)
                    qns[i].next = &qns[i+1];
        }

        if (setsockopt(ctx->sock, SOL_SOCKET, SO_RCVTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
        {
            free(qns);
            return (MDNS_NETERR);
        }
        if (setsockopt(ctx->sock, SOL_SOCKET, SO_SNDTIMEO, (const void *) &os_deadline, sizeof(os_deadline)) < 0)
        {
            free(qns);
            return (MDNS_NETERR);
        }

        if ((r = mdns_entries_send(ctx, &hdr, qns)) < 0) // send a first probe request
                callback(p_cookie, r, NULL);
        for (t1 = t2 = time(NULL); stop(p_cookie) == false; t2 = time(NULL)) {
                struct mdns_hdr ahdr = {0};
                struct rr_entry *entries;

                if (difftime(t2, t1) >= (double) interval) {
                        if ((r = mdns_entries_send(ctx, &hdr, qns)) < 0) {
                                callback(p_cookie, r, NULL);
                                continue;
                        }
                        t1 = t2;
                }
                r = mdns_recv(ctx, &ahdr, &entries);
                if (r == MDNS_NETERR && os_wouldblock())
                {
                        mdns_free(entries);
                        continue;
                }

                if (ahdr.num_ans_rr + ahdr.num_add_rr == 0)
                {
                        mdns_free(entries);
                        continue;
                }

                for (struct rr_entry *entry = entries; entry; entry = entry->next) {
                        for (unsigned int i = 0; i < nb_names; ++i) {
                                if (!strrcmp(entry->name, names[i])) {
                                        callback(p_cookie, r, entries);
                                        break;
                                }
                        }
                }
                mdns_free(entries);
        }
        free(qns);
        return (0);
}