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",
246 Status
= EFI_NOT_STARTED
;
251 // Return the operation status
258 Poll the socket for more work
260 @retval EFI_SUCCESS The application is running normally
261 @retval EFI_NOT_STARTED Listen socket error
262 @retval Other The user stopped the application
268 BOOLEAN bRemoveSocket
;
269 BOOLEAN bListenError
;
270 size_t BytesReceived
;
276 socklen_t LengthInBytes
;
277 struct sockaddr_in RemoteAddress
;
283 // Check for control-C
285 bListenError
= FALSE
;
286 Status
= ControlCCheck ( );
287 if ( !EFI_ERROR ( Status
)) {
291 FdCount
= poll ( &PollFd
[0],
294 if ( -1 == FdCount
) {
298 DEBUG (( DEBUG_ERROR
,
299 "ERROR - Poll error, errno: %d\r\n",
301 Status
= EFI_DEVICE_ERROR
;
305 // Process the poll output
309 bRemoveSocket
= FALSE
;
312 // Account for this descriptor
314 if ( 0 != PollFd
[ Index
].revents
) {
319 // Check for a broken connection
321 if ( 0 != ( PollFd
[ Index
].revents
& POLLHUP
)) {
322 bRemoveSocket
= TRUE
;
323 if ( ListenSocket
== PollFd
[ Index
].fd
) {
325 DEBUG (( DEBUG_ERROR
,
326 "ERROR - Network closed on listen socket, errno: %d\r\n",
330 DEBUG (( DEBUG_ERROR
,
331 "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",
332 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
333 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
334 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
335 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
336 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
342 CloseStatus
= close ( PollFd
[ Index
].fd
);
343 if ( 0 == CloseStatus
) {
344 bRemoveSocket
= TRUE
;
346 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
348 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
349 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
350 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
351 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
352 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
355 DEBUG (( DEBUG_ERROR
,
356 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
358 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
359 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
360 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
361 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
362 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
369 // Check for a connection or read data
371 if ( 0 != ( PollFd
[ Index
].revents
& POLLRDNORM
)) {
373 // Check for a connection
375 if ( ListenSocket
== PollFd
[ Index
].fd
) {
377 // Another client connection was received
379 LengthInBytes
= sizeof ( RemoteAddress
);
380 Socket
= accept ( ListenSocket
,
381 (struct sockaddr
*) &RemoteAddress
,
383 if ( -1 == Socket
) {
385 // Listen socket error
388 bRemoveSocket
= TRUE
;
389 DEBUG (( DEBUG_ERROR
,
390 "ERROR - Listen socket failure, errno: %d\r\n",
395 // Determine if there is room for this connection
397 if (( MAX_CONNECTIONS
<= MaxPort
)
398 || ((( MAX_CONNECTIONS
- 1 ) == MaxPort
) && ( -1 == ListenSocket
))) {
400 // Display the connection
402 Print ( L
"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",
403 RemoteAddress
.sin_addr
.s_addr
& 0xff,
404 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
405 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
406 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
407 htons ( RemoteAddress
.sin_port
));
410 // No room for this connection
411 // Close the connection
413 CloseStatus
= close ( Socket
);
414 if ( 0 == CloseStatus
) {
415 bRemoveSocket
= TRUE
;
417 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
419 RemoteAddress
.sin_addr
.s_addr
& 0xff,
420 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
421 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
422 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
423 htons ( RemoteAddress
.sin_port
)));
426 DEBUG (( DEBUG_ERROR
,
427 "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",
433 // Keep the application running
434 // No issue with the listen socket
436 Status
= EFI_SUCCESS
;
440 // Display the connection
442 Print ( L
"Connected to remote system %d.%d.%d.%d:%d\r\n",
443 RemoteAddress
.sin_addr
.s_addr
& 0xff,
444 ( RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
445 ( RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
446 ( RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
447 htons ( RemoteAddress
.sin_port
));
450 // Allocate the client connection
453 Port
[ Index
].BytesAverage
= 0;
454 Port
[ Index
].BytesPrevious
= 0;
455 Port
[ Index
].BytesTotal
= 0;
456 Port
[ Index
].Samples
= 0;
457 Port
[ Index
].RemoteAddress
.sin_len
= RemoteAddress
.sin_len
;
458 Port
[ Index
].RemoteAddress
.sin_family
= RemoteAddress
.sin_family
;
459 Port
[ Index
].RemoteAddress
.sin_port
= RemoteAddress
.sin_port
;
460 Port
[ Index
].RemoteAddress
.sin_addr
= RemoteAddress
.sin_addr
;
461 PollFd
[ Index
].fd
= Socket
;
462 PollFd
[ Index
].events
= POLLRDNORM
| POLLHUP
;
463 PollFd
[ Index
].revents
= 0;
471 BytesReceived
= read ( PollFd
[ Index
].fd
,
474 if ( 0 < BytesReceived
) {
476 // Display the amount of data received
479 "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",
482 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
483 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
484 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
485 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
486 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
489 // Synchronize with the TimerCallback routine
491 TplPrevious
= gBS
->RaiseTPL ( TPL_DATASINK
);
494 // Account for the data received
496 Port
[ Index
].BytesTotal
+= BytesReceived
;
499 // Release the synchronization with the TimerCallback routine
501 gBS
->RestoreTPL ( TplPrevious
);
503 else if ( -1 == BytesReceived
) {
508 "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",
509 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
510 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
511 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
512 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
513 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
515 CloseStatus
= close ( PollFd
[ Index
].fd
);
516 if ( 0 == CloseStatus
) {
517 bRemoveSocket
= TRUE
;
519 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
521 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
522 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
523 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
524 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
525 htons ( Port
[ Index
].RemoteAddress
.sin_port
)));
528 DEBUG (( DEBUG_ERROR
,
529 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
531 Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
& 0xff,
532 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 8 ) & 0xff,
533 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 16 ) & 0xff,
534 ( Port
[ Index
].RemoteAddress
.sin_addr
.s_addr
>> 24 ) & 0xff,
535 htons ( Port
[ Index
].RemoteAddress
.sin_port
),
541 // Keep the application running
542 // No issue with the listen socket
544 Status
= EFI_SUCCESS
;
549 // Remove the socket if necessary
551 if ( bRemoveSocket
) {
553 "0x%08x: Socket removed from polling\r\n",
554 PollFd
[ Index
].fd
));
556 for ( Entry
= Index
+ 1; MaxPort
>= Entry
; Entry
++ ) {
557 EntryPrevious
= Entry
;
558 Port
[ EntryPrevious
].BytesAverage
= Port
[ Entry
].BytesAverage
;
559 Port
[ EntryPrevious
].BytesPrevious
= Port
[ Entry
].BytesPrevious
;
560 Port
[ EntryPrevious
].BytesTotal
= Port
[ Entry
].BytesTotal
;
561 Port
[ EntryPrevious
].RemoteAddress
.sin_len
= Port
[ Entry
].RemoteAddress
.sin_len
;
562 Port
[ EntryPrevious
].RemoteAddress
.sin_family
= Port
[ Entry
].RemoteAddress
.sin_family
;
563 Port
[ EntryPrevious
].RemoteAddress
.sin_port
= Port
[ Entry
].RemoteAddress
.sin_port
;
564 Port
[ EntryPrevious
].RemoteAddress
.sin_addr
.s_addr
= Port
[ Entry
].RemoteAddress
.sin_addr
.s_addr
;
565 Port
[ EntryPrevious
].Samples
= Port
[ Entry
].Samples
;
566 PollFd
[ EntryPrevious
].events
= PollFd
[ Entry
].events
;
567 PollFd
[ EntryPrevious
].fd
= PollFd
[ Entry
].fd
;
568 PollFd
[ EntryPrevious
].revents
= PollFd
[ Entry
].revents
;
570 PollFd
[ MaxPort
].fd
= -1;
575 // Account for this socket
583 // Return the listen failure if necessary
585 if (( !EFI_ERROR ( Status
)) && bListenError
) {
586 Status
= EFI_NOT_STARTED
;
590 // Return the poll status
597 Handle the timer callback
599 @param [in] Event Event that caused this callback
600 @param [in] pContext Context for this routine
609 UINT64 BytesReceived
;
615 // Notify the other code of the timer tick
620 // Walk the list of ports
622 for ( Index
= 0; MaxPort
> Index
; Index
++ ) {
624 // Determine if any data was received
626 BytesReceived
= Port
[ Index
].BytesTotal
;
627 if (( ListenSocket
!= PollFd
[ Index
].fd
)
628 && ( 0 != BytesReceived
)) {
630 // Update the average bytes per second
632 DeltaBytes
= Port
[ Index
].BytesAverage
>> AVERAGE_SHIFT_COUNT
;
633 Port
[ Index
].BytesAverage
-= DeltaBytes
;
634 DeltaBytes
= BytesReceived
- Port
[ Index
].BytesPrevious
;
635 Port
[ Index
].BytesPrevious
= BytesReceived
;
636 Port
[ Index
].BytesAverage
+= DeltaBytes
;
639 // Separate the samples
641 if (( 2 << AVERAGE_SHIFT_COUNT
) == Port
[ Index
].Samples
) {
642 Print ( L
"---------- Stable average ----------\r\n" );
644 Port
[ Index
].Samples
+= 1;
647 // Display the data rate
649 Delta
= (UINT32
)( DeltaBytes
>> DATA_RATE_UPDATE_SHIFT
);
650 Average
= Port
[ Index
].BytesAverage
>> ( AVERAGE_SHIFT_COUNT
+ DATA_RATE_UPDATE_SHIFT
);
651 if ( Average
< RANGE_SWITCH
) {
652 Print ( L
"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",
658 if ( Average
< RANGE_SWITCH
) {
659 Print ( L
"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",
665 if ( Average
< RANGE_SWITCH
) {
666 Print ( L
"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",
672 if ( Average
< RANGE_SWITCH
) {
673 Print ( L
"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",
679 if ( Average
< RANGE_SWITCH
) {
680 Print ( L
"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",
686 Print ( L
"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",
702 @retval EFI_SUCCESS The timer was successfully created
703 @retval Other Timer initialization failed
714 Status
= gBS
->CreateEvent ( EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
719 if ( EFI_ERROR ( Status
)) {
720 DEBUG (( DEBUG_ERROR
,
721 "ERROR - Failed to allocate the timer event, Status: %r\r\n",
726 "0x%08x: Timer created\r\n",
731 // Return the operation status
740 @retval EFI_SUCCESS The timer was stopped successfully
741 @retval Other The timer failed to stop
752 Status
= EFI_SUCCESS
;
755 // Determine if the timer is running
757 if ( bTimerRunning
) {
761 Status
= gBS
->SetTimer ( pTimer
,
764 if ( EFI_ERROR ( Status
)) {
765 DEBUG (( DEBUG_ERROR
,
766 "ERROR - Failed to stop the timer, Status: %r\r\n",
771 // Timer timer is now stopped
773 bTimerRunning
= FALSE
;
775 "0x%08x: Timer stopped\r\n",
781 // Return the operation status
790 @param [in] Milliseconds The number of milliseconds between timer callbacks
792 @retval EFI_SUCCESS The timer was successfully created
793 @retval Other Timer initialization failed
804 // Stop the timer if necessary
806 Status
= EFI_SUCCESS
;
807 if ( bTimerRunning
) {
808 Status
= TimerStop ( );
810 if ( !EFI_ERROR ( Status
)) {
812 // Compute the new delay
814 TimeDelay
= Milliseconds
;
815 TimeDelay
*= 1000 * 10;
820 Status
= gBS
->SetTimer ( pTimer
,
823 if ( EFI_ERROR ( Status
)) {
824 DEBUG (( DEBUG_ERROR
,
825 "ERROR - Failed to start the timer, Status: %r\r\n",
830 // The timer is now running
832 bTimerRunning
= TRUE
;
834 "0x%08x: Timer running\r\n",
840 // Return the operation status
849 @retval EFI_SUCCESS The timer was destroyed successfully
850 @retval Other Failed to destroy the timer
861 Status
= EFI_SUCCESS
;
864 // Determine if the timer is running
866 if ( bTimerRunning
) {
870 Status
= TimerStop ( );
872 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pTimer
)) {
874 // Done with this timer
876 Status
= gBS
->CloseEvent ( pTimer
);
877 if ( EFI_ERROR ( Status
)) {
878 DEBUG (( DEBUG_ERROR
,
879 "ERROR - Failed to free the timer event, Status: %r\r\n",
884 "0x%08x: Timer Destroyed\r\n",
891 // Return the operation status
898 Receive data from the DataSource program to test a network's bandwidth.
900 @param [in] Argc The number of arguments
901 @param [in] Argv The argument value array
903 @retval 0 The application exited normally.
904 @retval Other An error occurred.
915 "DataSink starting\r\n" ));
918 // Use for/break instead of goto
925 Status
= TimerCreate ( );
926 if ( EFI_ERROR ( Status
)) {
931 // Start a timer to perform network polling and display updates
933 Status
= TimerStart ( 1 * 1000 );
934 if ( EFI_ERROR ( Status
)) {
939 // Loop forever waiting for abuse
945 // Complete any client operations
947 Status
= SocketPoll ( );
948 if ( EFI_ERROR ( Status
)) {
959 if ( EFI_ERROR ( Status
)) {
967 // Wait for the network layer to initialize
969 Status
= SocketNew ( );
970 if ( EFI_ERROR ( Status
)) {
975 // Wait for the remote network application to start
977 Status
= SocketAccept ( );
978 if ( EFI_NOT_STARTED
== Status
) {
979 Status
= SocketClose ( );
982 else if ( EFI_SUCCESS
!= Status
) {
990 // Send data until the connection breaks
993 Status
= SocketPoll ( );
994 } while ( !EFI_ERROR ( Status
));
997 // Done with the socket
999 Status
= SocketClose ( );
1000 } while ( !EFI_ERROR ( Status
));
1003 // Close the socket if necessary
1014 // Stop the timer if necessary
1020 // Return the operation status
1022 DEBUG (( DEBUG_INFO
,
1023 "DataSink exiting, Status: %r\r\n",