Commit b29b0ca2 authored by jan.koester's avatar jan.koester
Browse files

test

parent f827c082
Loading
Loading
Loading
Loading

src/mdns.h

0 → 100644
+108 −0
Changes for src/mdns.h: 108 added lines, 0 removed lines.
Original line number Diff line number Diff line
/*******************************************************************************
Copyright (c) 2026, Jan Koester jan.koester@gmx.net
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

/* Multicast DNS (RFC 6762) and DNS-SD (RFC 6763): the shares become
 * visible in the network's file browsers without any setup.
 *
 *   <host>.local                      A/AAAA, the addresses of the interface asked on
 *   <name>._smb._tcp.local            SMB (Windows, macOS, Linux file managers)
 *   <name>._device-info._tcp.local    model=RackMac: macOS shows a server
 *   <share> (<host>)._nfs._tcp.local  one per NFS share, path=<its NFSv4 path>
 *
 * <name> is the NetBIOS name if one is set, else the host name. Answers
 * go to the interface a query came in on; the records are announced at
 * start and after changes, withdrawn (TTL 0) when gone. Interfaces that
 * appear later are joined within 30 s. No name probing: the names are
 * the host's own. */

#pragma once

#include <cstdint>
#include <ctime>
#include <map>
#include <string>
#include <vector>

#include "config.h"

namespace sharedd {

class Mdns {
public:
    explicit Mdns(const Config &cfg) : _cfg(cfg) {}
    ~Mdns() { stop(); }

    bool start(std::string &error);
    /* withdraws everything, closes the sockets */
    void stop();
    bool running() const { return _fd4 >= 0 || _fd6 >= 0; }
    std::vector<int> fds() const;
    void process(int fd);
    /* the shares or settings changed: withdraw what went, announce what's there */
    void changed();
    /* when tick() wants to run next, for poll(); -1: no hurry */
    int timeoutMs() const;
    void tick();

    /* the DNS name codec, for tests */
    using Name = std::vector<std::string>;
    static std::string encodeName(const Name &n);
    /* a possibly compressed name at off, advances off; false if malformed */
    static bool decodeName(const std::string &msg, size_t &off, Name &out);

    struct Record {
        Name name;
        uint16_t type = 0;
        bool unique = false;    /* the cache-flush bit */
        uint32_t ttl = 0;
        std::string rdata;
    };
    /* the records for an interface with these addresses (raw, 4 or 16 bytes) */
    std::vector<Record> records(const std::vector<std::string> &addrs4, const std::vector<std::string> &addrs6) const;
    /* the answer to a query (empty: nothing of ours); legacy: a unicast DNS query */
    std::string answer(const std::string &query, const std::vector<Record> &recs, bool legacy) const;

private:
    struct Iface {
        int index = 0;
        std::vector<std::string> v4, v6;   /* raw addresses */
        bool joined4 = false, joined6 = false;
    };

    void scan();
    void announce(const Iface &i, bool goodbye);
    void sendTo(const Iface &i, bool v6, const std::string &msg);

    const Config &_cfg;
    int _fd4 = -1, _fd6 = -1;
    std::map<int, Iface> _ifaces;
    std::map<int, std::vector<Record>> _announced;  /* ifindex -> what it was told last */
    int _announcePending = 0;                       /* repeats still due (RFC 6762 8.3: at least two) */
    time_t _nextAnnounce = 0, _nextScan = 0;
};

} // namespace sharedd