Zeroconf*: move to zeroconf/
This commit is contained in:
146
src/zeroconf/AvahiPoll.cxx
Normal file
146
src/zeroconf/AvahiPoll.cxx
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "AvahiPoll.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/TimeoutMonitor.hxx"
|
||||
|
||||
static unsigned
|
||||
FromAvahiWatchEvent(AvahiWatchEvent e)
|
||||
{
|
||||
return (e & AVAHI_WATCH_IN ? SocketMonitor::READ : 0) |
|
||||
(e & AVAHI_WATCH_OUT ? SocketMonitor::WRITE : 0) |
|
||||
(e & AVAHI_WATCH_ERR ? SocketMonitor::ERROR : 0) |
|
||||
(e & AVAHI_WATCH_HUP ? SocketMonitor::HANGUP : 0);
|
||||
}
|
||||
|
||||
static AvahiWatchEvent
|
||||
ToAvahiWatchEvent(unsigned e)
|
||||
{
|
||||
return AvahiWatchEvent((e & SocketMonitor::READ ? AVAHI_WATCH_IN : 0) |
|
||||
(e & SocketMonitor::WRITE ? AVAHI_WATCH_OUT : 0) |
|
||||
(e & SocketMonitor::ERROR ? AVAHI_WATCH_ERR : 0) |
|
||||
(e & SocketMonitor::HANGUP ? AVAHI_WATCH_HUP : 0));
|
||||
}
|
||||
|
||||
struct AvahiWatch final : private SocketMonitor {
|
||||
private:
|
||||
const AvahiWatchCallback callback;
|
||||
void *const userdata;
|
||||
|
||||
AvahiWatchEvent received;
|
||||
|
||||
public:
|
||||
AvahiWatch(int _fd, AvahiWatchEvent _event,
|
||||
AvahiWatchCallback _callback, void *_userdata,
|
||||
EventLoop &_loop)
|
||||
:SocketMonitor(_fd, _loop),
|
||||
callback(_callback), userdata(_userdata),
|
||||
received(AvahiWatchEvent(0)) {
|
||||
Schedule(FromAvahiWatchEvent(_event));
|
||||
}
|
||||
|
||||
static void WatchUpdate(AvahiWatch *w, AvahiWatchEvent event) {
|
||||
w->Schedule(FromAvahiWatchEvent(event));
|
||||
}
|
||||
|
||||
static AvahiWatchEvent WatchGetEvents(AvahiWatch *w) {
|
||||
return w->received;
|
||||
}
|
||||
|
||||
static void WatchFree(AvahiWatch *w) {
|
||||
delete w;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool OnSocketReady(unsigned flags) {
|
||||
received = ToAvahiWatchEvent(flags);
|
||||
callback(this, Get(), received, userdata);
|
||||
received = AvahiWatchEvent(0);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr unsigned
|
||||
TimevalToMS(const timeval &tv)
|
||||
{
|
||||
return tv.tv_sec * 1000 + (tv.tv_usec + 500) / 1000;
|
||||
}
|
||||
|
||||
struct AvahiTimeout final : private TimeoutMonitor {
|
||||
private:
|
||||
const AvahiTimeoutCallback callback;
|
||||
void *const userdata;
|
||||
|
||||
public:
|
||||
AvahiTimeout(const struct timeval *tv,
|
||||
AvahiTimeoutCallback _callback, void *_userdata,
|
||||
EventLoop &_loop)
|
||||
:TimeoutMonitor(_loop),
|
||||
callback(_callback), userdata(_userdata) {
|
||||
if (tv != nullptr)
|
||||
Schedule(TimevalToMS(*tv));
|
||||
}
|
||||
|
||||
static void TimeoutUpdate(AvahiTimeout *t, const struct timeval *tv) {
|
||||
if (tv != nullptr)
|
||||
t->Schedule(TimevalToMS(*tv));
|
||||
else
|
||||
t->Cancel();
|
||||
}
|
||||
|
||||
static void TimeoutFree(AvahiTimeout *t) {
|
||||
delete t;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void OnTimeout() {
|
||||
callback(this, userdata);
|
||||
}
|
||||
};
|
||||
|
||||
MyAvahiPoll::MyAvahiPoll(EventLoop &_loop):event_loop(_loop)
|
||||
{
|
||||
watch_new = WatchNew;
|
||||
watch_update = AvahiWatch::WatchUpdate;
|
||||
watch_get_events = AvahiWatch::WatchGetEvents;
|
||||
watch_free = AvahiWatch::WatchFree;
|
||||
timeout_new = TimeoutNew;
|
||||
timeout_update = AvahiTimeout::TimeoutUpdate;
|
||||
timeout_free = AvahiTimeout::TimeoutFree;
|
||||
}
|
||||
|
||||
AvahiWatch *
|
||||
MyAvahiPoll::WatchNew(const AvahiPoll *api, int fd, AvahiWatchEvent event,
|
||||
AvahiWatchCallback callback, void *userdata) {
|
||||
const MyAvahiPoll &poll = *(const MyAvahiPoll *)api;
|
||||
|
||||
return new AvahiWatch(fd, event, callback, userdata,
|
||||
poll.event_loop);
|
||||
}
|
||||
|
||||
AvahiTimeout *
|
||||
MyAvahiPoll::TimeoutNew(const AvahiPoll *api, const struct timeval *tv,
|
||||
AvahiTimeoutCallback callback, void *userdata) {
|
||||
const MyAvahiPoll &poll = *(const MyAvahiPoll *)api;
|
||||
|
||||
return new AvahiTimeout(tv, callback, userdata,
|
||||
poll.event_loop);
|
||||
}
|
48
src/zeroconf/AvahiPoll.hxx
Normal file
48
src/zeroconf/AvahiPoll.hxx
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_AVAHI_POLL_HXX
|
||||
#define MPD_AVAHI_POLL_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <avahi-common/watch.h>
|
||||
|
||||
class EventLoop;
|
||||
|
||||
class MyAvahiPoll final : public AvahiPoll {
|
||||
EventLoop &event_loop;
|
||||
|
||||
public:
|
||||
MyAvahiPoll(EventLoop &_loop);
|
||||
|
||||
private:
|
||||
static AvahiWatch *WatchNew(const AvahiPoll *api, int fd,
|
||||
AvahiWatchEvent event,
|
||||
AvahiWatchCallback callback,
|
||||
void *userdata);
|
||||
|
||||
static AvahiTimeout *TimeoutNew(const AvahiPoll *api,
|
||||
const struct timeval *tv,
|
||||
AvahiTimeoutCallback callback,
|
||||
void *userdata);
|
||||
};
|
||||
|
||||
#endif
|
275
src/zeroconf/ZeroconfAvahi.cxx
Normal file
275
src/zeroconf/ZeroconfAvahi.cxx
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ZeroconfAvahi.hxx"
|
||||
#include "AvahiPoll.hxx"
|
||||
#include "ZeroconfInternal.hxx"
|
||||
#include "Listen.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
|
||||
#include <avahi-common/alternative.h>
|
||||
#include <avahi-common/domain.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/error.h>
|
||||
|
||||
static constexpr Domain avahi_domain("avahi");
|
||||
|
||||
static char *avahiName;
|
||||
static bool avahi_running;
|
||||
static MyAvahiPoll *avahi_poll;
|
||||
static AvahiClient *avahiClient;
|
||||
static AvahiEntryGroup *avahiGroup;
|
||||
|
||||
static void avahiRegisterService(AvahiClient * c);
|
||||
|
||||
/* Callback when the EntryGroup changes state */
|
||||
static void avahiGroupCallback(AvahiEntryGroup * g,
|
||||
AvahiEntryGroupState state,
|
||||
gcc_unused void *userdata)
|
||||
{
|
||||
char *n;
|
||||
assert(g);
|
||||
|
||||
FormatDebug(avahi_domain,
|
||||
"Service group changed to state %d", state);
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
/* The entry group has been established successfully */
|
||||
FormatDefault(avahi_domain,
|
||||
"Service '%s' successfully established.",
|
||||
avahiName);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_COLLISION:
|
||||
/* A service name collision happened. Let's pick a new name */
|
||||
n = avahi_alternative_service_name(avahiName);
|
||||
avahi_free(avahiName);
|
||||
avahiName = n;
|
||||
|
||||
FormatDefault(avahi_domain,
|
||||
"Service name collision, renaming service to '%s'",
|
||||
avahiName);
|
||||
|
||||
/* And recreate the services */
|
||||
avahiRegisterService(avahi_entry_group_get_client(g));
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
FormatError(avahi_domain,
|
||||
"Entry group failure: %s",
|
||||
avahi_strerror(avahi_client_errno
|
||||
(avahi_entry_group_get_client(g))));
|
||||
/* Some kind of failure happened while we were registering our services */
|
||||
avahi_running = false;
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
LogDebug(avahi_domain, "Service group is UNCOMMITED");
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||
LogDebug(avahi_domain, "Service group is REGISTERING");
|
||||
}
|
||||
}
|
||||
|
||||
/* Registers a new service with avahi */
|
||||
static void avahiRegisterService(AvahiClient * c)
|
||||
{
|
||||
FormatDebug(avahi_domain, "Registering service %s/%s",
|
||||
SERVICE_TYPE, avahiName);
|
||||
|
||||
int ret;
|
||||
assert(c);
|
||||
|
||||
/* If this is the first time we're called,
|
||||
* let's create a new entry group */
|
||||
if (!avahiGroup) {
|
||||
avahiGroup = avahi_entry_group_new(c, avahiGroupCallback, nullptr);
|
||||
if (!avahiGroup) {
|
||||
FormatError(avahi_domain,
|
||||
"Failed to create avahi EntryGroup: %s",
|
||||
avahi_strerror(avahi_client_errno(c)));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the service */
|
||||
/* TODO: This currently binds to ALL interfaces.
|
||||
* We could maybe add a service per actual bound interface,
|
||||
* if that's better. */
|
||||
ret = avahi_entry_group_add_service(avahiGroup,
|
||||
AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
|
||||
AvahiPublishFlags(0),
|
||||
avahiName, SERVICE_TYPE, nullptr,
|
||||
nullptr, listen_port, nullptr);
|
||||
if (ret < 0) {
|
||||
FormatError(avahi_domain, "Failed to add service %s: %s",
|
||||
SERVICE_TYPE, avahi_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Tell the server to register the service group */
|
||||
ret = avahi_entry_group_commit(avahiGroup);
|
||||
if (ret < 0) {
|
||||
FormatError(avahi_domain, "Failed to commit service group: %s",
|
||||
avahi_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
avahi_running = false;
|
||||
}
|
||||
|
||||
/* Callback when avahi changes state */
|
||||
static void avahiClientCallback(AvahiClient * c, AvahiClientState state,
|
||||
gcc_unused void *userdata)
|
||||
{
|
||||
int reason;
|
||||
assert(c);
|
||||
|
||||
/* Called whenever the client or server state changes */
|
||||
FormatDebug(avahi_domain, "Client changed to state %d", state);
|
||||
|
||||
switch (state) {
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
LogDebug(avahi_domain, "Client is RUNNING");
|
||||
|
||||
/* The server has startup successfully and registered its host
|
||||
* name on the network, so it's time to create our services */
|
||||
if (!avahiGroup)
|
||||
avahiRegisterService(c);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
reason = avahi_client_errno(c);
|
||||
if (reason == AVAHI_ERR_DISCONNECTED) {
|
||||
LogDefault(avahi_domain,
|
||||
"Client Disconnected, will reconnect shortly");
|
||||
if (avahiGroup) {
|
||||
avahi_entry_group_free(avahiGroup);
|
||||
avahiGroup = nullptr;
|
||||
}
|
||||
if (avahiClient)
|
||||
avahi_client_free(avahiClient);
|
||||
avahiClient =
|
||||
avahi_client_new(avahi_poll,
|
||||
AVAHI_CLIENT_NO_FAIL,
|
||||
avahiClientCallback, nullptr,
|
||||
&reason);
|
||||
if (!avahiClient) {
|
||||
FormatWarning(avahi_domain,
|
||||
"Could not reconnect: %s",
|
||||
avahi_strerror(reason));
|
||||
avahi_running = false;
|
||||
}
|
||||
} else {
|
||||
FormatWarning(avahi_domain,
|
||||
"Client failure: %s (terminal)",
|
||||
avahi_strerror(reason));
|
||||
avahi_running = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
LogDebug(avahi_domain, "Client is COLLISION");
|
||||
|
||||
/* Let's drop our registered services. When the server is back
|
||||
* in AVAHI_SERVER_RUNNING state we will register them
|
||||
* again with the new host name. */
|
||||
if (avahiGroup) {
|
||||
LogDebug(avahi_domain, "Resetting group");
|
||||
avahi_entry_group_reset(avahiGroup);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
LogDebug(avahi_domain, "Client is REGISTERING");
|
||||
|
||||
/* The server records are now being established. This
|
||||
* might be caused by a host name change. We need to wait
|
||||
* for our own records to register until the host name is
|
||||
* properly esatblished. */
|
||||
|
||||
if (avahiGroup) {
|
||||
LogDebug(avahi_domain, "Resetting group");
|
||||
avahi_entry_group_reset(avahiGroup);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
LogDebug(avahi_domain, "Client is CONNECTING");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AvahiInit(EventLoop &loop, const char *serviceName)
|
||||
{
|
||||
LogDebug(avahi_domain, "Initializing interface");
|
||||
|
||||
if (!avahi_is_valid_service_name(serviceName))
|
||||
FormatFatalError("Invalid zeroconf_name \"%s\"", serviceName);
|
||||
|
||||
avahiName = avahi_strdup(serviceName);
|
||||
|
||||
avahi_running = true;
|
||||
|
||||
avahi_poll = new MyAvahiPoll(loop);
|
||||
|
||||
int error;
|
||||
avahiClient = avahi_client_new(avahi_poll, AVAHI_CLIENT_NO_FAIL,
|
||||
avahiClientCallback, nullptr, &error);
|
||||
|
||||
if (!avahiClient) {
|
||||
FormatError(avahi_domain, "Failed to create client: %s",
|
||||
avahi_strerror(error));
|
||||
AvahiDeinit();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AvahiDeinit(void)
|
||||
{
|
||||
LogDebug(avahi_domain, "Shutting down interface");
|
||||
|
||||
if (avahiGroup) {
|
||||
avahi_entry_group_free(avahiGroup);
|
||||
avahiGroup = nullptr;
|
||||
}
|
||||
|
||||
if (avahiClient) {
|
||||
avahi_client_free(avahiClient);
|
||||
avahiClient = nullptr;
|
||||
}
|
||||
|
||||
delete avahi_poll;
|
||||
avahi_poll = nullptr;
|
||||
|
||||
avahi_free(avahiName);
|
||||
avahiName = nullptr;
|
||||
}
|
31
src/zeroconf/ZeroconfAvahi.hxx
Normal file
31
src/zeroconf/ZeroconfAvahi.hxx
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_ZEROCONF_AVAHI_HXX
|
||||
#define MPD_ZEROCONF_AVAHI_HXX
|
||||
|
||||
class EventLoop;
|
||||
|
||||
void
|
||||
AvahiInit(EventLoop &loop, const char *service_name);
|
||||
|
||||
void
|
||||
AvahiDeinit();
|
||||
|
||||
#endif
|
108
src/zeroconf/ZeroconfBonjour.cxx
Normal file
108
src/zeroconf/ZeroconfBonjour.cxx
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ZeroconfBonjour.hxx"
|
||||
#include "ZeroconfInternal.hxx"
|
||||
#include "Listen.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <dns_sd.h>
|
||||
|
||||
static constexpr Domain bonjour_domain("bonjour");
|
||||
|
||||
class BonjourMonitor final : public SocketMonitor {
|
||||
DNSServiceRef service_ref;
|
||||
|
||||
public:
|
||||
BonjourMonitor(EventLoop &_loop, DNSServiceRef _service_ref)
|
||||
:SocketMonitor(DNSServiceRefSockFD(_service_ref), _loop),
|
||||
service_ref(_service_ref) {
|
||||
ScheduleRead();
|
||||
}
|
||||
|
||||
~BonjourMonitor() {
|
||||
DNSServiceRefDeallocate(service_ref);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool OnSocketReady(gcc_unused unsigned flags) override {
|
||||
DNSServiceProcessResult(service_ref);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static BonjourMonitor *bonjour_monitor;
|
||||
|
||||
static void
|
||||
dnsRegisterCallback(gcc_unused DNSServiceRef sdRef,
|
||||
gcc_unused DNSServiceFlags flags,
|
||||
DNSServiceErrorType errorCode, const char *name,
|
||||
gcc_unused const char *regtype,
|
||||
gcc_unused const char *domain,
|
||||
gcc_unused void *context)
|
||||
{
|
||||
if (errorCode != kDNSServiceErr_NoError) {
|
||||
LogError(bonjour_domain,
|
||||
"Failed to register zeroconf service");
|
||||
|
||||
bonjour_monitor->Cancel();
|
||||
} else {
|
||||
FormatDebug(bonjour_domain,
|
||||
"Registered zeroconf service with name '%s'",
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BonjourInit(EventLoop &loop, const char *service_name)
|
||||
{
|
||||
DNSServiceRef dnsReference;
|
||||
DNSServiceErrorType error = DNSServiceRegister(&dnsReference,
|
||||
0, 0, service_name,
|
||||
SERVICE_TYPE, nullptr, nullptr,
|
||||
g_htons(listen_port), 0,
|
||||
nullptr,
|
||||
dnsRegisterCallback,
|
||||
nullptr);
|
||||
|
||||
if (error != kDNSServiceErr_NoError) {
|
||||
LogError(bonjour_domain,
|
||||
"Failed to register zeroconf service");
|
||||
|
||||
if (dnsReference) {
|
||||
DNSServiceRefDeallocate(dnsReference);
|
||||
dnsReference = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bonjour_monitor = new BonjourMonitor(loop, dnsReference);
|
||||
}
|
||||
|
||||
void
|
||||
BonjourDeinit()
|
||||
{
|
||||
delete bonjour_monitor;
|
||||
}
|
31
src/zeroconf/ZeroconfBonjour.hxx
Normal file
31
src/zeroconf/ZeroconfBonjour.hxx
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_ZEROCONF_BONJOUR_HXX
|
||||
#define MPD_ZEROCONF_BONJOUR_HXX
|
||||
|
||||
class EventLoop;
|
||||
|
||||
void
|
||||
BonjourInit(EventLoop &loop, const char *service_name);
|
||||
|
||||
void
|
||||
BonjourDeinit();
|
||||
|
||||
#endif
|
83
src/zeroconf/ZeroconfGlue.cxx
Normal file
83
src/zeroconf/ZeroconfGlue.cxx
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ZeroconfGlue.hxx"
|
||||
#include "ZeroconfAvahi.hxx"
|
||||
#include "ZeroconfBonjour.hxx"
|
||||
#include "ConfigGlobal.hxx"
|
||||
#include "ConfigOption.hxx"
|
||||
#include "Listen.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
static constexpr Domain zeroconf_domain("zeroconf");
|
||||
|
||||
/* The default service name to publish
|
||||
* (overridden by 'zeroconf_name' config parameter)
|
||||
*/
|
||||
#define SERVICE_NAME "Music Player"
|
||||
|
||||
#define DEFAULT_ZEROCONF_ENABLED 1
|
||||
|
||||
static int zeroconfEnabled;
|
||||
|
||||
void
|
||||
ZeroconfInit(gcc_unused EventLoop &loop)
|
||||
{
|
||||
const char *serviceName;
|
||||
|
||||
zeroconfEnabled = config_get_bool(CONF_ZEROCONF_ENABLED,
|
||||
DEFAULT_ZEROCONF_ENABLED);
|
||||
if (!zeroconfEnabled)
|
||||
return;
|
||||
|
||||
if (listen_port <= 0) {
|
||||
LogWarning(zeroconf_domain,
|
||||
"No global port, disabling zeroconf");
|
||||
zeroconfEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
serviceName = config_get_string(CONF_ZEROCONF_NAME, SERVICE_NAME);
|
||||
|
||||
#ifdef HAVE_AVAHI
|
||||
AvahiInit(loop, serviceName);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BONJOUR
|
||||
BonjourInit(loop, serviceName);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ZeroconfDeinit()
|
||||
{
|
||||
if (!zeroconfEnabled)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_AVAHI
|
||||
AvahiDeinit();
|
||||
#endif /* HAVE_AVAHI */
|
||||
|
||||
#ifdef HAVE_BONJOUR
|
||||
BonjourDeinit();
|
||||
#endif
|
||||
}
|
47
src/zeroconf/ZeroconfGlue.hxx
Normal file
47
src/zeroconf/ZeroconfGlue.hxx
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_ZEROCONF_GLUE_HXX
|
||||
#define MPD_ZEROCONF_GLUE_HXX
|
||||
|
||||
#include "check.h"
|
||||
|
||||
class EventLoop;
|
||||
|
||||
#ifdef HAVE_ZEROCONF
|
||||
|
||||
void
|
||||
ZeroconfInit(EventLoop &loop);
|
||||
|
||||
void
|
||||
ZeroconfDeinit();
|
||||
|
||||
#else /* ! HAVE_ZEROCONF */
|
||||
|
||||
static inline void
|
||||
ZeroconfInit(EventLoop &)
|
||||
{}
|
||||
|
||||
static inline void
|
||||
ZeroconfDeinit()
|
||||
{}
|
||||
|
||||
#endif /* ! HAVE_ZEROCONF */
|
||||
|
||||
#endif
|
26
src/zeroconf/ZeroconfInternal.hxx
Normal file
26
src/zeroconf/ZeroconfInternal.hxx
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef ZEROCONF_INTERNAL_H
|
||||
#define ZEROCONF_INTERNAL_H
|
||||
|
||||
/* The dns-sd service type qualifier to publish */
|
||||
#define SERVICE_TYPE "_mpd._tcp"
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user