From 35d4bc9ca5a600787dc405f453dd7e33b8f7d5bf Mon Sep 17 00:00:00 2001 From: Phil Karn Date: Thu, 11 Apr 2024 12:28:24 -0400 Subject: [PATCH] minor cleanups - buffer sizes, use asprintf when possible --- README.md | 18 +++++++++++++++--- aprsfeed.c | 2 +- audio.c | 18 ++++++++++-------- avahi.c | 53 ++++++++++++++++++++++++++--------------------------- main.c | 2 +- opusd.c | 10 +++++----- pcmrecord.c | 2 +- pcmspawn.c | 14 +++++++------- radio.c | 8 ++++---- spectrum.c | 4 ++-- 10 files changed, 72 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index f6637cfe..047fa341 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,17 @@ several respects: 1. Efficient multichannel reception. A single Raspberry Pi 4 can simultaneously demodulate, in real time, every NBFM channel on a VHF/UHF band (i.e., several hundred) with plenty of real time left -over. A mid-range x86 can handle the RX888 MkII at full sample rate +over. + +A mid-range x86 can handle the RX888 MkII at full sample rate (129.6 MHz), receiving multiple channels sumultaneously on all LF/MF/HF ham bands (or anything else) plus 6 meters. +A Raspberry Pi 5 can handle the RX888 MkII at half sample rate (64.8 +MHz), enough to receive up to 30 MHz. (An external hardware anti-alias +filter is required, and "FFTW Wisdom" must be generated for the Pi5 to +run this fast.) + 2. All I/O (both signal and control/status) uses IP multicasting. This makes it easy for more than one module, on the same computer or on a LAN, to operate on the outputs of other modules, or for @@ -34,7 +41,7 @@ downconverters and simple demodulators for various linear and FM modes, including AM, SSB, CW and a raw IQ mode intended mainly for use by other programs. -Previous versions of ka9q-radio had separate programs (e.g., +Previous versions (before mid-2023) of ka9q-radio had separate programs (e.g., *airspyd*) for talking to several makes of SDR front end hardware and generated an I/Q multicast stream for *radiod*. Because of performance problems, code and configuration complexity and general lack of @@ -60,6 +67,11 @@ by much more sophisticated user interfaces. Various utilities are provided to record or play back signal streams, compress PCM audio into Opus, pipe a stream into digital demodulators, etc. +*Radiod* now periodically multicasts ("beacons") status information on +each output stream and user programs are being enhanced to make +use of it. For example, *monitor* now displays the frequency, mode and +signal-to-noise ratio of each channe. + Although I've been running all this myself for several years, it is NOT yet ready for general use. A LOT of work still remains, especially documentation. But you're welcome to look at it, make comments and @@ -82,7 +94,7 @@ requirement is that the impulse response of the channel filters be shorter than the (configurable) overlap interval in the forward FFT. -Updated 10 September 2023 +Updated 11 April 2024 Phil Karn, KA9Q karn@ka9q.net diff --git a/aprsfeed.c b/aprsfeed.c index 39dd7481..865bdfb5 100644 --- a/aprsfeed.c +++ b/aprsfeed.c @@ -223,7 +223,7 @@ int main(int argc,char *argv[]){ } // Construct TNC2-style monitor string for APRS reporting - char monstring[2048]; // Should be large enough for any legal AX.25 frame; we'll assert this periodically + char monstring[PKTSIZE]; // Should be large enough for any legal AX.25 frame; we'll assert this periodically int sspace = sizeof(monstring); int infolen = 0; int is_tcpip = 0; diff --git a/audio.c b/audio.c index 240b290a..3e7ab732 100644 --- a/audio.c +++ b/audio.c @@ -1,6 +1,6 @@ // Audio multicast routines for ka9q-radio // Handles linear 16-bit PCM, mono and stereo -// Copyright 2017-2023 Phil Karn, KA9Q +// Copyright 2017-2024 Phil Karn, KA9Q #define _GNU_SOURCE 1 #include @@ -90,14 +90,16 @@ int send_output(struct channel * restrict const chan,float const * restrict buff int r = sendto(Output_fd,&packet,dp - packet,0,(struct sockaddr *)&chan->output.dest_socket,sizeof(chan->output.dest_socket)); chan->output.samples += chunk * chan->output.channels; // Count frames if(r <= 0){ - if(errno == EAGAIN && !TempSendFailure){ - fprintf(stdout,"Temporary send failure, suggest increased buffering (see sysctl net.core.wmem_max, net.core.wmem_default\n"); - fprintf(stdout,"Additional messages suppressed\n"); - TempSendFailure = true; - return 0; // Treat as soft failure + if(errno == EAGAIN){ + if(!TempSendFailure){ + fprintf(stdout,"Temporary send failure, suggest increased buffering (see sysctl net.core.wmem_max, net.core.wmem_default\n"); + fprintf(stdout,"Additional messages suppressed\n"); + TempSendFailure = true; + } + } else { + fprintf(stdout,"audio send failure: %s\n",strerror(errno)); + abort(); // Probably more serious, like the loss of an interface or route } - fprintf(stdout,"audio send failure: %s\n",strerror(errno)); - abort(); // Probably more serious, like the loss of an interface or route } frames -= chunk; if(chan->output.pacing && frames > 0) diff --git a/avahi.c b/avahi.c index 9946495c..d4edbe2e 100644 --- a/avahi.c +++ b/avahi.c @@ -7,25 +7,37 @@ #include "avahi.h" int avahi_start(char const *service_name,char const *service_type,int const service_port,char const *dns_name,int address,char const *description,void *sock,int *socksize){ - int pid = getpid(); + if(sock != NULL && socksize != NULL){ + // Return sockaddr structure + if(*socksize >= sizeof(struct sockaddr_in)){ + struct sockaddr_in *sin = sock; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl(address); + sin->sin_port = htons(service_port); + *socksize = sizeof(struct sockaddr_in); + } else + *socksize = 0; + } + int pid = getpid(); // Advertise the parent's pid, not the child's if(fork() == 0){ #if 0 fprintf(stdout,"avahi-publish-service child pid %d\n",getpid()); #endif - // run avahi-publish-service --no-fail --host=dns_name service_name service_type service_port description pid hostname in subprocess - char port_string[1024]; - snprintf(port_string, sizeof(port_string), "%d", service_port); + // run "avahi-publish-service --no-fail --host=dns_name service_name service_type service_port description pid hostname" in subprocess + // No need to free the asprintf-allocated strings, we're calling exec anyway + char *port_string; + asprintf(&port_string, "%d", service_port); - char host_string[1024]; - snprintf(host_string, sizeof(host_string), "--host=%s",dns_name); + char *host_string; + asprintf(&host_string, "--host=%s",dns_name); - char pid_string[1024]; - snprintf(pid_string, sizeof(pid_string), "pid=%d", pid); + char *pid_string; + asprintf(&pid_string, "pid=%d", pid); char hostname[sysconf(_SC_HOST_NAME_MAX)]; gethostname(hostname,sizeof(hostname)); - char source_string[1024]; - snprintf(source_string, sizeof(source_string), "source=%s", hostname); + char *source_string; + asprintf(&source_string, "source=%s", hostname); #if 0 fprintf(stdout,"%s %s %s %s %s %s %s %s %s %s\n", @@ -35,25 +47,12 @@ int avahi_start(char const *service_name,char const *service_type,int const serv perror("exec avahi publish service"); return -1; } - char ip_address_string[1024]; - snprintf(ip_address_string,sizeof(ip_address_string),"%d.%d.%d.%d",(address >> 24) & 0xff, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff); + if(fork() == 0){ + char *ip_address_string; // No need to free, we're calling exec + asprintf(&ip_address_string,"%d.%d.%d.%d",(address >> 24) & 0xff, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff); #if 0 - fprintf(stdout,"avahi start: ip address string = %s\n",ip_address_string); + fprintf(stdout,"avahi start: ip address string = %s\n",ip_address_string); #endif - - if(sock != NULL && socksize != NULL){ - // Return sockaddr structure - if(*socksize >= sizeof(struct sockaddr_in)){ - struct sockaddr_in *sin = sock; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = htonl(address); - sin->sin_port = htons(service_port); - *socksize = sizeof(struct sockaddr_in); - } else - *socksize = 0; - } - - if(fork() == 0){ fprintf(stdout,"avahi-publish-address child pid %d\n",getpid()); // run "avahi-publish-address dns_name address" #if 0 diff --git a/main.c b/main.c index 6ad90363..69b06cb8 100644 --- a/main.c +++ b/main.c @@ -377,7 +377,7 @@ static int loadconfig(char const * const file){ // Set up status/command stream, global for all receiver channels { // Form default status dns name - char hostname[1024]; + char hostname[sysconf(_SC_HOST_NAME_MAX)]; gethostname(hostname,sizeof(hostname)); // Edit off .domain, .local, etc char *cp = strchr(hostname,'.'); diff --git a/opusd.c b/opusd.c index 98e0b609..1fed6519 100644 --- a/opusd.c +++ b/opusd.c @@ -246,12 +246,12 @@ int main(int argc,char * const argv[]){ Status_fd = listen_mcast(&Metadata_in_socket,iface); } - char description[1024]; - snprintf(description,sizeof(description),"pcm-source=%s",Input); // what if it changes? - int socksize = sizeof(Opus_out_socket); - uint32_t addr = (239U << 24) | (ElfHashString(Output) & 0xffffff); - avahi_start(Name,"_opus._udp",DEFAULT_RTP_PORT,Output,addr,description,&Opus_out_socket,&socksize); { + char description[1024]; + snprintf(description,sizeof(description),"pcm-source=%s",Input); // what if it changes? + int socksize = sizeof(Opus_out_socket); + uint32_t addr = (239U << 24) | (ElfHashString(Output) & 0xffffff); + avahi_start(Name,"_opus._udp",DEFAULT_RTP_PORT,Output,addr,description,&Opus_out_socket,&socksize); struct sockaddr_in *sin = (struct sockaddr_in *)&Metadata_out_socket; sin->sin_family = AF_INET; sin->sin_addr.s_addr = htonl(addr); diff --git a/pcmrecord.c b/pcmrecord.c index 03fb7bbb..9ea0ca11 100644 --- a/pcmrecord.c +++ b/pcmrecord.c @@ -1,5 +1,5 @@ // Read and record PCM audio streams -// Copyright 2021 Phil Karn, KA9Q +// Copyright 2021-2024 Phil Karn, KA9Q #define _GNU_SOURCE 1 #include #include diff --git a/pcmspawn.c b/pcmspawn.c index 13b51c16..441799a3 100644 --- a/pcmspawn.c +++ b/pcmspawn.c @@ -48,7 +48,7 @@ struct session { // Command line params -const char *App_path; +char const *App_path; int Verbose; // Verbosity flag (currently unused) // Global variables @@ -61,9 +61,9 @@ int Status_out_fd = -1; // Writing to radio status int Input_fd = -1; // Multicast receive socket struct session *Sessions; pthread_mutex_t Session_protect = PTHREAD_MUTEX_INITIALIZER; -char *Command; -char *Input; -char *Status; +char const *Command; +char const *Input; +char const *Status; void closedown(int); struct session *lookup_session(const struct sockaddr *,uint32_t,int); @@ -223,7 +223,7 @@ int main(int argc,char * const argv[]){ // sample rate // sending IP address & port - char command_line[2048]; + char command_line[4096]; // I think that's the longest shell command int const samprate = samprate_from_pt(sp->type); int const channels = channels_from_pt(sp->type); @@ -294,7 +294,7 @@ void * status(void *p){ while(true){ socklen_t socklen = sizeof(Status_input_source_address); - uint8_t buffer[16384]; + uint8_t buffer[PKTSIZE]; int const length = recvfrom(Status_fd,buffer,sizeof(buffer),0,(struct sockaddr *)&Status_input_source_address,&socklen); if(length <= 0){ if(errno == EAGAIN || errno == ETIMEDOUT) @@ -459,7 +459,7 @@ void closedown(int s){ } // Send empty poll command on specified descriptor static int send_poll(int fd,int ssrc){ - uint8_t cmdbuffer[128]; + uint8_t cmdbuffer[PKTSIZE]; uint8_t *bp = cmdbuffer; *bp++ = 1; // Command diff --git a/radio.c b/radio.c index d65f643e..d18e4684 100644 --- a/radio.c +++ b/radio.c @@ -1,5 +1,5 @@ -// Core of 'radiod' program - control LOs, set frequency/mode, etc -// Copyright 2018-2023, Phil Karn, KA9Q +// Core of 'radiod' program - create/delete channels, control LOs, set frequency/mode, etc +// Copyright 2018-2024, Phil Karn, KA9Q #define _GNU_SOURCE 1 #include #include @@ -388,7 +388,7 @@ void *sap_send(void *p){ int const sess_version = 1; for(;;){ - char message[1500],*wp; + char message[PKTSIZE],*wp; int space = sizeof(message); wp = message; @@ -418,7 +418,7 @@ void *sap_send(void *p){ { // Originator o= - char hostname[128]; + char hostname[sysconf(_SC_HOST_NAME_MAX)]; gethostname(hostname,sizeof(hostname)); struct passwd pwd,*result = NULL; diff --git a/spectrum.c b/spectrum.c index 81f0984c..92a02b6c 100644 --- a/spectrum.c +++ b/spectrum.c @@ -1,5 +1,5 @@ // Spectral analysis service - far from complete - for ka9q-radio's radiod -// Copyright 2023, Phil Karn, KA9Q +// Copyright 2023-2024, Phil Karn, KA9Q #define _GNU_SOURCE 1 #include #include @@ -20,7 +20,7 @@ void *demod_spectrum(void *arg){ { char name[100]; - snprintf(name,sizeof(name),"spect %u",chan->output.rtp.ssrc); // SSRC is dummy for ID, there's no RTP stream + snprintf(name,sizeof(name),"spect %u",chan->output.rtp.ssrc); pthread_setname(name); } pthread_mutex_init(&chan->status.lock,NULL);