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