Created
October 5, 2018 02:04
-
-
Save s-u/b1684b3173d5b2859f187c5860b25de8 to your computer and use it in GitHub Desktop.
UDP broadcast discovery
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
/* minimalistic UDP-based broadcast discovery tool | |
(C)2018 Simon Urbanek <simon.urbanek@R-project.org> | |
License: MIT | |
*/ | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#include <errno.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
static char buf[512]; | |
static int active = 1; | |
const char *nomatch = ""; | |
int main(int ac, char **av) { | |
int verb = 0; | |
int port = -1; | |
int prefix = 0; | |
int maxat = 8; | |
int UDPs = socket(AF_INET,SOCK_DGRAM,0); | |
int reuse=1; | |
if (setsockopt(UDPs, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) /* allow reuse */ | |
perror("WARNING: Cannot activate socket addres re-usage for UDP"); | |
if (setsockopt(UDPs, SOL_SOCKET, SO_BROADCAST, &reuse, sizeof(reuse))) | |
perror("WARNING: Cannot activate broadcast for UDP"); | |
const char *req = 0; | |
int i = 0; | |
while (++i < ac) | |
if (av[i][0] == '-') switch(av[i][1]) { | |
case 'v': | |
verb++; | |
break; | |
case 'h': | |
printf("\n Usage: %s [-p=<port>] [-s] [-c=<query-content>] [-m=<max-attempts>] [<key>=<value> [...]]\n\n Default server port is 9552, default client port is 9551.\n If no query is specified server mode is assumed.\n\n", | |
av[0]); | |
return 0; | |
case 'p': | |
if (av[i][2] == '=') | |
port = atoi(av[i] + 3); | |
else { | |
fprintf(stderr, "ERROR: missing port in -p=<port>\n"); | |
return 1; | |
} | |
break; | |
case 's': | |
prefix = 1; | |
break; | |
case 'm': | |
if (av[i][2] == '=') | |
maxat = atoi(av[i] + 3); | |
else { | |
fprintf(stderr, "ERROR: missing value in -m=<max.attempts>\n"); | |
return 1; | |
} | |
break; | |
case 'c': | |
if (av[i][2] == '=') | |
req = av[i] + 3; | |
else { | |
fprintf(stderr, "ERROR: missing content in -c=<content>\n"); | |
return 1; | |
} | |
break; | |
default: | |
fprintf(stderr, "WARNING: unsupported option %s\n", av[i]); | |
} | |
if (port < 1) | |
port = req ? 9551 : 9552; | |
struct sockaddr_in UDPsrv, peer; | |
memset(&UDPsrv,0,sizeof(UDPsrv)); | |
UDPsrv.sin_family = AF_INET; | |
UDPsrv.sin_port = htons(port); | |
UDPsrv.sin_addr.s_addr = htonl(INADDR_ANY); | |
if (bind(UDPs, (struct sockaddr*)&UDPsrv, sizeof(UDPsrv))) { | |
perror("Can't bind UDP server"); | |
return 1; | |
} | |
if (req) { | |
socklen_t len = sizeof(peer); | |
memset(&peer, 0, sizeof(UDPsrv)); | |
peer.sin_family = AF_INET; | |
peer.sin_port = htons(9552); | |
peer.sin_addr.s_addr = htonl(INADDR_ANY); // inet_addr("127.0.0.1"); | |
int sn = (int) sendto(UDPs, req, strlen(req), 0, (const struct sockaddr*) &peer, len); | |
if (verb) | |
printf("INFO: sendto returned %d\n", sn); | |
if (sn < 0) | |
perror("ERROR: send failed"); | |
struct timeval tv; | |
tv.tv_sec = 0; | |
tv.tv_usec = 250000; | |
if (setsockopt(UDPs, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { | |
perror("Cannot set UDP receive timeout"); | |
return 1; | |
} | |
} | |
while (active) { | |
socklen_t len = sizeof(peer); | |
int n = recvfrom(UDPs, buf, sizeof(buf) - 1, 0, (struct sockaddr*) &peer, &len); | |
if (verb) | |
printf("%d\n", n); | |
if (n >= 0) { | |
buf[n] = 0; | |
if (verb) | |
printf("%x:%d \"%s\"\n", peer.sin_addr.s_addr, ntohs(peer.sin_port), buf); | |
if (req) { | |
if (prefix) | |
printf("%s:", inet_ntoa(peer.sin_addr)); | |
puts(buf); | |
break; | |
} | |
int answ = 0; | |
i = 0; | |
while (++i < ac) { | |
if (strncmp(av[i], buf, n) == 0 && | |
av[i][n] == '=') { | |
int sn = (int) sendto(UDPs, av[i] + n + 1, strlen(av[i] + n + 1), | |
0, (const struct sockaddr*) &peer, len); | |
if (sn < 0) | |
perror("Failed to send (valid) response"); | |
answ = 1; | |
} | |
} | |
} else if (req) { | |
maxat--; | |
if (maxat < 1) { | |
fprintf(stderr, "ERROR: maximum number of attempts exhausted, giving up\n"); | |
return 1; | |
} | |
int sn = (int) sendto(UDPs, req, strlen(req), 0, (const struct sockaddr*) &peer, len); | |
if (verb) | |
printf("INFO: sendto returned %d\n", sn); | |
if (sn < 0) | |
perror("ERROR: send failed"); | |
} | |
fflush(stdout); | |
} | |
close(UDPs); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment