-
Notifications
You must be signed in to change notification settings - Fork 318
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
iiod: Move Avahi support to its own dns-sd.c source file
Avoid having a huge #ifdef block in iiod.c by moving this code to a dns-sd.c source file, that will be compiled conditionally. Signed-off-by: Paul Cercueil <[email protected]>
- Loading branch information
Showing
5 changed files
with
359 additions
and
324 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,334 @@ | ||
// SPDX-license-identifier: LGPL-v2-or-later | ||
/* | ||
* libiio - Library for interfacing industrial I/O (IIO) devices | ||
* | ||
* Copyright (C) 2021 Analog Devices, Inc. | ||
* Author: Paul Cercueil <[email protected]> | ||
*/ | ||
|
||
#include "dns-sd.h" | ||
#include "ops.h" | ||
#include "thread-pool.h" | ||
|
||
#include "../debug.h" | ||
#include "../iio.h" | ||
|
||
#include <avahi-common/thread-watch.h> | ||
#include <avahi-common/error.h> | ||
#include <avahi-common/alternative.h> | ||
#include <avahi-common/malloc.h> | ||
#include <avahi-client/client.h> | ||
#include <avahi-client/publish.h> | ||
#include <avahi-common/domain.h> | ||
|
||
#include <stddef.h> | ||
#include <time.h> | ||
|
||
/*** | ||
* Parts of the avahi code are borrowed from the client-publish-service.c | ||
* https://www.avahi.org/doxygen/html/client-publish-service_8c-example.html | ||
* which is an example in the avahi library. Copyright Lennart Poettering | ||
* released under the LGPL 2.1 or (at your option) any later version. | ||
*/ | ||
|
||
/* Global Data */ | ||
|
||
static struct avahi_data { | ||
AvahiThreadedPoll *poll; | ||
AvahiClient *client; | ||
AvahiEntryGroup *group; | ||
char * name; | ||
} avahi; | ||
|
||
static void create_services(AvahiClient *c); | ||
static AvahiClient * client_new(void); | ||
|
||
static void client_free() | ||
{ | ||
/* This also frees the entry group, if any. */ | ||
if (avahi.client) { | ||
avahi_client_free(avahi.client); | ||
avahi.client = NULL; | ||
avahi.group = NULL; | ||
} | ||
} | ||
|
||
static void shutdown_avahi() | ||
{ | ||
/* Stop the avahi client, if it's running. */ | ||
if (avahi.poll) | ||
avahi_threaded_poll_stop(avahi.poll); | ||
|
||
/* Clean up the avahi objects. The order is significant. */ | ||
client_free(); | ||
if (avahi.poll) { | ||
avahi_threaded_poll_free(avahi.poll); | ||
avahi.poll = NULL; | ||
} | ||
if (avahi.name) { | ||
IIO_INFO("Avahi: Removing service '%s'\n", avahi.name); | ||
avahi_free(avahi.name); | ||
avahi.name = NULL; | ||
} | ||
} | ||
|
||
static void __avahi_group_cb(AvahiEntryGroup *group, | ||
AvahiEntryGroupState state, void *d) | ||
{ | ||
/* Called whenever the entry group state changes */ | ||
if (!group) { | ||
IIO_ERROR("__avahi_group_cb with no valid group\n"); | ||
return; | ||
} | ||
|
||
avahi.group = group; | ||
|
||
switch (state) { | ||
case AVAHI_ENTRY_GROUP_ESTABLISHED : | ||
IIO_INFO("Avahi: Service '%s' successfully established.\n", | ||
avahi.name); | ||
break; | ||
case AVAHI_ENTRY_GROUP_COLLISION : { | ||
char *n; | ||
/* A service name collision, pick a new name */ | ||
n = avahi_alternative_service_name(avahi.name); | ||
avahi_free(avahi.name); | ||
avahi.name = n; | ||
IIO_INFO("Avahi: Group Service name collision, renaming service to '%s'\n", | ||
avahi.name); | ||
create_services(avahi_entry_group_get_client(group)); | ||
break; | ||
} | ||
case AVAHI_ENTRY_GROUP_FAILURE : | ||
IIO_ERROR("Entry group failure: %s\n", | ||
avahi_strerror(avahi_client_errno( | ||
avahi_entry_group_get_client(group)))); | ||
break; | ||
case AVAHI_ENTRY_GROUP_UNCOMMITED: | ||
/* This is normal, | ||
* since we commit things in the create_services() | ||
*/ | ||
IIO_DEBUG("Avahi: Group uncommitted\n"); | ||
break; | ||
case AVAHI_ENTRY_GROUP_REGISTERING: | ||
IIO_DEBUG("Avahi: Group registering\n"); | ||
break; | ||
} | ||
} | ||
|
||
static void __avahi_client_cb(AvahiClient *client, | ||
AvahiClientState state, void *d) | ||
{ | ||
if (!client) { | ||
IIO_ERROR("__avahi_client_cb with no valid client\n"); | ||
return; | ||
} | ||
|
||
switch (state) { | ||
case AVAHI_CLIENT_S_RUNNING: | ||
/* Same as AVAHI_SERVER_RUNNING */ | ||
IIO_DEBUG("Avahi: create services\n"); | ||
/* The server has startup successfully, so create our services */ | ||
create_services(client); | ||
break; | ||
case AVAHI_CLIENT_FAILURE: | ||
if (avahi_client_errno(client) != AVAHI_ERR_DISCONNECTED) { | ||
IIO_ERROR("Avahi: Client failure: %s\n", | ||
avahi_strerror(avahi_client_errno(client))); | ||
break; | ||
} | ||
IIO_INFO("Avahi: server disconnected\n"); | ||
avahi_client_free(client); | ||
avahi.group = NULL; | ||
avahi.client = client_new(); | ||
break; | ||
case AVAHI_CLIENT_S_COLLISION: | ||
/* Same as AVAHI_SERVER_COLLISION */ | ||
/* When the server is back in AVAHI_SERVER_RUNNING state | ||
* we will register them again with the new host name. */ | ||
IIO_DEBUG("Avahi: Client collision\n"); | ||
/* Let's drop our registered services.*/ | ||
if (avahi.group) | ||
avahi_entry_group_reset(avahi.group); | ||
break; | ||
case AVAHI_CLIENT_S_REGISTERING: | ||
/* Same as AVAHI_SERVER_REGISTERING */ | ||
IIO_DEBUG("Avahi: Client group reset\n"); | ||
if (avahi.group) | ||
avahi_entry_group_reset(avahi.group); | ||
break; | ||
case AVAHI_CLIENT_CONNECTING: | ||
IIO_DEBUG("Avahi: Client Connecting\n"); | ||
break; | ||
} | ||
|
||
/* NOTE: group is freed by avahi_client_free */ | ||
} | ||
|
||
static AvahiClient * client_new(void) | ||
{ | ||
int ret; | ||
AvahiClient * client; | ||
|
||
client = avahi_client_new(avahi_threaded_poll_get(avahi.poll), | ||
AVAHI_CLIENT_NO_FAIL, __avahi_client_cb, NULL, &ret); | ||
|
||
/* No Daemon is handled by the avahi_start thread */ | ||
if (!client && ret != AVAHI_ERR_NO_DAEMON) { | ||
IIO_ERROR("Avahi: failure creating client: %s (%d)\n", | ||
avahi_strerror(ret), ret); | ||
} | ||
|
||
return client; | ||
} | ||
|
||
|
||
static void create_services(AvahiClient *c) | ||
{ | ||
int ret; | ||
|
||
if (!c) { | ||
IIO_ERROR("create_services called with no valid client\n"); | ||
goto fail; | ||
} | ||
|
||
if (!avahi.group) { | ||
avahi.group = avahi_entry_group_new(c, __avahi_group_cb, NULL); | ||
if (!avahi.group) { | ||
IIO_ERROR("avahi_entry_group_new() failed: %s\n", | ||
avahi_strerror(avahi_client_errno(c))); | ||
goto fail; | ||
} | ||
} | ||
|
||
if (!avahi_entry_group_is_empty(avahi.group)) { | ||
IIO_DEBUG("Avahi group not empty\n"); | ||
return; | ||
} | ||
|
||
ret = avahi_entry_group_add_service(avahi.group, | ||
AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, | ||
0, avahi.name, "_iio._tcp", NULL, NULL, IIOD_PORT, NULL); | ||
if (ret < 0) { | ||
if (ret == AVAHI_ERR_COLLISION) { | ||
char *n; | ||
n = avahi_alternative_service_name(avahi.name); | ||
avahi_free(avahi.name); | ||
avahi.name = n; | ||
IIO_DEBUG("Service name collision, renaming service to '%s'\n", | ||
avahi.name); | ||
avahi_entry_group_reset(avahi.group); | ||
create_services(c); | ||
return; | ||
} | ||
IIO_ERROR("Failed to add _iio._tcp service: %s\n", avahi_strerror(ret)); | ||
goto fail; | ||
} | ||
|
||
ret = avahi_entry_group_commit(avahi.group); | ||
if (ret < 0) { | ||
IIO_ERROR("Failed to commit entry group: %s\n", avahi_strerror(ret)); | ||
goto fail; | ||
} | ||
|
||
IIO_INFO("Avahi: Registered '%s' to ZeroConf server %s\n", | ||
avahi.name, avahi_client_get_version_string(c)); | ||
|
||
return; | ||
|
||
fail: | ||
avahi_entry_group_reset(avahi.group); | ||
} | ||
|
||
#define IIOD_ON "iiod on " | ||
|
||
static void start_avahi_thd(struct thread_pool *pool, void *d) | ||
{ | ||
|
||
struct pollfd pfd[2]; | ||
int ret = ENOMEM; | ||
char label[AVAHI_LABEL_MAX]; | ||
char host[AVAHI_LABEL_MAX - sizeof(IIOD_ON)]; | ||
struct timespec ts; | ||
ts.tv_nsec = 0; | ||
ts.tv_sec = 1; | ||
|
||
pfd[1].fd = thread_pool_get_poll_fd(pool); | ||
pfd[1].events = POLLIN; | ||
pfd[1].revents = 0; | ||
|
||
while(true) { | ||
if (pfd[1].revents & POLLIN) /* STOP event */ | ||
break; | ||
|
||
ret = gethostname(host, sizeof(host)); | ||
IIO_ERROR("host %s\n", host); | ||
if (ret || !strncmp(host, "none", sizeof("none") - 1)) | ||
goto again; | ||
|
||
iio_snprintf(label, sizeof(label), "%s%s", IIOD_ON, host); | ||
|
||
if (!avahi.name) | ||
avahi.name = avahi_strdup(label); | ||
if (!avahi.name) | ||
break; | ||
|
||
if (!avahi.poll) | ||
avahi.poll = avahi_threaded_poll_new(); | ||
if (!avahi.poll) { | ||
goto again; | ||
} | ||
|
||
if (!avahi.client) | ||
avahi.client = client_new(); | ||
if (avahi.client) | ||
break; | ||
again: | ||
IIO_INFO("Avahi didn't start, try again later\n"); | ||
nanosleep(&ts, NULL); | ||
ts.tv_sec++; | ||
/* If it hasn't started in 10 times over 60 seconds, | ||
* it is not going to, so stop | ||
*/ | ||
if (ts.tv_sec >= 11) | ||
break; | ||
} | ||
|
||
if (avahi.client && avahi.poll) { | ||
avahi_threaded_poll_start(avahi.poll); | ||
IIO_INFO("Avahi: Started.\n"); | ||
} else { | ||
shutdown_avahi(); | ||
IIO_INFO("Avahi: Failed to start.\n"); | ||
} | ||
} | ||
|
||
void start_avahi(struct thread_pool *pool) | ||
{ | ||
int ret; | ||
char err_str[1024]; | ||
|
||
IIO_INFO("Attempting to start Avahi\n"); | ||
|
||
avahi.poll = NULL; | ||
avahi.client = NULL; | ||
avahi.group = NULL; | ||
avahi.name = NULL; | ||
|
||
/* In case dbus, or avahi deamon are not started, we create a thread | ||
* that tries a few times to attach, if it can't within the first | ||
* minute, it gives up. | ||
*/ | ||
ret = thread_pool_add_thread(pool, start_avahi_thd, NULL, "avahi_thd"); | ||
if (ret) { | ||
iio_strerror(ret, err_str, sizeof(err_str)); | ||
IIO_ERROR("Failed to create new Avahi thread: %s\n", | ||
err_str); | ||
} | ||
} | ||
|
||
void stop_avahi(void) | ||
{ | ||
shutdown_avahi(); | ||
IIO_INFO("Avahi: Stopped\n"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* SPDX-license-identifier: LGPL-v2-or-later */ | ||
/* | ||
* libiio - Library for interfacing industrial I/O (IIO) devices | ||
* | ||
* Copyright (C) 2021 Analog Devices, Inc. | ||
* Author: Paul Cercueil <[email protected]> | ||
*/ | ||
|
||
#ifndef __IIOD_DNS_SD_H | ||
#define __IIOD_DNS_SD_H | ||
|
||
struct thread_pool; | ||
|
||
void start_avahi(struct thread_pool *pool); | ||
void stop_avahi(void); | ||
|
||
#endif /* __IIOD_DNS_SD_H */ |
Oops, something went wrong.