-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
// Copyright 2025 Shota FUJI
//
// Licensed under the Zero-Clause BSD License or the Apache License, Version 2.0, at your option.
// You may not use, copy, modify, or distribute this file except according to those terms. You can
// find a copy of the Zero-Clause BSD License at LICENSES/0BSD.txt, and a copy of the Apache License,
// Version 2.0 at LICENSES/Apache-2.0.txt. You may also obtain a copy of the Apache License, Version
// 2.0 at <https://www.apache.org/licenses/LICENSE-2.0>
//
// SPDX-License-Identifier: 0BSD OR Apache-2.0
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <sood.h>
int main(int argc, char **argv) {
struct sockaddr_in multicast_addr;
multicast_addr.sin_family = AF_INET;
// Port is network byte order both in Linux and macOS
multicast_addr.sin_port = htons(sood_discovery_server_udp_port);
#ifdef __linux__
// Linux uses network byte order for IP addr part. Great consistency.
multicast_addr.sin_addr.s_addr = sood_discovery_multicast_ipv4_address_be;
#else
// Windows and macOS seem to use host byte order. fuck.
multicast_addr.sin_addr.s_addr = ntohl(sood_discovery_multicast_ipv4_address_be);
#endif
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
printf("Failed to create socket: %d\n", errno);
return 1;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
printf("Failed to set SO_REUSEADDR=1: %d\n", errno);
close(sockfd);
return 1;
}
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
printf("Failed to set SO_RCVTIMEO: %d\n", errno);
close(sockfd);
return 1;
}
while (1) {
if (
sendto(
sockfd,
sood_discovery_query_prebuilt,
sizeof(sood_discovery_query_prebuilt),
0,
(struct sockaddr*)&multicast_addr,
sizeof(multicast_addr)
) < 0
) {
printf("Failed to send: %d\n", errno);
close(sockfd);
return 1;
}
char received[512];
ssize_t received_size = recv(sockfd, received, sizeof(received), 0);
if (received_size < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
printf("Retrying...\n");
continue;
}
printf("Failed to recv: %d\n", errno);
close(sockfd);
return 1;
}
sood_discovery_response resp;
sood_discovery_response_parse_result result = sood_discovery_response_parse(
&resp,
received,
received_size
);
if (result != SOOD_DISCOVERY_RESPONSE_PARSE_OK) {
printf("Parse error: %d\n", result);
close(sockfd);
return 2;
}
printf("Name: \t\t%.*s\n", resp.name_len, resp.name_ptr);
printf("Version: \t%.*s\n", resp.display_version_len, resp.display_version_ptr);
printf("Unique ID: \t%.*s\n", resp.unique_id_len, resp.unique_id_ptr);
printf("HTTP port: \t%d\n", resp.http_port);
return 0;
}
}