2 Data source for network testing.
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/PcdLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/UefiLib.h>
24 #include <netinet/in.h>
26 #include <sys/EfiSysCall.h>
28 #include <sys/socket.h>
31 #define MAX_CONNECTIONS ( 1 + 16 ) ///< Maximum number of client connections
32 #define RANGE_SWITCH 2048 ///< Switch display ranges
33 #define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates
34 #define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average
36 #define TPL_DATASINK TPL_CALLBACK ///< Synchronization TPL
38 #define PACKET_SIZE 1448 ///< Size of data packets
39 #define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes
41 typedef struct _DT_PORT
{
45 struct sockaddr_in RemoteAddress
;
49 volatile BOOLEAN bTick
;
50 BOOLEAN bTimerRunning
;
51 struct sockaddr_in LocalAddress
;
54 UINT8 Buffer
[ DATA_BUFFER_SIZE
];
55 struct pollfd PollFd
[ MAX_CONNECTIONS
];
56 DT_PORT Port
[ MAX_CONNECTIONS
];
61 // Forward routine declarations
63 EFI_STATUS
TimerStart ( UINTN Milliseconds
);
67 Check for control C entered at console
69 @retval EFI_SUCCESS Control C not entered
70 @retval EFI_ABORTED Control C entered
79 // Assume no user intervention
84 // Display user stop request
86 if ( EFI_ERROR ( Status
)) {
88 "User stop request!\r\n" ));
92 // Return the check status
99 Accept a socket connection
101 @retval EFI_SUCCESS The application is running normally
102 @retval EFI_NOT_STARTED Error with the listen socket
103 @retval Other The user stopped the application
116 Status
= EFI_DEVICE_ERROR
;
119 // Bind to the local address
121 SocketStatus
= bind ( ListenSocket
,
122 (struct sockaddr
*) &LocalAddress
,
123 LocalAddress
.sin_len
);
124 if ( 0 == SocketStatus
) {
126 // Start listening on the local socket
128 SocketStatus
= listen ( ListenSocket
, 5 );
129 if ( 0 == SocketStatus
) {
131 // Local socket in the listen state
133 Status
= EFI_SUCCESS
;
139 PollFd
[ Index
].fd
= ListenSocket
;
140 PollFd
[ Index
].events
= POLLRDNORM
| POLLHUP
;
141 PollFd
[ Index
].revents
= 0;
142 Port
[ Index
].BytesAverage
= 0;
143 Port
[ Index
].BytesPrevious
= 0;
144 Port
[ Index
].BytesTotal
= 0;
145 Port
[ Index
].Samples
= 0;
146 Port
[ Index
].RemoteAddress
.sin_len
= 0;
147 Port
[ Index
].RemoteAddress
.sin_family
= 0;
148 Port
[ Index
].RemoteAddress
.sin_port
= 0;
149 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
= 0;
154 // Return the operation status
163 @retval EFI_SUCCESS The application is running normally
164 @retval Other The user stopped the application
174 // Determine if the socket is open
176 Status
= EFI_DEVICE_ERROR
;
177 if ( -1 != ListenSocket
) {
179 // Attempt to close the socket
181 CloseStatus
= close ( ListenSocket
);
182 if ( 0 == CloseStatus
) {
184 "0x%08x: Socket closed\r\n",
187 Status
= EFI_SUCCESS
;
190 DEBUG (( DEBUG_ERROR
,
191 "ERROR: Failed to close socket, errno: %d\r\n",
197 // Return the operation status
206 @retval EFI_SUCCESS The application is running normally
207 @retval Other The user stopped the application
216 // Get the port number
218 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
219 LocalAddress
.sin_len
= sizeof ( LocalAddress
);
220 LocalAddress
.sin_family
= AF_INET
;
221 LocalAddress
.sin_port
= htons ( PcdGet16 ( DataSource_Port
));
224 // Loop creating the socket
227 "Creating the socket\r\n" ));
230 // Check for user stop request
232 Status
= ControlCCheck ( );
233 if ( !EFI_ERROR ( Status
)) {
235 // Attempt to create the socket
237 ListenSocket
= socket ( AF_INET
,
240 if ( -1 != ListenSocket
) {
242 "0x%08x: Socket created\r\n",
247 Status
= EFI_NOT_STARTED
;
252 // Return the operation status
259 Poll the socket for more work
261 @retval EFI_SUCCESS The application is running normally
262 @retval EFI_NOT_STARTED Listen socket error
263 @retval Other The user stopped the application
269 BOOLEAN bRemoveSocket
;
270 BOOLEAN bListenError
;
271 size_t BytesReceived
;
277 socklen_t LengthInBytes
;
278 struct sockaddr_in RemoteAddress
;
284 // Check for control-C
286 bListenError
= FALSE
;
287 Status
= ControlCCheck ( );
288 if ( !EFI_ERROR ( Status
)) {
292 FdCount
= poll ( &PollFd
[0],
295 if ( -1 == FdCount
) {
299 DEBUG (( DEBUG_ERROR
,
300 "ERROR - Poll error, errno: %d\r\n",
302 Status
= EFI_DEVICE_ERROR
;
306 // Process the poll output
310 bRemoveSocket
= FALSE
;
313 // Account for this descriptor
315 if ( 0 != PollFd
[ Index
].revents
) {
320 // Check for a broken connection
322 if ( 0 != ( PollFd
[ Index
].revents
& POLLHUP
)) {
323 bRemoveSocket
= TRUE
;
324 if ( ListenSocket
== PollFd
[ Index
].fd
) {
326 DEBUG (( DEBUG_ERROR
,
327 "ERROR - Network closed on listen socket, errno: %d\r\n",
331 DEBUG (( DEBUG_ERROR
,
332 "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",
333 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
334 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
335 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
336 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
337 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
343 CloseStatus
= close ( PollFd
[ Index
].fd
);
344 if ( 0 == CloseStatus
) {
345 bRemoveSocket
= TRUE
;
347 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
349 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
350 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
351 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
352 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
353 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
356 DEBUG (( DEBUG_ERROR
,
357 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
359 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
360 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
361 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
362 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
363 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
370 // Check for a connection or read data
372 if ( 0 != ( PollFd
[ Index
].revents
& POLLRDNORM
)) {
374 // Check for a connection
376 if ( ListenSocket
== PollFd
[ Index
].fd
) {
378 // Another client connection was received
380 LengthInBytes
= sizeof ( RemoteAddress
);
381 Socket
= accept ( ListenSocket
,
382 (struct sockaddr
*) &RemoteAddress
,
384 if ( -1 == Socket
) {
386 // Listen socket error
389 bRemoveSocket
= TRUE
;
390 DEBUG (( DEBUG_ERROR
,
391 "ERROR - Listen socket failure, errno: %d\r\n",
396 // Determine if there is room for this connection
398 if (( MAX_CONNECTIONS
<= MaxPort
)
399 || ((( MAX_CONNECTIONS
- 1 ) == MaxPort
) && ( -1 == ListenSocket
))) {
401 // Display the connection
403 Print ( L
"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",
404 RemoteAddress
.sin_addr
.s_addr
& 0xff,
405 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
406 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
407 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
408 htons ( RemoteAddress
.sin_port
));
411 // No room for this connection
412 // Close the connection
414 CloseStatus
= close ( Socket
);
415 if ( 0 == CloseStatus
) {
416 bRemoveSocket
= TRUE
;
418 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
420 RemoteAddress
.sin_addr
.s_addr
& 0xff,
421 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
422 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
423 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
424 htons ( RemoteAddress
.sin_port
)));
427 DEBUG (( DEBUG_ERROR
,
428 "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",
434 // Keep the application running
435 // No issue with the listen socket
437 Status
= EFI_SUCCESS
;
442 // Display the connection
444 Print ( L
"Connected to remote system %d.%d.%d.%d:%d\r\n",
445 RemoteAddress
.sin_addr
.s_addr
& 0xff,
446 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
447 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
448 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
449 htons ( RemoteAddress
.sin_port
));
452 // Allocate the client connection
455 Port
[ Index
].BytesAverage
= 0;
456 Port
[ Index
].BytesPrevious
= 0;
457 Port
[ Index
].BytesTotal
= 0;
458 Port
[ Index
].Samples
= 0;
459 Port
[ Index
].RemoteAddress
.sin_len
= RemoteAddress
.sin_len
;
460 Port
[ Index
].RemoteAddress
.sin_family
= RemoteAddress
.sin_family
;
461 Port
[ Index
].RemoteAddress
.sin_port
= RemoteAddress
.sin_port
;
462 Port
[ Index
].RemoteAddress
.sin_addr
= RemoteAddress
.sin_addr
;
463 PollFd
[ Index
].fd
= Socket
;
464 PollFd
[ Index
].events
= POLLRDNORM
| POLLHUP
;
465 PollFd
[ Index
].revents
= 0;
473 BytesReceived
= read ( PollFd
[ Index
].fd
,
476 if ( 0 < BytesReceived
) {
478 // Display the amount of data received
481 "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",
484 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
485 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
486 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
487 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
488 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
491 // Synchronize with the TimerCallback routine
493 TplPrevious
= gBS
->RaiseTPL ( TPL_DATASINK
);
496 // Account for the data received
498 Port
[ Index
].BytesTotal
+= BytesReceived
;
501 // Release the synchronization with the TimerCallback routine
503 gBS
->RestoreTPL ( TplPrevious
);
505 else if ( -1 == BytesReceived
) {
510 "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",
511 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
512 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
513 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
514 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
515 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
517 CloseStatus
= close ( PollFd
[ Index
].fd
);
518 if ( 0 == CloseStatus
) {
519 bRemoveSocket
= TRUE
;
521 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
523 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
524 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
525 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
526 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
527 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
530 DEBUG (( DEBUG_ERROR
,
531 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
533 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
534 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
535 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
536 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
537 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
543 // Keep the application running
544 // No issue with the listen socket
546 Status
= EFI_SUCCESS
;
551 // Remove the socket if necessary
553 if ( bRemoveSocket
) {
555 "0x%08x: Socket removed from polling\r\n",
556 PollFd
[ Index
].fd
));
558 for ( Entry
= Index
+ 1; MaxPort
>= Entry
; Entry
++ ) {
559 EntryPrevious
= Entry
;
560 Port
[ EntryPrevious
].BytesAverage
= Port
[ Entry
].BytesAverage
;
561 Port
[ EntryPrevious
].BytesPrevious
= Port
[ Entry
].BytesPrevious
;
562 Port
[ EntryPrevious
].BytesTotal
= Port
[ Entry
].BytesTotal
;
563 Port
[ EntryPrevious
].RemoteAddress
.sin_len
= Port
[ Entry
].RemoteAddress
.sin_len
;
564 Port
[ EntryPrevious
].RemoteAddress
.sin_family
= Port
[ Entry
].RemoteAddress
.sin_family
;
565 Port
[ EntryPrevious
].RemoteAddress
.sin_port
= Port
[ Entry
].RemoteAddress
.sin_port
;
566 Port
[ EntryPrevious
].RemoteAddress
.sin_addr
.s_addr
= Port
[ Entry
].RemoteAddress
.sin_addr
.s_addr
;
567 Port
[ EntryPrevious
].Samples
= Port
[ Entry
].Samples
;
568 PollFd
[ EntryPrevious
].events
= PollFd
[ Entry
].events
;
569 PollFd
[ EntryPrevious
].fd
= PollFd
[ Entry
].fd
;
570 PollFd
[ EntryPrevious
].revents
= PollFd
[ Entry
].revents
;
572 PollFd
[ MaxPort
].fd
= -1;
577 // Account for this socket
585 // Return the listen failure if necessary
587 if (( !EFI_ERROR ( Status
)) && bListenError
) {
588 Status
= EFI_NOT_STARTED
;
592 // Return the poll status
599 Handle the timer callback
601 @param [in] Event Event that caused this callback
602 @param [in] pContext Context for this routine
611 UINT64 BytesReceived
;
617 // Notify the other code of the timer tick
622 // Walk the list of ports
624 for ( Index
= 0; MaxPort
> Index
; Index
++ ) {
626 // Determine if any data was received
628 BytesReceived
= Port
[ Index
].BytesTotal
;
629 if (( ListenSocket
!= PollFd
[ Index
].fd
)
630 && ( 0 != BytesReceived
)) {
632 // Update the average bytes per second
634 DeltaBytes
= Port
[ Index
].BytesAverage
>> AVERAGE_SHIFT_COUNT
;
635 Port
[ Index
].BytesAverage
-= DeltaBytes
;
636 DeltaBytes
= BytesReceived
- Port
[ Index
].BytesPrevious
;
637 Port
[ Index
].BytesPrevious
= BytesReceived
;
638 Port
[ Index
].BytesAverage
+= DeltaBytes
;
641 // Separate the samples
643 if (( 2 << AVERAGE_SHIFT_COUNT
) == Port
[ Index
].Samples
) {
644 Print ( L
"---------- Stable average ----------\r\n" );
646 Port
[ Index
].Samples
+= 1;
649 // Display the data rate
651 Delta
= (UINT32
)( DeltaBytes
>> DATA_RATE_UPDATE_SHIFT
);
652 Average
= Port
[ Index
].BytesAverage
>> ( AVERAGE_SHIFT_COUNT
+ DATA_RATE_UPDATE_SHIFT
);
653 if ( Average
< RANGE_SWITCH
) {
654 Print ( L
"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",
660 if ( Average
< RANGE_SWITCH
) {
661 Print ( L
"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",
667 if ( Average
< RANGE_SWITCH
) {
668 Print ( L
"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",
674 if ( Average
< RANGE_SWITCH
) {
675 Print ( L
"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",
681 if ( Average
< RANGE_SWITCH
) {
682 Print ( L
"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",
688 Print ( L
"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",
704 @retval EFI_SUCCESS The timer was successfully created
705 @retval Other Timer initialization failed
716 Status
= gBS
->CreateEvent ( EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
721 if ( EFI_ERROR ( Status
)) {
722 DEBUG (( DEBUG_ERROR
,
723 "ERROR - Failed to allocate the timer event, Status: %r\r\n",
728 "0x%08x: Timer created\r\n",
733 // Return the operation status
742 @retval EFI_SUCCESS The timer was stopped successfully
743 @retval Other The timer failed to stop
754 Status
= EFI_SUCCESS
;
757 // Determine if the timer is running
759 if ( bTimerRunning
) {
763 Status
= gBS
->SetTimer ( pTimer
,
766 if ( EFI_ERROR ( Status
)) {
767 DEBUG (( DEBUG_ERROR
,
768 "ERROR - Failed to stop the timer, Status: %r\r\n",
773 // Timer timer is now stopped
775 bTimerRunning
= FALSE
;
777 "0x%08x: Timer stopped\r\n",
783 // Return the operation status
792 @param [in] Milliseconds The number of milliseconds between timer callbacks
794 @retval EFI_SUCCESS The timer was successfully created
795 @retval Other Timer initialization failed
806 // Stop the timer if necessary
808 Status
= EFI_SUCCESS
;
809 if ( bTimerRunning
) {
810 Status
= TimerStop ( );
812 if ( !EFI_ERROR ( Status
)) {
814 // Compute the new delay
816 TimeDelay
= Milliseconds
;
817 TimeDelay
*= 1000 * 10;
822 Status
= gBS
->SetTimer ( pTimer
,
825 if ( EFI_ERROR ( Status
)) {
826 DEBUG (( DEBUG_ERROR
,
827 "ERROR - Failed to start the timer, Status: %r\r\n",
832 // The timer is now running
834 bTimerRunning
= TRUE
;
836 "0x%08x: Timer running\r\n",
842 // Return the operation status
851 @retval EFI_SUCCESS The timer was destroyed successfully
852 @retval Other Failed to destroy the timer
863 Status
= EFI_SUCCESS
;
866 // Determine if the timer is running
868 if ( bTimerRunning
) {
872 Status
= TimerStop ( );
874 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pTimer
)) {
876 // Done with this timer
878 Status
= gBS
->CloseEvent ( pTimer
);
879 if ( EFI_ERROR ( Status
)) {
880 DEBUG (( DEBUG_ERROR
,
881 "ERROR - Failed to free the timer event, Status: %r\r\n",
886 "0x%08x: Timer Destroyed\r\n",
893 // Return the operation status
900 Receive data from the DataSource program to test a network's bandwidth.
902 @param [in] Argc The number of arguments
903 @param [in] Argv The argument value array
905 @retval 0 The application exited normally.
906 @retval Other An error occurred.
917 "DataSink starting\r\n" ));
920 // Use for/break instead of goto
928 Status
= TimerCreate ( );
929 if ( EFI_ERROR ( Status
)) {
934 // Start a timer to perform network polling and display updates
936 Status
= TimerStart ( 1 * 1000 );
937 if ( EFI_ERROR ( Status
)) {
942 // Loop forever waiting for abuse
948 // Complete any client operations
950 Status
= SocketPoll ( );
951 if ( EFI_ERROR ( Status
)) {
962 if ( EFI_ERROR ( Status
)) {
970 // Wait for the network layer to initialize
972 Status
= SocketNew ( );
973 if ( EFI_ERROR ( Status
)) {
978 // Wait for the remote network application to start
980 Status
= SocketAccept ( );
981 if ( EFI_NOT_STARTED
== Status
) {
982 Status
= SocketClose ( );
985 else if ( EFI_SUCCESS
!= Status
) {
993 // Send data until the connection breaks
996 Status
= SocketPoll ( );
997 } while ( !EFI_ERROR ( Status
));
1000 // Done with the socket
1002 Status
= SocketClose ( );
1003 } while ( !EFI_ERROR ( Status
));
1006 // Close the socket if necessary
1017 // Stop the timer if necessary
1023 // Return the operation status
1025 DEBUG (( DEBUG_INFO
,
1026 "DataSink exiting, Status: %r\r\n",