Update the sockets library code
[mirror_edk2.git] / AppPkg / Applications / Sockets / DataSink / DataSink.c
CommitLineData
4684b66f 1/** @file\r
2 Data source for network testing.\r
3\r
4 Copyright (c) 2011, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <errno.h>\r
16#include <Uefi.h>\r
17\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/PcdLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/UefiLib.h>\r
23\r
24#include <netinet/in.h>\r
25\r
26#include <sys/EfiSysCall.h>\r
27#include <sys/poll.h>\r
28#include <sys/socket.h>\r
29\r
30\r
31#define MAX_CONNECTIONS ( 1 + 16 ) ///< Maximum number of client connections\r
32#define RANGE_SWITCH 2048 ///< Switch display ranges\r
33#define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates\r
34#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average\r
35\r
36#define TPL_DATASINK TPL_CALLBACK ///< Synchronization TPL\r
37\r
38#define PACKET_SIZE 1448 ///< Size of data packets\r
39#define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes\r
40\r
41typedef struct _DT_PORT {\r
42 UINT64 BytesAverage;\r
43 UINT64 BytesPrevious;\r
44 UINT64 BytesTotal;\r
45 struct sockaddr_in RemoteAddress;\r
46 UINT64 Samples;\r
47} DT_PORT;\r
48\r
49volatile BOOLEAN bTick;\r
50BOOLEAN bTimerRunning;\r
51struct sockaddr_in LocalAddress;\r
52EFI_EVENT pTimer;\r
53int ListenSocket;\r
54UINT8 Buffer [ DATA_BUFFER_SIZE ];\r
55struct pollfd PollFd [ MAX_CONNECTIONS ];\r
56DT_PORT Port [ MAX_CONNECTIONS ];\r
57nfds_t MaxPort;\r
58\r
59\r
60//\r
61// Forward routine declarations\r
62//\r
63EFI_STATUS TimerStart ( UINTN Milliseconds );\r
64\r
65\r
66/**\r
67 Check for control C entered at console\r
68\r
69 @retval EFI_SUCCESS Control C not entered\r
70 @retval EFI_ABORTED Control C entered\r
71**/\r
72EFI_STATUS\r
73ControlCCheck (\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
77\r
78 //\r
79 // Assume no user intervention\r
80 //\r
81 Status = EFI_SUCCESS;\r
82\r
83 //\r
84 // Display user stop request\r
85 //\r
86 if ( EFI_ERROR ( Status )) {\r
87 DEBUG (( DEBUG_INFO,\r
88 "User stop request!\r\n" ));\r
89 }\r
90\r
91 //\r
92 // Return the check status\r
93 //\r
94 return Status;\r
95}\r
96\r
97\r
98/**\r
99 Accept a socket connection\r
100\r
101 @retval EFI_SUCCESS The application is running normally\r
102 @retval EFI_NOT_STARTED Error with the listen socket\r
103 @retval Other The user stopped the application\r
104**/\r
105EFI_STATUS\r
106SocketAccept (\r
107 )\r
108{\r
109 INT32 SocketStatus;\r
110 EFI_STATUS Status;\r
111 INTN Index;\r
112\r
113 //\r
114 // Assume failure\r
115 //\r
116 Status = EFI_DEVICE_ERROR;\r
117\r
118 //\r
119 // Bind to the local address\r
120 //\r
121 SocketStatus = bind ( ListenSocket,\r
122 (struct sockaddr *) &LocalAddress,\r
123 LocalAddress.sin_len );\r
124 if ( 0 == SocketStatus ) {\r
125 //\r
126 // Start listening on the local socket\r
127 //\r
128 SocketStatus = listen ( ListenSocket, 5 );\r
129 if ( 0 == SocketStatus ) {\r
130 //\r
131 // Local socket in the listen state\r
132 //\r
133 Status = EFI_SUCCESS;\r
134\r
135 //\r
136 // Allocate a port\r
137 //\r
138 Index = MaxPort++;\r
139 PollFd [ Index ].fd = ListenSocket;\r
140 PollFd [ Index ].events = POLLRDNORM | POLLHUP;\r
141 PollFd [ Index ].revents = 0;\r
142 Port [ Index ].BytesAverage = 0;\r
143 Port [ Index ].BytesPrevious = 0;\r
144 Port [ Index ].BytesTotal = 0;\r
145 Port [ Index ].Samples = 0;\r
146 Port [ Index ].RemoteAddress.sin_len = 0;\r
147 Port [ Index ].RemoteAddress.sin_family = 0;\r
148 Port [ Index ].RemoteAddress.sin_port = 0;\r
149 Port [ Index ].RemoteAddress.sin_addr.s_addr= 0;\r
150 }\r
151 }\r
152\r
153 //\r
154 // Return the operation status\r
155 //\r
156 return Status;\r
157}\r
158\r
159\r
160/**\r
161 Close the socket\r
162\r
163 @retval EFI_SUCCESS The application is running normally\r
164 @retval Other The user stopped the application\r
165**/\r
166EFI_STATUS\r
167SocketClose (\r
168 )\r
169{\r
170 INT32 CloseStatus;\r
171 EFI_STATUS Status;\r
172\r
173 //\r
174 // Determine if the socket is open\r
175 //\r
176 Status = EFI_DEVICE_ERROR;\r
177 if ( -1 != ListenSocket ) {\r
178 //\r
179 // Attempt to close the socket\r
180 //\r
181 CloseStatus = close ( ListenSocket );\r
182 if ( 0 == CloseStatus ) {\r
183 DEBUG (( DEBUG_INFO,\r
184 "0x%08x: Socket closed\r\n",\r
185 ListenSocket ));\r
186 ListenSocket = -1;\r
187 Status = EFI_SUCCESS;\r
188 }\r
189 else {\r
190 DEBUG (( DEBUG_ERROR,\r
191 "ERROR: Failed to close socket, errno: %d\r\n",\r
192 errno ));\r
193 }\r
194 }\r
195\r
196 //\r
197 // Return the operation status\r
198 //\r
199 return Status;\r
200}\r
201\r
202\r
203/**\r
204 Create the socket\r
205\r
206 @retval EFI_SUCCESS The application is running normally\r
207 @retval Other The user stopped the application\r
208**/\r
209EFI_STATUS\r
210SocketNew (\r
211 )\r
212{\r
213 EFI_STATUS Status;\r
214\r
215 //\r
216 // Get the port number\r
217 //\r
218 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
219 LocalAddress.sin_len = sizeof ( LocalAddress );\r
220 LocalAddress.sin_family = AF_INET;\r
221 LocalAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));\r
222 \r
223 //\r
224 // Loop creating the socket\r
225 //\r
226 DEBUG (( DEBUG_INFO,\r
227 "Creating the socket\r\n" ));\r
228\r
229 //\r
230 // Check for user stop request\r
231 //\r
232 Status = ControlCCheck ( );\r
233 if ( !EFI_ERROR ( Status )) {\r
234 //\r
235 // Attempt to create the socket\r
236 //\r
237 ListenSocket = socket ( AF_INET,\r
238 SOCK_STREAM,\r
239 IPPROTO_TCP );\r
240 if ( -1 != ListenSocket ) {\r
241 DEBUG (( DEBUG_INFO,\r
242 "0x%08x: Socket created\r\n",\r
243 ListenSocket ));\r
244 }\r
245 else\r
246 {\r
247 Status = EFI_NOT_STARTED;\r
248 }\r
249 }\r
250\r
251 //\r
252 // Return the operation status\r
253 //\r
254 return Status;\r
255}\r
256\r
257\r
258/**\r
259 Poll the socket for more work\r
260\r
261 @retval EFI_SUCCESS The application is running normally\r
262 @retval EFI_NOT_STARTED Listen socket error\r
263 @retval Other The user stopped the application\r
264**/\r
265EFI_STATUS\r
266SocketPoll (\r
267 )\r
268{\r
269 BOOLEAN bRemoveSocket;\r
270 BOOLEAN bListenError;\r
271 size_t BytesReceived;\r
272 int CloseStatus;\r
273 nfds_t Entry;\r
274 INTN EntryPrevious;\r
275 int FdCount;\r
276 nfds_t Index;\r
277 socklen_t LengthInBytes;\r
278 struct sockaddr_in RemoteAddress;\r
279 int Socket;\r
280 EFI_STATUS Status;\r
281 EFI_TPL TplPrevious;\r
282\r
283 //\r
284 // Check for control-C\r
285 //\r
286 bListenError = FALSE;\r
287 Status = ControlCCheck ( );\r
288 if ( !EFI_ERROR ( Status )) {\r
289 //\r
290 // Poll the sockets\r
291 //\r
292 FdCount = poll ( &PollFd[0],\r
293 MaxPort,\r
294 0 );\r
295 if ( -1 == FdCount ) {\r
296 //\r
297 // Poll error\r
298 //\r
299 DEBUG (( DEBUG_ERROR,\r
300 "ERROR - Poll error, errno: %d\r\n",\r
301 errno ));\r
302 Status = EFI_DEVICE_ERROR;\r
303 }\r
304 else {\r
305 //\r
306 // Process the poll output\r
307 //\r
308 Index = 0;\r
309 while ( FdCount ) {\r
310 bRemoveSocket = FALSE;\r
311\r
312 //\r
313 // Account for this descriptor\r
314 //\r
315 if ( 0 != PollFd [ Index ].revents ) {\r
316 FdCount -= 1;\r
317 }\r
318\r
319 //\r
320 // Check for a broken connection\r
321 //\r
322 if ( 0 != ( PollFd [ Index ].revents & POLLHUP )) {\r
323 bRemoveSocket = TRUE;\r
324 if ( ListenSocket == PollFd [ Index ].fd ) {\r
325 bListenError = TRUE;\r
326 DEBUG (( DEBUG_ERROR,\r
327 "ERROR - Network closed on listen socket, errno: %d\r\n",\r
328 errno ));\r
329 }\r
330 else {\r
331 DEBUG (( DEBUG_ERROR,\r
332 "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",\r
333 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
334 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
335 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
336 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
337 htons ( Port [ Index ].RemoteAddress.sin_port ),\r
338 errno ));\r
339\r
340 //\r
341 // Close the socket\r
342 //\r
343 CloseStatus = close ( PollFd [ Index ].fd );\r
344 if ( 0 == CloseStatus ) {\r
345 bRemoveSocket = TRUE;\r
346 DEBUG (( DEBUG_INFO,\r
347 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
348 PollFd [ Index ].fd,\r
349 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
350 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
351 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
352 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
353 htons ( Port [ Index ].RemoteAddress.sin_port )));\r
354 }\r
355 else {\r
356 DEBUG (( DEBUG_ERROR,\r
357 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
358 PollFd [ Index ].fd,\r
359 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
360 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
361 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
362 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
363 htons ( Port [ Index ].RemoteAddress.sin_port ),\r
364 errno ));\r
365 }\r
366 }\r
367 }\r
368 \r
369 //\r
370 // Check for a connection or read data\r
371 //\r
372 if ( 0 != ( PollFd [ Index ].revents & POLLRDNORM )) {\r
373 //\r
374 // Check for a connection\r
375 //\r
376 if ( ListenSocket == PollFd [ Index ].fd ) {\r
377 //\r
378 // Another client connection was received\r
379 //\r
380 LengthInBytes = sizeof ( RemoteAddress );\r
381 Socket = accept ( ListenSocket,\r
382 (struct sockaddr *) &RemoteAddress,\r
383 &LengthInBytes );\r
384 if ( -1 == Socket ) {\r
385 //\r
386 // Listen socket error\r
387 //\r
388 bListenError = TRUE;\r
389 bRemoveSocket = TRUE;\r
390 DEBUG (( DEBUG_ERROR,\r
391 "ERROR - Listen socket failure, errno: %d\r\n",\r
392 errno ));\r
393 }\r
394 else {\r
395 //\r
396 // Determine if there is room for this connection\r
397 //\r
398 if (( MAX_CONNECTIONS <= MaxPort )\r
399 || ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {\r
400 //\r
401 // Display the connection\r
402 //\r
403 Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",\r
404 RemoteAddress.sin_addr.s_addr & 0xff,\r
405 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
406 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
407 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
408 htons ( RemoteAddress.sin_port ));\r
409\r
410 //\r
411 // No room for this connection\r
412 // Close the connection\r
413 //\r
414 CloseStatus = close ( Socket );\r
415 if ( 0 == CloseStatus ) {\r
416 bRemoveSocket = TRUE;\r
417 DEBUG (( DEBUG_INFO,\r
418 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
419 PollFd [ Index ].fd,\r
420 RemoteAddress.sin_addr.s_addr & 0xff,\r
421 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
422 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
423 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
424 htons ( RemoteAddress.sin_port )));\r
425 }\r
426 else {\r
427 DEBUG (( DEBUG_ERROR,\r
428 "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",\r
429 PollFd [ Index ].fd,\r
430 errno ));\r
431 }\r
432\r
433 //\r
434 // Keep the application running\r
435 // No issue with the listen socket\r
436 //\r
437 Status = EFI_SUCCESS;\r
438 }\r
439 else\r
440 {\r
441 //\r
442 // Display the connection\r
443 //\r
444 Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",\r
445 RemoteAddress.sin_addr.s_addr & 0xff,\r
446 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
447 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
448 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
449 htons ( RemoteAddress.sin_port ));\r
450\r
451 //\r
452 // Allocate the client connection\r
453 //\r
454 Index = MaxPort++;\r
455 Port [ Index ].BytesAverage = 0;\r
456 Port [ Index ].BytesPrevious = 0;\r
457 Port [ Index ].BytesTotal = 0;\r
458 Port [ Index ].Samples = 0;\r
459 Port [ Index ].RemoteAddress.sin_len = RemoteAddress.sin_len;\r
460 Port [ Index ].RemoteAddress.sin_family = RemoteAddress.sin_family;\r
461 Port [ Index ].RemoteAddress.sin_port = RemoteAddress.sin_port;\r
462 Port [ Index ].RemoteAddress.sin_addr = RemoteAddress.sin_addr;\r
463 PollFd [ Index ].fd = Socket;\r
464 PollFd [ Index ].events = POLLRDNORM | POLLHUP;\r
465 PollFd [ Index ].revents = 0;\r
466 }\r
467 }\r
468 }\r
469 else {\r
470 //\r
471 // Data received\r
472 //\r
473 BytesReceived = read ( PollFd [ Index ].fd,\r
474 &Buffer,\r
475 sizeof ( Buffer ));\r
476 if ( 0 < BytesReceived ) {\r
477 //\r
478 // Display the amount of data received\r
479 //\r
480 DEBUG (( DEBUG_INFO,\r
481 "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",\r
482 PollFd [ Index ].fd,\r
483 BytesReceived,\r
484 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
485 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
486 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
487 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
488 htons ( Port [ Index ].RemoteAddress.sin_port )));\r
489\r
490 //\r
491 // Synchronize with the TimerCallback routine\r
492 //\r
493 TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );\r
494\r
495 //\r
496 // Account for the data received\r
497 //\r
498 Port [ Index ].BytesTotal += BytesReceived;\r
499\r
500 //\r
501 // Release the synchronization with the TimerCallback routine\r
502 //\r
503 gBS->RestoreTPL ( TplPrevious );\r
504 }\r
505 else if ( -1 == BytesReceived ) {\r
506 //\r
507 // Close the socket\r
508 //\r
509 DEBUG (( DEBUG_INFO,\r
510 "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",\r
511 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
512 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
513 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
514 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
515 htons ( Port [ Index ].RemoteAddress.sin_port ),\r
516 errno ));\r
517 CloseStatus = close ( PollFd [ Index ].fd );\r
518 if ( 0 == CloseStatus ) {\r
519 bRemoveSocket = TRUE;\r
520 DEBUG (( DEBUG_INFO,\r
521 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
522 PollFd [ Index ].fd,\r
523 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
524 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
525 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
526 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
527 htons ( Port [ Index ].RemoteAddress.sin_port )));\r
528 }\r
529 else {\r
530 DEBUG (( DEBUG_ERROR,\r
531 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
532 PollFd [ Index ].fd,\r
533 Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
534 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
535 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
536 ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
537 htons ( Port [ Index ].RemoteAddress.sin_port ),\r
538 errno ));\r
539 }\r
540 }\r
541\r
542 //\r
543 // Keep the application running\r
544 // No issue with the listen socket\r
545 //\r
546 Status = EFI_SUCCESS;\r
547 }\r
548 }\r
549\r
550 //\r
551 // Remove the socket if necessary\r
552 //\r
553 if ( bRemoveSocket ) {\r
554 DEBUG (( DEBUG_INFO,\r
555 "0x%08x: Socket removed from polling\r\n",\r
556 PollFd [ Index ].fd ));\r
557 MaxPort -= 1;\r
558 for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {\r
559 EntryPrevious = Entry;\r
560 Port [ EntryPrevious ].BytesAverage = Port [ Entry ].BytesAverage;\r
561 Port [ EntryPrevious ].BytesPrevious = Port [ Entry ].BytesPrevious;\r
562 Port [ EntryPrevious ].BytesTotal = Port [ Entry ].BytesTotal;\r
563 Port [ EntryPrevious ].RemoteAddress.sin_len = Port [ Entry ].RemoteAddress.sin_len;\r
564 Port [ EntryPrevious ].RemoteAddress.sin_family = Port [ Entry ].RemoteAddress.sin_family;\r
565 Port [ EntryPrevious ].RemoteAddress.sin_port = Port [ Entry ].RemoteAddress.sin_port;\r
566 Port [ EntryPrevious ].RemoteAddress.sin_addr.s_addr = Port [ Entry ].RemoteAddress.sin_addr.s_addr;\r
567 Port [ EntryPrevious ].Samples = Port [ Entry ].Samples;\r
568 PollFd [ EntryPrevious ].events = PollFd [ Entry ].events;\r
569 PollFd [ EntryPrevious ].fd = PollFd [ Entry ].fd;\r
570 PollFd [ EntryPrevious ].revents = PollFd [ Entry ].revents;\r
571 }\r
572 PollFd [ MaxPort ].fd = -1;\r
573 Index -= 1;\r
574 }\r
575\r
576 //\r
577 // Account for this socket\r
578 //\r
579 Index += 1;\r
580 }\r
581 }\r
582 }\r
583\r
584 //\r
585 // Return the listen failure if necessary\r
586 //\r
587 if (( !EFI_ERROR ( Status )) && bListenError ) {\r
588 Status = EFI_NOT_STARTED;\r
589 }\r
590\r
591 //\r
592 // Return the poll status\r
593 //\r
594 return Status;\r
595}\r
596\r
597\r
598/**\r
599 Handle the timer callback\r
600\r
601 @param [in] Event Event that caused this callback\r
602 @param [in] pContext Context for this routine\r
603**/\r
604VOID\r
605TimerCallback (\r
606 IN EFI_EVENT Event,\r
607 IN VOID * pContext\r
608 )\r
609{\r
610 UINT64 Average;\r
611 UINT64 BytesReceived;\r
612 UINT32 Delta;\r
613 UINT64 DeltaBytes;\r
614 nfds_t Index;\r
615\r
616 //\r
617 // Notify the other code of the timer tick\r
618 //\r
619 bTick = TRUE;\r
620\r
621 //\r
622 // Walk the list of ports\r
623 //\r
624 for ( Index = 0; MaxPort > Index; Index++ ) {\r
625 //\r
626 // Determine if any data was received\r
627 //\r
628 BytesReceived = Port [ Index ].BytesTotal;\r
629 if (( ListenSocket != PollFd [ Index ].fd )\r
630 && ( 0 != BytesReceived )) {\r
631 //\r
632 // Update the average bytes per second\r
633 //\r
634 DeltaBytes = Port [ Index ].BytesAverage >> AVERAGE_SHIFT_COUNT;\r
635 Port [ Index ].BytesAverage -= DeltaBytes;\r
636 DeltaBytes = BytesReceived - Port [ Index ].BytesPrevious;\r
637 Port [ Index ].BytesPrevious = BytesReceived;\r
638 Port [ Index ].BytesAverage += DeltaBytes;\r
639\r
640 //\r
641 // Separate the samples\r
642 //\r
643 if (( 2 << AVERAGE_SHIFT_COUNT ) == Port [ Index ].Samples ) {\r
644 Print ( L"---------- Stable average ----------\r\n" );\r
645 }\r
646 Port [ Index ].Samples += 1;\r
647\r
648 //\r
649 // Display the data rate\r
650 //\r
651 Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );\r
652 Average = Port [ Index ].BytesAverage >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );\r
653 if ( Average < RANGE_SWITCH ) {\r
654 Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",\r
655 Delta,\r
656 (UINT32) Average );\r
657 }\r
658 else {\r
659 Average >>= 10;\r
660 if ( Average < RANGE_SWITCH ) {\r
661 Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",\r
662 Delta,\r
663 (UINT32) Average );\r
664 }\r
665 else {\r
666 Average >>= 10;\r
667 if ( Average < RANGE_SWITCH ) {\r
668 Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",\r
669 Delta,\r
670 (UINT32) Average );\r
671 }\r
672 else {\r
673 Average >>= 10;\r
674 if ( Average < RANGE_SWITCH ) {\r
675 Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",\r
676 Delta,\r
677 (UINT32) Average );\r
678 }\r
679 else {\r
680 Average >>= 10;\r
681 if ( Average < RANGE_SWITCH ) {\r
682 Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",\r
683 Delta,\r
684 Average );\r
685 }\r
686 else {\r
687 Average >>= 10;\r
688 Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",\r
689 Delta,\r
690 (UINT32) Average );\r
691 }\r
692 }\r
693 }\r
694 }\r
695 }\r
696 }\r
697 }\r
698}\r
699\r
700\r
701/**\r
702 Create the timer\r
703\r
704 @retval EFI_SUCCESS The timer was successfully created\r
705 @retval Other Timer initialization failed\r
706**/\r
707EFI_STATUS\r
708TimerCreate (\r
709 )\r
710{\r
711 EFI_STATUS Status;\r
712\r
713 //\r
714 // Create the timer\r
715 //\r
716 Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
717 TPL_DATASINK,\r
718 TimerCallback,\r
719 NULL,\r
720 &pTimer );\r
721 if ( EFI_ERROR ( Status )) {\r
722 DEBUG (( DEBUG_ERROR,\r
723 "ERROR - Failed to allocate the timer event, Status: %r\r\n",\r
724 Status ));\r
725 }\r
726 else {\r
727 DEBUG (( DEBUG_INFO,\r
728 "0x%08x: Timer created\r\n",\r
729 pTimer ));\r
730 }\r
731\r
732 //\r
733 // Return the operation status\r
734 //\r
735 return Status;\r
736}\r
737\r
738\r
739/**\r
740 Stop the timer\r
741\r
742 @retval EFI_SUCCESS The timer was stopped successfully\r
743 @retval Other The timer failed to stop\r
744**/\r
745EFI_STATUS\r
746TimerStop (\r
747 )\r
748{\r
749 EFI_STATUS Status;\r
750\r
751 //\r
752 // Assume success\r
753 //\r
754 Status = EFI_SUCCESS;\r
755\r
756 //\r
757 // Determine if the timer is running\r
758 //\r
759 if ( bTimerRunning ) {\r
760 //\r
761 // Stop the timer\r
762 //\r
763 Status = gBS->SetTimer ( pTimer,\r
764 TimerCancel,\r
765 0 );\r
766 if ( EFI_ERROR ( Status )) {\r
767 DEBUG (( DEBUG_ERROR,\r
768 "ERROR - Failed to stop the timer, Status: %r\r\n",\r
769 Status ));\r
770 }\r
771 else {\r
772 //\r
773 // Timer timer is now stopped\r
774 //\r
775 bTimerRunning = FALSE;\r
776 DEBUG (( DEBUG_INFO,\r
777 "0x%08x: Timer stopped\r\n",\r
778 pTimer ));\r
779 }\r
780 }\r
781\r
782 //\r
783 // Return the operation status\r
784 //\r
785 return Status;\r
786}\r
787\r
788\r
789/**\r
790 Start the timer\r
791\r
792 @param [in] Milliseconds The number of milliseconds between timer callbacks\r
793\r
794 @retval EFI_SUCCESS The timer was successfully created\r
795 @retval Other Timer initialization failed\r
796**/\r
797EFI_STATUS\r
798TimerStart (\r
799 UINTN Milliseconds\r
800 )\r
801{\r
802 EFI_STATUS Status;\r
803 UINT64 TimeDelay;\r
804\r
805 //\r
806 // Stop the timer if necessary\r
807 //\r
808 Status = EFI_SUCCESS;\r
809 if ( bTimerRunning ) {\r
810 Status = TimerStop ( );\r
811 }\r
812 if ( !EFI_ERROR ( Status )) {\r
813 //\r
814 // Compute the new delay\r
815 //\r
816 TimeDelay = Milliseconds;\r
817 TimeDelay *= 1000 * 10;\r
818\r
819 //\r
820 // Start the timer\r
821 //\r
822 Status = gBS->SetTimer ( pTimer,\r
823 TimerPeriodic,\r
824 TimeDelay );\r
825 if ( EFI_ERROR ( Status )) {\r
826 DEBUG (( DEBUG_ERROR,\r
827 "ERROR - Failed to start the timer, Status: %r\r\n",\r
828 Status ));\r
829 }\r
830 else {\r
831 //\r
832 // The timer is now running\r
833 //\r
834 bTimerRunning = TRUE;\r
835 DEBUG (( DEBUG_INFO,\r
836 "0x%08x: Timer running\r\n",\r
837 pTimer ));\r
838 }\r
839 }\r
840\r
841 //\r
842 // Return the operation status\r
843 //\r
844 return Status;\r
845}\r
846\r
847\r
848/**\r
849 Destroy the timer\r
850\r
851 @retval EFI_SUCCESS The timer was destroyed successfully\r
852 @retval Other Failed to destroy the timer\r
853**/\r
854EFI_STATUS\r
855TimerDestroy (\r
856 )\r
857{\r
858 EFI_STATUS Status;\r
859\r
860 //\r
861 // Assume success\r
862 //\r
863 Status = EFI_SUCCESS;\r
864\r
865 //\r
866 // Determine if the timer is running\r
867 //\r
868 if ( bTimerRunning ) {\r
869 //\r
870 // Stop the timer\r
871 //\r
872 Status = TimerStop ( );\r
873 }\r
874 if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {\r
875 //\r
876 // Done with this timer\r
877 //\r
878 Status = gBS->CloseEvent ( pTimer );\r
879 if ( EFI_ERROR ( Status )) {\r
880 DEBUG (( DEBUG_ERROR,\r
881 "ERROR - Failed to free the timer event, Status: %r\r\n",\r
882 Status ));\r
883 }\r
884 else {\r
885 DEBUG (( DEBUG_INFO,\r
886 "0x%08x: Timer Destroyed\r\n",\r
887 pTimer ));\r
888 pTimer = NULL;\r
889 }\r
890 }\r
891\r
892 //\r
893 // Return the operation status\r
894 //\r
895 return Status;\r
896}\r
897\r
898\r
899/**\r
900 Receive data from the DataSource program to test a network's bandwidth.\r
901\r
902 @param [in] Argc The number of arguments\r
903 @param [in] Argv The argument value array\r
904\r
905 @retval 0 The application exited normally.\r
906 @retval Other An error occurred.\r
907**/\r
908int\r
909main (\r
910 IN int Argc,\r
911 IN char **Argv\r
912 )\r
913{\r
914 EFI_STATUS Status;\r
915\r
916 DEBUG (( DEBUG_INFO,\r
917 "DataSink starting\r\n" ));\r
918\r
919 //\r
920 // Use for/break instead of goto\r
921 //\r
922 for ( ; ; )\r
923 {\r
924 //\r
925 // Create the timer\r
926 //\r
927 bTick = TRUE;\r
928 Status = TimerCreate ( );\r
929 if ( EFI_ERROR ( Status )) {\r
930 break;\r
931 }\r
932\r
933 //\r
934 // Start a timer to perform network polling and display updates\r
935 //\r
936 Status = TimerStart ( 1 * 1000 );\r
937 if ( EFI_ERROR ( Status )) {\r
938 break;\r
939 }\r
940\r
941 //\r
942 // Loop forever waiting for abuse\r
943 //\r
944 do {\r
945 ListenSocket = -1;\r
946 do {\r
947 //\r
948 // Complete any client operations\r
949 //\r
950 Status = SocketPoll ( );\r
951 if ( EFI_ERROR ( Status )) {\r
952 //\r
953 // Control-C\r
954 //\r
955 break;\r
956 }\r
957 \r
958 //\r
959 // Wait for a while\r
960 //\r
961 } while ( !bTick );\r
962 if ( EFI_ERROR ( Status )) {\r
963 //\r
964 // Control-C\r
965 //\r
966 break;\r
967 }\r
968 \r
969 //\r
970 // Wait for the network layer to initialize\r
971 //\r
972 Status = SocketNew ( );\r
973 if ( EFI_ERROR ( Status )) {\r
974 continue;\r
975 }\r
976\r
977 //\r
978 // Wait for the remote network application to start\r
979 //\r
980 Status = SocketAccept ( );\r
981 if ( EFI_NOT_STARTED == Status ) {\r
982 Status = SocketClose ( );\r
983 continue;\r
984 }\r
985 else if ( EFI_SUCCESS != Status ) {\r
986 //\r
987 // Control-C\r
988 //\r
989 break;\r
990 }\r
991\r
992 //\r
993 // Send data until the connection breaks\r
994 //\r
995 do {\r
996 Status = SocketPoll ( );\r
997 } while ( !EFI_ERROR ( Status ));\r
998\r
999 //\r
1000 // Done with the socket\r
1001 //\r
1002 Status = SocketClose ( );\r
1003 } while ( !EFI_ERROR ( Status ));\r
1004\r
1005 //\r
1006 // Close the socket if necessary\r
1007 //\r
1008 SocketClose ( );\r
1009\r
1010 //\r
1011 // All done\r
1012 //\r
1013 break;\r
1014 }\r
1015\r
1016 //\r
1017 // Stop the timer if necessary\r
1018 //\r
1019 TimerStop ( );\r
1020 TimerDestroy ( );\r
1021\r
1022 //\r
1023 // Return the operation status\r
1024 //\r
1025 DEBUG (( DEBUG_INFO,\r
1026 "DataSink exiting, Status: %r\r\n",\r
1027 Status ));\r
1028 return Status;\r
1029}\r