PAPI  5.0.1.0
pit_server.c
Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines