110 lines
3.4 KiB
C
110 lines
3.4 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <unistd.h>
|
||
#include <arpa/inet.h>
|
||
|
||
#include "discovery.h"
|
||
#include "error.h"
|
||
|
||
static void flags_str(uint16_t flags, char *buf, size_t len) {
|
||
buf[0] = '\0';
|
||
if (flags & DISCOVERY_FLAG_SOURCE) { strncat(buf, "source ", len - strlen(buf) - 1); }
|
||
if (flags & DISCOVERY_FLAG_RELAY) { strncat(buf, "relay ", len - strlen(buf) - 1); }
|
||
if (flags & DISCOVERY_FLAG_SINK) { strncat(buf, "sink ", len - strlen(buf) - 1); }
|
||
if (flags & DISCOVERY_FLAG_CONTROLLER) { strncat(buf, "controller ", len - strlen(buf) - 1); }
|
||
/* trim trailing space */
|
||
size_t l = strlen(buf);
|
||
if (l > 0 && buf[l - 1] == ' ') { buf[l - 1] = '\0'; }
|
||
}
|
||
|
||
static void on_peer_found(const struct Discovery_Peer *peer, void *userdata) {
|
||
(void)userdata;
|
||
char addr[INET_ADDRSTRLEN];
|
||
inet_ntop(AF_INET, &peer->addr, addr, sizeof(addr));
|
||
char flags[64];
|
||
flags_str(peer->function_flags, flags, sizeof(flags));
|
||
printf("found %-30s %s:%u site=%u [%s]\n",
|
||
peer->name, addr, peer->tcp_port, peer->site_id, flags);
|
||
}
|
||
|
||
static void on_peer_lost(const struct Discovery_Peer *peer, void *userdata) {
|
||
(void)userdata;
|
||
char addr[INET_ADDRSTRLEN];
|
||
inet_ntop(AF_INET, &peer->addr, addr, sizeof(addr));
|
||
printf("lost %-30s %s:%u\n", peer->name, addr, peer->tcp_port);
|
||
}
|
||
|
||
static void usage(void) {
|
||
fprintf(stderr,
|
||
"usage: discovery_cli <name> <tcp_port> [flags]\n"
|
||
"\n"
|
||
" name node name in namespace:instance form, e.g. v4l2:microscope\n"
|
||
" tcp_port port this node listens on for transport connections\n"
|
||
" flags comma-separated roles: source,relay,sink,controller\n"
|
||
" default: source\n"
|
||
"\n"
|
||
"Announces this node on the multicast group and prints peers as they\n"
|
||
"appear and disappear. Press Ctrl-C to exit.\n");
|
||
}
|
||
|
||
static uint16_t parse_flags(const char *s) {
|
||
uint16_t f = 0;
|
||
if (strstr(s, "source")) { f |= DISCOVERY_FLAG_SOURCE; }
|
||
if (strstr(s, "relay")) { f |= DISCOVERY_FLAG_RELAY; }
|
||
if (strstr(s, "sink")) { f |= DISCOVERY_FLAG_SINK; }
|
||
if (strstr(s, "controller")) { f |= DISCOVERY_FLAG_CONTROLLER; }
|
||
return f;
|
||
}
|
||
|
||
int main(int argc, char **argv) {
|
||
if (argc < 3) {
|
||
usage();
|
||
return 1;
|
||
}
|
||
|
||
const char *name = argv[1];
|
||
uint16_t tcp_port = (uint16_t)atoi(argv[2]);
|
||
uint16_t flags = argc >= 4 ? parse_flags(argv[3]) : DISCOVERY_FLAG_SOURCE;
|
||
|
||
if (strlen(name) == 0 || strlen(name) > DISCOVERY_MAX_NAME_LEN) {
|
||
fprintf(stderr, "name must be 1–%d characters\n", DISCOVERY_MAX_NAME_LEN);
|
||
return 1;
|
||
}
|
||
|
||
struct Discovery_Config config = {
|
||
.site_id = 0,
|
||
.tcp_port = tcp_port,
|
||
.function_flags = flags,
|
||
.name = name,
|
||
.interval_ms = 0, /* use default */
|
||
.timeout_intervals = 0, /* use default */
|
||
.on_peer_found = on_peer_found,
|
||
.on_peer_lost = on_peer_lost,
|
||
.userdata = NULL,
|
||
};
|
||
|
||
struct Discovery *d;
|
||
struct App_Error err = discovery_create(&d, &config);
|
||
if (!APP_IS_OK(err)) {
|
||
fprintf(stderr, "discovery_create: errno %d\n", err.detail.syscall.err_no);
|
||
return 1;
|
||
}
|
||
|
||
err = discovery_start(d);
|
||
if (!APP_IS_OK(err)) {
|
||
fprintf(stderr, "discovery_start: errno %d\n", err.detail.syscall.err_no);
|
||
return 1;
|
||
}
|
||
|
||
char flags_buf[64];
|
||
flags_str(flags, flags_buf, sizeof(flags_buf));
|
||
printf("announcing %-30s port=%u [%s]\n", name, tcp_port, flags_buf);
|
||
printf("listening on %s:%d\n\n", DISCOVERY_MULTICAST_GROUP, DISCOVERY_PORT);
|
||
|
||
pause();
|
||
|
||
discovery_destroy(d);
|
||
return 0;
|
||
}
|