fixing mess with search update serialization and parenting
[oweals/gnunet.git] / src / transport / gnunet-nat-server-udp.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/transport/gnunet-nat-server-udp.c
23  * @brief Test for NAT traversal using ICMP method.
24  * @author Christian Grothoff
25  */
26 #include <sys/types.h> 
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36 #include <netinet/in.h> 
37 #include <time.h>
38
39
40
41 /**
42  * How often do we send our UDP messages to keep ports open (and to
43  * try to connect, of course).  Assuming the NAT closes UDP ports
44  * after 60s, we need at least about 100ms here for 512 ports;
45  * however, we should open the ports quickly (and we don't yet
46  * differentiate between the first round and later rounds), so we pick
47  * a much lower value here for now.
48  */
49 #define UDP_SEND_FREQUENCY_MS 50
50
51 /**
52  * Port we always try to use.
53  */
54 #define NAT_TRAV_PORT 22225
55
56 /**
57  * Number of UDP ports to keep open at the same time (typically >= 256).
58  * Should be less than FD_SETSIZE.
59  */
60 #define NUM_UDP_PORTS 1000
61
62 /**
63  * How often do we retry to open and bind a UDP socket before giving up?
64  */
65 #define MAX_BIND_TRIES 10
66
67 /**
68  * How long do we try at most?  We expect the other side to give
69  * up after about one minute for now.
70  */
71 #define MAX_DURATION 60000
72
73 #define LOW_PORT 32768
74
75 /**
76  * create a random port number that is not totally
77  * unlikely to be chosen by the nat box.
78  */
79 static uint16_t 
80 make_port ()
81 {
82   return LOW_PORT + ( (unsigned int)rand ()) % (64 * 1024 - LOW_PORT - 2);
83 }
84
85
86 /**
87  * create a fresh udp socket bound to a random local port,
88  * or, if the argument is zero, to the NAT_TRAV_PORT.
89  *
90  * @param i counter
91  * @return -1 on error
92  */
93 static int
94 make_udp_socket (int i)
95 {
96   int ret;
97   int tries;
98   struct sockaddr_in src;
99
100   for (tries=0;tries<MAX_BIND_TRIES;tries++)
101     {
102       ret = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
103       if (-1 == ret)
104         {
105           fprintf (stderr,
106                    "Error opening udp socket: %s\n",
107                    strerror (errno));
108           return -1;
109         }
110       if (ret >= FD_SETSIZE)
111         {
112           fprintf (stderr,
113                    "Socket number too large (%d > %u)\n",
114                    ret,
115                    (unsigned int) FD_SETSIZE);
116           close (ret);
117           return -1;
118         }
119       memset (&src, 0, sizeof (src));
120       src.sin_family = AF_INET;
121       if (i == 0)
122         src.sin_port = htons (NAT_TRAV_PORT);
123       else
124         src.sin_port = htons (make_port ());
125       if (0 != bind (ret, (struct sockaddr*) &src, sizeof (src)))
126         {
127           close (ret);
128           continue;
129         }
130       return ret;
131     }
132   fprintf (stderr,
133            "Error binding udp socket: %s\n",
134            strerror (errno));
135   return -1;
136 }
137
138
139 int
140 main (int argc, char *const *argv)
141 {
142   int udpsocks[NUM_UDP_PORTS];
143   char command[512];
144   struct in_addr external;
145   struct in_addr target;
146   int ret;
147   unsigned int pos;
148   int i;
149   int max;
150   struct sockaddr_in dst;
151   struct sockaddr_in src;
152   int first_round = 1;
153   char dummybuf[65536];
154   unsigned int tries;
155   struct timeval tv;
156   socklen_t slen;
157   fd_set rs;
158   time_t stime;
159  
160   if (argc != 3)
161     {
162       fprintf (stderr,
163                "This program must be started with our IP and the targets external IP as arguments.\n");
164       return 1;
165     }
166   if ( (1 != inet_pton (AF_INET, argv[1], &external)) ||
167        (1 != inet_pton (AF_INET, argv[2], &target)) )
168     {
169       fprintf (stderr,
170                "Error parsing IPv4 address: %s\n",
171                strerror (errno));
172       return 1;
173     }
174   fprintf (stderr,
175            "Trying to connect to %s\n",
176            argv[2]);
177   srand (stime = time(NULL));
178   for (i=0;i<NUM_UDP_PORTS;i++)
179     udpsocks[i] = make_udp_socket (i); 
180   memset (&dst, 0, sizeof (dst));
181   dst.sin_family = AF_INET;
182   dst.sin_addr = target;
183   pos = 0;
184   tries = 0;
185   while (stime + MAX_DURATION >= time (NULL))
186     {
187       tries++;
188       FD_ZERO (&rs);
189       for (i=0;i<NUM_UDP_PORTS;i++)
190         {
191           if (udpsocks[i] != -1)
192             FD_SET (udpsocks[i], &rs);
193           if (udpsocks[i] > max)
194             max = udpsocks[i];
195         }
196       tv.tv_sec = 0;
197       tv.tv_usec = UDP_SEND_FREQUENCY_MS * 1000;
198       select (max + 1, &rs, NULL, NULL, &tv);
199       for (i=0;i<NUM_UDP_PORTS;i++)
200         {
201           if (udpsocks[i] == -1)
202             continue;
203           if (! FD_ISSET (udpsocks[i], &rs))
204             continue;
205           slen = sizeof (src);
206           recvfrom (udpsocks[i], 
207                     dummybuf, sizeof (dummybuf), 0,
208                     (struct sockaddr*) &src,
209                     &slen);
210           if (slen != sizeof (src))
211             {
212               fprintf (stderr,
213                        "Unexpected size of address.\n");
214               continue;
215             }
216           if (0 != memcmp (&src.sin_addr,
217                            &target,
218                            sizeof (external)))
219             {
220               fprintf (stderr,
221                        "Unexpected sender IP\n");
222               continue;
223             }
224           /* discovered port! */
225           fprintf (stdout,
226                    "%s:%u\n",
227                    argv[2],
228                    ntohs (src.sin_port));
229           dst.sin_port = src.sin_port;
230           if (-1 == sendto (udpsocks[i],
231                             NULL, 0, 0,
232                             (struct sockaddr*) &dst, sizeof (dst)))
233             {
234               fprintf (stderr,
235                        "sendto failed: %s\n",
236                        strerror (errno));             
237               return 2; /* oops */
238             }     
239           /* success! */
240           fprintf (stderr,
241                    "Succeeded after %u packets.\n",
242                    tries);
243           return 0;
244         }
245       if (udpsocks[pos] == -1)
246         {
247           udpsocks[pos] = make_udp_socket (pos);
248           continue;
249         }
250       if ( (0 == ((unsigned int)rand() % NUM_UDP_PORTS)) ||
251            (1 == first_round) )
252         dst.sin_port = htons (NAT_TRAV_PORT);
253       else
254         dst.sin_port = htons (make_port ());
255       fprintf (stderr,
256                "Sending UDP packet to `%s:%u'\n",
257                argv[2],
258                ntohs (dst.sin_port));
259       first_round = 0;
260       if (-1 == sendto (udpsocks[pos],
261                         NULL, 0, 0,
262                         (struct sockaddr*) &dst, sizeof (dst)))
263         {
264           fprintf (stderr,
265                    "sendto failed: %s\n",
266                    strerror (errno));
267           close (udpsocks[pos]);
268           udpsocks[pos] = make_udp_socket (pos);
269         }
270       pos = (pos+1) % NUM_UDP_PORTS;
271     }
272   fprintf (stderr,
273            "Giving up after %u tries.\n",
274            tries);
275   return 3;
276 }
277
278 /* end of server-test.c */