1 #include <cassert>
2 #include <cstring>
3 #include <iostream>
4 #include <cstdlib>
5
6 #ifdef WIN32
7 #include <time.h>
8 #else
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <netinet/in.h>
13 #include <errno.h>
14 #endif
15
16 #include "udp.h"
17 #include "stun.h"
18
19 using namespace std;
20
21
22 void
usage()23 usage()
24 {
25 cerr << "Usage:" << endl
26 << " ./client stunServerHostname [testNumber] [-v] [-p srcPort] [-i nicAddr1] [-i nicAddr2] [-i nicAddr3]" << endl
27 << "For example, if the STUN server was larry.gloo.net, you could do:" << endl
28 << " ./client larry.gloo.net" << endl
29 << "The testNumber is just used for special tests." << endl
30 << " test 1 runs test 1 from the RFC. For example:" << endl
31 << " ./client larry.gloo.net 0" << endl << endl
32 << endl;
33 }
34
35 #define MAX_NIC 3
36
37 int
main(int argc,char * argv[])38 main(int argc, char* argv[])
39 {
40 assert( sizeof(UInt8 ) == 1 );
41 assert( sizeof(UInt16) == 2 );
42 assert( sizeof(UInt32) == 4 );
43
44 initNetwork();
45
46 cout << "STUN client version " << STUN_VERSION << endl;
47
48 int testNum = 0;
49 bool verbose = false;
50
51 StunAddress4 stunServerAddr;
52 stunServerAddr.addr=0;
53
54 int srcPort=0;
55 StunAddress4 sAddr[MAX_NIC];
56 int retval[MAX_NIC];
57 int numNic=0;
58
59 for ( int i=0; i<MAX_NIC; i++ )
60 {
61 sAddr[i].addr=0;
62 sAddr[i].port=0;
63 retval[i]=0;
64 }
65
66 for ( int arg = 1; arg<argc; arg++ )
67 {
68 if ( !strcmp( argv[arg] , "-v" ) )
69 {
70 verbose = true;
71 }
72 else if ( !strcmp( argv[arg] , "-i" ) )
73 {
74 arg++;
75 if ( argc <= arg )
76 {
77 usage();
78 exit(-1);
79 }
80 if ( numNic >= MAX_NIC )
81 {
82 cerr << "Can not have more than "<< MAX_NIC <<" -i options" << endl;
83 usage();
84 exit(-1);
85 }
86
87 stunParseServerName(argv[arg], sAddr[numNic++]);
88 }
89 else if ( !strcmp( argv[arg] , "-p" ) )
90 {
91 arg++;
92 if ( argc <= arg )
93 {
94 usage();
95 exit(-1);
96 }
97 srcPort = strtol( argv[arg], NULL, 10);
98 }
99 else
100 {
101 char* ptr;
102 int t = strtol( argv[arg], &ptr, 10 );
103 if ( *ptr == 0 )
104 {
105 // conversion worked
106 testNum = t;
107 cout << "running test number " << testNum << endl;
108 }
109 else
110 {
111 bool ret = stunParseServerName( argv[arg], stunServerAddr);
112 if ( ret != true )
113 {
114 cerr << argv[arg] << " is not a valid host name " << endl;
115 usage();
116 exit(-1);
117 }
118 }
119 }
120 }
121
122 if ( srcPort == 0 )
123 {
124 srcPort = stunRandomPort();
125 }
126
127 if ( numNic == 0 )
128 {
129 // use default
130 numNic = 1;
131 }
132
133 for ( int nic=0; nic<numNic; nic++ )
134 {
135 sAddr[nic].port=srcPort;
136 if ( stunServerAddr.addr == 0 )
137 {
138 usage();
139 exit(-1);
140 }
141
142 if (testNum==0)
143 {
144 bool presPort=false;
145 bool hairpin=false;
146
147 NatType stype = stunNatType( stunServerAddr, verbose, &presPort, &hairpin,
148 srcPort, &sAddr[nic]);
149
150 if ( nic == 0 )
151 {
152 cout << "Primary: ";
153 }
154 else
155 {
156 cout << "Secondary: ";
157 }
158
159 switch (stype)
160 {
161 case StunTypeFailure:
162 cout << "Some stun error detetecting NAT type";
163 retval[nic] = -1;
164 exit(-1);
165 break;
166 case StunTypeUnknown:
167 cout << "Some unknown type error detetecting NAT type";
168 retval[nic] = 0xEE;
169 break;
170 case StunTypeOpen:
171 cout << "Open";
172 retval[nic] = 0x00;
173 break;
174 case StunTypeIndependentFilter:
175 cout << "Independent Mapping, Independent Filter";
176 if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
177 if ( hairpin ) cout << ", will hairpin"; else cout << ", no hairpin";
178 retval[nic] = 0x02;
179 break;
180 case StunTypeDependentFilter:
181 cout << "Independedt Mapping, Address Dependendent Filter";
182 if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
183 if ( hairpin ) cout << ", will hairpin"; else cout << ", no hairpin";
184 retval[nic] = 0x04;
185 break;
186 case StunTypePortDependedFilter:
187 cout << "Indepndent Mapping, Port Dependent Filter";
188 if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
189 if ( hairpin ) cout << ", will hairpin"; else cout << ", no hairpin";
190 retval[nic] = 0x06;
191 break;
192 case StunTypeDependentMapping:
193 cout << "Dependent Mapping";
194 if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
195 if ( hairpin ) cout << ", will hairpin"; else cout << ", no hairpin";
196 retval[nic] = 0x08;
197 break;
198 case StunTypeFirewall:
199 cout << "Firewall";
200 retval[nic] = 0x0A;
201 break;
202 case StunTypeBlocked:
203 cout << "Blocked or could not reach STUN server";
204 retval[nic] = 0x0C;
205 break;
206 default:
207 cout << stype;
208 cout << "Unkown NAT type";
209 retval[nic] = 0x0E; // Unknown NAT type
210 break;
211 }
212 cout << "\t"; cout.flush();
213
214 if (!hairpin)
215 {
216 retval[nic] |= 0x10;
217 }
218
219 if (presPort)
220 {
221 retval[nic] |= 0x01;
222 }
223 }
224 else if (testNum==100)
225 {
226 Socket myFd = openPort(srcPort,sAddr[nic].addr,verbose);
227
228 StunMessage req;
229 memset(&req, 0, sizeof(StunMessage));
230
231 StunAtrString username;
232 StunAtrString password;
233 username.sizeValue = 0;
234 password.sizeValue = 0;
235
236 stunBuildReqSimple( &req, username,
237 false , false ,
238 0x0c );
239
240 char buf[STUN_MAX_MESSAGE_SIZE];
241 int len = STUN_MAX_MESSAGE_SIZE;
242
243 len = stunEncodeMessage( req, buf, len, password,verbose );
244
245 if ( verbose )
246 {
247 cout << "About to send msg of len " << len
248 << " to " << stunServerAddr << endl;
249 }
250
251 while (1)
252 {
253 for ( int i=0; i<100; i++ )
254 {
255 sendMessage( myFd,
256 buf, len,
257 stunServerAddr.addr,
258 stunServerAddr.port,verbose );
259 }
260 #ifdef WIN32 // !cj! TODO - should fix this up in windows
261 clock_t now = clock();
262 assert( CLOCKS_PER_SEC == 1000 );
263 while ( clock() <= now+10 ) { };
264 #else
265 usleep(10*1000);
266 #endif
267 }
268 }
269 else if (testNum==-2)
270 {
271 const int numPort = 5;
272 int fd[numPort];
273 StunAddress4 mappedAddr;
274
275 for( int i=0; i<numPort; i++ )
276 {
277 fd[i] = stunOpenSocket( stunServerAddr, &mappedAddr,
278 (srcPort==0)?0:(srcPort+i), &sAddr[nic],
279 verbose );
280 cout << "Got port at " << mappedAddr.port << endl;
281 }
282
283 for( int i=0; i<numPort; i++ )
284 {
285 closesocket(fd[i]);
286 }
287 }
288 else if (testNum==-1)
289 {
290 int fd3,fd4;
291 StunAddress4 mappedAddr;
292
293 bool ok = stunOpenSocketPair(stunServerAddr,
294 &mappedAddr,
295 &fd3,
296 &fd4,
297 srcPort,
298 &sAddr[nic],
299 verbose);
300 if ( ok )
301 {
302 closesocket(fd3);
303 closesocket(fd4);
304 cout << "Got port pair at " << mappedAddr.port << endl;
305 }
306 else
307 {
308 cerr << "Opened a stun socket pair FAILED" << endl;
309 }
310 }
311 else
312 {
313 stunTest( stunServerAddr,testNum,verbose,&(sAddr[nic]) );
314 }
315 } // end of for loop
316 cout << endl;
317
318 UInt32 ret=0;
319 for ( int i=numNic-1; i>=0; i-- )
320 {
321 if ( retval[i] == -1 )
322 {
323 ret = 0xFFFFFFFF;
324 break;
325 }
326 ret = ret << 8;
327 ret = ret | ( retval[i] & 0xFF );
328 }
329
330 cout << "Return value is " << hex << "0x";
331 cout.fill('0');
332 cout.width(6);
333 cout << ret << dec << endl;
334 cout.fill(' ');
335
336 return ret;
337 }
338
339
340 /* ====================================================================
341 * The Vovida Software License, Version 1.0
342 *
343 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
344 *
345 * Redistribution and use in source and binary forms, with or without
346 * modification, are permitted provided that the following conditions
347 * are met:
348 *
349 * 1. Redistributions of source code must retain the above copyright
350 * notice, this list of conditions and the following disclaimer.
351 *
352 * 2. Redistributions in binary form must reproduce the above copyright
353 * notice, this list of conditions and the following disclaimer in
354 * the documentation and/or other materials provided with the
355 * distribution.
356 *
357 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
358 * and "Vovida Open Communication Application Library (VOCAL)" must
359 * not be used to endorse or promote products derived from this
360 * software without prior written permission. For written
361 * permission, please contact vocal@vovida.org.
362 *
363 * 4. Products derived from this software may not be called "VOCAL", nor
364 * may "VOCAL" appear in their name, without prior written
365 * permission of Vovida Networks, Inc.
366 *
367 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
368 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
369 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
370 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
371 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
372 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
373 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
374 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
375 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
376 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
377 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
378 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
379 * DAMAGE.
380 *
381 * ====================================================================
382 *
383 * This software consists of voluntary contributions made by Vovida
384 * Networks, Inc. and many individuals on behalf of Vovida Networks,
385 * Inc. For more information on Vovida Networks, Inc., please see
386 * <http://www.vovida.org/>.
387 *
388 */
389
390 // Local Variables:
391 // mode:c++
392 // c-file-style:"ellemtel"
393 // c-file-offsets:((case-label . +))
394 // indent-tabs-mode:nil
395 // End:
396