]> sjero.net Git - iperf/blob - src/SocketAddr.c
0278bdf935260ccb37cdf02526220bd8d4380f4b
[iperf] / src / SocketAddr.c
1 /*--------------------------------------------------------------- 
2  * Copyright (c) 1999,2000,2001,2002,2003                              
3  * The Board of Trustees of the University of Illinois            
4  * All Rights Reserved.                                           
5  *--------------------------------------------------------------- 
6  * Permission is hereby granted, free of charge, to any person    
7  * obtaining a copy of this software (Iperf) and associated       
8  * documentation files (the "Software"), to deal in the Software  
9  * without restriction, including without limitation the          
10  * rights to use, copy, modify, merge, publish, distribute,        
11  * sublicense, and/or sell copies of the Software, and to permit     
12  * persons to whom the Software is furnished to do
13  * so, subject to the following conditions: 
14  *
15  *     
16  * Redistributions of source code must retain the above 
17  * copyright notice, this list of conditions and 
18  * the following disclaimers. 
19  *
20  *     
21  * Redistributions in binary form must reproduce the above 
22  * copyright notice, this list of conditions and the following 
23  * disclaimers in the documentation and/or other materials 
24  * provided with the distribution. 
25  * 
26  *     
27  * Neither the names of the University of Illinois, NCSA, 
28  * nor the names of its contributors may be used to endorse 
29  * or promote products derived from this Software without
30  * specific prior written permission. 
31  * 
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
33  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
34  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
35  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT 
36  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
37  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
38  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
40  * ________________________________________________________________
41  * National Laboratory for Applied Network Research 
42  * National Center for Supercomputing Applications 
43  * University of Illinois at Urbana-Champaign 
44  * http://www.ncsa.uiuc.edu
45  * ________________________________________________________________ 
46  *
47  * Socket.cpp
48  * by       Ajay Tirumala <tirumala@ncsa.uiuc.edu>
49  * and      Mark Gates <mgates@nlanr.net>
50  * ------------------------------------------------------------------- */
51
52 #define HEADERS()
53
54 #include "headers.h"
55
56 #include "SocketAddr.h"
57
58
59 #ifdef __cplusplus
60 extern "C" {
61 #endif
62 /* -------------------------------------------------------------------
63  * Create a socket address. If inHostname is not null, resolve that
64  * address and fill it in. Fill in the port number. Use IPv6 ADDR_ANY
65  * if that is what is desired.
66  * ------------------------------------------------------------------- */
67
68 void SockAddr_remoteAddr( thread_Settings *inSettings ) {
69     SockAddr_zeroAddress( &inSettings->peer );
70     if ( inSettings->mHost != NULL ) {
71         SockAddr_setHostname( inSettings->mHost, &inSettings->peer, 
72                               isIPV6( inSettings ) );
73     } else {
74 #ifdef HAVE_IPV6
75         if ( isIPV6( inSettings ) ) {
76             ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET6;
77         } else {
78             ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET;
79         }
80     }
81
82     if ( SockAddr_isIPv6( &inSettings->peer ) ) {
83         inSettings->size_peer = sizeof( struct sockaddr_in6 );
84     } else {
85         inSettings->size_peer = sizeof( struct sockaddr_in );
86     }
87 #else
88         ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET;
89     }
90     inSettings->size_peer = sizeof( struct sockaddr_in );
91 #endif
92     SockAddr_setPort( &inSettings->peer, inSettings->mPort );
93 }
94 // end SocketAddr
95
96 void SockAddr_localAddr( thread_Settings *inSettings ) {
97     SockAddr_zeroAddress( &inSettings->local );
98     if ( inSettings->mLocalhost != NULL ) {
99         SockAddr_setHostname( inSettings->mLocalhost, &inSettings->local, 
100                               isIPV6( inSettings ) );
101     } else {
102 #ifdef HAVE_IPV6
103         if ( isIPV6( inSettings ) ) {
104             ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET6;
105         } else {
106             ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET;
107         }
108     }
109
110     if ( SockAddr_isIPv6( &inSettings->local ) ) {
111         inSettings->size_local = sizeof( struct sockaddr_in6 );
112     } else {
113         inSettings->size_local = sizeof( struct sockaddr_in );
114     }
115 #else
116         ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET;
117     }
118         inSettings->size_local = sizeof( struct sockaddr_in );
119 #endif
120     SockAddr_setPort( &inSettings->local, inSettings->mPort );
121 }
122 // end SocketAddr
123
124 /* -------------------------------------------------------------------
125  * Resolve the hostname address and fill it in.
126  * ------------------------------------------------------------------- */
127
128 void SockAddr_setHostname( const char* inHostname, 
129                            iperf_sockaddr *inSockAddr, 
130                            int isIPv6 ) {
131
132     // ..I think this works for both ipv6 & ipv4... we'll see
133 #if defined(HAVE_IPV6)
134     {
135         struct addrinfo *res, *itr;
136         int ret_ga;
137
138         ret_ga = getaddrinfo(inHostname, NULL, NULL, &res);
139         if ( ret_ga ) {
140             fprintf(stderr, "error: %s\n", gai_strerror(ret_ga));
141             exit(1);
142         }
143         if ( !res->ai_addr ) {
144             fprintf(stderr, "getaddrinfo failed to get an address... target was '%s'\n", inHostname);
145             exit(1);
146         }
147
148         // Check address type before filling in the address
149         // ai_family = PF_xxx; ai_protocol = IPPROTO_xxx, see netdb.h
150         // ...but AF_INET6 == PF_INET6
151         itr = res;
152         if ( isIPv6 ) {
153             // First check all results for a IPv6 Address
154             while ( itr != NULL ) {
155                 if ( itr->ai_family == AF_INET6 ) {
156                     memcpy(inSockAddr, (itr->ai_addr),
157                            (itr->ai_addrlen));
158                     freeaddrinfo(res);
159                     return;
160                 } else {
161                     itr = itr->ai_next;
162                 }
163             }
164         }
165         itr = res;
166         // Now find a IPv4 Address
167         while ( itr != NULL ) {
168             if ( itr->ai_family == AF_INET ) {
169                 memcpy(inSockAddr, (itr->ai_addr),
170                        (itr->ai_addrlen));
171                 freeaddrinfo(res);
172                 return;
173             } else {
174                 itr = itr->ai_next;
175             }
176         }
177     }
178 #else
179     // first try just converting dotted decimal
180     // on Windows gethostbyname doesn't understand dotted decimal
181     int rc = inet_pton( AF_INET, inHostname, 
182                         (unsigned char*)&(((struct sockaddr_in*)inSockAddr)->sin_addr) );
183     inSockAddr->sin_family = AF_INET;
184     if ( rc == 0 ) {
185         struct hostent *hostP = gethostbyname( inHostname );
186         if ( hostP == NULL ) {
187             /* this is the same as herror() but works on more systems */
188             const char* format;
189             switch ( h_errno ) {
190                 case HOST_NOT_FOUND:
191                     format = "%s: Unknown host\n";
192                     break;
193                 case NO_ADDRESS:
194                     format = "%s: No address associated with name\n";
195                     break;
196                 case NO_RECOVERY:
197                     format = "%s: Unknown server error\n";
198                     break;
199                 case TRY_AGAIN:
200                     format = "%s: Host name lookup failure\n";
201                     break;
202
203                 default:
204                     format = "%s: Unknown resolver error\n";
205                     break;
206             }
207             fprintf( stderr, format, inHostname );
208             exit(1);
209
210             return; // TODO throw
211         }
212
213         memcpy(&(((struct sockaddr_in*)inSockAddr)->sin_addr), *(hostP->h_addr_list),
214                (hostP->h_length));
215     }
216 #endif
217 }
218 // end setHostname
219
220 /* -------------------------------------------------------------------
221  * Copy the IP address into the string.
222  * ------------------------------------------------------------------- */
223 void SockAddr_getHostAddress( iperf_sockaddr *inSockAddr, char* outAddress, 
224                                 size_t len ) {
225     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET ) {
226         inet_ntop( AF_INET, &(((struct sockaddr_in*) inSockAddr)->sin_addr), 
227                    outAddress, len);
228     }
229 #ifdef HAVE_IPV6
230     else {
231         inet_ntop( AF_INET6, &(((struct sockaddr_in6*) inSockAddr)->sin6_addr), 
232                    outAddress, len);
233     }
234 #endif
235 }
236 // end getHostAddress
237
238 /* -------------------------------------------------------------------
239  * Set the address to any (generally all zeros).
240  * ------------------------------------------------------------------- */
241
242 void SockAddr_setAddressAny( iperf_sockaddr *inSockAddr ) {
243     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
244         memset( &(((struct sockaddr_in*) inSockAddr)->sin_addr), 0, 
245                 sizeof( struct in_addr ));
246 #if defined(HAVE_IPV6)  
247     else
248         memset( &(((struct sockaddr_in6*) inSockAddr)->sin6_addr), 0, 
249                 sizeof( struct in6_addr ));
250 #endif
251 }
252 // end setAddressAny
253
254 /* -------------------------------------------------------------------
255  * Set the port to the given port. Handles the byte swapping.
256  * ------------------------------------------------------------------- */
257
258 void SockAddr_setPort( iperf_sockaddr *inSockAddr, unsigned short inPort ) {
259     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
260         ((struct sockaddr_in*) inSockAddr)->sin_port = htons( inPort );
261 #if defined(HAVE_IPV6)  
262     else
263         ((struct sockaddr_in6*) inSockAddr)->sin6_port = htons( inPort );
264 #endif
265
266 }
267 // end setPort
268
269 /* -------------------------------------------------------------------
270  * Set the port to zero, which lets the OS pick the port.
271  * ------------------------------------------------------------------- */
272
273 void SockAddr_setPortAny( iperf_sockaddr *inSockAddr ) {
274     SockAddr_setPort( inSockAddr, 0 );
275 }
276 // end setPortAny
277
278 /* -------------------------------------------------------------------
279  * Return the port. Handles the byte swapping.
280  * ------------------------------------------------------------------- */
281
282 unsigned short SockAddr_getPort( iperf_sockaddr *inSockAddr ) {
283     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
284         return ntohs( ((struct sockaddr_in*) inSockAddr)->sin_port );
285 #if defined(HAVE_IPV6)
286     else
287         return ntohs( ((struct sockaddr_in6*) inSockAddr)->sin6_port);
288 #endif
289     return 0;
290
291 }
292 // end getPort
293
294 /* -------------------------------------------------------------------
295  * Return the IPv4 Internet Address from the sockaddr_in structure
296  * ------------------------------------------------------------------- */
297
298 struct in_addr* SockAddr_get_in_addr( iperf_sockaddr *inSockAddr ) {
299     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET )
300         return &(((struct sockaddr_in*) inSockAddr)->sin_addr);
301
302     fprintf(stderr, "FATAL: get_in_addr called on IPv6 address\n");
303     return NULL;
304 }
305
306 /* -------------------------------------------------------------------
307  * Return the IPv6 Internet Address from the sockaddr_in6 structure
308  * ------------------------------------------------------------------- */
309 #ifdef HAVE_IPV6
310 struct in6_addr* SockAddr_get_in6_addr( iperf_sockaddr *inSockAddr ) {
311     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 )
312         return &(((struct sockaddr_in6*) inSockAddr)->sin6_addr);
313
314     fprintf(stderr, "FATAL: get_in6_addr called on IPv4 address\n");
315     return NULL;
316 }
317 #endif
318
319
320 /* -------------------------------------------------------------------
321  * Return the size of the appropriate address structure.
322  * ------------------------------------------------------------------- */
323
324 Socklen_t SockAddr_get_sizeof_sockaddr( iperf_sockaddr *inSockAddr ) {
325
326 #if defined(HAVE_IPV6)
327     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
328         return(sizeof(struct sockaddr_in6));
329     }
330 #endif
331     return(sizeof(struct sockaddr_in));
332 }
333 // end get_sizeof_sockaddr
334
335
336 /* -------------------------------------------------------------------
337  * Return if IPv6 socket
338  * ------------------------------------------------------------------- */
339
340 int SockAddr_isIPv6( iperf_sockaddr *inSockAddr ) {
341
342 #if defined(HAVE_IPV6)
343     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
344         return 1;
345     }
346 #endif
347     return 0;
348 }
349 // end get_sizeof_sockaddr
350
351 /* -------------------------------------------------------------------
352  * Return true if the address is a IPv4 multicast address.
353  * ------------------------------------------------------------------- */
354
355 int SockAddr_isMulticast( iperf_sockaddr *inSockAddr ) {
356
357 #if defined(HAVE_IPV6)
358     if ( ((struct sockaddr*)inSockAddr)->sa_family == AF_INET6 ) {
359         return( IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6*) inSockAddr)->sin6_addr) ));
360     } else
361 #endif
362     {
363         // 224.0.0.0 to 239.255.255.255 (e0.00.00.00 to ef.ff.ff.ff)
364         const unsigned long kMulticast_Mask = 0xe0000000L;
365
366         return(kMulticast_Mask ==
367                (ntohl( ((struct sockaddr_in*) inSockAddr)->sin_addr.s_addr) & kMulticast_Mask));
368     }
369 }
370 // end isMulticast
371
372 /* -------------------------------------------------------------------
373  * Zero out the address structure.
374  * ------------------------------------------------------------------- */
375
376 void SockAddr_zeroAddress( iperf_sockaddr *inSockAddr ) {
377     memset( inSockAddr, 0, sizeof( iperf_sockaddr ));
378 }
379 // zeroAddress
380
381 /* -------------------------------------------------------------------
382  * Compare two sockaddrs and return true if they are equal
383  * ------------------------------------------------------------------- */
384 int SockAddr_are_Equal( struct sockaddr* first, struct sockaddr* second ) {
385     if ( first->sa_family == AF_INET && second->sa_family == AF_INET ) {
386         // compare IPv4 adresses
387         return( ((long) ((struct sockaddr_in*)first)->sin_addr.s_addr == (long) ((struct sockaddr_in*)second)->sin_addr.s_addr)
388                 && ( ((struct sockaddr_in*)first)->sin_port == ((struct sockaddr_in*)second)->sin_port) );
389     }
390 #if defined(HAVE_IPV6)      
391     if ( first->sa_family == AF_INET6 && second->sa_family == AF_INET6 ) {
392         // compare IPv6 addresses
393         return( !memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr, ((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr)) 
394                 && (((struct sockaddr_in6*)first)->sin6_port == ((struct sockaddr_in6*)second)->sin6_port) );
395     }
396 #endif 
397     return 0;
398
399 }
400
401 /* -------------------------------------------------------------------
402  * Compare two sockaddrs and return true if the hosts are equal
403  * ------------------------------------------------------------------- */
404 int SockAddr_Hostare_Equal( struct sockaddr* first, struct sockaddr* second ) {
405     if ( first->sa_family == AF_INET && second->sa_family == AF_INET ) {
406         // compare IPv4 adresses
407         return( (long) ((struct sockaddr_in*)first)->sin_addr.s_addr == 
408                 (long) ((struct sockaddr_in*)second)->sin_addr.s_addr);
409     }
410 #if defined(HAVE_IPV6)      
411     if ( first->sa_family == AF_INET6 && second->sa_family == AF_INET6 ) {
412         // compare IPv6 addresses
413         return( !memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr, 
414                         ((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr)));
415     }
416 #endif 
417     return 0;
418
419 }
420 #ifdef __cplusplus
421 } /* end extern "C" */
422 #endif