Add counters for MPTP buffers and syscalls.
[swifty.git] / src / libswift / nat_test.cpp
1 /*
2  *  nat_test.cpp
3  *  NAT type testing.
4  *
5  *  Created by Gertjan Halkes.
6  *  Copyright 2010 Delft University of Technology. All rights reserved.
7  *
8  */
9
10 #include "swift.h"
11 #ifdef _WIN32
12 #include <iphlpapi.h>
13 #else
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <ifaddrs.h>
17 #include <errno.h>
18 #include <netinet/in.h>
19 #endif
20
21 #define REQUEST_MAGIC 0x5a9e5fa1
22 #define REPLY_MAGIC 0xa655c5d5
23 #define REPLY_SEC_MAGIC 0x85e4a5ca
24 #define MAX_TRIES 3
25 namespace swift {
26
27 static void on_may_receive(SOCKET sock);
28 static void on_may_send(SOCKET sock);
29 static tint test_start;
30 static int tries;
31 static int packets_since_last_try;
32
33 static sckrwecb_t callbacks(0, on_may_receive, on_may_send, NULL);
34 /* Note that we lookup the addresses when we actually send, because Windows requires that
35    the winsock library is first intialized. If we use Address type variables here, the
36    lookup would be tried before that initialization, which fails... */
37 //FIXME: Change addresses to actual addresses used in test (at least 2 should be provided!)
38 static const char *servers[] = { "dutigp.st.ewi.tudelft.nl:18375" ,
39     "127.0.0.3:18375" };
40
41 static void on_may_receive(SOCKET sock) {
42     Datagram data(sock);
43
44     data.Recv();
45
46     uint32_t magic = data.Pull32();
47     if ((magic != REPLY_MAGIC && magic != REPLY_SEC_MAGIC) ||
48             (magic == REPLY_MAGIC && data.size() != 6) || (magic == REPLY_SEC_MAGIC && data.size() != 0))
49     {
50         dprintf("%s #0 NATTEST weird packet %s \n", tintstr(), data.address().str());
51         return;
52     }
53
54     if (magic == REPLY_MAGIC) {
55         uint32_t ip = data.Pull32();
56         uint16_t port = data.Pull16();
57         Address reported(ip, port);
58         dprintf("%s #0 NATTEST incoming %s %s\n", tintstr(), data.address().str(), reported.str());
59     } else {
60         dprintf("%s #0 NATTEST incoming secondary %s\n", tintstr(), data.address().str());
61     }
62     packets_since_last_try++;
63 }
64
65 static void on_may_send(SOCKET sock) {
66     callbacks.may_write = NULL;
67     Datagram::Listen3rdPartySocket(callbacks);
68
69     for (size_t i = 0; i < (sizeof(servers)/sizeof(servers[0])); i++) {
70         Datagram request(sock, Address(servers[i]));
71
72         request.Push32(REQUEST_MAGIC);
73         request.Send();
74     }
75     test_start = NOW;
76
77     struct sockaddr_in name;
78     socklen_t namelen = sizeof(name);
79     if (getsockname(sock, (struct sockaddr *) &name, &namelen) < 0) {
80         dprintf("%s #0 NATTEST could not get local address\n", tintstr());
81     } else {
82         Address local(ntohl(name.sin_addr.s_addr), ntohs(name.sin_port));
83         dprintf("%s #0 NATTEST local %s\n", tintstr(), local.str());
84     }
85 }
86
87 static void printAddresses(void) {
88 #ifdef _WIN32
89     IP_ADAPTER_INFO *adapterInfo = NULL;
90     IP_ADAPTER_INFO *adapter = NULL;
91     DWORD retval = 0;
92     UINT i;
93     ULONG size = 0;
94
95     if ((retval = GetAdaptersInfo(adapterInfo, &size)) != ERROR_BUFFER_OVERFLOW) {
96         dprintf("ERROR: %d\n", (int) retval);
97         return;
98     }
99
100     adapterInfo = (IP_ADAPTER_INFO *) malloc(size);
101     if (adapterInfo == NULL) {
102         dprintf("ERROR: out of memory\n");
103         return;
104     }
105
106     if ((retval = GetAdaptersInfo(adapterInfo, &size)) == NO_ERROR) {
107         adapter = adapterInfo;
108         while (adapter) {
109             IP_ADDR_STRING *address;
110             for (address = &adapter->IpAddressList; address != NULL; address = address->Next) {
111                 if (address->IpAddress.String[0] != 0)
112                     dprintf("ADDRESS: %s\n", address->IpAddress.String);
113             }
114             adapter = adapter->Next;
115         }
116     } else {
117         dprintf("ERROR: %d\n", (int) retval);
118     }
119     free(adapterInfo);
120 #else
121     struct ifaddrs *addrs, *ptr;
122     if (getifaddrs(&addrs) < 0) {
123         dprintf("ERROR: %s\n", strerror(errno));
124         return;
125     }
126
127     for (ptr = addrs; ptr != NULL; ptr = ptr->ifa_next) {
128         if (ptr->ifa_addr->sa_family == AF_INET) {
129             dprintf("ADDRESS: %s\n", inet_ntoa(((struct sockaddr_in *) ptr->ifa_addr)->sin_addr));
130         }
131     }
132     freeifaddrs(addrs);
133 #endif
134 }
135
136
137 void nat_test_update(void) {
138     static bool initialized;
139     if (!initialized) {
140         initialized = true;
141         printAddresses();
142     }
143
144     if (tries < MAX_TRIES && NOW - test_start > 30 * TINT_SEC) {
145         if (tries == 0) {
146             Address any;
147             SOCKET sock = Datagram::Bind(any, callbacks);
148             callbacks.sock = sock;
149         } else if (packets_since_last_try == 0) {
150             // Keep on trying if we didn't receive _any_ packet in response to our last request
151             tries--;
152         }
153         tries++;
154         callbacks.may_write = on_may_send;
155         Datagram::Listen3rdPartySocket(callbacks);
156     }
157 }
158
159 }