|
PAPI
5.0.1.0
|
00001 /****************************************************************************** 00002 * File: pit_server.c 00003 * 00004 * Description: Contains source code for an IPv6-capable 'PIT' server. 00005 * This is a derivative of the tod6 (time-of-day) server that was written 00006 * by John Wenker. 00007 * ....... 00008 * Author of tod6: John Wenker, Sr. Software Engineer, 00009 * Performance Technologies, San Diego, USA 00010 * ....... 00011 * The program tod6 was a time of day server. It has beeen modified 00012 * to provide a microsecond timestamp on request. Modified and adapted 00013 * for PIT purposes by Don Capps. [ capps@iozone.org ] 00014 * 00015 * This server sends the current value of gettimeofday() in 00016 * microseconds back to the client, as a numerical string. 00017 * 00018 * /etc/services should contain "PIT" with a specified port value. 00019 * 00020 ******************************************************************************/ 00021 /* 00022 ** System header files. 00023 */ 00024 #include <errno.h> /* errno declaration & error codes. */ 00025 #include <netdb.h> /* getaddrinfo(3) et al. */ 00026 #include <netinet/in.h> /* sockaddr_in & sockaddr_in6 definition. */ 00027 #include <stdio.h> /* printf(3) et al. */ 00028 #include <stdlib.h> /* exit(2). */ 00029 #include <string.h> /* String manipulation & memory functions. */ 00030 #if defined(_SUA_) 00031 #include <poll.h> /* poll(2) and related definitions. */ 00032 #else 00033 #include <sys/poll.h> /* poll(2) and related definitions. */ 00034 #endif 00035 #include <sys/socket.h> /* Socket functions (socket(2), bind(2), etc). */ 00036 #include <time.h> /* time(2) & ctime(3). */ 00037 #include <sys/time.h> /* gettimeofday */ 00038 #include <unistd.h> /* getopt(3), read(2), etc. */ 00039 /* Include for Cygnus development environment for Windows */ 00040 #if defined (Windows) 00041 #include <Windows.h> 00042 int errno; 00043 #endif 00044 00045 #if defined(_SUA_) 00046 extern char *optarg, *opterr; 00047 #endif 00048 00049 /* 00050 ** Constants. 00051 ** 00052 ** Please remember to add PIT service to the /etc/services file. 00053 */ 00054 #define DFLT_SERVICE "PIT" /* Programmable Interdimensional Timer */ 00055 00056 #define INVALID_DESC -1 /* Invalid file descriptor. */ 00057 #define MAXCONNQLEN 3 /* Max nbr of connection requests to queue. */ 00058 #define MAXTCPSCKTS 2 /* One TCP socket for IPv4 & one for IPv6. */ 00059 #define MAXUDPSCKTS 2 /* One UDP socket for IPv4 & one for IPv6. */ 00060 #define VALIDOPTS "vh:p:" /* Valid command options. */ 00061 /* 00062 ** Simple boolean type definition. 00063 */ 00064 int false = 0; 00065 int true = 1; 00066 /* 00067 ** Prototypes for internal helper functions. 00068 */ 00069 static int openSckt( const char *service, 00070 const char *protocol, 00071 int desc[ ], 00072 size_t *descSize ); 00073 static void pit( int tSckt[ ], 00074 size_t tScktSize, 00075 int uSckt[ ], 00076 size_t uScktSize ); 00077 /* 00078 ** Global data objects. 00079 */ 00080 static char hostBfr[ NI_MAXHOST ]; /* For use w/getnameinfo(3). */ 00081 static const char *pgmName; /* Program name w/o dir prefix. */ 00082 static char servBfr[ NI_MAXSERV ]; /* For use w/getnameinfo(3). */ 00083 static int verbose = 0; /* Verbose mode indication. */ 00084 struct timeval tm; /* Timeval structure, used with gettimeofday() */ 00085 char timeStr[40]; /* String for time in microseconds */ 00086 char service_name[20]; 00087 int need; 00088 /* 00089 ** Usage macro for command syntax violations. 00090 */ 00091 #define USAGE \ 00092 { \ 00093 fprintf( stderr, \ 00094 "Usage: %s [-v] -p service \n", \ 00095 pgmName ); \ 00096 exit( 127 ); \ 00097 } /* End USAGE macro. */ 00098 /* 00099 ** Macro to terminate the program if a system call error occurs. The system 00100 ** call must be one of the usual type that returns -1 on error. 00101 */ 00102 #define CHK(expr) \ 00103 do \ 00104 { \ 00105 if ( (expr) == -1 ) \ 00106 { \ 00107 fprintf( stderr, \ 00108 "%s (line %d): System call ERROR - %s.\n", \ 00109 pgmName, \ 00110 __LINE__, \ 00111 strerror( errno ) ); \ 00112 exit( 1 ); \ 00113 } /* End IF system call failed. */ \ 00114 } while ( false ) 00115 /****************************************************************************** 00116 * Function: main 00117 * 00118 * Description: 00119 * Set up a PIT server and handle network requests. This server 00120 * handles both TCP and UDP requests. 00121 * 00122 * Parameters: 00123 * The usual argc and argv parameters to a main() function. 00124 * 00125 * Return Value: 00126 * This is a daemon program and never returns. However, in the degenerate 00127 * case where no sockets are created, the function returns zero. 00128 ******************************************************************************/ 00129 int main( int argc, 00130 char *argv[ ] ) 00131 { 00132 int opt; 00133 int tSckt[ MAXTCPSCKTS ]; /* Array of TCP socket descriptors. */ 00134 size_t tScktSize = MAXTCPSCKTS; /* Size of uSckt (# of elements). */ 00135 int uSckt[ MAXUDPSCKTS ]; /* Array of UDP socket descriptors. */ 00136 size_t uScktSize = MAXUDPSCKTS; /* Size of uSckt (# of elements). */ 00137 00138 strcpy(service_name,DFLT_SERVICE); 00139 /* 00140 ** Set the program name (w/o directory prefix). 00141 */ 00142 pgmName = strrchr( argv[ 0 ], '/' ); 00143 pgmName = pgmName == NULL ? argv[ 0 ] : pgmName + 1; 00144 /* 00145 ** Process command options. 00146 */ 00147 opterr = 0; /* Turns off "invalid option" error messages. */ 00148 while ( ( opt = getopt( argc, argv, VALIDOPTS ) ) >= 0 ) 00149 { 00150 switch ( opt ) 00151 { 00152 case 'v': /* Verbose mode. */ 00153 { 00154 verbose = true; 00155 break; 00156 } 00157 case 'p': /* Get the port number */ 00158 { 00159 strcpy(service_name,optarg); 00160 need++; 00161 break; 00162 } 00163 default: 00164 { 00165 USAGE; 00166 } 00167 } /* End SWITCH on command option. */ 00168 } /* End WHILE processing options. */ 00169 00170 if(need < 1) 00171 { 00172 USAGE; 00173 exit; 00174 } 00175 /* 00176 ** Open both a TCP and UDP socket, for both IPv4 & IPv6, on which to receive 00177 ** service requests. 00178 */ 00179 if ( ( openSckt( service_name, "tcp", tSckt, &tScktSize ) < 0 ) || 00180 ( openSckt( service_name, "udp", uSckt, &uScktSize ) < 0 ) ) 00181 { 00182 exit( 1 ); 00183 } 00184 /* 00185 ** Run the Programmable Interdimensional Timer server. 00186 */ 00187 if ( ( tScktSize > 0 ) || ( uScktSize > 0 ) ) 00188 { 00189 pit( tSckt, /* pit() never returns. */ 00190 tScktSize, 00191 uSckt, 00192 uScktSize ); 00193 } 00194 /* 00195 ** Since pit() never returns, execution only gets here if no sockets were 00196 ** created. 00197 */ 00198 if ( verbose ) 00199 { 00200 fprintf( stderr, 00201 "%s: No sockets opened... terminating.\n", 00202 pgmName ); 00203 } 00204 return 0; 00205 } /* End main() */ 00206 /****************************************************************************** 00207 * Function: openSckt 00208 * 00209 * Description: 00210 * Open passive (server) sockets for the indicated inet service & protocol. 00211 * Notice in the last sentence that "sockets" is plural. During the interim 00212 * transition period while everyone is switching over to IPv6, the server 00213 * application has to open two sockets on which to listen for connections... 00214 * one for IPv4 traffic and one for IPv6 traffic. 00215 * 00216 * Parameters: 00217 * service - Pointer to a character string representing the well-known port 00218 * on which to listen (can be a service name or a decimal number). 00219 * protocol - Pointer to a character string representing the transport layer 00220 * protocol (only "tcp" or "udp" are valid). 00221 * desc - Pointer to an array into which the socket descriptors are 00222 * placed when opened. 00223 * descSize - This is a value-result parameter. On input, it contains the 00224 * max number of descriptors that can be put into 'desc' (i.e. the 00225 * number of elements in the array). Upon return, it will contain 00226 * the number of descriptors actually opened. Any unused slots in 00227 * 'desc' are set to INVALID_DESC. 00228 * 00229 * Return Value: 00230 * 0 on success, -1 on error. 00231 ******************************************************************************/ 00232 static int openSckt( const char *service, 00233 const char *protocol, 00234 int desc[ ], 00235 size_t *descSize ) 00236 { 00237 struct addrinfo *ai; 00238 int aiErr; 00239 struct addrinfo *aiHead; 00240 struct addrinfo hints = { .ai_flags = AI_PASSIVE, /* Server mode. */ 00241 .ai_family = PF_UNSPEC }; /* IPv4 or IPv6. */ 00242 size_t maxDescs = *descSize; 00243 /* 00244 ** Initialize output parameters. When the loop completes, *descSize is 0. 00245 */ 00246 while ( *descSize > 0 ) 00247 { 00248 desc[ --( *descSize ) ] = INVALID_DESC; 00249 } 00250 /* 00251 ** Check which protocol is selected (only TCP and UDP are valid). 00252 */ 00253 if ( strcmp( protocol, "tcp" ) == 0 ) /* TCP protocol. */ 00254 { 00255 hints.ai_socktype = SOCK_STREAM; 00256 hints.ai_protocol = IPPROTO_TCP; 00257 } 00258 else if ( strcmp( protocol, "udp" ) == 0 ) /* UDP protocol. */ 00259 { 00260 hints.ai_socktype = SOCK_DGRAM; 00261 hints.ai_protocol = IPPROTO_UDP; 00262 } 00263 else /* Invalid protocol. */ 00264 { 00265 fprintf( stderr, 00266 "%s (line %d): ERROR - Unknown transport " 00267 "layer protocol \"%s\".\n", 00268 pgmName, 00269 __LINE__, 00270 protocol ); 00271 return -1; 00272 } 00273 /* 00274 ** Look up the service's "well-known" port number. Notice that NULL is being 00275 ** passed for the 'node' parameter, and that the AI_PASSIVE flag is set in 00276 ** 'hints'. Thus, the program is requesting passive address information. 00277 ** The network address is initialized to :: (all zeros) for IPv6 records, or 00278 ** 0.0.0.0 for IPv4 records. 00279 */ 00280 if ( ( aiErr = getaddrinfo( NULL, 00281 service, 00282 &hints, 00283 &aiHead ) ) != 0 ) 00284 { 00285 fprintf( stderr, 00286 "%s (line %d): ERROR - %s.\n", 00287 pgmName, 00288 __LINE__, 00289 gai_strerror( aiErr ) ); 00290 return -1; 00291 } 00292 /* 00293 ** For each of the address records returned, attempt to set up a passive 00294 ** socket. 00295 */ 00296 for ( ai = aiHead; 00297 ( ai != NULL ) && ( *descSize < maxDescs ); 00298 ai = ai->ai_next ) 00299 { 00300 if ( verbose ) 00301 { 00302 /* 00303 ** Display the current address info. Start with the protocol- 00304 ** independent fields first. 00305 */ 00306 fprintf( stderr, 00307 "Setting up a passive socket based on the " 00308 "following address info:\n" 00309 " ai_flags = 0x%02X\n" 00310 " ai_family = %d (PF_INET = %d, PF_INET6 = %d)\n" 00311 " ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d)\n" 00312 " ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d)\n" 00313 " ai_addrlen = %d (sockaddr_in = %lu, " 00314 "sockaddr_in6 = %lu)\n", 00315 ai->ai_flags, 00316 ai->ai_family, 00317 PF_INET, 00318 PF_INET6, 00319 ai->ai_socktype, 00320 SOCK_STREAM, 00321 SOCK_DGRAM, 00322 ai->ai_protocol, 00323 IPPROTO_TCP, 00324 IPPROTO_UDP, 00325 ai->ai_addrlen, 00326 sizeof( struct sockaddr_in ), 00327 sizeof( struct sockaddr_in6 ) ); 00328 /* 00329 ** Now display the protocol-specific formatted socket address. Note 00330 ** that the program is requesting that getnameinfo(3) convert the 00331 ** host & service into numeric strings. 00332 */ 00333 getnameinfo( ai->ai_addr, 00334 ai->ai_addrlen, 00335 hostBfr, 00336 sizeof( hostBfr ), 00337 servBfr, 00338 sizeof( servBfr ), 00339 NI_NUMERICHOST | NI_NUMERICSERV ); 00340 switch ( ai->ai_family ) 00341 { 00342 case PF_INET: /* IPv4 address record. */ 00343 { 00344 struct sockaddr_in *p = (struct sockaddr_in*) ai->ai_addr; 00345 fprintf( stderr, 00346 " ai_addr = sin_family: %d (AF_INET = %d, " 00347 "AF_INET6 = %d)\n" 00348 " sin_addr: %s\n" 00349 " sin_port: %s\n", 00350 p->sin_family, 00351 AF_INET, 00352 AF_INET6, 00353 hostBfr, 00354 servBfr ); 00355 break; 00356 } /* End CASE of IPv4. */ 00357 case PF_INET6: /* IPv6 address record. */ 00358 { 00359 struct sockaddr_in6 *p = (struct sockaddr_in6*) ai->ai_addr; 00360 fprintf( stderr, 00361 " ai_addr = sin6_family: %d (AF_INET = %d, " 00362 "AF_INET6 = %d)\n" 00363 " sin6_addr: %s\n" 00364 " sin6_port: %s\n" 00365 " sin6_flowinfo: %d\n" 00366 " sin6_scope_id: %d\n", 00367 p->sin6_family, 00368 AF_INET, 00369 AF_INET6, 00370 hostBfr, 00371 servBfr, 00372 p->sin6_flowinfo, 00373 p->sin6_scope_id ); 00374 break; 00375 } /* End CASE of IPv6. */ 00376 default: /* Can never get here, but just for completeness. */ 00377 { 00378 fprintf( stderr, 00379 "%s (line %d): ERROR - Unknown protocol family (%d).\n", 00380 pgmName, 00381 __LINE__, 00382 ai->ai_family ); 00383 freeaddrinfo( aiHead ); 00384 return -1; 00385 } /* End DEFAULT case (unknown protocol family). */ 00386 } /* End SWITCH on protocol family. */ 00387 } /* End IF verbose mode. */ 00388 /* 00389 ** Create a socket using the info in the addrinfo structure. 00390 */ 00391 CHK( desc[ *descSize ] = socket( ai->ai_family, 00392 ai->ai_socktype, 00393 ai->ai_protocol ) ); 00394 /* 00395 ** Here is the code that prevents "IPv4 mapped addresses", as discussed 00396 ** in Section 22.1.3.1. If an IPv6 socket was just created, then set the 00397 ** IPV6_V6ONLY socket option. 00398 */ 00399 if ( ai->ai_family == PF_INET6 ) 00400 { 00401 #if defined( IPV6_V6ONLY ) 00402 /* 00403 ** Disable IPv4 mapped addresses. 00404 */ 00405 int v6Only = 1; 00406 CHK( setsockopt( desc[ *descSize ], 00407 IPPROTO_IPV6, 00408 IPV6_V6ONLY, 00409 &v6Only, 00410 sizeof( v6Only ) ) ); 00411 #else 00412 /* 00413 ** IPV6_V6ONLY is not defined, so the socket option can't be set and 00414 ** thus IPv4 mapped addresses can't be disabled. Print a warning 00415 ** message and close the socket. Design note: If the 00416 ** #if...#else...#endif construct were removed, then this program 00417 ** would not compile (because IPV6_V6ONLY isn't defined). That's an 00418 ** acceptable approach; IPv4 mapped addresses are certainly disabled 00419 ** if the program can't build! However, since this program is also 00420 ** designed to work for IPv4 sockets as well as IPv6, I decided to 00421 ** allow the program to compile when IPV6_V6ONLY is not defined, and 00422 ** turn it into a run-time warning rather than a compile-time error. 00423 ** IPv4 mapped addresses are still disabled because _all_ IPv6 traffic 00424 ** is disabled (all IPv6 sockets are closed here), but at least this 00425 ** way the server can still service IPv4 network traffic. 00426 */ 00427 fprintf( stderr, 00428 "%s (line %d): WARNING - Cannot set IPV6_V6ONLY socket " 00429 "option. Closing IPv6 %s socket.\n", 00430 pgmName, 00431 __LINE__, 00432 ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP" ); 00433 CHK( close( desc[ *descSize ] ) ); 00434 continue; /* Go to top of FOR loop w/o updating *descSize! */ 00435 #endif /* IPV6_V6ONLY */ 00436 } /* End IF this is an IPv6 socket. */ 00437 /* 00438 ** Bind the socket. Again, the info from the addrinfo structure is used. 00439 */ 00440 CHK( bind( desc[ *descSize ], 00441 ai->ai_addr, 00442 ai->ai_addrlen ) ); 00443 /* 00444 ** If this is a TCP socket, put the socket into passive listening mode 00445 ** (listen is only valid on connection-oriented sockets). 00446 */ 00447 if ( ai->ai_socktype == SOCK_STREAM ) 00448 { 00449 CHK( listen( desc[ *descSize ], 00450 MAXCONNQLEN ) ); 00451 } 00452 /* 00453 ** Socket set up okay. Bump index to next descriptor array element. 00454 */ 00455 *descSize += 1; 00456 } /* End FOR each address info structure returned. */ 00457 /* 00458 ** Dummy check for unused address records. 00459 */ 00460 if ( verbose && ( ai != NULL ) ) 00461 { 00462 fprintf( stderr, 00463 "%s (line %d): WARNING - Some address records were " 00464 "not processed due to insufficient array space.\n", 00465 pgmName, 00466 __LINE__ ); 00467 } /* End IF verbose and some address records remain unprocessed. */ 00468 /* 00469 ** Clean up. 00470 */ 00471 freeaddrinfo( aiHead ); 00472 return 0; 00473 } /* End openSckt() */ 00474 /****************************************************************************** 00475 * Function: pit 00476 * 00477 * Description: 00478 * Listen on a set of sockets and send the current microsecond counter 00479 * that was produced by gettimeofday(), to any clients. This function 00480 * never returns. 00481 * 00482 * Parameters: 00483 * tSckt - Array of TCP socket descriptors on which to listen. 00484 * tScktSize - Size of the tSckt array (nbr of elements). 00485 * uSckt - Array of UDP socket descriptors on which to listen. 00486 * uScktSize - Size of the uSckt array (nbr of elements). 00487 * 00488 * Return Value: None. 00489 ******************************************************************************/ 00490 static void pit( int tSckt[ ], 00491 size_t tScktSize, 00492 int uSckt[ ], 00493 size_t uScktSize ) 00494 { 00495 char bfr[ 256 ]; 00496 ssize_t count; 00497 struct pollfd *desc; 00498 size_t descSize = tScktSize + uScktSize; 00499 int idx; 00500 int newSckt; 00501 struct sockaddr *sadr; 00502 socklen_t sadrLen; 00503 struct sockaddr_storage sockStor; 00504 int status; 00505 size_t timeLen; 00506 time_t timeVal; 00507 ssize_t wBytes; 00508 unsigned long long secs; 00509 int ret; 00510 /* 00511 ** Allocate memory for the poll(2) array. 00512 */ 00513 desc = malloc( descSize * sizeof( struct pollfd ) ); 00514 if ( desc == NULL ) 00515 { 00516 fprintf( stderr, 00517 "%s (line %d): ERROR - %s.\n", 00518 pgmName, 00519 __LINE__, 00520 strerror( ENOMEM ) ); 00521 exit( 1 ); 00522 } 00523 /* 00524 ** Initialize the poll(2) array. 00525 */ 00526 for ( idx = 0; idx < descSize; idx++ ) 00527 { 00528 desc[ idx ].fd = idx < tScktSize ? tSckt[ idx ] 00529 : uSckt[ idx - tScktSize ]; 00530 desc[ idx ].events = POLLIN; 00531 desc[ idx ].revents = 0; 00532 } 00533 /* 00534 ** Main PIT server loop. Handles both TCP & UDP requests. This is 00535 ** an interative server, and all requests are handled directly within the 00536 ** main loop. 00537 */ 00538 while ( true ) /* Do forever. */ 00539 { 00540 /* 00541 ** Wait for activity on one of the sockets. The DO..WHILE construct is 00542 ** used to restart the system call in the event the process is 00543 ** interrupted by a signal. 00544 */ 00545 do 00546 { 00547 status = poll( desc, 00548 descSize, 00549 -1 /* Wait indefinitely for input. */ ); 00550 } while ( ( status < 0 ) && ( errno == EINTR ) ); 00551 CHK( status ); /* Check for a bona fide system call error. */ 00552 /* 00553 ** Get the current time. 00554 */ 00555 #if defined(Windows) 00556 LARGE_INTEGER freq,counter; 00557 double wintime,bigcounter; 00558 /* For Windows the time_of_day() is useless. It increments in 55 milli 00559 * second increments. By using the Win32api one can get access to the 00560 * high performance measurement interfaces. With this one can get back 00561 * into the 8 to 9 microsecond resolution. 00562 */ 00563 QueryPerformanceFrequency(&freq); 00564 QueryPerformanceCounter(&counter); 00565 bigcounter=(double)counter.HighPart *(double)0xffffffff + 00566 (double)counter.LowPart; 00567 wintime = (double)(bigcounter/(double)freq.LowPart); 00568 secs = (long long)(wintime * 1000000); 00569 #else 00570 ret = gettimeofday( &tm,0 ); 00571 secs = ((unsigned long long)tm.tv_sec * 1000000) 00572 + (unsigned long long)tm.tv_usec; 00573 #endif 00574 00575 ret = sprintf(timeStr,"%llu",secs); 00576 timeLen = strlen( timeStr ); 00577 /* 00578 ** Process sockets with input available. 00579 */ 00580 for ( idx = 0; idx < descSize; idx++ ) 00581 { 00582 switch ( desc[ idx ].revents ) 00583 { 00584 case 0: /* No activity on this socket; try the next. */ 00585 continue; 00586 case POLLIN: /* Network activity. Go process it. */ 00587 break; 00588 default: /* Invalid poll events. */ 00589 { 00590 fprintf( stderr, 00591 "%s (line %d): ERROR - Invalid poll event (0x%02X).\n", 00592 pgmName, 00593 __LINE__, 00594 desc[ idx ].revents ); 00595 exit( 1 ); 00596 } 00597 } /* End SWITCH on returned poll events. */ 00598 /* 00599 ** Determine if this is a TCP request or UDP request. 00600 */ 00601 if ( idx < tScktSize ) 00602 { 00603 /* 00604 ** TCP connection requested. Accept it. Notice the use of 00605 ** the sockaddr_storage data type. 00606 */ 00607 sadrLen = sizeof( sockStor ); 00608 sadr = (struct sockaddr*) &sockStor; 00609 CHK( newSckt = accept( desc[ idx ].fd, 00610 sadr, 00611 &sadrLen ) ); 00612 CHK( shutdown( newSckt, /* Server never recv's anything. */ 00613 SHUT_RD ) ); 00614 if ( verbose ) 00615 { 00616 /* 00617 ** Display the socket address of the remote client. Begin with 00618 ** the address-independent fields. 00619 */ 00620 fprintf( stderr, 00621 "Sockaddr info for new TCP client:\n" 00622 " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n" 00623 " addr len = %d (sockaddr_in = %lu, " 00624 "sockaddr_in6 = %lu)\n", 00625 sadr->sa_family, 00626 AF_INET, 00627 AF_INET6, 00628 sadrLen, 00629 sizeof( struct sockaddr_in ), 00630 sizeof( struct sockaddr_in6 ) ); 00631 /* 00632 ** Display the address-specific fields. 00633 */ 00634 getnameinfo( sadr, 00635 sadrLen, 00636 hostBfr, 00637 sizeof( hostBfr ), 00638 servBfr, 00639 sizeof( servBfr ), 00640 NI_NUMERICHOST | NI_NUMERICSERV ); 00641 /* 00642 ** Notice that we're switching on an address family now, not a 00643 ** protocol family. 00644 */ 00645 switch ( sadr->sa_family ) 00646 { 00647 case AF_INET: /* IPv4 address. */ 00648 { 00649 struct sockaddr_in *p = (struct sockaddr_in*) sadr; 00650 fprintf( stderr, 00651 " sin_addr = sin_family: %d\n" 00652 " sin_addr: %s\n" 00653 " sin_port: %s\n", 00654 p->sin_family, 00655 hostBfr, 00656 servBfr ); 00657 break; 00658 } /* End CASE of IPv4. */ 00659 case AF_INET6: /* IPv6 address. */ 00660 { 00661 struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr; 00662 fprintf( stderr, 00663 " sin6_addr = sin6_family: %d\n" 00664 " sin6_addr: %s\n" 00665 " sin6_port: %s\n" 00666 " sin6_flowinfo: %d\n" 00667 " sin6_scope_id: %d\n", 00668 p->sin6_family, 00669 hostBfr, 00670 servBfr, 00671 p->sin6_flowinfo, 00672 p->sin6_scope_id ); 00673 break; 00674 } /* End CASE of IPv6. */ 00675 default: /* Can never get here, but for completeness. */ 00676 { 00677 fprintf( stderr, 00678 "%s (line %d): ERROR - Unknown address " 00679 "family (%d).\n", 00680 pgmName, 00681 __LINE__, 00682 sadr->sa_family ); 00683 break; 00684 } /* End DEFAULT case (unknown address family). */ 00685 } /* End SWITCH on address family. */ 00686 } /* End IF verbose mode. */ 00687 /* 00688 ** Send the PIT to the client. 00689 */ 00690 wBytes = timeLen; 00691 while ( wBytes > 0 ) 00692 { 00693 do 00694 { 00695 count = write( newSckt, 00696 timeStr, 00697 wBytes ); 00698 } while ( ( count < 0 ) && ( errno == EINTR ) ); 00699 CHK( count ); /* Check for an error. */ 00700 wBytes -= count; 00701 } /* End WHILE there is data to send. */ 00702 CHK( close( newSckt ) ); 00703 } /* End IF this was a TCP connection request. */ 00704 else 00705 { 00706 /* 00707 ** This is a UDP socket, and a datagram is available. The funny 00708 ** thing about UDP requests is that this server doesn't require any 00709 ** client input; but it can't send the PIT unless it knows a client 00710 ** wants the data, and the only way that can occur with UDP is if 00711 ** the server receives a datagram from the client. Thus, the 00712 ** server must receive _something_, but the content of the datagram 00713 ** is irrelevant. Read in the datagram. Again note the use of 00714 ** sockaddr_storage to receive the address. 00715 */ 00716 sadrLen = sizeof( sockStor ); 00717 sadr = (struct sockaddr*) &sockStor; 00718 CHK( count = recvfrom( desc[ idx ].fd, 00719 bfr, 00720 sizeof( bfr ), 00721 0, 00722 sadr, 00723 &sadrLen ) ); 00724 /* 00725 ** Display whatever was received on stdout. 00726 */ 00727 if ( verbose ) 00728 { 00729 ssize_t rBytes = count; 00730 fprintf( stderr, 00731 "%s: UDP datagram received (%ld bytes).\n", 00732 pgmName, 00733 count ); 00734 while ( count > 0 ) 00735 { 00736 fputc( bfr[ rBytes - count-- ], 00737 stdout ); 00738 } 00739 if ( bfr[ rBytes-1 ] != '\n' ) 00740 fputc( '\n', stdout ); /* Newline also flushes stdout. */ 00741 /* 00742 ** Display the socket address of the remote client. Address- 00743 ** independent fields first. 00744 */ 00745 fprintf( stderr, 00746 "Remote client's sockaddr info:\n" 00747 " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n" 00748 " addr len = %d (sockaddr_in = %lu, " 00749 "sockaddr_in6 = %lu)\n", 00750 sadr->sa_family, 00751 AF_INET, 00752 AF_INET6, 00753 sadrLen, 00754 sizeof( struct sockaddr_in ), 00755 sizeof( struct sockaddr_in6 ) ); 00756 /* 00757 ** Display the address-specific information. 00758 */ 00759 getnameinfo( sadr, 00760 sadrLen, 00761 hostBfr, 00762 sizeof( hostBfr ), 00763 servBfr, 00764 sizeof( servBfr ), 00765 NI_NUMERICHOST | NI_NUMERICSERV ); 00766 switch ( sadr->sa_family ) 00767 { 00768 case AF_INET: /* IPv4 address. */ 00769 { 00770 struct sockaddr_in *p = (struct sockaddr_in*) sadr; 00771 fprintf( stderr, 00772 " sin_addr = sin_family: %d\n" 00773 " sin_addr: %s\n" 00774 " sin_port: %s\n", 00775 p->sin_family, 00776 hostBfr, 00777 servBfr ); 00778 break; 00779 } /* End CASE of IPv4 address. */ 00780 case AF_INET6: /* IPv6 address. */ 00781 { 00782 struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr; 00783 fprintf( stderr, 00784 " sin6_addr = sin6_family: %d\n" 00785 " sin6_addr: %s\n" 00786 " sin6_port: %s\n" 00787 " sin6_flowinfo: %d\n" 00788 " sin6_scope_id: %d\n", 00789 p->sin6_family, 00790 hostBfr, 00791 servBfr, 00792 p->sin6_flowinfo, 00793 p->sin6_scope_id ); 00794 break; 00795 } /* End CASE of IPv6 address. */ 00796 default: /* Can never get here, but for completeness. */ 00797 { 00798 fprintf( stderr, 00799 "%s (line %d): ERROR - Unknown address " 00800 "family (%d).\n", 00801 pgmName, 00802 __LINE__, 00803 sadr->sa_family ); 00804 break; 00805 } /* End DEFAULT case (unknown address family). */ 00806 } /* End SWITCH on address family. */ 00807 } /* End IF verbose mode. */ 00808 /* 00809 ** Send the PIT to the client. 00810 */ 00811 wBytes = timeLen; 00812 while ( wBytes > 0 ) 00813 { 00814 do 00815 { 00816 count = sendto( desc[ idx ].fd, 00817 timeStr, 00818 wBytes, 00819 0, 00820 sadr, /* Address & address length */ 00821 sadrLen ); /* received in recvfrom(). */ 00822 } while ( ( count < 0 ) && ( errno == EINTR ) ); 00823 CHK( count ); /* Check for a bona fide error. */ 00824 wBytes -= count; 00825 } /* End WHILE there is data to send. */ 00826 } /* End ELSE a UDP datagram is available. */ 00827 desc[ idx ].revents = 0; /* Clear the returned poll events. */ 00828 } /* End FOR each socket descriptor. */ 00829 } /* End WHILE forever. */ 00830 } /* End pit() */ 00831