123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- /******************************************************************************
- * File: pit_server.c
- *
- * Description: Contains source code for an IPv6-capable 'PIT' server.
- * This is a derivative of the tod6 (time-of-day) server that was written
- * by John Wenker.
- * .......
- * Author of tod6: John Wenker, Sr. Software Engineer,
- * Performance Technologies, San Diego, USA
- * .......
- * The program tod6 was a time of day server. It has beeen modified
- * to provide a microsecond timestamp on request. Modified and adapted
- * for PIT purposes by Don Capps. [ capps@iozone.org ]
- *
- * This server sends the current value of gettimeofday() in
- * microseconds back to the client, as a numerical string.
- *
- * /etc/services should contain "PIT" with a specified port value.
- *
- ******************************************************************************/
- /*
- ** System header files.
- */
- #include <errno.h> /* errno declaration & error codes. */
- #include <netdb.h> /* getaddrinfo(3) et al. */
- #include <netinet/in.h> /* sockaddr_in & sockaddr_in6 definition. */
- #include <stdio.h> /* printf(3) et al. */
- #include <stdlib.h> /* exit(2). */
- #include <string.h> /* String manipulation & memory functions. */
- #if defined(_SUA_)
- #include <poll.h> /* poll(2) and related definitions. */
- #else
- #include <sys/poll.h> /* poll(2) and related definitions. */
- #endif
- #include <sys/socket.h> /* Socket functions (socket(2), bind(2), etc). */
- #include <time.h> /* time(2) & ctime(3). */
- #include <sys/time.h> /* gettimeofday */
- #include <unistd.h> /* getopt(3), read(2), etc. */
- /* Include for Cygnus development environment for Windows */
- #if defined (Windows)
- #include <Windows.h>
- int errno;
- #endif
- #if defined(_SUA_)
- extern char *optarg, *opterr;
- #endif
- /*
- ** Constants.
- **
- ** Please remember to add PIT service to the /etc/services file.
- */
- #define DFLT_SERVICE "PIT" /* Programmable Interdimensional Timer */
- #define INVALID_DESC -1 /* Invalid file descriptor. */
- #define MAXCONNQLEN 3 /* Max nbr of connection requests to queue. */
- #define MAXTCPSCKTS 2 /* One TCP socket for IPv4 & one for IPv6. */
- #define MAXUDPSCKTS 2 /* One UDP socket for IPv4 & one for IPv6. */
- #define VALIDOPTS "vh:p:" /* Valid command options. */
- /*
- ** Simple boolean type definition.
- */
- int false = 0;
- int true = 1;
- /*
- ** Prototypes for internal helper functions.
- */
- static int openSckt( const char *service,
- const char *protocol,
- int desc[ ],
- size_t *descSize );
- static void pit( int tSckt[ ],
- size_t tScktSize,
- int uSckt[ ],
- size_t uScktSize );
- /*
- ** Global data objects.
- */
- static char hostBfr[ NI_MAXHOST ]; /* For use w/getnameinfo(3). */
- static const char *pgmName; /* Program name w/o dir prefix. */
- static char servBfr[ NI_MAXSERV ]; /* For use w/getnameinfo(3). */
- static int verbose = 0; /* Verbose mode indication. */
- struct timeval tm; /* Timeval structure, used with gettimeofday() */
- char timeStr[40]; /* String for time in microseconds */
- char service_name[20];
- int need;
- /*
- ** Usage macro for command syntax violations.
- */
- #define USAGE \
- { \
- fprintf( stderr, \
- "Usage: %s [-v] -p service \n", \
- pgmName ); \
- exit( 127 ); \
- } /* End USAGE macro. */
- /*
- ** Macro to terminate the program if a system call error occurs. The system
- ** call must be one of the usual type that returns -1 on error.
- */
- #define CHK(expr) \
- do \
- { \
- if ( (expr) == -1 ) \
- { \
- fprintf( stderr, \
- "%s (line %d): System call ERROR - %s.\n", \
- pgmName, \
- __LINE__, \
- strerror( errno ) ); \
- exit( 1 ); \
- } /* End IF system call failed. */ \
- } while ( false )
- /******************************************************************************
- * Function: main
- *
- * Description:
- * Set up a PIT server and handle network requests. This server
- * handles both TCP and UDP requests.
- *
- * Parameters:
- * The usual argc and argv parameters to a main() function.
- *
- * Return Value:
- * This is a daemon program and never returns. However, in the degenerate
- * case where no sockets are created, the function returns zero.
- ******************************************************************************/
- int main( int argc,
- char *argv[ ] )
- {
- int opt;
- int tSckt[ MAXTCPSCKTS ]; /* Array of TCP socket descriptors. */
- size_t tScktSize = MAXTCPSCKTS; /* Size of uSckt (# of elements). */
- int uSckt[ MAXUDPSCKTS ]; /* Array of UDP socket descriptors. */
- size_t uScktSize = MAXUDPSCKTS; /* Size of uSckt (# of elements). */
- strcpy(service_name,DFLT_SERVICE);
- /*
- ** Set the program name (w/o directory prefix).
- */
- pgmName = strrchr( argv[ 0 ], '/' );
- pgmName = pgmName == NULL ? argv[ 0 ] : pgmName + 1;
- /*
- ** Process command options.
- */
- opterr = 0; /* Turns off "invalid option" error messages. */
- while ( ( opt = getopt( argc, argv, VALIDOPTS ) ) >= 0 )
- {
- switch ( opt )
- {
- case 'v': /* Verbose mode. */
- {
- verbose = true;
- break;
- }
- case 'p': /* Get the port number */
- {
- strcpy(service_name,optarg);
- need++;
- break;
- }
- default:
- {
- USAGE;
- }
- } /* End SWITCH on command option. */
- } /* End WHILE processing options. */
- if(need < 1)
- {
- USAGE;
- exit;
- }
- /*
- ** Open both a TCP and UDP socket, for both IPv4 & IPv6, on which to receive
- ** service requests.
- */
- if ( ( openSckt( service_name, "tcp", tSckt, &tScktSize ) < 0 ) ||
- ( openSckt( service_name, "udp", uSckt, &uScktSize ) < 0 ) )
- {
- exit( 1 );
- }
- /*
- ** Run the Programmable Interdimensional Timer server.
- */
- if ( ( tScktSize > 0 ) || ( uScktSize > 0 ) )
- {
- pit( tSckt, /* pit() never returns. */
- tScktSize,
- uSckt,
- uScktSize );
- }
- /*
- ** Since pit() never returns, execution only gets here if no sockets were
- ** created.
- */
- if ( verbose )
- {
- fprintf( stderr,
- "%s: No sockets opened... terminating.\n",
- pgmName );
- }
- return 0;
- } /* End main() */
- /******************************************************************************
- * Function: openSckt
- *
- * Description:
- * Open passive (server) sockets for the indicated inet service & protocol.
- * Notice in the last sentence that "sockets" is plural. During the interim
- * transition period while everyone is switching over to IPv6, the server
- * application has to open two sockets on which to listen for connections...
- * one for IPv4 traffic and one for IPv6 traffic.
- *
- * Parameters:
- * service - Pointer to a character string representing the well-known port
- * on which to listen (can be a service name or a decimal number).
- * protocol - Pointer to a character string representing the transport layer
- * protocol (only "tcp" or "udp" are valid).
- * desc - Pointer to an array into which the socket descriptors are
- * placed when opened.
- * descSize - This is a value-result parameter. On input, it contains the
- * max number of descriptors that can be put into 'desc' (i.e. the
- * number of elements in the array). Upon return, it will contain
- * the number of descriptors actually opened. Any unused slots in
- * 'desc' are set to INVALID_DESC.
- *
- * Return Value:
- * 0 on success, -1 on error.
- ******************************************************************************/
- static int openSckt( const char *service,
- const char *protocol,
- int desc[ ],
- size_t *descSize )
- {
- struct addrinfo *ai;
- int aiErr;
- struct addrinfo *aiHead;
- struct addrinfo hints = { .ai_flags = AI_PASSIVE, /* Server mode. */
- .ai_family = PF_UNSPEC }; /* IPv4 or IPv6. */
- size_t maxDescs = *descSize;
- /*
- ** Initialize output parameters. When the loop completes, *descSize is 0.
- */
- while ( *descSize > 0 )
- {
- desc[ --( *descSize ) ] = INVALID_DESC;
- }
- /*
- ** Check which protocol is selected (only TCP and UDP are valid).
- */
- if ( strcmp( protocol, "tcp" ) == 0 ) /* TCP protocol. */
- {
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- }
- else if ( strcmp( protocol, "udp" ) == 0 ) /* UDP protocol. */
- {
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_protocol = IPPROTO_UDP;
- }
- else /* Invalid protocol. */
- {
- fprintf( stderr,
- "%s (line %d): ERROR - Unknown transport "
- "layer protocol \"%s\".\n",
- pgmName,
- __LINE__,
- protocol );
- return -1;
- }
- /*
- ** Look up the service's "well-known" port number. Notice that NULL is being
- ** passed for the 'node' parameter, and that the AI_PASSIVE flag is set in
- ** 'hints'. Thus, the program is requesting passive address information.
- ** The network address is initialized to :: (all zeros) for IPv6 records, or
- ** 0.0.0.0 for IPv4 records.
- */
- if ( ( aiErr = getaddrinfo( NULL,
- service,
- &hints,
- &aiHead ) ) != 0 )
- {
- fprintf( stderr,
- "%s (line %d): ERROR - %s.\n",
- pgmName,
- __LINE__,
- gai_strerror( aiErr ) );
- return -1;
- }
- /*
- ** For each of the address records returned, attempt to set up a passive
- ** socket.
- */
- for ( ai = aiHead;
- ( ai != NULL ) && ( *descSize < maxDescs );
- ai = ai->ai_next )
- {
- if ( verbose )
- {
- /*
- ** Display the current address info. Start with the protocol-
- ** independent fields first.
- */
- fprintf( stderr,
- "Setting up a passive socket based on the "
- "following address info:\n"
- " ai_flags = 0x%02X\n"
- " ai_family = %d (PF_INET = %d, PF_INET6 = %d)\n"
- " ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d)\n"
- " ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d)\n"
- " ai_addrlen = %d (sockaddr_in = %lu, "
- "sockaddr_in6 = %lu)\n",
- ai->ai_flags,
- ai->ai_family,
- PF_INET,
- PF_INET6,
- ai->ai_socktype,
- SOCK_STREAM,
- SOCK_DGRAM,
- ai->ai_protocol,
- IPPROTO_TCP,
- IPPROTO_UDP,
- ai->ai_addrlen,
- sizeof( struct sockaddr_in ),
- sizeof( struct sockaddr_in6 ) );
- /*
- ** Now display the protocol-specific formatted socket address. Note
- ** that the program is requesting that getnameinfo(3) convert the
- ** host & service into numeric strings.
- */
- getnameinfo( ai->ai_addr,
- ai->ai_addrlen,
- hostBfr,
- sizeof( hostBfr ),
- servBfr,
- sizeof( servBfr ),
- NI_NUMERICHOST | NI_NUMERICSERV );
- switch ( ai->ai_family )
- {
- case PF_INET: /* IPv4 address record. */
- {
- struct sockaddr_in *p = (struct sockaddr_in*) ai->ai_addr;
- fprintf( stderr,
- " ai_addr = sin_family: %d (AF_INET = %d, "
- "AF_INET6 = %d)\n"
- " sin_addr: %s\n"
- " sin_port: %s\n",
- p->sin_family,
- AF_INET,
- AF_INET6,
- hostBfr,
- servBfr );
- break;
- } /* End CASE of IPv4. */
- case PF_INET6: /* IPv6 address record. */
- {
- struct sockaddr_in6 *p = (struct sockaddr_in6*) ai->ai_addr;
- fprintf( stderr,
- " ai_addr = sin6_family: %d (AF_INET = %d, "
- "AF_INET6 = %d)\n"
- " sin6_addr: %s\n"
- " sin6_port: %s\n"
- " sin6_flowinfo: %d\n"
- " sin6_scope_id: %d\n",
- p->sin6_family,
- AF_INET,
- AF_INET6,
- hostBfr,
- servBfr,
- p->sin6_flowinfo,
- p->sin6_scope_id );
- break;
- } /* End CASE of IPv6. */
- default: /* Can never get here, but just for completeness. */
- {
- fprintf( stderr,
- "%s (line %d): ERROR - Unknown protocol family (%d).\n",
- pgmName,
- __LINE__,
- ai->ai_family );
- freeaddrinfo( aiHead );
- return -1;
- } /* End DEFAULT case (unknown protocol family). */
- } /* End SWITCH on protocol family. */
- } /* End IF verbose mode. */
- /*
- ** Create a socket using the info in the addrinfo structure.
- */
- CHK( desc[ *descSize ] = socket( ai->ai_family,
- ai->ai_socktype,
- ai->ai_protocol ) );
- /*
- ** Here is the code that prevents "IPv4 mapped addresses", as discussed
- ** in Section 22.1.3.1. If an IPv6 socket was just created, then set the
- ** IPV6_V6ONLY socket option.
- */
- if ( ai->ai_family == PF_INET6 )
- {
- #if defined( IPV6_V6ONLY )
- /*
- ** Disable IPv4 mapped addresses.
- */
- int v6Only = 1;
- CHK( setsockopt( desc[ *descSize ],
- IPPROTO_IPV6,
- IPV6_V6ONLY,
- &v6Only,
- sizeof( v6Only ) ) );
- #else
- /*
- ** IPV6_V6ONLY is not defined, so the socket option can't be set and
- ** thus IPv4 mapped addresses can't be disabled. Print a warning
- ** message and close the socket. Design note: If the
- ** #if...#else...#endif construct were removed, then this program
- ** would not compile (because IPV6_V6ONLY isn't defined). That's an
- ** acceptable approach; IPv4 mapped addresses are certainly disabled
- ** if the program can't build! However, since this program is also
- ** designed to work for IPv4 sockets as well as IPv6, I decided to
- ** allow the program to compile when IPV6_V6ONLY is not defined, and
- ** turn it into a run-time warning rather than a compile-time error.
- ** IPv4 mapped addresses are still disabled because _all_ IPv6 traffic
- ** is disabled (all IPv6 sockets are closed here), but at least this
- ** way the server can still service IPv4 network traffic.
- */
- fprintf( stderr,
- "%s (line %d): WARNING - Cannot set IPV6_V6ONLY socket "
- "option. Closing IPv6 %s socket.\n",
- pgmName,
- __LINE__,
- ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP" );
- CHK( close( desc[ *descSize ] ) );
- continue; /* Go to top of FOR loop w/o updating *descSize! */
- #endif /* IPV6_V6ONLY */
- } /* End IF this is an IPv6 socket. */
- /*
- ** Bind the socket. Again, the info from the addrinfo structure is used.
- */
- CHK( bind( desc[ *descSize ],
- ai->ai_addr,
- ai->ai_addrlen ) );
- /*
- ** If this is a TCP socket, put the socket into passive listening mode
- ** (listen is only valid on connection-oriented sockets).
- */
- if ( ai->ai_socktype == SOCK_STREAM )
- {
- CHK( listen( desc[ *descSize ],
- MAXCONNQLEN ) );
- }
- /*
- ** Socket set up okay. Bump index to next descriptor array element.
- */
- *descSize += 1;
- } /* End FOR each address info structure returned. */
- /*
- ** Dummy check for unused address records.
- */
- if ( verbose && ( ai != NULL ) )
- {
- fprintf( stderr,
- "%s (line %d): WARNING - Some address records were "
- "not processed due to insufficient array space.\n",
- pgmName,
- __LINE__ );
- } /* End IF verbose and some address records remain unprocessed. */
- /*
- ** Clean up.
- */
- freeaddrinfo( aiHead );
- return 0;
- } /* End openSckt() */
- /******************************************************************************
- * Function: pit
- *
- * Description:
- * Listen on a set of sockets and send the current microsecond counter
- * that was produced by gettimeofday(), to any clients. This function
- * never returns.
- *
- * Parameters:
- * tSckt - Array of TCP socket descriptors on which to listen.
- * tScktSize - Size of the tSckt array (nbr of elements).
- * uSckt - Array of UDP socket descriptors on which to listen.
- * uScktSize - Size of the uSckt array (nbr of elements).
- *
- * Return Value: None.
- ******************************************************************************/
- static void pit( int tSckt[ ],
- size_t tScktSize,
- int uSckt[ ],
- size_t uScktSize )
- {
- char bfr[ 256 ];
- ssize_t count;
- struct pollfd *desc;
- size_t descSize = tScktSize + uScktSize;
- int idx;
- int newSckt;
- struct sockaddr *sadr;
- socklen_t sadrLen;
- struct sockaddr_storage sockStor;
- int status;
- size_t timeLen;
- time_t timeVal;
- ssize_t wBytes;
- unsigned long long secs;
- int ret;
- /*
- ** Allocate memory for the poll(2) array.
- */
- desc = malloc( descSize * sizeof( struct pollfd ) );
- if ( desc == NULL )
- {
- fprintf( stderr,
- "%s (line %d): ERROR - %s.\n",
- pgmName,
- __LINE__,
- strerror( ENOMEM ) );
- exit( 1 );
- }
- /*
- ** Initialize the poll(2) array.
- */
- for ( idx = 0; idx < descSize; idx++ )
- {
- desc[ idx ].fd = idx < tScktSize ? tSckt[ idx ]
- : uSckt[ idx - tScktSize ];
- desc[ idx ].events = POLLIN;
- desc[ idx ].revents = 0;
- }
- /*
- ** Main PIT server loop. Handles both TCP & UDP requests. This is
- ** an interative server, and all requests are handled directly within the
- ** main loop.
- */
- while ( true ) /* Do forever. */
- {
- /*
- ** Wait for activity on one of the sockets. The DO..WHILE construct is
- ** used to restart the system call in the event the process is
- ** interrupted by a signal.
- */
- do
- {
- status = poll( desc,
- descSize,
- -1 /* Wait indefinitely for input. */ );
- } while ( ( status < 0 ) && ( errno == EINTR ) );
- CHK( status ); /* Check for a bona fide system call error. */
- /*
- ** Get the current time.
- */
- #if defined(Windows)
- LARGE_INTEGER freq,counter;
- double wintime,bigcounter;
- /* For Windows the time_of_day() is useless. It increments in 55 milli
- * second increments. By using the Win32api one can get access to the
- * high performance measurement interfaces. With this one can get back
- * into the 8 to 9 microsecond resolution.
- */
- QueryPerformanceFrequency(&freq);
- QueryPerformanceCounter(&counter);
- bigcounter=(double)counter.HighPart *(double)0xffffffff +
- (double)counter.LowPart;
- wintime = (double)(bigcounter/(double)freq.LowPart);
- secs = (long long)(wintime * 1000000);
- #else
- ret = gettimeofday( &tm,0 );
- secs = ((unsigned long long)tm.tv_sec * 1000000)
- + (unsigned long long)tm.tv_usec;
- #endif
- ret = sprintf(timeStr,"%llu",secs);
- timeLen = strlen( timeStr );
- /*
- ** Process sockets with input available.
- */
- for ( idx = 0; idx < descSize; idx++ )
- {
- switch ( desc[ idx ].revents )
- {
- case 0: /* No activity on this socket; try the next. */
- continue;
- case POLLIN: /* Network activity. Go process it. */
- break;
- default: /* Invalid poll events. */
- {
- fprintf( stderr,
- "%s (line %d): ERROR - Invalid poll event (0x%02X).\n",
- pgmName,
- __LINE__,
- desc[ idx ].revents );
- exit( 1 );
- }
- } /* End SWITCH on returned poll events. */
- /*
- ** Determine if this is a TCP request or UDP request.
- */
- if ( idx < tScktSize )
- {
- /*
- ** TCP connection requested. Accept it. Notice the use of
- ** the sockaddr_storage data type.
- */
- sadrLen = sizeof( sockStor );
- sadr = (struct sockaddr*) &sockStor;
- CHK( newSckt = accept( desc[ idx ].fd,
- sadr,
- &sadrLen ) );
- CHK( shutdown( newSckt, /* Server never recv's anything. */
- SHUT_RD ) );
- if ( verbose )
- {
- /*
- ** Display the socket address of the remote client. Begin with
- ** the address-independent fields.
- */
- fprintf( stderr,
- "Sockaddr info for new TCP client:\n"
- " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
- " addr len = %d (sockaddr_in = %lu, "
- "sockaddr_in6 = %lu)\n",
- sadr->sa_family,
- AF_INET,
- AF_INET6,
- sadrLen,
- sizeof( struct sockaddr_in ),
- sizeof( struct sockaddr_in6 ) );
- /*
- ** Display the address-specific fields.
- */
- getnameinfo( sadr,
- sadrLen,
- hostBfr,
- sizeof( hostBfr ),
- servBfr,
- sizeof( servBfr ),
- NI_NUMERICHOST | NI_NUMERICSERV );
- /*
- ** Notice that we're switching on an address family now, not a
- ** protocol family.
- */
- switch ( sadr->sa_family )
- {
- case AF_INET: /* IPv4 address. */
- {
- struct sockaddr_in *p = (struct sockaddr_in*) sadr;
- fprintf( stderr,
- " sin_addr = sin_family: %d\n"
- " sin_addr: %s\n"
- " sin_port: %s\n",
- p->sin_family,
- hostBfr,
- servBfr );
- break;
- } /* End CASE of IPv4. */
- case AF_INET6: /* IPv6 address. */
- {
- struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
- fprintf( stderr,
- " sin6_addr = sin6_family: %d\n"
- " sin6_addr: %s\n"
- " sin6_port: %s\n"
- " sin6_flowinfo: %d\n"
- " sin6_scope_id: %d\n",
- p->sin6_family,
- hostBfr,
- servBfr,
- p->sin6_flowinfo,
- p->sin6_scope_id );
- break;
- } /* End CASE of IPv6. */
- default: /* Can never get here, but for completeness. */
- {
- fprintf( stderr,
- "%s (line %d): ERROR - Unknown address "
- "family (%d).\n",
- pgmName,
- __LINE__,
- sadr->sa_family );
- break;
- } /* End DEFAULT case (unknown address family). */
- } /* End SWITCH on address family. */
- } /* End IF verbose mode. */
- /*
- ** Send the PIT to the client.
- */
- wBytes = timeLen;
- while ( wBytes > 0 )
- {
- do
- {
- count = write( newSckt,
- timeStr,
- wBytes );
- } while ( ( count < 0 ) && ( errno == EINTR ) );
- CHK( count ); /* Check for an error. */
- wBytes -= count;
- } /* End WHILE there is data to send. */
- CHK( close( newSckt ) );
- } /* End IF this was a TCP connection request. */
- else
- {
- /*
- ** This is a UDP socket, and a datagram is available. The funny
- ** thing about UDP requests is that this server doesn't require any
- ** client input; but it can't send the PIT unless it knows a client
- ** wants the data, and the only way that can occur with UDP is if
- ** the server receives a datagram from the client. Thus, the
- ** server must receive _something_, but the content of the datagram
- ** is irrelevant. Read in the datagram. Again note the use of
- ** sockaddr_storage to receive the address.
- */
- sadrLen = sizeof( sockStor );
- sadr = (struct sockaddr*) &sockStor;
- CHK( count = recvfrom( desc[ idx ].fd,
- bfr,
- sizeof( bfr ),
- 0,
- sadr,
- &sadrLen ) );
- /*
- ** Display whatever was received on stdout.
- */
- if ( verbose )
- {
- ssize_t rBytes = count;
- fprintf( stderr,
- "%s: UDP datagram received (%ld bytes).\n",
- pgmName,
- count );
- while ( count > 0 )
- {
- fputc( bfr[ rBytes - count-- ],
- stdout );
- }
- if ( bfr[ rBytes-1 ] != '\n' )
- fputc( '\n', stdout ); /* Newline also flushes stdout. */
- /*
- ** Display the socket address of the remote client. Address-
- ** independent fields first.
- */
- fprintf( stderr,
- "Remote client's sockaddr info:\n"
- " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
- " addr len = %d (sockaddr_in = %lu, "
- "sockaddr_in6 = %lu)\n",
- sadr->sa_family,
- AF_INET,
- AF_INET6,
- sadrLen,
- sizeof( struct sockaddr_in ),
- sizeof( struct sockaddr_in6 ) );
- /*
- ** Display the address-specific information.
- */
- getnameinfo( sadr,
- sadrLen,
- hostBfr,
- sizeof( hostBfr ),
- servBfr,
- sizeof( servBfr ),
- NI_NUMERICHOST | NI_NUMERICSERV );
- switch ( sadr->sa_family )
- {
- case AF_INET: /* IPv4 address. */
- {
- struct sockaddr_in *p = (struct sockaddr_in*) sadr;
- fprintf( stderr,
- " sin_addr = sin_family: %d\n"
- " sin_addr: %s\n"
- " sin_port: %s\n",
- p->sin_family,
- hostBfr,
- servBfr );
- break;
- } /* End CASE of IPv4 address. */
- case AF_INET6: /* IPv6 address. */
- {
- struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
- fprintf( stderr,
- " sin6_addr = sin6_family: %d\n"
- " sin6_addr: %s\n"
- " sin6_port: %s\n"
- " sin6_flowinfo: %d\n"
- " sin6_scope_id: %d\n",
- p->sin6_family,
- hostBfr,
- servBfr,
- p->sin6_flowinfo,
- p->sin6_scope_id );
- break;
- } /* End CASE of IPv6 address. */
- default: /* Can never get here, but for completeness. */
- {
- fprintf( stderr,
- "%s (line %d): ERROR - Unknown address "
- "family (%d).\n",
- pgmName,
- __LINE__,
- sadr->sa_family );
- break;
- } /* End DEFAULT case (unknown address family). */
- } /* End SWITCH on address family. */
- } /* End IF verbose mode. */
- /*
- ** Send the PIT to the client.
- */
- wBytes = timeLen;
- while ( wBytes > 0 )
- {
- do
- {
- count = sendto( desc[ idx ].fd,
- timeStr,
- wBytes,
- 0,
- sadr, /* Address & address length */
- sadrLen ); /* received in recvfrom(). */
- } while ( ( count < 0 ) && ( errno == EINTR ) );
- CHK( count ); /* Check for a bona fide error. */
- wBytes -= count;
- } /* End WHILE there is data to send. */
- } /* End ELSE a UDP datagram is available. */
- desc[ idx ].revents = 0; /* Clear the returned poll events. */
- } /* End FOR each socket descriptor. */
- } /* End WHILE forever. */
- } /* End pit() */
|