configure.ac: Move the encoders before the audio outputs.
[mpd-mk.git] / src / zeroconf-avahi.c
blobd9b0c22a8f2c8b59d90f922df94ad3e84f15c7d5
1 /*
2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "config.h"
21 #include "zeroconf-internal.h"
22 #include "listen.h"
24 #include <glib.h>
26 #include <avahi-client/client.h>
27 #include <avahi-client/publish.h>
29 #include <avahi-common/alternative.h>
30 #include <avahi-common/domain.h>
31 #include <avahi-common/malloc.h>
32 #include <avahi-common/error.h>
34 #include <avahi-glib/glib-watch.h>
36 #undef G_LOG_DOMAIN
37 #define G_LOG_DOMAIN "avahi"
39 static char *avahiName;
40 static int avahiRunning;
41 static AvahiGLibPoll *avahi_glib_poll;
42 static const AvahiPoll *avahi_poll;
43 static AvahiClient *avahiClient;
44 static AvahiEntryGroup *avahiGroup;
46 static void avahiRegisterService(AvahiClient * c);
48 /* Callback when the EntryGroup changes state */
49 static void avahiGroupCallback(AvahiEntryGroup * g,
50 AvahiEntryGroupState state,
51 G_GNUC_UNUSED void *userdata)
53 char *n;
54 assert(g);
56 g_debug("Service group changed to state %d", state);
58 switch (state) {
59 case AVAHI_ENTRY_GROUP_ESTABLISHED:
60 /* The entry group has been established successfully */
61 g_message("Service '%s' successfully established.",
62 avahiName);
63 break;
65 case AVAHI_ENTRY_GROUP_COLLISION:
66 /* A service name collision happened. Let's pick a new name */
67 n = avahi_alternative_service_name(avahiName);
68 avahi_free(avahiName);
69 avahiName = n;
71 g_message("Service name collision, renaming service to '%s'",
72 avahiName);
74 /* And recreate the services */
75 avahiRegisterService(avahi_entry_group_get_client(g));
76 break;
78 case AVAHI_ENTRY_GROUP_FAILURE:
79 g_warning("Entry group failure: %s",
80 avahi_strerror(avahi_client_errno
81 (avahi_entry_group_get_client(g))));
82 /* Some kind of failure happened while we were registering our services */
83 avahiRunning = 0;
84 break;
86 case AVAHI_ENTRY_GROUP_UNCOMMITED:
87 g_debug("Service group is UNCOMMITED");
88 break;
89 case AVAHI_ENTRY_GROUP_REGISTERING:
90 g_debug("Service group is REGISTERING");
94 /* Registers a new service with avahi */
95 static void avahiRegisterService(AvahiClient * c)
97 int ret;
98 assert(c);
99 g_debug("Registering service %s/%s", SERVICE_TYPE, avahiName);
101 /* If this is the first time we're called,
102 * let's create a new entry group */
103 if (!avahiGroup) {
104 avahiGroup = avahi_entry_group_new(c, avahiGroupCallback, NULL);
105 if (!avahiGroup) {
106 g_warning("Failed to create avahi EntryGroup: %s",
107 avahi_strerror(avahi_client_errno(c)));
108 goto fail;
112 /* Add the service */
113 /* TODO: This currently binds to ALL interfaces.
114 * We could maybe add a service per actual bound interface,
115 * if that's better. */
116 ret = avahi_entry_group_add_service(avahiGroup,
117 AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
118 0, avahiName, SERVICE_TYPE, NULL,
119 NULL, listen_port, NULL);
120 if (ret < 0) {
121 g_warning("Failed to add service %s: %s", SERVICE_TYPE,
122 avahi_strerror(ret));
123 goto fail;
126 /* Tell the server to register the service group */
127 ret = avahi_entry_group_commit(avahiGroup);
128 if (ret < 0) {
129 g_warning("Failed to commit service group: %s",
130 avahi_strerror(ret));
131 goto fail;
133 return;
135 fail:
136 avahiRunning = 0;
139 /* Callback when avahi changes state */
140 static void avahiClientCallback(AvahiClient * c, AvahiClientState state,
141 G_GNUC_UNUSED void *userdata)
143 int reason;
144 assert(c);
146 /* Called whenever the client or server state changes */
147 g_debug("Client changed to state %d", state);
149 switch (state) {
150 case AVAHI_CLIENT_S_RUNNING:
151 g_debug("Client is RUNNING");
153 /* The server has startup successfully and registered its host
154 * name on the network, so it's time to create our services */
155 if (!avahiGroup)
156 avahiRegisterService(c);
157 break;
159 case AVAHI_CLIENT_FAILURE:
160 reason = avahi_client_errno(c);
161 if (reason == AVAHI_ERR_DISCONNECTED) {
162 g_message("Client Disconnected, will reconnect shortly");
163 if (avahiGroup) {
164 avahi_entry_group_free(avahiGroup);
165 avahiGroup = NULL;
167 if (avahiClient)
168 avahi_client_free(avahiClient);
169 avahiClient =
170 avahi_client_new(avahi_poll,
171 AVAHI_CLIENT_NO_FAIL,
172 avahiClientCallback, NULL,
173 &reason);
174 if (!avahiClient) {
175 g_warning("Could not reconnect: %s",
176 avahi_strerror(reason));
177 avahiRunning = 0;
179 } else {
180 g_warning("Client failure: %s (terminal)",
181 avahi_strerror(reason));
182 avahiRunning = 0;
184 break;
186 case AVAHI_CLIENT_S_COLLISION:
187 g_debug("Client is COLLISION");
188 /* Let's drop our registered services. When the server is back
189 * in AVAHI_SERVER_RUNNING state we will register them
190 * again with the new host name. */
191 if (avahiGroup) {
192 g_debug("Resetting group");
193 avahi_entry_group_reset(avahiGroup);
196 case AVAHI_CLIENT_S_REGISTERING:
197 g_debug("Client is REGISTERING");
198 /* The server records are now being established. This
199 * might be caused by a host name change. We need to wait
200 * for our own records to register until the host name is
201 * properly esatblished. */
203 if (avahiGroup) {
204 g_debug("Resetting group");
205 avahi_entry_group_reset(avahiGroup);
208 break;
210 case AVAHI_CLIENT_CONNECTING:
211 g_debug("Client is CONNECTING");
215 void init_avahi(const char *serviceName)
217 int error;
218 g_debug("Initializing interface");
220 if (!avahi_is_valid_service_name(serviceName))
221 g_error("Invalid zeroconf_name \"%s\"", serviceName);
223 avahiName = avahi_strdup(serviceName);
225 avahiRunning = 1;
227 avahi_glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
228 avahi_poll = avahi_glib_poll_get(avahi_glib_poll);
230 avahiClient = avahi_client_new(avahi_poll, AVAHI_CLIENT_NO_FAIL,
231 avahiClientCallback, NULL, &error);
233 if (!avahiClient) {
234 g_warning("Failed to create client: %s",
235 avahi_strerror(error));
236 goto fail;
239 return;
241 fail:
242 avahi_finish();
245 void avahi_finish(void)
247 g_debug("Shutting down interface");
249 if (avahiGroup) {
250 avahi_entry_group_free(avahiGroup);
251 avahiGroup = NULL;
254 if (avahiClient) {
255 avahi_client_free(avahiClient);
256 avahiClient = NULL;
259 if (avahi_glib_poll != NULL) {
260 avahi_glib_poll_free(avahi_glib_poll);
261 avahi_glib_poll = NULL;
264 avahi_free(avahiName);
265 avahiName = NULL;