1#include <base/logger.h>
2#include <base/mem.h>
3#include <base/net.h>
4#include <base/os.h>
5
6#include <engine/shared/stun.h>
7
8#include <chrono>
9
10using namespace std::chrono_literals;
11
12int main(int argc, const char **argv)
13{
14 CCmdlineFix CmdlineFix(&argc, &argv);
15
16 log_set_global_logger_default();
17
18 if(argc < 2)
19 {
20 log_info("stun", "usage: %s <STUN ADDRESS>", argc > 0 ? argv[0] : "stun");
21 return 1;
22 }
23 NETADDR Addr;
24 if(net_addr_from_str(addr: &Addr, string: argv[1]))
25 {
26 log_error("stun", "couldn't parse address");
27 return 2;
28 }
29
30 net_init();
31 NETADDR BindAddr;
32 mem_zero(block: &BindAddr, size: sizeof(BindAddr));
33 BindAddr.type = NETTYPE_ALL;
34 NETSOCKET Socket = net_udp_create(bindaddr: BindAddr);
35 if(net_socket_type(sock: Socket) == NETTYPE_INVALID)
36 {
37 log_error("stun", "couldn't open udp socket");
38 return 2;
39 }
40
41 CStunData Stun;
42 unsigned char aRequest[32];
43 int RequestSize = StunMessagePrepare(pBuffer: aRequest, BufferSize: sizeof(aRequest), pData: &Stun);
44 if(net_udp_send(sock: Socket, addr: &Addr, data: aRequest, size: RequestSize) == -1)
45 {
46 log_error("stun", "failed sending stun request");
47 return 2;
48 }
49
50 NETADDR ResponseAddr;
51 unsigned char *pResponse;
52 while(true)
53 {
54 if(!net_socket_read_wait(sock: Socket, nanoseconds: 1s))
55 {
56 log_error("stun", "no udp message received from server until timeout");
57 return 3;
58 }
59 int ResponseSize = net_udp_recv(sock: Socket, addr: &ResponseAddr, data: &pResponse);
60 if(ResponseSize == -1)
61 {
62 log_error("stun", "failed receiving udp message");
63 return 2;
64 }
65 else if(ResponseSize == 0)
66 {
67 continue;
68 }
69 if(net_addr_comp(a: &Addr, b: &ResponseAddr) != 0)
70 {
71 char aResponseAddr[NETADDR_MAXSTRSIZE];
72 char aAddr[NETADDR_MAXSTRSIZE];
73 net_addr_str(addr: &ResponseAddr, string: aResponseAddr, max_length: sizeof(aResponseAddr), add_port: true);
74 net_addr_str(addr: &Addr, string: aAddr, max_length: sizeof(aAddr), add_port: true);
75 log_debug("stun", "got message from %s while expecting one from %s", aResponseAddr, aAddr);
76 continue;
77 }
78 bool Success;
79 NETADDR StunAddr;
80 if(StunMessageParse(pMessage: pResponse, MessageSize: ResponseSize, pData: &Stun, pSuccess: &Success, pAddr: &StunAddr))
81 {
82 log_debug("stun", "received message from stun server that was not understood");
83 continue;
84 }
85 if(Success)
86 {
87 char aStunAddr[NETADDR_MAXSTRSIZE];
88 net_addr_str(addr: &StunAddr, string: aStunAddr, max_length: sizeof(aStunAddr), add_port: true);
89 log_info("stun", "public ip address: %s", aStunAddr);
90 break;
91 }
92 else
93 {
94 log_info("stun", "error response from stun server");
95 break;
96 }
97 }
98}
99