forked from triblerteam/libswift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nat_test.cpp
159 lines (138 loc) · 4.6 KB
/
nat_test.cpp
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
* nat_test.cpp
* NAT type testing.
*
* Created by Gertjan Halkes.
* Copyright 2010 Delft University of Technology. All rights reserved.
*
*/
#include "swift.h"
#ifdef _WIN32
#include <iphlpapi.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <errno.h>
#include <netinet/in.h>
#endif
#define REQUEST_MAGIC 0x5a9e5fa1
#define REPLY_MAGIC 0xa655c5d5
#define REPLY_SEC_MAGIC 0x85e4a5ca
#define MAX_TRIES 3
namespace swift {
static void on_may_receive(SOCKET sock);
static void on_may_send(SOCKET sock);
static tint test_start;
static int tries;
static int packets_since_last_try;
static sckrwecb_t callbacks(0, on_may_receive, on_may_send, NULL);
/* Note that we lookup the addresses when we actually send, because Windows requires that
the winsock library is first intialized. If we use Address type variables here, the
lookup would be tried before that initialization, which fails... */
//FIXME: Change addresses to actual addresses used in test (at least 2 should be provided!)
static const char *servers[] = { "dutigp.st.ewi.tudelft.nl:18375" ,
"127.0.0.3:18375" };
static void on_may_receive(SOCKET sock) {
Datagram data(sock);
data.Recv();
uint32_t magic = data.Pull32();
if ((magic != REPLY_MAGIC && magic != REPLY_SEC_MAGIC) ||
(magic == REPLY_MAGIC && data.size() != 6) || (magic == REPLY_SEC_MAGIC && data.size() != 0))
{
dprintf("%s #0 NATTEST weird packet %s \n", tintstr(), data.address().str());
return;
}
if (magic == REPLY_MAGIC) {
uint32_t ip = data.Pull32();
uint16_t port = data.Pull16();
Address reported(ip, port);
dprintf("%s #0 NATTEST incoming %s %s\n", tintstr(), data.address().str(), reported.str());
} else {
dprintf("%s #0 NATTEST incoming secondary %s\n", tintstr(), data.address().str());
}
packets_since_last_try++;
}
static void on_may_send(SOCKET sock) {
callbacks.may_write = NULL;
Datagram::Listen3rdPartySocket(callbacks);
for (size_t i = 0; i < (sizeof(servers)/sizeof(servers[0])); i++) {
Datagram request(sock, Address(servers[i]));
request.Push32(REQUEST_MAGIC);
request.Send();
}
test_start = NOW;
struct sockaddr_in name;
socklen_t namelen = sizeof(name);
if (getsockname(sock, (struct sockaddr *) &name, &namelen) < 0) {
dprintf("%s #0 NATTEST could not get local address\n", tintstr());
} else {
Address local(ntohl(name.sin_addr.s_addr), ntohs(name.sin_port));
dprintf("%s #0 NATTEST local %s\n", tintstr(), local.str());
}
}
static void printAddresses(void) {
#ifdef _WIN32
IP_ADAPTER_INFO *adapterInfo = NULL;
IP_ADAPTER_INFO *adapter = NULL;
DWORD retval = 0;
UINT i;
ULONG size = 0;
if ((retval = GetAdaptersInfo(adapterInfo, &size)) != ERROR_BUFFER_OVERFLOW) {
dprintf("ERROR: %d\n", (int) retval);
return;
}
adapterInfo = (IP_ADAPTER_INFO *) malloc(size);
if (adapterInfo == NULL) {
dprintf("ERROR: out of memory\n");
return;
}
if ((retval = GetAdaptersInfo(adapterInfo, &size)) == NO_ERROR) {
adapter = adapterInfo;
while (adapter) {
IP_ADDR_STRING *address;
for (address = &adapter->IpAddressList; address != NULL; address = address->Next) {
if (address->IpAddress.String[0] != 0)
dprintf("ADDRESS: %s\n", address->IpAddress.String);
}
adapter = adapter->Next;
}
} else {
dprintf("ERROR: %d\n", (int) retval);
}
free(adapterInfo);
#else
struct ifaddrs *addrs, *ptr;
if (getifaddrs(&addrs) < 0) {
dprintf("ERROR: %s\n", strerror(errno));
return;
}
for (ptr = addrs; ptr != NULL; ptr = ptr->ifa_next) {
if (ptr->ifa_addr->sa_family == AF_INET) {
dprintf("ADDRESS: %s\n", inet_ntoa(((struct sockaddr_in *) ptr->ifa_addr)->sin_addr));
}
}
freeifaddrs(addrs);
#endif
}
void nat_test_update(void) {
static bool initialized;
if (!initialized) {
initialized = true;
printAddresses();
}
if (tries < MAX_TRIES && NOW - test_start > 30 * TINT_SEC) {
if (tries == 0) {
Address any;
SOCKET sock = Datagram::Bind(any, callbacks);
callbacks.sock = sock;
} else if (packets_since_last_try == 0) {
// Keep on trying if we didn't receive _any_ packet in response to our last request
tries--;
}
tries++;
callbacks.may_write = on_may_send;
Datagram::Listen3rdPartySocket(callbacks);
}
}
}