[wpiutil] Handle multicast service collision on linux (#3734)

This commit is contained in:
Thad House
2021-11-26 23:20:54 -08:00
committed by GitHub
parent d8418be7d1
commit f6e9fc7d71
3 changed files with 107 additions and 10 deletions

View File

@@ -40,6 +40,8 @@ AvahiFunctionTable::AvahiFunctionTable() {
AvahiFunctionLoad(string_list_new_from_array);
AvahiFunctionLoad(string_list_free);
AvahiFunctionLoad(unescape_label);
AvahiFunctionLoad(alternative_service_name);
AvahiFunctionLoad(free);
lib = dlopen("libavahi-client.so.3", RTLD_LAZY);
@@ -60,6 +62,7 @@ AvahiFunctionTable::AvahiFunctionTable() {
AvahiFunctionLoad(entry_group_reset);
AvahiFunctionLoad(entry_group_is_empty);
AvahiFunctionLoad(entry_group_commit);
AvahiFunctionLoad(entry_group_get_client);
valid = true;
}

View File

@@ -159,6 +159,70 @@ enum { AVAHI_IF_UNSPEC = -1 };
enum { AVAHI_PROTO_INET = 0, AVAHI_PROTO_INET6 = 1, AVAHI_PROTO_UNSPEC = -1 };
enum {
AVAHI_OK = 0,
AVAHI_ERR_FAILURE = -1,
AVAHI_ERR_BAD_STATE = -2,
AVAHI_ERR_INVALID_HOST_NAME = -3,
AVAHI_ERR_INVALID_DOMAIN_NAME = -4,
AVAHI_ERR_NO_NETWORK = -5,
AVAHI_ERR_INVALID_TTL = -6,
AVAHI_ERR_IS_PATTERN = -7,
AVAHI_ERR_COLLISION = -8,
AVAHI_ERR_INVALID_RECORD = -9,
AVAHI_ERR_INVALID_SERVICE_NAME = -10,
AVAHI_ERR_INVALID_SERVICE_TYPE = -11,
AVAHI_ERR_INVALID_PORT = -12,
AVAHI_ERR_INVALID_KEY = -13,
AVAHI_ERR_INVALID_ADDRESS = -14,
AVAHI_ERR_TIMEOUT = -15,
AVAHI_ERR_TOO_MANY_CLIENTS = -16,
AVAHI_ERR_TOO_MANY_OBJECTS = -17,
AVAHI_ERR_TOO_MANY_ENTRIES = -18,
AVAHI_ERR_OS = -19,
AVAHI_ERR_ACCESS_DENIED = -20,
AVAHI_ERR_INVALID_OPERATION = -21,
AVAHI_ERR_DBUS_ERROR = -22,
AVAHI_ERR_DISCONNECTED = -23,
AVAHI_ERR_NO_MEMORY = -24,
AVAHI_ERR_INVALID_OBJECT = -25,
AVAHI_ERR_NO_DAEMON = -26,
AVAHI_ERR_INVALID_INTERFACE = -27,
AVAHI_ERR_INVALID_PROTOCOL = -28,
AVAHI_ERR_INVALID_FLAGS = -29,
AVAHI_ERR_NOT_FOUND = -30,
AVAHI_ERR_INVALID_CONFIG = -31,
AVAHI_ERR_VERSION_MISMATCH = -32,
AVAHI_ERR_INVALID_SERVICE_SUBTYPE = -33,
AVAHI_ERR_INVALID_PACKET = -34,
AVAHI_ERR_INVALID_DNS_ERROR = -35,
AVAHI_ERR_DNS_FORMERR = -36,
AVAHI_ERR_DNS_SERVFAIL = -37,
AVAHI_ERR_DNS_NXDOMAIN = -38,
AVAHI_ERR_DNS_NOTIMP = -39,
AVAHI_ERR_DNS_REFUSED = -40,
AVAHI_ERR_DNS_YXDOMAIN = -41,
AVAHI_ERR_DNS_YXRRSET = -42,
AVAHI_ERR_DNS_NXRRSET = -43,
AVAHI_ERR_DNS_NOTAUTH = -44,
AVAHI_ERR_DNS_NOTZONE = -45,
AVAHI_ERR_INVALID_RDATA = -46,
AVAHI_ERR_INVALID_DNS_CLASS = -47,
AVAHI_ERR_INVALID_DNS_TYPE = -48,
AVAHI_ERR_NOT_SUPPORTED = -49,
AVAHI_ERR_NOT_PERMITTED = -50,
AVAHI_ERR_INVALID_ARGUMENT = -51,
AVAHI_ERR_IS_EMPTY = -52,
AVAHI_ERR_NO_CHANGE = -53,
AVAHI_ERR_MAX = -54
};
namespace wpi {
class AvahiFunctionTable {
public:
@@ -208,6 +272,7 @@ class AvahiFunctionTable {
AvahiFunction(entry_group_reset, int, (AvahiEntryGroup*));
AvahiFunction(entry_group_is_empty, int, (AvahiEntryGroup*));
AvahiFunction(entry_group_commit, int, (AvahiEntryGroup*));
AvahiFunction(entry_group_get_client, AvahiClient*, (AvahiEntryGroup*));
AvahiFunction(string_list_new_from_array, AvahiStringList*,
(const char** array, int len));
@@ -217,6 +282,8 @@ class AvahiFunctionTable {
(AvahiServiceBrowser*));
AvahiFunction(unescape_label, char*, (const char**, char*, size_t));
AvahiFunction(alternative_service_name, char*, (const char*));
AvahiFunction(free, void, (void*));
bool IsValid() const { return valid; }

View File

@@ -29,22 +29,49 @@ struct MulticastServiceAnnouncer::Impl {
}
};
static void EntryGroupCallback(AvahiEntryGroup*, AvahiEntryGroupState, void*) {}
static void RegisterService(AvahiClient* client,
MulticastServiceAnnouncer::Impl* impl);
static void EntryGroupCallback(AvahiEntryGroup* group,
AvahiEntryGroupState state, void* userdata) {
if (state == AVAHI_ENTRY_GROUP_COLLISION) {
// Remote collision
MulticastServiceAnnouncer::Impl* impl =
reinterpret_cast<MulticastServiceAnnouncer::Impl*>(userdata);
char* newName =
impl->table.alternative_service_name(impl->serviceName.c_str());
impl->serviceName = newName;
impl->table.free(newName);
RegisterService(impl->table.entry_group_get_client(group), impl);
}
}
static void RegisterService(AvahiClient* client,
MulticastServiceAnnouncer::Impl* impl) {
if (impl->group == nullptr) {
impl->group =
impl->table.entry_group_new(client, EntryGroupCallback, nullptr);
impl->group = impl->table.entry_group_new(client, EntryGroupCallback, impl);
}
if (impl->table.entry_group_is_empty(impl->group)) {
impl->table.entry_group_add_service_strlst(
impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
impl->serviceType.c_str(), "local", nullptr, impl->port,
impl->stringList);
impl->table.entry_group_commit(impl->group);
while (true) {
if (impl->table.entry_group_is_empty(impl->group)) {
auto ret = impl->table.entry_group_add_service_strlst(
impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
impl->serviceType.c_str(), "local", nullptr, impl->port,
impl->stringList);
if (ret == AVAHI_ERR_COLLISION) {
// Local collision
char* newName =
impl->table.alternative_service_name(impl->serviceName.c_str());
impl->serviceName = newName;
impl->table.free(newName);
continue;
} else if (ret != AVAHI_OK) {
break;
}
impl->table.entry_group_commit(impl->group);
break;
}
}
}