pit_server.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. /******************************************************************************
  2. * File: pit_server.c
  3. *
  4. * Description: Contains source code for an IPv6-capable 'PIT' server.
  5. * This is a derivative of the tod6 (time-of-day) server that was written
  6. * by John Wenker.
  7. * .......
  8. * Author of tod6: John Wenker, Sr. Software Engineer,
  9. * Performance Technologies, San Diego, USA
  10. * .......
  11. * The program tod6 was a time of day server. It has beeen modified
  12. * to provide a microsecond timestamp on request. Modified and adapted
  13. * for PIT purposes by Don Capps. [ capps@iozone.org ]
  14. *
  15. * This server sends the current value of gettimeofday() in
  16. * microseconds back to the client, as a numerical string.
  17. *
  18. * /etc/services should contain "PIT" with a specified port value.
  19. *
  20. ******************************************************************************/
  21. /*
  22. ** System header files.
  23. */
  24. #include <errno.h> /* errno declaration & error codes. */
  25. #include <netdb.h> /* getaddrinfo(3) et al. */
  26. #include <netinet/in.h> /* sockaddr_in & sockaddr_in6 definition. */
  27. #include <stdio.h> /* printf(3) et al. */
  28. #include <stdlib.h> /* exit(2). */
  29. #include <string.h> /* String manipulation & memory functions. */
  30. #if defined(_SUA_)
  31. #include <poll.h> /* poll(2) and related definitions. */
  32. #else
  33. #include <sys/poll.h> /* poll(2) and related definitions. */
  34. #endif
  35. #include <sys/socket.h> /* Socket functions (socket(2), bind(2), etc). */
  36. #include <time.h> /* time(2) & ctime(3). */
  37. #include <sys/time.h> /* gettimeofday */
  38. #include <unistd.h> /* getopt(3), read(2), etc. */
  39. /* Include for Cygnus development environment for Windows */
  40. #if defined (Windows)
  41. #include <Windows.h>
  42. int errno;
  43. #endif
  44. #if defined(_SUA_)
  45. extern char *optarg, *opterr;
  46. #endif
  47. /*
  48. ** Constants.
  49. **
  50. ** Please remember to add PIT service to the /etc/services file.
  51. */
  52. #define DFLT_SERVICE "PIT" /* Programmable Interdimensional Timer */
  53. #define INVALID_DESC -1 /* Invalid file descriptor. */
  54. #define MAXCONNQLEN 3 /* Max nbr of connection requests to queue. */
  55. #define MAXTCPSCKTS 2 /* One TCP socket for IPv4 & one for IPv6. */
  56. #define MAXUDPSCKTS 2 /* One UDP socket for IPv4 & one for IPv6. */
  57. #define VALIDOPTS "vh:p:" /* Valid command options. */
  58. /*
  59. ** Simple boolean type definition.
  60. */
  61. int false = 0;
  62. int true = 1;
  63. /*
  64. ** Prototypes for internal helper functions.
  65. */
  66. static int openSckt( const char *service,
  67. const char *protocol,
  68. int desc[ ],
  69. size_t *descSize );
  70. static void pit( int tSckt[ ],
  71. size_t tScktSize,
  72. int uSckt[ ],
  73. size_t uScktSize );
  74. /*
  75. ** Global data objects.
  76. */
  77. static char hostBfr[ NI_MAXHOST ]; /* For use w/getnameinfo(3). */
  78. static const char *pgmName; /* Program name w/o dir prefix. */
  79. static char servBfr[ NI_MAXSERV ]; /* For use w/getnameinfo(3). */
  80. static int verbose = 0; /* Verbose mode indication. */
  81. struct timeval tm; /* Timeval structure, used with gettimeofday() */
  82. char timeStr[40]; /* String for time in microseconds */
  83. char service_name[20];
  84. int need;
  85. /*
  86. ** Usage macro for command syntax violations.
  87. */
  88. #define USAGE \
  89. { \
  90. fprintf( stderr, \
  91. "Usage: %s [-v] -p service \n", \
  92. pgmName ); \
  93. exit( 127 ); \
  94. } /* End USAGE macro. */
  95. /*
  96. ** Macro to terminate the program if a system call error occurs. The system
  97. ** call must be one of the usual type that returns -1 on error.
  98. */
  99. #define CHK(expr) \
  100. do \
  101. { \
  102. if ( (expr) == -1 ) \
  103. { \
  104. fprintf( stderr, \
  105. "%s (line %d): System call ERROR - %s.\n", \
  106. pgmName, \
  107. __LINE__, \
  108. strerror( errno ) ); \
  109. exit( 1 ); \
  110. } /* End IF system call failed. */ \
  111. } while ( false )
  112. /******************************************************************************
  113. * Function: main
  114. *
  115. * Description:
  116. * Set up a PIT server and handle network requests. This server
  117. * handles both TCP and UDP requests.
  118. *
  119. * Parameters:
  120. * The usual argc and argv parameters to a main() function.
  121. *
  122. * Return Value:
  123. * This is a daemon program and never returns. However, in the degenerate
  124. * case where no sockets are created, the function returns zero.
  125. ******************************************************************************/
  126. int main( int argc,
  127. char *argv[ ] )
  128. {
  129. int opt;
  130. int tSckt[ MAXTCPSCKTS ]; /* Array of TCP socket descriptors. */
  131. size_t tScktSize = MAXTCPSCKTS; /* Size of uSckt (# of elements). */
  132. int uSckt[ MAXUDPSCKTS ]; /* Array of UDP socket descriptors. */
  133. size_t uScktSize = MAXUDPSCKTS; /* Size of uSckt (# of elements). */
  134. strcpy(service_name,DFLT_SERVICE);
  135. /*
  136. ** Set the program name (w/o directory prefix).
  137. */
  138. pgmName = strrchr( argv[ 0 ], '/' );
  139. pgmName = pgmName == NULL ? argv[ 0 ] : pgmName + 1;
  140. /*
  141. ** Process command options.
  142. */
  143. opterr = 0; /* Turns off "invalid option" error messages. */
  144. while ( ( opt = getopt( argc, argv, VALIDOPTS ) ) >= 0 )
  145. {
  146. switch ( opt )
  147. {
  148. case 'v': /* Verbose mode. */
  149. {
  150. verbose = true;
  151. break;
  152. }
  153. case 'p': /* Get the port number */
  154. {
  155. strcpy(service_name,optarg);
  156. need++;
  157. break;
  158. }
  159. default:
  160. {
  161. USAGE;
  162. }
  163. } /* End SWITCH on command option. */
  164. } /* End WHILE processing options. */
  165. if(need < 1)
  166. {
  167. USAGE;
  168. exit;
  169. }
  170. /*
  171. ** Open both a TCP and UDP socket, for both IPv4 & IPv6, on which to receive
  172. ** service requests.
  173. */
  174. if ( ( openSckt( service_name, "tcp", tSckt, &tScktSize ) < 0 ) ||
  175. ( openSckt( service_name, "udp", uSckt, &uScktSize ) < 0 ) )
  176. {
  177. exit( 1 );
  178. }
  179. /*
  180. ** Run the Programmable Interdimensional Timer server.
  181. */
  182. if ( ( tScktSize > 0 ) || ( uScktSize > 0 ) )
  183. {
  184. pit( tSckt, /* pit() never returns. */
  185. tScktSize,
  186. uSckt,
  187. uScktSize );
  188. }
  189. /*
  190. ** Since pit() never returns, execution only gets here if no sockets were
  191. ** created.
  192. */
  193. if ( verbose )
  194. {
  195. fprintf( stderr,
  196. "%s: No sockets opened... terminating.\n",
  197. pgmName );
  198. }
  199. return 0;
  200. } /* End main() */
  201. /******************************************************************************
  202. * Function: openSckt
  203. *
  204. * Description:
  205. * Open passive (server) sockets for the indicated inet service & protocol.
  206. * Notice in the last sentence that "sockets" is plural. During the interim
  207. * transition period while everyone is switching over to IPv6, the server
  208. * application has to open two sockets on which to listen for connections...
  209. * one for IPv4 traffic and one for IPv6 traffic.
  210. *
  211. * Parameters:
  212. * service - Pointer to a character string representing the well-known port
  213. * on which to listen (can be a service name or a decimal number).
  214. * protocol - Pointer to a character string representing the transport layer
  215. * protocol (only "tcp" or "udp" are valid).
  216. * desc - Pointer to an array into which the socket descriptors are
  217. * placed when opened.
  218. * descSize - This is a value-result parameter. On input, it contains the
  219. * max number of descriptors that can be put into 'desc' (i.e. the
  220. * number of elements in the array). Upon return, it will contain
  221. * the number of descriptors actually opened. Any unused slots in
  222. * 'desc' are set to INVALID_DESC.
  223. *
  224. * Return Value:
  225. * 0 on success, -1 on error.
  226. ******************************************************************************/
  227. static int openSckt( const char *service,
  228. const char *protocol,
  229. int desc[ ],
  230. size_t *descSize )
  231. {
  232. struct addrinfo *ai;
  233. int aiErr;
  234. struct addrinfo *aiHead;
  235. struct addrinfo hints = { .ai_flags = AI_PASSIVE, /* Server mode. */
  236. .ai_family = PF_UNSPEC }; /* IPv4 or IPv6. */
  237. size_t maxDescs = *descSize;
  238. /*
  239. ** Initialize output parameters. When the loop completes, *descSize is 0.
  240. */
  241. while ( *descSize > 0 )
  242. {
  243. desc[ --( *descSize ) ] = INVALID_DESC;
  244. }
  245. /*
  246. ** Check which protocol is selected (only TCP and UDP are valid).
  247. */
  248. if ( strcmp( protocol, "tcp" ) == 0 ) /* TCP protocol. */
  249. {
  250. hints.ai_socktype = SOCK_STREAM;
  251. hints.ai_protocol = IPPROTO_TCP;
  252. }
  253. else if ( strcmp( protocol, "udp" ) == 0 ) /* UDP protocol. */
  254. {
  255. hints.ai_socktype = SOCK_DGRAM;
  256. hints.ai_protocol = IPPROTO_UDP;
  257. }
  258. else /* Invalid protocol. */
  259. {
  260. fprintf( stderr,
  261. "%s (line %d): ERROR - Unknown transport "
  262. "layer protocol \"%s\".\n",
  263. pgmName,
  264. __LINE__,
  265. protocol );
  266. return -1;
  267. }
  268. /*
  269. ** Look up the service's "well-known" port number. Notice that NULL is being
  270. ** passed for the 'node' parameter, and that the AI_PASSIVE flag is set in
  271. ** 'hints'. Thus, the program is requesting passive address information.
  272. ** The network address is initialized to :: (all zeros) for IPv6 records, or
  273. ** 0.0.0.0 for IPv4 records.
  274. */
  275. if ( ( aiErr = getaddrinfo( NULL,
  276. service,
  277. &hints,
  278. &aiHead ) ) != 0 )
  279. {
  280. fprintf( stderr,
  281. "%s (line %d): ERROR - %s.\n",
  282. pgmName,
  283. __LINE__,
  284. gai_strerror( aiErr ) );
  285. return -1;
  286. }
  287. /*
  288. ** For each of the address records returned, attempt to set up a passive
  289. ** socket.
  290. */
  291. for ( ai = aiHead;
  292. ( ai != NULL ) && ( *descSize < maxDescs );
  293. ai = ai->ai_next )
  294. {
  295. if ( verbose )
  296. {
  297. /*
  298. ** Display the current address info. Start with the protocol-
  299. ** independent fields first.
  300. */
  301. fprintf( stderr,
  302. "Setting up a passive socket based on the "
  303. "following address info:\n"
  304. " ai_flags = 0x%02X\n"
  305. " ai_family = %d (PF_INET = %d, PF_INET6 = %d)\n"
  306. " ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d)\n"
  307. " ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d)\n"
  308. " ai_addrlen = %d (sockaddr_in = %lu, "
  309. "sockaddr_in6 = %lu)\n",
  310. ai->ai_flags,
  311. ai->ai_family,
  312. PF_INET,
  313. PF_INET6,
  314. ai->ai_socktype,
  315. SOCK_STREAM,
  316. SOCK_DGRAM,
  317. ai->ai_protocol,
  318. IPPROTO_TCP,
  319. IPPROTO_UDP,
  320. ai->ai_addrlen,
  321. sizeof( struct sockaddr_in ),
  322. sizeof( struct sockaddr_in6 ) );
  323. /*
  324. ** Now display the protocol-specific formatted socket address. Note
  325. ** that the program is requesting that getnameinfo(3) convert the
  326. ** host & service into numeric strings.
  327. */
  328. getnameinfo( ai->ai_addr,
  329. ai->ai_addrlen,
  330. hostBfr,
  331. sizeof( hostBfr ),
  332. servBfr,
  333. sizeof( servBfr ),
  334. NI_NUMERICHOST | NI_NUMERICSERV );
  335. switch ( ai->ai_family )
  336. {
  337. case PF_INET: /* IPv4 address record. */
  338. {
  339. struct sockaddr_in *p = (struct sockaddr_in*) ai->ai_addr;
  340. fprintf( stderr,
  341. " ai_addr = sin_family: %d (AF_INET = %d, "
  342. "AF_INET6 = %d)\n"
  343. " sin_addr: %s\n"
  344. " sin_port: %s\n",
  345. p->sin_family,
  346. AF_INET,
  347. AF_INET6,
  348. hostBfr,
  349. servBfr );
  350. break;
  351. } /* End CASE of IPv4. */
  352. case PF_INET6: /* IPv6 address record. */
  353. {
  354. struct sockaddr_in6 *p = (struct sockaddr_in6*) ai->ai_addr;
  355. fprintf( stderr,
  356. " ai_addr = sin6_family: %d (AF_INET = %d, "
  357. "AF_INET6 = %d)\n"
  358. " sin6_addr: %s\n"
  359. " sin6_port: %s\n"
  360. " sin6_flowinfo: %d\n"
  361. " sin6_scope_id: %d\n",
  362. p->sin6_family,
  363. AF_INET,
  364. AF_INET6,
  365. hostBfr,
  366. servBfr,
  367. p->sin6_flowinfo,
  368. p->sin6_scope_id );
  369. break;
  370. } /* End CASE of IPv6. */
  371. default: /* Can never get here, but just for completeness. */
  372. {
  373. fprintf( stderr,
  374. "%s (line %d): ERROR - Unknown protocol family (%d).\n",
  375. pgmName,
  376. __LINE__,
  377. ai->ai_family );
  378. freeaddrinfo( aiHead );
  379. return -1;
  380. } /* End DEFAULT case (unknown protocol family). */
  381. } /* End SWITCH on protocol family. */
  382. } /* End IF verbose mode. */
  383. /*
  384. ** Create a socket using the info in the addrinfo structure.
  385. */
  386. CHK( desc[ *descSize ] = socket( ai->ai_family,
  387. ai->ai_socktype,
  388. ai->ai_protocol ) );
  389. /*
  390. ** Here is the code that prevents "IPv4 mapped addresses", as discussed
  391. ** in Section 22.1.3.1. If an IPv6 socket was just created, then set the
  392. ** IPV6_V6ONLY socket option.
  393. */
  394. if ( ai->ai_family == PF_INET6 )
  395. {
  396. #if defined( IPV6_V6ONLY )
  397. /*
  398. ** Disable IPv4 mapped addresses.
  399. */
  400. int v6Only = 1;
  401. CHK( setsockopt( desc[ *descSize ],
  402. IPPROTO_IPV6,
  403. IPV6_V6ONLY,
  404. &v6Only,
  405. sizeof( v6Only ) ) );
  406. #else
  407. /*
  408. ** IPV6_V6ONLY is not defined, so the socket option can't be set and
  409. ** thus IPv4 mapped addresses can't be disabled. Print a warning
  410. ** message and close the socket. Design note: If the
  411. ** #if...#else...#endif construct were removed, then this program
  412. ** would not compile (because IPV6_V6ONLY isn't defined). That's an
  413. ** acceptable approach; IPv4 mapped addresses are certainly disabled
  414. ** if the program can't build! However, since this program is also
  415. ** designed to work for IPv4 sockets as well as IPv6, I decided to
  416. ** allow the program to compile when IPV6_V6ONLY is not defined, and
  417. ** turn it into a run-time warning rather than a compile-time error.
  418. ** IPv4 mapped addresses are still disabled because _all_ IPv6 traffic
  419. ** is disabled (all IPv6 sockets are closed here), but at least this
  420. ** way the server can still service IPv4 network traffic.
  421. */
  422. fprintf( stderr,
  423. "%s (line %d): WARNING - Cannot set IPV6_V6ONLY socket "
  424. "option. Closing IPv6 %s socket.\n",
  425. pgmName,
  426. __LINE__,
  427. ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP" );
  428. CHK( close( desc[ *descSize ] ) );
  429. continue; /* Go to top of FOR loop w/o updating *descSize! */
  430. #endif /* IPV6_V6ONLY */
  431. } /* End IF this is an IPv6 socket. */
  432. /*
  433. ** Bind the socket. Again, the info from the addrinfo structure is used.
  434. */
  435. CHK( bind( desc[ *descSize ],
  436. ai->ai_addr,
  437. ai->ai_addrlen ) );
  438. /*
  439. ** If this is a TCP socket, put the socket into passive listening mode
  440. ** (listen is only valid on connection-oriented sockets).
  441. */
  442. if ( ai->ai_socktype == SOCK_STREAM )
  443. {
  444. CHK( listen( desc[ *descSize ],
  445. MAXCONNQLEN ) );
  446. }
  447. /*
  448. ** Socket set up okay. Bump index to next descriptor array element.
  449. */
  450. *descSize += 1;
  451. } /* End FOR each address info structure returned. */
  452. /*
  453. ** Dummy check for unused address records.
  454. */
  455. if ( verbose && ( ai != NULL ) )
  456. {
  457. fprintf( stderr,
  458. "%s (line %d): WARNING - Some address records were "
  459. "not processed due to insufficient array space.\n",
  460. pgmName,
  461. __LINE__ );
  462. } /* End IF verbose and some address records remain unprocessed. */
  463. /*
  464. ** Clean up.
  465. */
  466. freeaddrinfo( aiHead );
  467. return 0;
  468. } /* End openSckt() */
  469. /******************************************************************************
  470. * Function: pit
  471. *
  472. * Description:
  473. * Listen on a set of sockets and send the current microsecond counter
  474. * that was produced by gettimeofday(), to any clients. This function
  475. * never returns.
  476. *
  477. * Parameters:
  478. * tSckt - Array of TCP socket descriptors on which to listen.
  479. * tScktSize - Size of the tSckt array (nbr of elements).
  480. * uSckt - Array of UDP socket descriptors on which to listen.
  481. * uScktSize - Size of the uSckt array (nbr of elements).
  482. *
  483. * Return Value: None.
  484. ******************************************************************************/
  485. static void pit( int tSckt[ ],
  486. size_t tScktSize,
  487. int uSckt[ ],
  488. size_t uScktSize )
  489. {
  490. char bfr[ 256 ];
  491. ssize_t count;
  492. struct pollfd *desc;
  493. size_t descSize = tScktSize + uScktSize;
  494. int idx;
  495. int newSckt;
  496. struct sockaddr *sadr;
  497. socklen_t sadrLen;
  498. struct sockaddr_storage sockStor;
  499. int status;
  500. size_t timeLen;
  501. time_t timeVal;
  502. ssize_t wBytes;
  503. unsigned long long secs;
  504. int ret;
  505. /*
  506. ** Allocate memory for the poll(2) array.
  507. */
  508. desc = malloc( descSize * sizeof( struct pollfd ) );
  509. if ( desc == NULL )
  510. {
  511. fprintf( stderr,
  512. "%s (line %d): ERROR - %s.\n",
  513. pgmName,
  514. __LINE__,
  515. strerror( ENOMEM ) );
  516. exit( 1 );
  517. }
  518. /*
  519. ** Initialize the poll(2) array.
  520. */
  521. for ( idx = 0; idx < descSize; idx++ )
  522. {
  523. desc[ idx ].fd = idx < tScktSize ? tSckt[ idx ]
  524. : uSckt[ idx - tScktSize ];
  525. desc[ idx ].events = POLLIN;
  526. desc[ idx ].revents = 0;
  527. }
  528. /*
  529. ** Main PIT server loop. Handles both TCP & UDP requests. This is
  530. ** an interative server, and all requests are handled directly within the
  531. ** main loop.
  532. */
  533. while ( true ) /* Do forever. */
  534. {
  535. /*
  536. ** Wait for activity on one of the sockets. The DO..WHILE construct is
  537. ** used to restart the system call in the event the process is
  538. ** interrupted by a signal.
  539. */
  540. do
  541. {
  542. status = poll( desc,
  543. descSize,
  544. -1 /* Wait indefinitely for input. */ );
  545. } while ( ( status < 0 ) && ( errno == EINTR ) );
  546. CHK( status ); /* Check for a bona fide system call error. */
  547. /*
  548. ** Get the current time.
  549. */
  550. #if defined(Windows)
  551. LARGE_INTEGER freq,counter;
  552. double wintime,bigcounter;
  553. /* For Windows the time_of_day() is useless. It increments in 55 milli
  554. * second increments. By using the Win32api one can get access to the
  555. * high performance measurement interfaces. With this one can get back
  556. * into the 8 to 9 microsecond resolution.
  557. */
  558. QueryPerformanceFrequency(&freq);
  559. QueryPerformanceCounter(&counter);
  560. bigcounter=(double)counter.HighPart *(double)0xffffffff +
  561. (double)counter.LowPart;
  562. wintime = (double)(bigcounter/(double)freq.LowPart);
  563. secs = (long long)(wintime * 1000000);
  564. #else
  565. ret = gettimeofday( &tm,0 );
  566. secs = ((unsigned long long)tm.tv_sec * 1000000)
  567. + (unsigned long long)tm.tv_usec;
  568. #endif
  569. ret = sprintf(timeStr,"%llu",secs);
  570. timeLen = strlen( timeStr );
  571. /*
  572. ** Process sockets with input available.
  573. */
  574. for ( idx = 0; idx < descSize; idx++ )
  575. {
  576. switch ( desc[ idx ].revents )
  577. {
  578. case 0: /* No activity on this socket; try the next. */
  579. continue;
  580. case POLLIN: /* Network activity. Go process it. */
  581. break;
  582. default: /* Invalid poll events. */
  583. {
  584. fprintf( stderr,
  585. "%s (line %d): ERROR - Invalid poll event (0x%02X).\n",
  586. pgmName,
  587. __LINE__,
  588. desc[ idx ].revents );
  589. exit( 1 );
  590. }
  591. } /* End SWITCH on returned poll events. */
  592. /*
  593. ** Determine if this is a TCP request or UDP request.
  594. */
  595. if ( idx < tScktSize )
  596. {
  597. /*
  598. ** TCP connection requested. Accept it. Notice the use of
  599. ** the sockaddr_storage data type.
  600. */
  601. sadrLen = sizeof( sockStor );
  602. sadr = (struct sockaddr*) &sockStor;
  603. CHK( newSckt = accept( desc[ idx ].fd,
  604. sadr,
  605. &sadrLen ) );
  606. CHK( shutdown( newSckt, /* Server never recv's anything. */
  607. SHUT_RD ) );
  608. if ( verbose )
  609. {
  610. /*
  611. ** Display the socket address of the remote client. Begin with
  612. ** the address-independent fields.
  613. */
  614. fprintf( stderr,
  615. "Sockaddr info for new TCP client:\n"
  616. " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
  617. " addr len = %d (sockaddr_in = %lu, "
  618. "sockaddr_in6 = %lu)\n",
  619. sadr->sa_family,
  620. AF_INET,
  621. AF_INET6,
  622. sadrLen,
  623. sizeof( struct sockaddr_in ),
  624. sizeof( struct sockaddr_in6 ) );
  625. /*
  626. ** Display the address-specific fields.
  627. */
  628. getnameinfo( sadr,
  629. sadrLen,
  630. hostBfr,
  631. sizeof( hostBfr ),
  632. servBfr,
  633. sizeof( servBfr ),
  634. NI_NUMERICHOST | NI_NUMERICSERV );
  635. /*
  636. ** Notice that we're switching on an address family now, not a
  637. ** protocol family.
  638. */
  639. switch ( sadr->sa_family )
  640. {
  641. case AF_INET: /* IPv4 address. */
  642. {
  643. struct sockaddr_in *p = (struct sockaddr_in*) sadr;
  644. fprintf( stderr,
  645. " sin_addr = sin_family: %d\n"
  646. " sin_addr: %s\n"
  647. " sin_port: %s\n",
  648. p->sin_family,
  649. hostBfr,
  650. servBfr );
  651. break;
  652. } /* End CASE of IPv4. */
  653. case AF_INET6: /* IPv6 address. */
  654. {
  655. struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
  656. fprintf( stderr,
  657. " sin6_addr = sin6_family: %d\n"
  658. " sin6_addr: %s\n"
  659. " sin6_port: %s\n"
  660. " sin6_flowinfo: %d\n"
  661. " sin6_scope_id: %d\n",
  662. p->sin6_family,
  663. hostBfr,
  664. servBfr,
  665. p->sin6_flowinfo,
  666. p->sin6_scope_id );
  667. break;
  668. } /* End CASE of IPv6. */
  669. default: /* Can never get here, but for completeness. */
  670. {
  671. fprintf( stderr,
  672. "%s (line %d): ERROR - Unknown address "
  673. "family (%d).\n",
  674. pgmName,
  675. __LINE__,
  676. sadr->sa_family );
  677. break;
  678. } /* End DEFAULT case (unknown address family). */
  679. } /* End SWITCH on address family. */
  680. } /* End IF verbose mode. */
  681. /*
  682. ** Send the PIT to the client.
  683. */
  684. wBytes = timeLen;
  685. while ( wBytes > 0 )
  686. {
  687. do
  688. {
  689. count = write( newSckt,
  690. timeStr,
  691. wBytes );
  692. } while ( ( count < 0 ) && ( errno == EINTR ) );
  693. CHK( count ); /* Check for an error. */
  694. wBytes -= count;
  695. } /* End WHILE there is data to send. */
  696. CHK( close( newSckt ) );
  697. } /* End IF this was a TCP connection request. */
  698. else
  699. {
  700. /*
  701. ** This is a UDP socket, and a datagram is available. The funny
  702. ** thing about UDP requests is that this server doesn't require any
  703. ** client input; but it can't send the PIT unless it knows a client
  704. ** wants the data, and the only way that can occur with UDP is if
  705. ** the server receives a datagram from the client. Thus, the
  706. ** server must receive _something_, but the content of the datagram
  707. ** is irrelevant. Read in the datagram. Again note the use of
  708. ** sockaddr_storage to receive the address.
  709. */
  710. sadrLen = sizeof( sockStor );
  711. sadr = (struct sockaddr*) &sockStor;
  712. CHK( count = recvfrom( desc[ idx ].fd,
  713. bfr,
  714. sizeof( bfr ),
  715. 0,
  716. sadr,
  717. &sadrLen ) );
  718. /*
  719. ** Display whatever was received on stdout.
  720. */
  721. if ( verbose )
  722. {
  723. ssize_t rBytes = count;
  724. fprintf( stderr,
  725. "%s: UDP datagram received (%ld bytes).\n",
  726. pgmName,
  727. count );
  728. while ( count > 0 )
  729. {
  730. fputc( bfr[ rBytes - count-- ],
  731. stdout );
  732. }
  733. if ( bfr[ rBytes-1 ] != '\n' )
  734. fputc( '\n', stdout ); /* Newline also flushes stdout. */
  735. /*
  736. ** Display the socket address of the remote client. Address-
  737. ** independent fields first.
  738. */
  739. fprintf( stderr,
  740. "Remote client's sockaddr info:\n"
  741. " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
  742. " addr len = %d (sockaddr_in = %lu, "
  743. "sockaddr_in6 = %lu)\n",
  744. sadr->sa_family,
  745. AF_INET,
  746. AF_INET6,
  747. sadrLen,
  748. sizeof( struct sockaddr_in ),
  749. sizeof( struct sockaddr_in6 ) );
  750. /*
  751. ** Display the address-specific information.
  752. */
  753. getnameinfo( sadr,
  754. sadrLen,
  755. hostBfr,
  756. sizeof( hostBfr ),
  757. servBfr,
  758. sizeof( servBfr ),
  759. NI_NUMERICHOST | NI_NUMERICSERV );
  760. switch ( sadr->sa_family )
  761. {
  762. case AF_INET: /* IPv4 address. */
  763. {
  764. struct sockaddr_in *p = (struct sockaddr_in*) sadr;
  765. fprintf( stderr,
  766. " sin_addr = sin_family: %d\n"
  767. " sin_addr: %s\n"
  768. " sin_port: %s\n",
  769. p->sin_family,
  770. hostBfr,
  771. servBfr );
  772. break;
  773. } /* End CASE of IPv4 address. */
  774. case AF_INET6: /* IPv6 address. */
  775. {
  776. struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
  777. fprintf( stderr,
  778. " sin6_addr = sin6_family: %d\n"
  779. " sin6_addr: %s\n"
  780. " sin6_port: %s\n"
  781. " sin6_flowinfo: %d\n"
  782. " sin6_scope_id: %d\n",
  783. p->sin6_family,
  784. hostBfr,
  785. servBfr,
  786. p->sin6_flowinfo,
  787. p->sin6_scope_id );
  788. break;
  789. } /* End CASE of IPv6 address. */
  790. default: /* Can never get here, but for completeness. */
  791. {
  792. fprintf( stderr,
  793. "%s (line %d): ERROR - Unknown address "
  794. "family (%d).\n",
  795. pgmName,
  796. __LINE__,
  797. sadr->sa_family );
  798. break;
  799. } /* End DEFAULT case (unknown address family). */
  800. } /* End SWITCH on address family. */
  801. } /* End IF verbose mode. */
  802. /*
  803. ** Send the PIT to the client.
  804. */
  805. wBytes = timeLen;
  806. while ( wBytes > 0 )
  807. {
  808. do
  809. {
  810. count = sendto( desc[ idx ].fd,
  811. timeStr,
  812. wBytes,
  813. 0,
  814. sadr, /* Address & address length */
  815. sadrLen ); /* received in recvfrom(). */
  816. } while ( ( count < 0 ) && ( errno == EINTR ) );
  817. CHK( count ); /* Check for a bona fide error. */
  818. wBytes -= count;
  819. } /* End WHILE there is data to send. */
  820. } /* End ELSE a UDP datagram is available. */
  821. desc[ idx ].revents = 0; /* Clear the returned poll events. */
  822. } /* End FOR each socket descriptor. */
  823. } /* End WHILE forever. */
  824. } /* End pit() */