98a0c9f1209db132fa5d40b47ce5e139f746ccdc
[mirror_edk2.git] / AppPkg / Applications / Sockets / DataSource / DataSource.c
1 /** @file
2 Data source for network testing.
3
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
9
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.
12
13 **/
14
15 #include <errno.h>
16 #include <Uefi.h>
17
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>
23
24 #include <netinet/in.h>
25
26 #include <Protocol/ServiceBinding.h>
27 #include <Protocol/Tcp4.h>
28
29 #include <sys/EfiSysCall.h>
30 #include <sys/poll.h>
31 #include <sys/socket.h>
32
33
34 #define RANGE_SWITCH 2048 ///< Switch display ranges
35 #define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates
36 #define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average
37
38 #define TPL_DATASOURCE TPL_CALLBACK ///< Synchronization TPL
39
40 #define PACKET_SIZE 1448 ///< Size of data packets
41 #define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes
42
43
44 //
45 // Socket Data
46 //
47 int Socket = -1;
48
49 //
50 // TCP V4 Data
51 //
52 BOOLEAN bTcp4; ///< TRUE if TCP4 is being used
53 BOOLEAN bTcp4Connected; ///< TRUE if connected to remote system
54 BOOLEAN bTcp4Connecting; ///< TRUE while connection in progress
55 UINTN Tcp4Index; ///< Index into handle array
56 EFI_HANDLE Tcp4Controller; ///< Network controller handle
57 EFI_HANDLE Tcp4Handle; ///< TCP4 port handle
58 EFI_TCP4_PROTOCOL * pTcp4Protocol; ///< TCP4 protocol pointer
59 EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service; ///< TCP4 Service binding
60 EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///< TCP4 configuration data
61 EFI_TCP4_OPTION Tcp4Option; ///< TCP4 port options
62 EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///< Close control
63 EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///< Connection control
64 EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken; ///< Listen control
65 EFI_TCP4_IO_TOKEN Tcp4TxToken; ///< Normal data token
66
67 //
68 // Timer Data
69 //
70 volatile BOOLEAN bTick;
71 BOOLEAN bTimerRunning;
72 EFI_EVENT pTimer;
73
74 //
75 // Remote IP Address Data
76 //
77 struct sockaddr_in RemoteHostAddress;
78 CHAR8 * pRemoteHost;
79
80 //
81 // Traffic Data
82 //
83 UINT64 TotalBytesSent;
84 UINT64 PreviousBytes;
85 UINT64 AverageBytes;
86 UINT64 Samples;
87 UINT8 Buffer[ DATA_BUFFER_SIZE ];
88
89
90 //
91 // Forward routine declarations
92 //
93 EFI_STATUS TimerStart ( UINTN Milliseconds );
94
95
96 /**
97 Check for control C entered at console
98
99 @retval EFI_SUCCESS Control C not entered
100 @retval EFI_ABORTED Control C entered
101 **/
102 EFI_STATUS
103 ControlCCheck (
104 )
105 {
106 EFI_STATUS Status;
107
108 //
109 // Assume no user intervention
110 //
111 Status = EFI_SUCCESS;
112
113 //
114 // Display user stop request
115 //
116 if ( EFI_ERROR ( Status )) {
117 DEBUG (( DEBUG_INFO,
118 "User stop request!\r\n" ));
119 }
120
121 //
122 // Return the check status
123 //
124 return Status;
125 }
126
127
128 /**
129 Get a digit
130
131 @param [in] pDigit The address of the next digit
132 @param [out] pValue The address to receive the value
133
134 @return Returns the address of the separator
135
136 **/
137 CHAR8 *
138 GetDigit (
139 CHAR8 * pDigit,
140 UINT32 * pValue
141 )
142 {
143 UINT32 Value;
144
145 //
146 // Walk the digits
147 //
148 Value = 0;
149 while (( '0' <= *pDigit ) && ( '9' >= *pDigit )) {
150 //
151 // Make room for the new least significant digit
152 //
153 Value *= 10;
154
155 //
156 // Convert the digit from ASCII to binary
157 //
158 Value += *pDigit - '0';
159
160 //
161 // Set the next digit
162 //
163 pDigit += 1;
164 }
165
166 //
167 // Return the value
168 //
169 *pValue = Value;
170
171 //
172 // Return the next separator
173 //
174 return pDigit;
175 }
176
177
178 /**
179 Get the IP address
180
181 @retval EFI_SUCCESS The IP address is valid
182 @retval Other Failure to convert the IP address
183 **/
184 EFI_STATUS
185 IpAddress (
186 )
187 {
188 CHAR8 * pSeparator;
189 INT32 RemoteAddress;
190 EFI_STATUS Status;
191 UINT32 Value1;
192 UINT32 Value2;
193 UINT32 Value3;
194 UINT32 Value4;
195
196 //
197 // Assume failure
198 //
199 Status = EFI_INVALID_PARAMETER;
200
201 //
202 // Convert the IP address from a string to a numeric value
203 //
204 pSeparator = GetDigit ( pRemoteHost, &Value1 );
205 if (( 255 >= Value1 ) && ( '.' == *pSeparator )) {
206 pSeparator = GetDigit ( ++pSeparator, &Value2 );
207 if (( 255 >= Value2 ) && ( '.' == *pSeparator )) {
208 pSeparator = GetDigit ( ++pSeparator, &Value3 );
209 if (( 255 >= Value3 ) && ( '.' == *pSeparator )) {
210 pSeparator = GetDigit ( ++pSeparator, &Value4 );
211 if (( 255 >= Value4 ) && ( 0 == *pSeparator )) {
212 RemoteAddress = Value1
213 | ( Value2 << 8 )
214 | ( Value3 << 16 )
215 | ( Value4 << 24 );
216 RemoteHostAddress.sin_addr.s_addr = (UINT32) RemoteAddress;
217 Status = EFI_SUCCESS;
218 DEBUG (( DEBUG_INFO,
219 "%d.%d.%d.%d: Remote host IP address\r\n",
220 Value1,
221 Value2,
222 Value3,
223 Value4 ));
224 }
225 }
226 }
227 }
228 if ( EFI_ERROR ( Status )) {
229 Print ( L"Invalid digit detected: %d\r\n", *pSeparator );
230 }
231
232 //
233 // Return the operation status
234 //
235 return Status;
236 }
237
238
239 /**
240 Close the socket
241
242 @retval EFI_SUCCESS The application is running normally
243 @retval Other The user stopped the application
244 **/
245 EFI_STATUS
246 SocketClose (
247 )
248 {
249 int CloseStatus;
250 EFI_STATUS Status;
251
252 //
253 // Determine if the socket is open
254 //
255 Status = EFI_DEVICE_ERROR;
256 if ( -1 != Socket ) {
257 //
258 // Attempt to close the socket
259 //
260 CloseStatus = close ( Socket );
261 if ( 0 == CloseStatus ) {
262 DEBUG (( DEBUG_INFO,
263 "0x%08x: Socket closed\r\n",
264 Socket ));
265 Socket = -1;
266 Status = EFI_SUCCESS;
267 }
268 else {
269 DEBUG (( DEBUG_ERROR,
270 "ERROR: Failed to close socket, errno: %d\r\n",
271 errno ));
272 }
273 }
274
275 //
276 // Return the operation status
277 //
278 return Status;
279 }
280
281
282 /**
283 Connect the socket
284
285 @retval EFI_SUCCESS The application is running normally
286 @retval Other The user stopped the application
287 **/
288 EFI_STATUS
289 SocketConnect (
290 )
291 {
292 int ConnectStatus;
293 UINT32 RemoteAddress;
294 EFI_STATUS Status;
295
296 //
297 // Display the connecting message
298 //
299 RemoteAddress = RemoteHostAddress.sin_addr.s_addr;
300 Print ( L"Connecting to remote system %d.%d.%d.%d:%d\r\n",
301 RemoteAddress & 0xff,
302 ( RemoteAddress >> 8 ) & 0xff,
303 ( RemoteAddress >> 16 ) & 0xff,
304 ( RemoteAddress >> 24 ) & 0xff,
305 htons ( RemoteHostAddress.sin_port ));
306
307 //
308 // Connect to the remote system
309 //
310 Status = EFI_SUCCESS;
311 do {
312 //
313 // Check for user stop request
314 //
315 while ( !bTick ) {
316 Status = ControlCCheck ( );
317 if ( EFI_ERROR ( Status )) {
318 break;
319 }
320 }
321 bTick = FALSE;
322 if ( EFI_ERROR ( Status )) {
323 break;
324 }
325
326 //
327 // Connect to the remote system
328 //
329 ConnectStatus = connect ( Socket,
330 (struct sockaddr *) &RemoteHostAddress,
331 RemoteHostAddress.sin_len );
332 if ( -1 != ConnectStatus ) {
333 Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
334 RemoteAddress & 0xff,
335 ( RemoteAddress >> 8 ) & 0xff,
336 ( RemoteAddress >> 16 ) & 0xff,
337 ( RemoteAddress >> 24 ) & 0xff,
338 htons ( RemoteHostAddress.sin_port ));
339 }
340 else {
341 //
342 // Close the socket and try again
343 //
344 if ( EAGAIN != errno ) {
345 Status = EFI_NOT_STARTED;
346 break;
347 }
348 }
349 } while ( -1 == ConnectStatus );
350
351 //
352 // Return the operation status
353 //
354 return Status;
355 }
356
357
358 /**
359 Create the socket
360
361 @retval EFI_SUCCESS The application is running normally
362 @retval Other The user stopped the application
363 **/
364 EFI_STATUS
365 SocketNew (
366 )
367 {
368 EFI_STATUS Status;
369
370 //
371 // Loop creating the socket
372 //
373 DEBUG (( DEBUG_INFO,
374 "Creating the socket\r\n" ));
375 do {
376 //
377 // Check for user stop request
378 //
379 Status = ControlCCheck ( );
380 if ( EFI_ERROR ( Status )) {
381 break;
382 }
383
384 //
385 // Attempt to create the socket
386 //
387 Socket = socket ( AF_INET,
388 SOCK_STREAM,
389 IPPROTO_TCP );
390 if ( -1 != Socket ) {
391 DEBUG (( DEBUG_INFO,
392 "0x%08x: Socket created\r\n",
393 Socket ));
394 break;
395 }
396 } while ( -1 == Socket );
397
398 //
399 // Return the operation status
400 //
401 return Status;
402 }
403
404
405 /**
406 Send data over the socket
407
408 @retval EFI_SUCCESS The application is running normally
409 @retval Other The user stopped the application
410 **/
411 EFI_STATUS
412 SocketSend (
413 )
414 {
415 size_t BytesSent;
416 EFI_STATUS Status;
417 EFI_TPL TplPrevious;
418
419 //
420 // Restart the timer
421 //
422 TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );
423
424 //
425 // Loop until the connection breaks or the user stops
426 //
427 do {
428 //
429 // Check for user stop request
430 //
431 Status = ControlCCheck ( );
432 if ( EFI_ERROR ( Status )) {
433 break;
434 }
435
436 //
437 // Send some bytes
438 //
439 BytesSent = write ( Socket, &Buffer[0], sizeof ( Buffer ));
440 if ( -1 == BytesSent ) {
441 DEBUG (( DEBUG_INFO,
442 "ERROR: send failed, errno: %d\r\n",
443 errno ));
444
445 //
446 // Try again
447 //
448 Status = EFI_SUCCESS;
449
450 //
451 // Exit now
452 //
453 Status = EFI_NOT_STARTED;
454 break;
455 }
456
457 //
458 // Synchronize with the TimerCallback routine
459 //
460 TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
461
462 //
463 // Account for the data sent
464 //
465 TotalBytesSent += BytesSent;
466
467 //
468 // Release the TimerCallback routine synchronization
469 //
470 gBS->RestoreTPL ( TplPrevious );
471 } while ( !EFI_ERROR ( Status ));
472
473 //
474 // Return the operation status
475 //
476 return Status;
477 }
478
479
480 /**
481 Open the network connection and send the data.
482
483 @retval EFI_SUCCESS Continue looping
484 @retval other Stopped by user's Control-C input
485
486 **/
487 EFI_STATUS
488 SocketOpen (
489 )
490 {
491 EFI_STATUS Status;
492
493 //
494 // Use do/while and break instead of goto
495 //
496 do {
497 //
498 // Wait for the network layer to initialize
499 //
500 Status = SocketNew ( );
501 if ( EFI_ERROR ( Status )) {
502 break;
503 }
504
505 //
506 // Wait for the remote network application to start
507 //
508 Status = SocketConnect ( );
509 if ( EFI_NOT_STARTED == Status ) {
510 Status = SocketClose ( );
511 continue;
512 }
513 else if ( EFI_SUCCESS != Status ) {
514 //
515 // Control-C
516 //
517 break;
518 }
519
520 //
521 // Send data until the connection breaks
522 //
523 Status = SocketSend ( );
524 if ( EFI_ERROR ( Status )) {
525 break;
526 }
527 } while ( FALSE );
528
529 //
530 // Return the operation status
531 //
532 return Status;
533 }
534
535
536 /**
537 Close the TCP connection
538
539 @retval EFI_SUCCESS The application is running normally
540 @retval Other The user stopped the application
541 **/
542 EFI_STATUS
543 Tcp4Close (
544 )
545 {
546 UINTN Index;
547 UINT8 * pIpAddress;
548 EFI_STATUS Status;
549
550 //
551 // Close the port
552 //
553 if ( bTcp4Connected ) {
554 Tcp4CloseToken.AbortOnClose = TRUE;
555 Status = pTcp4Protocol->Close ( pTcp4Protocol,
556 &Tcp4CloseToken );
557 if ( EFI_ERROR ( Status )) {
558 DEBUG (( DEBUG_ERROR,
559 "ERROR - Failed to start the TCP port close, Status: %r\r\n",
560 Status ));
561 }
562 else {
563 Status = gBS->WaitForEvent ( 1,
564 &Tcp4CloseToken.CompletionToken.Event,
565 &Index );
566 if ( EFI_ERROR ( Status )) {
567 DEBUG (( DEBUG_ERROR,
568 "ERROR - Failed to wait for close event, Status: %r\r\n",
569 Status ));
570 }
571 else {
572 Status = Tcp4CloseToken.CompletionToken.Status;
573 if ( EFI_ERROR ( Status )) {
574 DEBUG (( DEBUG_ERROR,
575 "ERROR - Failed to close the TCP port, Status: %r\r\n",
576 Status ));
577 }
578 else {
579 DEBUG (( DEBUG_INFO,
580 "0x%08x: TCP port closed\r\n",
581 pTcp4Protocol ));
582 bTcp4Connected = FALSE;
583
584 //
585 // Display the port closed message
586 //
587 pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
588 Print ( L"Closed connection to %d.%d.%d.%d:%d\r\n",
589 pIpAddress[0],
590 pIpAddress[1],
591 pIpAddress[2],
592 pIpAddress[3],
593 htons ( RemoteHostAddress.sin_port ));
594 }
595 }
596 }
597 }
598
599 //
600 // Release the events
601 //
602 if ( NULL != Tcp4TxToken.CompletionToken.Event ) {
603 Status = gBS->CloseEvent ( Tcp4TxToken.CompletionToken.Event );
604 if ( !EFI_ERROR ( Status )) {
605 DEBUG (( DEBUG_INFO,
606 "0x%08x: TX event closed\r\n",
607 Tcp4TxToken.CompletionToken.Event ));
608 Tcp4TxToken.CompletionToken.Event = NULL;
609 }
610 else {
611 DEBUG (( DEBUG_ERROR,
612 "ERROR - Failed to close the Tcp4TxToken event, Status: %r\r\n",
613 Status ));
614 }
615 }
616
617 if ( NULL != Tcp4ListenToken.CompletionToken.Event ) {
618 Status = gBS->CloseEvent ( Tcp4ListenToken.CompletionToken.Event );
619 if ( !EFI_ERROR ( Status )) {
620 DEBUG (( DEBUG_INFO,
621 "0x%08x: Listen event closed\r\n",
622 Tcp4ListenToken.CompletionToken.Event ));
623 Tcp4ListenToken.CompletionToken.Event = NULL;
624 }
625 else {
626 DEBUG (( DEBUG_ERROR,
627 "ERROR - Failed to close the Tcp4ListenToken event, Status: %r\r\n",
628 Status ));
629 }
630 }
631
632 if ( NULL != Tcp4ConnectToken.CompletionToken.Event ) {
633 Status = gBS->CloseEvent ( Tcp4ConnectToken.CompletionToken.Event );
634 if ( !EFI_ERROR ( Status )) {
635 DEBUG (( DEBUG_INFO,
636 "0x%08x: Connect event closed\r\n",
637 Tcp4ConnectToken.CompletionToken.Event ));
638 Tcp4ConnectToken.CompletionToken.Event = NULL;
639 }
640 else {
641 DEBUG (( DEBUG_ERROR,
642 "ERROR - Failed to close the Tcp4ConnectToken event, Status: %r\r\n",
643 Status ));
644 }
645 }
646
647 if ( NULL != Tcp4CloseToken.CompletionToken.Event ) {
648 Status = gBS->CloseEvent ( Tcp4CloseToken.CompletionToken.Event );
649 if ( !EFI_ERROR ( Status )) {
650 DEBUG (( DEBUG_INFO,
651 "0x%08x: Close event closed\r\n",
652 Tcp4CloseToken.CompletionToken.Event ));
653 Tcp4CloseToken.CompletionToken.Event = NULL;
654 }
655 else {
656 DEBUG (( DEBUG_ERROR,
657 "ERROR - Failed to close the Tcp4CloseToken event, Status: %r\r\n",
658 Status ));
659 }
660 }
661
662 //
663 // Close the TCP protocol
664 //
665 if ( NULL != pTcp4Protocol ) {
666 Status = gBS->CloseProtocol ( Tcp4Handle,
667 &gEfiTcp4ProtocolGuid,
668 gImageHandle,
669 NULL );
670 if ( EFI_ERROR ( Status )) {
671 DEBUG (( DEBUG_ERROR,
672 "ERROR - Failed to close the TCP protocol, Status: %r\r\n",
673 Status ));
674 }
675 else {
676 DEBUG (( DEBUG_INFO,
677 "0x%08x: TCP4 protocol closed\r\n",
678 pTcp4Protocol ));
679 pTcp4Protocol = NULL;
680 }
681 }
682
683 //
684 // Done with the TCP service
685 //
686 if ( NULL != Tcp4Handle ) {
687 Status = pTcp4Service->DestroyChild ( pTcp4Service,
688 Tcp4Handle );
689 if ( EFI_ERROR ( Status )) {
690 DEBUG (( DEBUG_ERROR,
691 "ERROR - Failed to release TCP service handle, Status: %r\r\n",
692 Status ));
693 }
694 else {
695 DEBUG (( DEBUG_INFO,
696 "Ox%08x: TCP service closed\r\n",
697 Tcp4Handle ));
698 Tcp4Handle = NULL;
699 }
700 }
701
702 //
703 // Close the service protocol
704 //
705 if ( NULL != pTcp4Service ) {
706 Status = gBS->CloseProtocol ( Tcp4Controller,
707 &gEfiTcp4ServiceBindingProtocolGuid,
708 gImageHandle,
709 NULL );
710 if ( !EFI_ERROR ( Status )) {
711 DEBUG (( DEBUG_INFO,
712 "0x%08x: Controller closed gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
713 Tcp4Controller ));
714 pTcp4Service = NULL;
715 }
716 else {
717 DEBUG (( DEBUG_ERROR,
718 "ERROR - Failed to close the gEfiTcp4ServiceBindingProtocolGuid protocol, Status: %r\r\n",
719 Status ));
720 }
721 }
722 Tcp4Controller = NULL;
723 bTcp4Connecting = TRUE;
724
725 //
726 // Mark the connection as closed
727 //
728 Status = EFI_SUCCESS;
729
730 //
731 // Return the operation status
732 //
733 return Status;
734 }
735
736
737 /**
738 Locate TCP protocol
739
740 @retval EFI_SUCCESS Protocol found
741 @retval other Protocl not found
742 **/
743 EFI_STATUS
744 Tcp4Locate (
745 )
746 {
747 UINTN HandleCount;
748 EFI_HANDLE * pHandles;
749 UINT8 * pIpAddress;
750 EFI_STATUS Status;
751
752 //
753 // Use do/while and break instead of goto
754 //
755 do {
756 //
757 // Attempt to locate the next TCP adapter in the system
758 //
759 Status = gBS->LocateHandleBuffer ( ByProtocol,
760 &gEfiTcp4ServiceBindingProtocolGuid,
761 NULL,
762 &HandleCount,
763 &pHandles );
764 if ( EFI_ERROR ( Status )) {
765 DEBUG (( DEBUG_WARN,
766 "WARNING - No network controllers or TCP4 available, Status: %r\r\n",
767 Status ));
768 break;
769 }
770
771 //
772 // Wrap the index if necessary
773 //
774 if ( HandleCount <= Tcp4Index ) {
775 Tcp4Index = 0;
776
777 //
778 // Wait for the next timer tick
779 //
780 do {
781 } while ( !bTick );
782 bTick = FALSE;
783 }
784
785 //
786 // Display the connecting message
787 //
788 if ( bTcp4Connecting ) {
789 pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
790 Print ( L"Connecting to %d.%d.%d.%d:%d\r\n",
791 pIpAddress[0],
792 pIpAddress[1],
793 pIpAddress[2],
794 pIpAddress[3],
795 htons ( RemoteHostAddress.sin_port ));
796 bTcp4Connecting = FALSE;
797 }
798
799 //
800 // Open the network controller's service protocol
801 //
802 Tcp4Controller = pHandles[ Tcp4Index++ ];
803 Status = gBS->OpenProtocol (
804 Tcp4Controller,
805 &gEfiTcp4ServiceBindingProtocolGuid,
806 (VOID **) &pTcp4Service,
807 gImageHandle,
808 NULL,
809 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
810 if ( EFI_ERROR ( Status )) {
811 DEBUG (( DEBUG_ERROR,
812 "ERROR - Failed to open gEfiTcp4ServiceBindingProtocolGuid on controller 0x%08x\r\n",
813 Tcp4Controller ));
814 Tcp4Controller = NULL;
815 break;
816 }
817 DEBUG (( DEBUG_INFO,
818 "0x%08x: Controller opened gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
819 Tcp4Controller ));
820
821 //
822 // Connect to the TCP service
823 //
824 Status = pTcp4Service->CreateChild ( pTcp4Service,
825 &Tcp4Handle );
826 if ( EFI_ERROR ( Status )) {
827 DEBUG (( DEBUG_ERROR,
828 "ERROR - Failed to open TCP service, Status: %r\r\n",
829 Status ));
830 Tcp4Handle = NULL;
831 break;
832 }
833 DEBUG (( DEBUG_INFO,
834 "Ox%08x: TCP service opened\r\n",
835 Tcp4Handle ));
836
837 //
838 // Locate the TCP protcol
839 //
840 Status = gBS->OpenProtocol ( Tcp4Handle,
841 &gEfiTcp4ProtocolGuid,
842 (VOID **)&pTcp4Protocol,
843 gImageHandle,
844 NULL,
845 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
846 if ( EFI_ERROR ( Status )) {
847 DEBUG (( DEBUG_ERROR,
848 "ERROR - Failed to open the TCP protocol, Status: %r\r\n",
849 Status ));
850 pTcp4Protocol = NULL;
851 break;
852 }
853 DEBUG (( DEBUG_INFO,
854 "0x%08x: TCP4 protocol opened\r\n",
855 pTcp4Protocol ));
856 }while ( FALSE );
857
858 //
859 // Release the handle buffer
860 //
861 gBS->FreePool ( pHandles );
862
863 //
864 // Return the operation status
865 //
866 return Status;
867 }
868
869
870 /**
871 Send data over the TCP4 connection
872
873 @retval EFI_SUCCESS The application is running normally
874 @retval Other The user stopped the application
875 **/
876 EFI_STATUS
877 Tcp4Send (
878 )
879 {
880 UINTN Index;
881 EFI_TCP4_TRANSMIT_DATA Packet;
882 EFI_STATUS Status;
883 EFI_TPL TplPrevious;
884
885 //
886 // Restart the timer
887 //
888 TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );
889
890 //
891 // Initialize the packet
892 //
893 Packet.DataLength = sizeof ( Buffer );
894 Packet.FragmentCount = 1;
895 Packet.Push = FALSE;
896 Packet.Urgent = FALSE;
897 Packet.FragmentTable[0].FragmentBuffer = &Buffer[0];
898 Packet.FragmentTable[0].FragmentLength = sizeof ( Buffer );
899 Tcp4TxToken.Packet.TxData = &Packet;
900
901 //
902 // Loop until the connection breaks or the user stops
903 //
904 do {
905 //
906 // Check for user stop request
907 //
908 Status = ControlCCheck ( );
909 if ( EFI_ERROR ( Status )) {
910 break;
911 }
912
913 //
914 // Send some bytes
915 //
916 Status = pTcp4Protocol->Transmit ( pTcp4Protocol,
917 &Tcp4TxToken );
918 if ( EFI_ERROR ( Status )) {
919 DEBUG (( DEBUG_ERROR,
920 "ERROR - Failed to start the transmit, Status: %r\r\n",
921 Status ));
922
923 //
924 // Try again
925 //
926 Status = EFI_SUCCESS;
927 break;
928 }
929
930 //
931 // Wait for the transmit to complete
932 //
933 Status = gBS->WaitForEvent ( 1,
934 &Tcp4TxToken.CompletionToken.Event,
935 &Index );
936 if ( EFI_ERROR ( Status )) {
937 DEBUG (( DEBUG_ERROR,
938 "ERROR - Failed to wait for transmit completion, Status: %r\r\n",
939 Status ));
940
941 //
942 // Try again
943 //
944 Status = EFI_SUCCESS;
945 break;
946 }
947
948 //
949 // Get the transmit status
950 //
951 Status = Tcp4TxToken.CompletionToken.Status;
952 if ( EFI_ERROR ( Status )) {
953 DEBUG (( DEBUG_WARN,
954 "WARNING - Failed the transmission, Status: %r\r\n",
955 Status ));
956
957 //
958 // Try again
959 //
960 Status = EFI_SUCCESS;
961
962 //
963 // Exit now
964 //
965 Status = EFI_NOT_STARTED;
966 break;
967 }
968
969 //
970 // Synchronize with the TimerCallback routine
971 //
972 TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
973
974 //
975 // Account for the data sent
976 //
977 TotalBytesSent += Packet.DataLength;
978
979 //
980 // Release the TimerCallback routine synchronization
981 //
982 gBS->RestoreTPL ( TplPrevious );
983 } while ( !EFI_ERROR ( Status ));
984
985 //
986 // Return the operation status
987 //
988 return Status;
989 }
990
991
992 /**
993 Open the network connection and send the data.
994
995 @retval EFI_SUCCESS Continue looping
996 @retval other Stopped by user's Control-C input
997
998 **/
999 EFI_STATUS
1000 Tcp4Open (
1001 )
1002 {
1003 UINTN Index;
1004 UINT8 * pIpAddress;
1005 EFI_STATUS Status;
1006
1007 //
1008 // Use do/while and break instead of goto
1009 //
1010 do {
1011 //
1012 // Locate the TCP protocol
1013 //
1014 Status = Tcp4Locate ( );
1015 if ( EFI_ERROR ( Status )) {
1016 break;
1017 }
1018
1019 //
1020 // Create the necessary events
1021 //
1022 Status = gBS->CreateEvent ( 0,
1023 TPL_CALLBACK,
1024 NULL,
1025 NULL,
1026 &Tcp4CloseToken.CompletionToken.Event );
1027 if ( EFI_ERROR ( Status )) {
1028 DEBUG (( DEBUG_ERROR,
1029 "ERROR - Failed to create the close event, Status: %r\r\n",
1030 Status ));
1031 Tcp4CloseToken.CompletionToken.Event = NULL;
1032 break;
1033 }
1034 DEBUG (( DEBUG_INFO,
1035 "0x%08x: Close event open\r\n",
1036 Tcp4CloseToken.CompletionToken.Event ));
1037
1038 Status = gBS->CreateEvent ( 0,
1039 TPL_CALLBACK,
1040 NULL,
1041 NULL,
1042 &Tcp4ConnectToken.CompletionToken.Event );
1043 if ( EFI_ERROR ( Status )) {
1044 DEBUG (( DEBUG_ERROR,
1045 "ERROR - Failed to create the connect event, Status: %r\r\n",
1046 Status ));
1047 Tcp4ConnectToken.CompletionToken.Event = NULL;
1048 break;
1049 }
1050 DEBUG (( DEBUG_INFO,
1051 "0x%08x: Connect event open\r\n",
1052 Tcp4ConnectToken.CompletionToken.Event ));
1053
1054 Status = gBS->CreateEvent ( 0,
1055 TPL_CALLBACK,
1056 NULL,
1057 NULL,
1058 &Tcp4ListenToken.CompletionToken.Event );
1059 if ( EFI_ERROR ( Status )) {
1060 DEBUG (( DEBUG_ERROR,
1061 "ERROR - Failed to create the listen event, Status: %r\r\n",
1062 Status ));
1063 Tcp4ListenToken.CompletionToken.Event = NULL;
1064 break;
1065 }
1066 DEBUG (( DEBUG_INFO,
1067 "0x%08x: Listen event open\r\n",
1068 Tcp4ListenToken.CompletionToken.Event ));
1069
1070 Status = gBS->CreateEvent ( 0,
1071 TPL_CALLBACK,
1072 NULL,
1073 NULL,
1074 &Tcp4TxToken.CompletionToken.Event );
1075 if ( EFI_ERROR ( Status )) {
1076 DEBUG (( DEBUG_ERROR,
1077 "ERROR - Failed to create the TX event, Status: %r\r\n",
1078 Status ));
1079 Tcp4TxToken.CompletionToken.Event = NULL;
1080 break;
1081 }
1082 DEBUG (( DEBUG_INFO,
1083 "0x%08x: TX event open\r\n",
1084 Tcp4TxToken.CompletionToken.Event ));
1085
1086 //
1087 // Configure the local TCP port
1088 //
1089 Tcp4ConfigData.TimeToLive = 255;
1090 Tcp4ConfigData.TypeOfService = 0;
1091 Tcp4ConfigData.ControlOption = NULL;
1092 Tcp4ConfigData.AccessPoint.ActiveFlag = TRUE;
1093 Tcp4ConfigData.AccessPoint.StationAddress.Addr[0] = 0;
1094 Tcp4ConfigData.AccessPoint.StationAddress.Addr[1] = 0;
1095 Tcp4ConfigData.AccessPoint.StationAddress.Addr[2] = 0;
1096 Tcp4ConfigData.AccessPoint.StationAddress.Addr[3] = 0;
1097 Tcp4ConfigData.AccessPoint.StationPort = 0;
1098 Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8) RemoteHostAddress.sin_addr.s_addr;
1099 Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 8 );
1100 Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 16 );
1101 Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 24 );
1102 Tcp4ConfigData.AccessPoint.RemotePort = RemoteHostAddress.sin_port;
1103 Tcp4ConfigData.AccessPoint.UseDefaultAddress = TRUE;
1104 Tcp4ConfigData.AccessPoint.SubnetMask.Addr[0] = 0;
1105 Tcp4ConfigData.AccessPoint.SubnetMask.Addr[1] = 0;
1106 Tcp4ConfigData.AccessPoint.SubnetMask.Addr[2] = 0;
1107 Tcp4ConfigData.AccessPoint.SubnetMask.Addr[3] = 0;
1108 Status = pTcp4Protocol->Configure ( pTcp4Protocol,
1109 &Tcp4ConfigData );
1110 if ( EFI_ERROR ( Status )) {
1111 DEBUG (( DEBUG_ERROR,
1112 "ERROR - Failed to configure TCP port, Status: %r\r\n",
1113 Status ));
1114 break;
1115 }
1116 DEBUG (( DEBUG_INFO,
1117 "0x%08x: TCP4 port configured\r\n",
1118 pTcp4Protocol ));
1119
1120 //
1121 // Connect to the remote TCP port
1122 //
1123 Status = pTcp4Protocol->Connect ( pTcp4Protocol,
1124 &Tcp4ConnectToken );
1125 if ( EFI_ERROR ( Status )) {
1126 DEBUG (( DEBUG_ERROR,
1127 "ERROR - Failed to start the connection to the remote system, Status: %r\r\n",
1128 Status ));
1129 break;
1130 }
1131 Status = gBS->WaitForEvent ( 1,
1132 &Tcp4ConnectToken.CompletionToken.Event,
1133 &Index );
1134 if ( EFI_ERROR ( Status )) {
1135 DEBUG (( DEBUG_ERROR,
1136 "ERROR - Failed to wait for the connection, Status: %r\r\n",
1137 Status ));
1138 break;
1139 }
1140 Status = Tcp4ConnectToken.CompletionToken.Status;
1141 if ( EFI_ERROR ( Status )) {
1142 DEBUG (( DEBUG_WARN,
1143 "WARNING - Failed to connect to the remote system, Status: %r\r\n",
1144 Status ));
1145 break;
1146 }
1147 DEBUG (( DEBUG_INFO,
1148 "0x%08x: TCP4 port connected\r\n",
1149 pTcp4Protocol ));
1150 bTcp4Connected = TRUE;
1151
1152 //
1153 // Display the connection
1154 //
1155 pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
1156 Print ( L"Connected to %d.%d.%d.%d:%d\r\n",
1157 pIpAddress[0],
1158 pIpAddress[1],
1159 pIpAddress[2],
1160 pIpAddress[3],
1161 htons ( RemoteHostAddress.sin_port ));
1162 } while ( 0 );
1163
1164 if ( EFI_ERROR ( Status )) {
1165 //
1166 // Try again
1167 //
1168 Status = EFI_SUCCESS;
1169 }
1170 else {
1171 //
1172 // Semd data until the connection breaks
1173 //
1174 Status = Tcp4Send ( );
1175 }
1176
1177 //
1178 // Return the operation status
1179 //
1180 return Status;
1181 }
1182
1183
1184 /**
1185 Handle the timer callback
1186
1187 @param [in] Event Event that caused this callback
1188 @param [in] pContext Context for this routine
1189 **/
1190 VOID
1191 TimerCallback (
1192 IN EFI_EVENT Event,
1193 IN VOID * pContext
1194 )
1195 {
1196 UINT64 BytesSent;
1197 UINT64 DeltaBytes;
1198 UINT32 Delta;
1199 UINT64 Average;
1200
1201 //
1202 // Notify the other code of the timer tick
1203 //
1204 bTick = TRUE;
1205
1206 //
1207 // Update the average bytes per second
1208 //
1209 BytesSent = TotalBytesSent;
1210 if ( 0 != BytesSent ) {
1211 DeltaBytes = AverageBytes >> AVERAGE_SHIFT_COUNT;
1212 AverageBytes -= DeltaBytes;
1213 DeltaBytes = BytesSent - PreviousBytes;
1214 PreviousBytes = BytesSent;
1215 AverageBytes += DeltaBytes;
1216
1217 //
1218 // Separate the samples
1219 //
1220 if (( 2 << AVERAGE_SHIFT_COUNT ) == Samples ) {
1221 Print ( L"---------- Stable average ----------\r\n" );
1222 }
1223 Samples += 1;
1224
1225 //
1226 // Display the data rate
1227 //
1228 Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );
1229 Average = AverageBytes >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );
1230 if ( Average < RANGE_SWITCH ) {
1231 Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",
1232 Delta,
1233 (UINT32) Average );
1234 }
1235 else {
1236 Average >>= 10;
1237 if ( Average < RANGE_SWITCH ) {
1238 Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",
1239 Delta,
1240 (UINT32) Average );
1241 }
1242 else {
1243 Average >>= 10;
1244 if ( Average < RANGE_SWITCH ) {
1245 Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",
1246 Delta,
1247 (UINT32) Average );
1248 }
1249 else {
1250 Average >>= 10;
1251 if ( Average < RANGE_SWITCH ) {
1252 Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",
1253 Delta,
1254 (UINT32) Average );
1255 }
1256 else {
1257 Average >>= 10;
1258 if ( Average < RANGE_SWITCH ) {
1259 Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",
1260 Delta,
1261 Average );
1262 }
1263 else {
1264 Average >>= 10;
1265 Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",
1266 Delta,
1267 (UINT32) Average );
1268 }
1269 }
1270 }
1271 }
1272 }
1273 }
1274 }
1275
1276
1277 /**
1278 Create the timer
1279
1280 @retval EFI_SUCCESS The timer was successfully created
1281 @retval Other Timer initialization failed
1282 **/
1283 EFI_STATUS
1284 TimerCreate (
1285 )
1286 {
1287 EFI_STATUS Status;
1288
1289 //
1290 // Create the timer
1291 //
1292 Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
1293 TPL_DATASOURCE,
1294 TimerCallback,
1295 NULL,
1296 &pTimer );
1297 if ( EFI_ERROR ( Status )) {
1298 DEBUG (( DEBUG_ERROR,
1299 "ERROR - Failed to allocate the timer event, Status: %r\r\n",
1300 Status ));
1301 }
1302 else {
1303 DEBUG (( DEBUG_INFO,
1304 "0x%08x: Timer created\r\n",
1305 pTimer ));
1306 }
1307
1308 //
1309 // Return the operation status
1310 //
1311 return Status;
1312 }
1313
1314
1315 /**
1316 Stop the timer
1317
1318 @retval EFI_SUCCESS The timer was stopped successfully
1319 @retval Other The timer failed to stop
1320 **/
1321 EFI_STATUS
1322 TimerStop (
1323 )
1324 {
1325 EFI_STATUS Status;
1326
1327 //
1328 // Assume success
1329 //
1330 Status = EFI_SUCCESS;
1331
1332 //
1333 // Determine if the timer is running
1334 //
1335 if ( bTimerRunning ) {
1336 //
1337 // Stop the timer
1338 //
1339 Status = gBS->SetTimer ( pTimer,
1340 TimerCancel,
1341 0 );
1342 if ( EFI_ERROR ( Status )) {
1343 DEBUG (( DEBUG_ERROR,
1344 "ERROR - Failed to stop the timer, Status: %r\r\n",
1345 Status ));
1346 }
1347 else {
1348 //
1349 // Timer timer is now stopped
1350 //
1351 bTimerRunning = FALSE;
1352 DEBUG (( DEBUG_INFO,
1353 "0x%08x: Timer stopped\r\n",
1354 pTimer ));
1355 }
1356 }
1357
1358 //
1359 // Return the operation status
1360 //
1361 return Status;
1362 }
1363
1364
1365 /**
1366 Start the timer
1367
1368 @param [in] Milliseconds The number of milliseconds between timer callbacks
1369
1370 @retval EFI_SUCCESS The timer was successfully created
1371 @retval Other Timer initialization failed
1372 **/
1373 EFI_STATUS
1374 TimerStart (
1375 UINTN Milliseconds
1376 )
1377 {
1378 EFI_STATUS Status;
1379 UINT64 TimeDelay;
1380
1381 //
1382 // Stop the timer if necessary
1383 //
1384 Status = EFI_SUCCESS;
1385 if ( bTimerRunning ) {
1386 Status = TimerStop ( );
1387 }
1388 if ( !EFI_ERROR ( Status )) {
1389 //
1390 // Compute the new delay
1391 //
1392 TimeDelay = Milliseconds;
1393 TimeDelay *= 1000 * 10;
1394
1395 //
1396 // Start the timer
1397 //
1398 Status = gBS->SetTimer ( pTimer,
1399 TimerPeriodic,
1400 TimeDelay );
1401 if ( EFI_ERROR ( Status )) {
1402 DEBUG (( DEBUG_ERROR,
1403 "ERROR - Failed to start the timer, Status: %r\r\n",
1404 Status ));
1405 }
1406 else {
1407 //
1408 // The timer is now running
1409 //
1410 bTimerRunning = TRUE;
1411 DEBUG (( DEBUG_INFO,
1412 "0x%08x: Timer running\r\n",
1413 pTimer ));
1414 }
1415 }
1416
1417 //
1418 // Return the operation status
1419 //
1420 return Status;
1421 }
1422
1423
1424 /**
1425 Destroy the timer
1426
1427 @retval EFI_SUCCESS The timer was destroyed successfully
1428 @retval Other Failed to destroy the timer
1429 **/
1430 EFI_STATUS
1431 TimerDestroy (
1432 )
1433 {
1434 EFI_STATUS Status;
1435
1436 //
1437 // Assume success
1438 //
1439 Status = EFI_SUCCESS;
1440
1441 //
1442 // Determine if the timer is running
1443 //
1444 if ( bTimerRunning ) {
1445 //
1446 // Stop the timer
1447 //
1448 Status = TimerStop ( );
1449 }
1450 if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
1451 //
1452 // Done with this timer
1453 //
1454 Status = gBS->CloseEvent ( pTimer );
1455 if ( EFI_ERROR ( Status )) {
1456 DEBUG (( DEBUG_ERROR,
1457 "ERROR - Failed to free the timer event, Status: %r\r\n",
1458 Status ));
1459 }
1460 else {
1461 DEBUG (( DEBUG_INFO,
1462 "0x%08x: Timer Destroyed\r\n",
1463 pTimer ));
1464 pTimer = NULL;
1465 }
1466 }
1467
1468 //
1469 // Return the operation status
1470 //
1471 return Status;
1472 }
1473
1474
1475 /**
1476 Send data to the DataSink program to test a network's bandwidth.
1477
1478 @param [in] Argc The number of arguments
1479 @param [in] Argv The argument value array
1480
1481 @retval 0 The application exited normally.
1482 @retval Other An error occurred.
1483 **/
1484 int
1485 main (
1486 IN int Argc,
1487 IN char **Argv
1488 )
1489 {
1490 EFI_STATUS (* pClose) ();
1491 EFI_STATUS (* pOpen) ();
1492 EFI_STATUS Status;
1493
1494 DEBUG (( DEBUG_INFO,
1495 "DataSource starting\r\n" ));
1496
1497 //
1498 // Validate the command line
1499 //
1500 if ( 2 > Argc ) {
1501 Print ( L"%s <remote IP address> [Use TCP]\r\n", Argv[0] );
1502 return -1;
1503 }
1504
1505 //
1506 // Determine if TCP should be used
1507 //
1508 bTcp4 = (BOOLEAN)( 2 < Argc );
1509
1510 //
1511 // Determine the support routines
1512 //
1513 if ( bTcp4 ) {
1514 pOpen = Tcp4Open;
1515 pClose = Tcp4Close;
1516 bTcp4Connecting = TRUE;
1517 }
1518 else {
1519 pOpen = SocketOpen;
1520 pClose = SocketClose;
1521 }
1522
1523 //
1524 // Use for/break instead of goto
1525 //
1526 for ( ; ; ) {
1527 //
1528 // No bytes sent so far
1529 //
1530 TotalBytesSent = 0;
1531 AverageBytes = 0;
1532 PreviousBytes = 0;
1533 Samples = 0;
1534
1535 //
1536 // Get the port number
1537 //
1538 ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress ));
1539 RemoteHostAddress.sin_len = sizeof ( RemoteHostAddress );
1540 RemoteHostAddress.sin_family = AF_INET;
1541 RemoteHostAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));
1542
1543 //
1544 // Get the IP address
1545 //
1546 pRemoteHost = Argv[1];
1547 Status = IpAddress ( );
1548 if ( EFI_ERROR ( Status )) {
1549 break;
1550 }
1551
1552 //
1553 // Create the timer
1554 //
1555 bTick = TRUE;
1556 Status = TimerCreate ( );
1557 if ( EFI_ERROR ( Status )) {
1558 break;
1559 }
1560
1561 //
1562 // Loop forever abusing the specified system
1563 //
1564 do {
1565 //
1566 // Start a timer to perform connection polling and display updates
1567 //
1568 Status = TimerStart ( 2 * 1000 );
1569 if ( EFI_ERROR ( Status )) {
1570 break;
1571 }
1572
1573 //
1574 // Open the network connection and send the data
1575 //
1576 Status = pOpen ( );
1577 if ( EFI_ERROR ( Status )) {
1578 break;
1579 }
1580
1581 //
1582 // Done with the network connection
1583 //
1584 Status = pClose ( );
1585 } while ( !EFI_ERROR ( Status ));
1586
1587 //
1588 // Close the network connection if necessary
1589 //
1590 pClose ( );
1591
1592 //
1593 // All done
1594 //
1595 break;
1596 }
1597
1598 //
1599 // Stop the timer if necessary
1600 //
1601 TimerStop ( );
1602 TimerDestroy ( );
1603
1604 //
1605 // Return the operation status
1606 //
1607 DEBUG (( DEBUG_INFO,
1608 "DataSource exiting, Status: %r\r\n",
1609 Status ));
1610 return Status;
1611 }