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