udp server

This commit is contained in:
2025-07-12 17:54:52 +02:00
parent e1218542d2
commit eff6a1ff5e
5 changed files with 157 additions and 17 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"port": 13452, "port": 13452,
"time": 1751819046475, "time": 1752334981843,
"version": "0.0.3" "version": "0.0.3"
} }
+1 -1
Submodule inih updated: 57188e8acd...498f34b786
+53 -15
View File
@@ -9,6 +9,7 @@
#include "rds.h" #include "rds.h"
#include "modulator.h" #include "modulator.h"
#include "control_pipe.h" #include "control_pipe.h"
#include "udp_server.h"
#include "lib.h" #include "lib.h"
#include "ascii_cmd.h" #include "ascii_cmd.h"
@@ -37,6 +38,16 @@ static void *control_pipe_worker(void* modulator) {
pthread_exit(NULL); pthread_exit(NULL);
} }
static void *udp_server_worker() {
while (!stop_rds) {
poll_udp_server();
msleep(READ_TIMEOUT_MS);
}
close_udp_server();
pthread_exit(NULL);
}
static inline void show_help(char *name) { static inline void show_help(char *name) {
printf( printf(
"\n" "\n"
@@ -52,27 +63,32 @@ static inline void show_help(char *name) {
typedef struct typedef struct
{ {
char control_pipe[51]; char control_pipe[51];
uint16_t udp_port;
char rds_device_name[32]; char rds_device_name[32];
uint8_t num_streams; uint8_t num_streams;
} RDS95_Config; } RDS95_Config;
static int config_handler(void* user, const char* section, const char* name, const char* value) { static int config_handler(void* user, const char* section, const char* name, const char* value) {
RDS95_Config* config = (RDS95_Config*)user; RDS95_Config* config = (RDS95_Config*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0 #define MATCH(s, n) (strcmp(section, s) == 0 && strcmp(name, n) == 0)
if(MATCH("rds95", "control_pipe")) {
strncpy(config->control_pipe, value, 49); if (MATCH("rds95", "control_pipe")) {
config->control_pipe[50] = '\0'; strncpy(config->control_pipe, value, sizeof(config->control_pipe) - 1);
} else if(MATCH("devices", "rds95")) { config->control_pipe[sizeof(config->control_pipe) - 1] = '\0';
strncpy(config->rds_device_name, value, 30); } else if (MATCH("rds95", "udp_port")) {
config->rds_device_name[31] = '\0'; config->udp_port = (uint16_t)atoi(value);
} else if(MATCH("rds95", "streams")) { } else if (MATCH("devices", "rds95")) {
config->num_streams = atoi(value); strncpy(config->rds_device_name, value, sizeof(config->rds_device_name) - 1);
if(config->num_streams > MAX_STREAMS || config->num_streams == 0) return 1; config->rds_device_name[sizeof(config->rds_device_name) - 1] = '\0';
} else { } else if (MATCH("rds95", "streams")) {
return 0; int streams = atoi(value);
} if (streams > MAX_STREAMS || streams == 0) return 0;
return 1; config->num_streams = (uint8_t)streams;
} else {
return 0; // Unknown config key
}
return 1;
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
@@ -81,6 +97,7 @@ int main(int argc, char **argv) {
char config_path[64] = DEFAULT_CONFIG_PATH; char config_path[64] = DEFAULT_CONFIG_PATH;
RDS95_Config config = { RDS95_Config config = {
.control_pipe = "\0", .control_pipe = "\0",
.udp_port = 0,
.rds_device_name = RDS_DEVICE, .rds_device_name = RDS_DEVICE,
.num_streams = DEFAULT_STREAMS .num_streams = DEFAULT_STREAMS
}; };
@@ -91,6 +108,7 @@ int main(int argc, char **argv) {
pthread_attr_t attr; pthread_attr_t attr;
pthread_t control_pipe_thread; pthread_t control_pipe_thread;
pthread_t udp_server_thread;
const char *short_opt = "c:h"; const char *short_opt = "c:h";
@@ -174,6 +192,21 @@ int main(int argc, char **argv) {
} }
} }
if(config.udp_port) {
if(open_udp_server(config.udp_port, &rdsModulator) == 0) {
fprintf(stderr, "Reading control commands on UDP:%d.\n", config.udp_port);
int r = pthread_create(&udp_server_thread, &attr, udp_server_worker, NULL);
if (r < 0) {
fprintf(stderr, "Could not create UDP server thread.\n");
config.udp_port = 0;
goto exit;
} else fprintf(stderr, "Created UDP server thread.\n");
} else {
fprintf(stderr, "Failed to open UDP server\n");
config.udp_port = 0;
}
}
int pulse_error; int pulse_error;
// Dynamically allocate buffer based on stream count // Dynamically allocate buffer based on stream count
@@ -202,6 +235,11 @@ exit:
pthread_join(control_pipe_thread, NULL); pthread_join(control_pipe_thread, NULL);
} }
if(config.udp_port) {
fprintf(stderr, "Waiting for UDP thread to shut down.\n");
pthread_join(udp_server_thread, NULL);
}
cleanup_rds_modulator(&rdsModulator); // Clean up dynamically allocated memory cleanup_rds_modulator(&rdsModulator); // Clean up dynamically allocated memory
pthread_attr_destroy(&attr); pthread_attr_destroy(&attr);
if (rds_device != NULL) pa_simple_free(rds_device); if (rds_device != NULL) pa_simple_free(rds_device);
+83
View File
@@ -0,0 +1,83 @@
#include "udp_server.h"
#define BUF_SIZE 512
#define UDP_READ_TIMEOUT_MS 500
static int sockfd = -1;
static struct pollfd poller;
static struct sockaddr_in client_addr;
static socklen_t client_len = sizeof(client_addr);
static RDSModulator* mod = NULL; // Store modulator pointer globally or pass it somehow
int open_udp_server(int port, RDSModulator* rds_mod) {
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) return -1;
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
close(sockfd);
sockfd = -1;
return -1;
}
poller.fd = sockfd;
poller.events = POLLIN;
mod = rds_mod; // Save mod pointer
return 0;
}
void poll_udp_server() {
static char buf[BUF_SIZE];
static char cmd_buf[BUF_SIZE];
static char cmd_output[BUF_SIZE]; // Buffer to collect output from process_ascii_cmd
ssize_t bytes_read;
if (poll(&poller, 1, UDP_READ_TIMEOUT_MS) <= 0) return;
if (!(poller.revents & POLLIN)) return;
memset(buf, 0, BUF_SIZE);
client_len = sizeof(client_addr);
bytes_read = recvfrom(sockfd, buf, BUF_SIZE - 1, 0,
(struct sockaddr *)&client_addr, &client_len);
if (bytes_read <= 0) return;
buf[bytes_read] = '\0';
char *token = strtok(buf, "\r\n");
while (token != NULL) {
size_t len = strlen(token);
if (len > 0 && len < BUF_SIZE) {
memset(cmd_buf, 0, BUF_SIZE);
strncpy(cmd_buf, token, BUF_SIZE - 1);
memset(cmd_output, 0, BUF_SIZE);
// Pass cmd_output buffer to collect output from the command processor
process_ascii_cmd(mod, cmd_buf, cmd_output);
// Send cmd_output back to client (even if empty, send it)
size_t out_len = strlen(cmd_output);
if (out_len > 0) {
ssize_t sent = sendto(sockfd, cmd_output, out_len, 0,
(struct sockaddr *)&client_addr, client_len);
if (sent == -1) {
perror("sendto");
}
}
}
token = strtok(NULL, "\r\n");
}
}
void close_udp_server() {
if (sockfd >= 0) close(sockfd);
sockfd = -1;
}
+19
View File
@@ -0,0 +1,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "modulator.h"
#include "ascii_cmd.h"
int open_udp_server(int port, RDSModulator *rds_mod);
void poll_udp_server();
void close_udp_server();