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