diff --git a/CMakeLists.txt b/CMakeLists.txt index 2952bbc..95ee0c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,6 +157,10 @@ elseif(APPLE) set(CMAKE_MACOSX_RPATH ON) message(STATUS "RPATH support: ${CMAKE_MACOSX_RPATH}") + # just blindly enable dns-sd + set(USE_MACOS_DNSSD ON) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_MACOS_DNSSD") + elseif (WIN32) if(NOT VS2015 AND NOT VS2017) message(FATAL_ERROR "You must use Microsoft Visual Studio 2015 or 2017 as compiler") @@ -277,6 +281,11 @@ if(LINUX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CM108") endif() + find_package(Avahi) + if(AVAHI_CLIENT_FOUND) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_AVAHI_CLIENT") + endif() + elseif (NOT WIN32 AND NOT CYGWIN) find_package(Portaudio REQUIRED) if(PORTAUDIO_FOUND) diff --git a/README.md b/README.md index e9c78f9..29554f9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + # Dire Wolf # ### Decoded Information from Radio Emissions for Windows Or Linux Fans ### @@ -39,6 +39,7 @@ It can also be used as a virtual TNC for other applications such as [APRSIS32](h Send periodic beacons to provide information to others. For tracking the location is provided by a GPS receiver. Build your own telemetry applications with the toolkit. + - **APRStt Gateway.** Very few hams have portable equipment for APRS but nearly everyone has a handheld radio that can send DTMF tones. APRStt allows a user, equipped with only DTMF (commonly known as Touch Tone) generation capability, to enter information into the global APRS data network. Responses can be sent by Morse Code or synthesized speech. @@ -130,15 +131,17 @@ On Debian / Ubuntu / Raspbian / Raspberry Pi OS: sudo apt-get install cmake sudo apt-get install libasound2-dev sudo apt-get install libudev-dev + sudo apt-get install libavahi-client-dev Or on Red Hat / Fedora / CentOS: - sudo yum install git - sudo yum install gcc - sudo yum install gcc-c++ - sudo yum install make + sudo yum install git + sudo yum install gcc + sudo yum install gcc-c++ + sudo yum install make sudo yum install alsa-lib-devel sudo yum install libudev-devel + sudo yum install avahi-devel CentOS 6 & 7 currently have cmake 2.8 but we need 3.1 or later. First you need to enable the EPEL repository. Add a symlink if you don't already have the older version and want to type cmake rather than cmake3. diff --git a/cmake/modules/FindAvahi.cmake b/cmake/modules/FindAvahi.cmake new file mode 100644 index 0000000..4a3cdd0 --- /dev/null +++ b/cmake/modules/FindAvahi.cmake @@ -0,0 +1,19 @@ + +find_library(AVAHI_COMMON_LIBRARY NAMES avahi-common PATHS ${PC_AVAHI_CLIENT_LIBRARY_DIRS}) +if(AVAHI_COMMON_LIBRARY) + set(AVAHI_COMMON_FOUND TRUE) +endif() + +find_library(AVAHI_CLIENT_LIBRARY NAMES avahi-client PATHS ${PC_AVAHI_CLIENT_LIBRARY_DIRS}) +if(AVAHI_CLIENT_LIBRARY) + set(AVAHI_CLIENT_FOUND TRUE) +endif() + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(AVAHI DEFAULT_MSG AVAHI_COMMON_FOUND AVAHI_CLIENT_FOUND) + +if (AVAHI_FOUND) + set(AVAHI_INCLUDE_DIRS ${AVAHI_UI_INCLUDE_DIR}) + set(AVAHI_LIBRARIES ${AVAHI_COMMON_LIBRARY} ${AVAHI_CLIENT_LIBRARY}) +endif() + +mark_as_advanced(AVAHI_INCLUDE_DIRS AVAHI_LIBRARIES) diff --git a/doc/README.md b/doc/README.md index ae74035..40aa77d 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,4 @@ -# Documentation for Dire Wolf # +# Documentation for Dire Wolf # Click on the document name to view in your web browser or the link following to download the PDF file. @@ -11,11 +11,11 @@ Brief summary of packet radio / APRS history and the capbilities of Dire Wolf. ## Essential Reading ## -- [**User Guide**](User-Guide.pdf) [ [*download*](../../../raw/dev/doc/User-Guide.pdf) ] +- [**User Guide**](User-Guide.pdf) [ [*download*](../../../raw/master/doc/User-Guide.pdf) ] This is your primary source of information about installation, operation, and configuration. -- [**Raspberry Pi APRS**](Raspberry-Pi-APRS.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-APRS.pdf) ] +- [**Raspberry Pi APRS**](Raspberry-Pi-APRS.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-APRS.pdf) ] The Raspberry Pi has some special considerations that make it different from other generic Linux systems. @@ -46,38 +46,40 @@ These dive into more detail for specialized topics or typical usage scenarios. - [**Successful APRS IGate Operation**](Successful-APRS-IGate-Operation.pdf) [ [*download*](../../../raw/dev/doc/Successful-APRS-IGate-Operation.pdf) ] + Dire Wolf can serve as a gateway between the APRS radio network and APRS-IS servers on the Internet. This explains how it all works, proper configuration, and troubleshooting. -- [**Bluetooth KISS TNC**](Bluetooth-KISS-TNC.pdf) [ [*download*](../../../raw/dev/doc/Bluetooth-KISS-TNC.pdf) ] +- [**Bluetooth KISS TNC**](Bluetooth-KISS-TNC.pdf) [ [*download*](../../../raw/master/doc/Bluetooth-KISS-TNC.pdf) ] Eliminate the cable between your TNC and application. Use Bluetooth instead. -- [**APRStt Implementation Notes**](APRStt-Implementation-Notes.pdf) [ [*download*](../../../raw/dev/doc/APRStt-Implementation-Notes.pdf) ] +- [**APRStt Implementation Notes**](APRStt-Implementation-Notes.pdf) [ [*download*](../../../raw/master/doc/APRStt-Implementation-Notes.pdf) ] Very few hams have portable equipment for APRS but nearly everyone has a handheld radio that can send DTMF tones. APRStt allows a user, equipped with only DTMF (commonly known as Touch Tone) generation capability, to enter information into the global APRS data network. This document explains how the APRStt concept was implemented in the Dire Wolf application. -- [**APRStt Interface for SARTrack**](APRStt-interface-for-SARTrack.pdf) [ [*download*](../../../raw/dev/doc/APRStt-interface-for-SARTrack.pdf) ] + +- [**APRStt Interface for SARTrack**](APRStt-interface-for-SARTrack.pdf) [ [*download*](../../../raw/master/doc/APRStt-interface-for-SARTrack.pdf) ] This example illustrates how APRStt can be integrated with other applications such as SARTrack, APRSISCE/32, YAAC, or Xastir. -- [**APRStt Listening Example**](APRStt-Listening-Example.pdf) [ [*download*](../../../raw/dev/doc/APRStt-Listening-Example.pdf) ] +- [**APRStt Listening Example**](APRStt-Listening-Example.pdf) [ [*download*](../../../raw/master/doc/APRStt-Listening-Example.pdf) ] WB4APR described a useful application for the [QIKCOM-2 Satallite Transponder](http://www.tapr.org/pipermail/aprssig/2015-November/045035.html). Don’t have your own QIKCOM-2 Satellite Transponder? No Problem. You can do the same thing with an ordinary computer and the APRStt gateway built into Dire Wolf. Here’s how. -- [**Raspberry Pi APRS Tracker**](Raspberry-Pi-APRS-Tracker.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-APRS-Tracker.pdf) ] +- [**Raspberry Pi APRS Tracker**](Raspberry-Pi-APRS-Tracker.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-APRS-Tracker.pdf) ] Build a tracking device which transmits position from a GPS receiver. -- [**Raspberry Pi SDR IGate**](Raspberry-Pi-SDR-IGate.pdf) [ [*download*](../../../raw/dev/doc/Raspberry-Pi-SDR-IGate.pdf) ] +- [**Raspberry Pi SDR IGate**](Raspberry-Pi-SDR-IGate.pdf) [ [*download*](../../../raw/master/doc/Raspberry-Pi-SDR-IGate.pdf) ] It's easy to build a receive-only APRS Internet Gateway (IGate) with only a Raspberry Pi and a software defined radio (RTL-SDR) dongle. Here’s how. -- [**APRS Telemetry Toolkit**](APRS-Telemetry-Toolkit.pdf) [ [*download*](../../../raw/dev/doc/APRS-Telemetry-Toolkit.pdf) ] +- [**APRS Telemetry Toolkit**](APRS-Telemetry-Toolkit.pdf) [ [*download*](../../../raw/master/doc/APRS-Telemetry-Toolkit.pdf) ] Describes scripts and methods to generate telemetry. Includes a complete example of attaching an analog to @@ -86,12 +88,12 @@ These dive into more detail for specialized topics or typical usage scenarios. -- [**2400 & 4800 bps PSK for APRS / Packet Radio**](2400-4800-PSK-for-APRS-Packet-Radio.pdf) [ [*download*](../../../raw/dev/doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf) ] +- [**2400 & 4800 bps PSK for APRS / Packet Radio**](2400-4800-PSK-for-APRS-Packet-Radio.pdf) [ [*download*](../../../raw/master/doc/2400-4800-PSK-for-APRS-Packet-Radio.pdf) ] Double or quadruple your data rate by sending multiple bits at the same time. -- [**Going beyond 9600 baud**](Going-beyond-9600-baud.pdf) [ [*download*](../../../raw/dev/doc/Going-beyond-9600-baud.pdf) ] +- [**Going beyond 9600 baud**](Going-beyond-9600-baud.pdf) [ [*download*](../../../raw/master/doc/Going-beyond-9600-baud.pdf) ] Why stop at 9600 baud? Go faster if your soundcard and radio can handle it. @@ -120,7 +122,7 @@ These dive into more detail for specialized topics or typical usage scenarios. There have been other occasional mentions of merging Ham Radio with the Internet of Things but only ad hoc incompatible narrowly focused applications. Here is a proposal for a standardized more flexible method so different systems can communicate with each other. -- [**A Better APRS Packet Demodulator, part 1, 1200 baud**](A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) [ [*download*](../../../raw/dev/doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) ] +- [**A Better APRS Packet Demodulator, part 1, 1200 baud**](A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) [ [*download*](../../../raw/master/doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf) ] Sometimes it's a little mystifying why an APRS / AX.25 Packet TNC will decode some signals @@ -132,7 +134,7 @@ and a couple things that can be done about it. -- [**A Better APRS Packet Demodulator, part 2, 9600 baud**](A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) [ [*download*](../../../raw/dev/doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) ] +- [**A Better APRS Packet Demodulator, part 2, 9600 baud**](A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) [ [*download*](../../../raw/master/doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf) ] In the first part of this series we discussed 1200 baud audio frequency shift keying (AFSK). The mismatch between FM transmitter pre-emphasis and the @@ -141,13 +143,13 @@ and a couple things that can be done about it. This makes it more difficult to demodulate them accurately. 9600 baud operation is an entirely different animal. ... -- [**WA8LMF TNC Test CD Results a.k.a. Battle of the TNCs**](WA8LMF-TNC-Test-CD-Results.pdf) [ [*download*](../../../raw/dev/doc/WA8LMF-TNC-Test-CD-Results.pdf) ] +- [**WA8LMF TNC Test CD Results a.k.a. Battle of the TNCs**](WA8LMF-TNC-Test-CD-Results.pdf) [ [*download*](../../../raw/master/doc/WA8LMF-TNC-Test-CD-Results.pdf) ] How can we compare how well the TNCs perform under real world conditions? The de facto standard of measurement is the number of packets decoded from [WA8LMF’s TNC Test CD](http://wa8lmf.net/TNCtest/index.htm). Many have published the number of packets they have been able to decode from this test. Here they are, all gathered in one place, for your reading pleasure. -- [**A Closer Look at the WA8LMF TNC Test CD**](A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) [ [*download*](../../../raw/dev/doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) ] +- [**A Closer Look at the WA8LMF TNC Test CD**](A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) [ [*download*](../../../raw/master/doc/A-Closer-Look-at-the-WA8LMF-TNC-Test-CD.pdf) ] Here, we take a closer look at some of the frames on the TNC Test CD in hopes of gaining some insights into why some are easily decoded and others are more difficult. There are a lot of ugly signals out there. Many can be improved by decreasing the transmit volume. Others are just plain weird and you have to wonder how they are being generated. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af747e5..44c6c17 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,12 @@ if(LINUX) cm108.c ) endif() + if(AVAHI_CLIENT_FOUND) + list(APPEND direwolf_SOURCES + dns_sd_common.c + dns_sd_avahi.c + ) + endif() elseif(WIN32 OR CYGWIN) # windows list(APPEND direwolf_SOURCES audio_win.c @@ -124,6 +130,12 @@ if(LINUX) list(APPEND direwolf_SOURCES audio_portaudio.c ) + if(USE_MACOS_DNSSD) + list(APPEND direwolf_SOURCES + dns_sd_common.c + dns_sd_macos.c + ) + endif() endif() add_executable(direwolf @@ -140,6 +152,7 @@ target_link_libraries(direwolf ${ALSA_LIBRARIES} ${UDEV_LIBRARIES} ${PORTAUDIO_LIBRARIES} + ${AVAHI_LIBRARIES} ) if(WIN32 OR CYGWIN) diff --git a/src/config.c b/src/config.c index 93b92a1..52d50f0 100644 --- a/src/config.c +++ b/src/config.c @@ -856,6 +856,8 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_misc_config->enable_kiss_pt = 0; /* -p option */ p_misc_config->kiss_copy = 0; + p_misc_config->dns_sd_enabled = 1; + /* Defaults from http://info.aprs.net/index.php?title=SmartBeaconing */ p_misc_config->sb_configured = 0; /* TRUE if SmartBeaconing is configured. */ @@ -4564,6 +4566,43 @@ void config_init (char *fname, struct audio_s *p_audio_config, } +/* + * DNSSD - Enable or disable (1/0) dns-sd, DNS Service Discovery announcements + * DNSSDNAME - Set DNS-SD service name, defaults to "Dire Wolf on " + */ + + else if (strcasecmp(t, "DNSSD") == 0) { + int n; + t = split(NULL,0); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Missing integer value for DNSSD command.\n", line); + continue; + } + n = atoi(t); + if (n == 0 || n == 1) { + p_misc_config->dns_sd_enabled = n; + } else { + p_misc_config->dns_sd_enabled = 0; + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Invalid integer value for DNSSD. Disabling dns-sd.\n", line); + } + } + + else if (strcasecmp(t, "DNSSDNAME") == 0) { + t = split(NULL, 1); + if (t == NULL) { + text_color_set(DW_COLOR_ERROR); + dw_printf ("Line %d: Missing service name for DNSSDNAME.\n", line); + continue; + } + else { + strlcpy(p_misc_config->dns_sd_name, t, sizeof(p_misc_config->dns_sd_name)); + } + } + + + /* * GPSNMEA - Device name for reading from GPS receiver. */ diff --git a/src/config.h b/src/config.h index 8a708ae..41ba90c 100644 --- a/src/config.h +++ b/src/config.h @@ -88,6 +88,9 @@ struct misc_config_s { char log_path[80]; /* Either directory or full file name depending on above. */ + int dns_sd_enabled; /* DNS Service Discovery announcement enabled. */ + char dns_sd_name[64]; /* Name announced on dns-sd; defaults to "Dire Wolf on " */ + int sb_configured; /* TRUE if SmartBeaconing is configured. */ int sb_fast_speed; /* MPH */ int sb_fast_rate; /* seconds */ diff --git a/src/direwolf.c b/src/direwolf.c index 11ec8a6..5db881b 100644 --- a/src/direwolf.c +++ b/src/direwolf.c @@ -125,6 +125,7 @@ #include "dtime_now.h" #include "fx25.h" #include "dwsock.h" +#include "dns_sd_dw.h" //static int idx_decoded = 0; @@ -1029,6 +1030,11 @@ int main (int argc, char *argv[]) server_init (&audio_config, &misc_config); kissnet_init (&misc_config); +#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD) + if (misc_config.kiss_port > 0 && misc_config.dns_sd_enabled) + dns_sd_announce(&misc_config); +#endif + /* * Create a pseudo terminal and KISS TNC emulator. */ diff --git a/src/dns_sd_avahi.c b/src/dns_sd_avahi.c new file mode 100644 index 0000000..81e9f19 --- /dev/null +++ b/src/dns_sd_avahi.c @@ -0,0 +1,259 @@ +// +// This file is part of Dire Wolf, an amateur radio packet TNC. +// +// Copyright (C) 2020 Heikki Hannikainen, OH7LZB +// +// +// 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, see . + +/*------------------------------------------------------------------ + * + * Module: dns_sd_avahi.c + * + * Purpose: Announce the KISS over TCP service using DNS-SD via Avahi + * + * Description: + * + * Most people have typed in enough IP addresses and ports by now, and + * would rather just select an available TNC that is automatically + * discovered on the local network. Even more so on a mobile device + * such an Android or iOS phone or tablet. + * + * On Linux, the announcement can be made through Avahi, the mDNS + * framework commonly deployed on Linux systems. + * + * This is largely based on the publishing example of the Avahi library. + */ + +#ifdef USE_AVAHI_CLIENT + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "dns_sd_dw.h" +#include "dns_sd_common.h" +#include "textcolor.h" + +static AvahiEntryGroup *group = NULL; +static AvahiSimplePoll *simple_poll = NULL; +static AvahiClient *client = NULL; +static char *name = NULL; +static int kiss_port = 0; + +pthread_t avahi_thread; + +static void create_services(AvahiClient *c); + +#define PRINT_PREFIX "DNS-SD: Avahi: " + +static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, AVAHI_GCC_UNUSED void *userdata) +{ + assert(g == group || group == NULL); + group = g; + + /* Called whenever the entry group state changes */ + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + /* The entry group has been established successfully */ + text_color_set(DW_COLOR_INFO); + dw_printf(PRINT_PREFIX "Service '%s' successfully registered.\n", name); + break; + case AVAHI_ENTRY_GROUP_COLLISION: { + char *n; + /* A service name collision with a remote service + * happened. Let's pick a new name. */ + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n; + text_color_set(DW_COLOR_INFO); + dw_printf(PRINT_PREFIX "Service name collision, renaming service to '%s'\n", name); + /* And recreate the services */ + create_services(avahi_entry_group_get_client(g)); + break; + } + case AVAHI_ENTRY_GROUP_FAILURE: + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); + /* Some kind of failure happened while we were registering our services */ + avahi_simple_poll_quit(simple_poll); + break; + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + } +} + +static void create_services(AvahiClient *c) +{ + char *n; + int ret; + assert(c); + /* If this is the first time we're called, let's create a new + * entry group if necessary */ + if (!group) { + if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) { + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c))); + goto fail; + } + } else { + avahi_entry_group_reset(group); + } + + /* If the group is empty (either because it was just created, or + * because it was reset previously, add our entries. */ + if (avahi_entry_group_is_empty(group)) { + text_color_set(DW_COLOR_INFO); + dw_printf(PRINT_PREFIX "Announcing KISS TCP on port %d as '%s'\n", kiss_port, name); + + /* Announce with AVAHI_PROTO_INET instead of AVAHI_PROTO_UNSPEC, since Dire Wolf currently + * only listens on IPv4. + */ + + if ((ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_INET, 0, name, DNS_SD_SERVICE, NULL, NULL, kiss_port, NULL)) < 0) { + if (ret == AVAHI_ERR_COLLISION) + goto collision; + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Failed to add _kiss-tnc._tcp service: %s\n", avahi_strerror(ret)); + goto fail; + } + + /* Tell the server to register the service */ + if ((ret = avahi_entry_group_commit(group)) < 0) { + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Failed to commit entry group: %s\n", avahi_strerror(ret)); + goto fail; + } + } + return; + +collision: + /* A service name collision with a local service happened. Let's + * pick a new name */ + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n; + text_color_set(DW_COLOR_INFO); + dw_printf(PRINT_PREFIX "Service name collision, renaming service to '%s'\n", name); + avahi_entry_group_reset(group); + create_services(c); + return; + +fail: + avahi_simple_poll_quit(simple_poll); +} + +static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) +{ + assert(c); + /* Called whenever the client or server state changes */ + switch (state) { + case AVAHI_CLIENT_S_RUNNING: + /* The server has startup successfully and registered its host + * name on the network, so it's time to create our services */ + create_services(c); + break; + case AVAHI_CLIENT_FAILURE: + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Client failure: %s\n", avahi_strerror(avahi_client_errno(c))); + avahi_simple_poll_quit(simple_poll); + break; + case AVAHI_CLIENT_S_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. */ + case AVAHI_CLIENT_S_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 (group) + avahi_entry_group_reset(group); + break; + case AVAHI_CLIENT_CONNECTING: + ; + } +} + +static void cleanup(void) +{ + /* Cleanup things */ + if (client) + avahi_client_free(client); + + if (simple_poll) + avahi_simple_poll_free(simple_poll); + + avahi_free(name); +} + + +static void *avahi_mainloop(void *arg) +{ + /* Run the main loop */ + avahi_simple_poll_loop(simple_poll); + + cleanup(); + + return NULL; +} + +void dns_sd_announce (struct misc_config_s *mc) +{ + text_color_set(DW_COLOR_DEBUG); + kiss_port = mc->kiss_port; + + int error; + + /* Allocate main loop object */ + if (!(simple_poll = avahi_simple_poll_new())) { + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Failed to create Avahi simple poll object.\n"); + goto fail; + } + + if (mc->dns_sd_name[0]) { + name = avahi_strdup(mc->dns_sd_name); + } else { + name = dns_sd_default_service_name(); + } + + /* Allocate a new client */ + client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error); + + /* Check wether creating the client object succeeded */ + if (!client) { + text_color_set(DW_COLOR_ERROR); + dw_printf(PRINT_PREFIX "Failed to create Avahi client: %s\n", avahi_strerror(error)); + goto fail; + } + + pthread_create(&avahi_thread, NULL, &avahi_mainloop, NULL); + + return; + +fail: + cleanup(); +} + +#endif // USE_AVAHI_CLIENT + diff --git a/src/dns_sd_common.c b/src/dns_sd_common.c new file mode 100644 index 0000000..65a1cbf --- /dev/null +++ b/src/dns_sd_common.c @@ -0,0 +1,65 @@ +// +// This file is part of Dire Wolf, an amateur radio packet TNC. +// +// Copyright (C) 2020 Heikki Hannikainen, OH7LZB +// +// +// 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, see . + +/*------------------------------------------------------------------ + * + * Module: dns_sd_common.c + * + * Purpose: Announce the KISS over TCP service using DNS-SD, common functions + * + * Description: + * + * Most people have typed in enough IP addresses and ports by now, and + * would rather just select an available TNC that is automatically + * discovered on the local network. Even more so on a mobile device + * such an Android or iOS phone or tablet. + * + * This module contains common functions needed on Linux and MacOS. + */ + + +#include +#include +#include + +/* Get a default service name to publish. By default, + * "Dire Wolf on ", or just "Dire Wolf" if hostname cannot + * be obtained. + */ +char *dns_sd_default_service_name(void) +{ + char hostname[51]; + char sname[64]; + + int i = gethostname(hostname, sizeof(hostname)); + if (i == 0) { + hostname[sizeof(hostname)-1] = 0; + + // on some systems, an FQDN is returned; remove domain part + char *dot = strchr(hostname, '.'); + if (dot) + *dot = 0; + + snprintf(sname, sizeof(sname), "Dire Wolf on %s", hostname); + return strdup(sname); + } + + return strdup("Dire Wolf"); +} + diff --git a/src/dns_sd_common.h b/src/dns_sd_common.h new file mode 100644 index 0000000..f104bf8 --- /dev/null +++ b/src/dns_sd_common.h @@ -0,0 +1,7 @@ + +#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD) + +char *dns_sd_default_service_name(void); + +#endif + diff --git a/src/dns_sd_dw.h b/src/dns_sd_dw.h new file mode 100644 index 0000000..79f4b86 --- /dev/null +++ b/src/dns_sd_dw.h @@ -0,0 +1,10 @@ + +#if (USE_AVAHI_CLIENT|USE_MACOS_DNSSD) + +#include "config.h" + +#define DNS_SD_SERVICE "_kiss-tnc._tcp" + +void dns_sd_announce (struct misc_config_s *mc); + +#endif // USE_AVAHI_CLIENT diff --git a/src/dns_sd_macos.c b/src/dns_sd_macos.c new file mode 100644 index 0000000..27cca8c --- /dev/null +++ b/src/dns_sd_macos.c @@ -0,0 +1,88 @@ +// +// This file is part of Dire Wolf, an amateur radio packet TNC. +// +// Copyright (C) 2020 Heikki Hannikainen, OH7LZB +// +// +// 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, see . + +/*------------------------------------------------------------------ + * + * Module: dns_sd_macos.c + * + * Purpose: Announce the KISS over TCP service using MacOS dns-sd + * + * Description: + * + * Most people have typed in enough IP addresses and ports by now, and + * would rather just select an available TNC that is automatically + * discovered on the local network. Even more so on a mobile device + * such an Android or iOS phone or tablet. + * + * On MacOs, the announcement can be made through dns-sd. + */ + +#ifdef USE_MACOS_DNSSD + +#include +#include +#include + +#include "dns_sd_dw.h" +#include "dns_sd_common.h" +#include "textcolor.h" + +static char *name = NULL; + +static void registerServiceCallBack(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, + const char* name, const char* regType, const char* domain, void* context) +{ + if (errorCode == kDNSServiceErr_NoError) { + text_color_set(DW_COLOR_INFO); + dw_printf("DNS-SD: Successfully registered '%s'\n", name); + } else { + text_color_set(DW_COLOR_ERROR); + dw_printf("DNS-SD: Failed to register '%s': %d\n", name, errorCode); + } +} + +void dns_sd_announce (struct misc_config_s *mc) +{ + int kiss_port = mc->kiss_port; + + if (mc->dns_sd_name[0]) { + name = strdup(mc->dns_sd_name); + } else { + name = dns_sd_default_service_name(); + } + + uint16_t port_nw = htons(kiss_port); + + DNSServiceRef registerRef; + DNSServiceErrorType err = DNSServiceRegister( + ®isterRef, 0, 0, name, DNS_SD_SERVICE, NULL, NULL, + port_nw, 0, NULL, registerServiceCallBack, NULL); + + if (err == kDNSServiceErr_NoError) { + text_color_set(DW_COLOR_INFO); + dw_printf("DNS-SD: Announcing KISS TCP on port %d as '%s'\n", kiss_port, name); + } else { + text_color_set(DW_COLOR_ERROR); + dw_printf("DNS-SD: Failed to announce '%s': %d\n", name, err); + } +} + +#endif // USE_MACOS_DNSSD + + diff --git a/src/dwgpsd.c b/src/dwgpsd.c index b64fcd3..70b650b 100644 --- a/src/dwgpsd.c +++ b/src/dwgpsd.c @@ -56,6 +56,7 @@ #include + // An incompatibility was introduced with version 7 // and again with 9 and again with 10.