Merged socket development branch:
[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
59bc0593 54UINT8 Buffer[ DATA_BUFFER_SIZE ];\r
55struct pollfd PollFd[ MAX_CONNECTIONS ];\r
56DT_PORT Port[ MAX_CONNECTIONS ];\r
4684b66f 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
59bc0593 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
4684b66f 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
59bc0593 245 else {\r
4684b66f 246 Status = EFI_NOT_STARTED;\r
247 }\r
248 }\r
249\r
250 //\r
251 // Return the operation status\r
252 //\r
253 return Status;\r
254}\r
255\r
256\r
257/**\r
258 Poll the socket for more work\r
259\r
260 @retval EFI_SUCCESS The application is running normally\r
261 @retval EFI_NOT_STARTED Listen socket error\r
262 @retval Other The user stopped the application\r
263**/\r
264EFI_STATUS\r
265SocketPoll (\r
266 )\r
267{\r
268 BOOLEAN bRemoveSocket;\r
269 BOOLEAN bListenError;\r
270 size_t BytesReceived;\r
271 int CloseStatus;\r
272 nfds_t Entry;\r
273 INTN EntryPrevious;\r
274 int FdCount;\r
275 nfds_t Index;\r
276 socklen_t LengthInBytes;\r
277 struct sockaddr_in RemoteAddress;\r
278 int Socket;\r
279 EFI_STATUS Status;\r
280 EFI_TPL TplPrevious;\r
281\r
282 //\r
283 // Check for control-C\r
284 //\r
285 bListenError = FALSE;\r
286 Status = ControlCCheck ( );\r
287 if ( !EFI_ERROR ( Status )) {\r
288 //\r
289 // Poll the sockets\r
290 //\r
291 FdCount = poll ( &PollFd[0],\r
292 MaxPort,\r
293 0 );\r
294 if ( -1 == FdCount ) {\r
295 //\r
296 // Poll error\r
297 //\r
298 DEBUG (( DEBUG_ERROR,\r
299 "ERROR - Poll error, errno: %d\r\n",\r
300 errno ));\r
301 Status = EFI_DEVICE_ERROR;\r
302 }\r
303 else {\r
304 //\r
305 // Process the poll output\r
306 //\r
307 Index = 0;\r
308 while ( FdCount ) {\r
309 bRemoveSocket = FALSE;\r
310\r
311 //\r
312 // Account for this descriptor\r
313 //\r
59bc0593 314 if ( 0 != PollFd[ Index ].revents ) {\r
4684b66f 315 FdCount -= 1;\r
316 }\r
317\r
318 //\r
319 // Check for a broken connection\r
320 //\r
59bc0593 321 if ( 0 != ( PollFd[ Index ].revents & POLLHUP )) {\r
4684b66f 322 bRemoveSocket = TRUE;\r
59bc0593 323 if ( ListenSocket == PollFd[ Index ].fd ) {\r
4684b66f 324 bListenError = TRUE;\r
325 DEBUG (( DEBUG_ERROR,\r
326 "ERROR - Network closed on listen socket, errno: %d\r\n",\r
327 errno ));\r
328 }\r
329 else {\r
330 DEBUG (( DEBUG_ERROR,\r
331 "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",\r
59bc0593 332 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
333 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
334 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
335 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
336 htons ( Port[ Index ].RemoteAddress.sin_port ),\r
4684b66f 337 errno ));\r
338\r
339 //\r
340 // Close the socket\r
341 //\r
59bc0593 342 CloseStatus = close ( PollFd[ Index ].fd );\r
4684b66f 343 if ( 0 == CloseStatus ) {\r
344 bRemoveSocket = TRUE;\r
345 DEBUG (( DEBUG_INFO,\r
346 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
59bc0593 347 PollFd[ Index ].fd,\r
348 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
349 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
350 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
351 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
352 htons ( Port[ Index ].RemoteAddress.sin_port )));\r
4684b66f 353 }\r
354 else {\r
355 DEBUG (( DEBUG_ERROR,\r
356 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
59bc0593 357 PollFd[ Index ].fd,\r
358 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
359 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
360 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
361 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
362 htons ( Port[ Index ].RemoteAddress.sin_port ),\r
4684b66f 363 errno ));\r
364 }\r
365 }\r
366 }\r
367 \r
368 //\r
369 // Check for a connection or read data\r
370 //\r
59bc0593 371 if ( 0 != ( PollFd[ Index ].revents & POLLRDNORM )) {\r
4684b66f 372 //\r
373 // Check for a connection\r
374 //\r
59bc0593 375 if ( ListenSocket == PollFd[ Index ].fd ) {\r
4684b66f 376 //\r
377 // Another client connection was received\r
378 //\r
379 LengthInBytes = sizeof ( RemoteAddress );\r
380 Socket = accept ( ListenSocket,\r
381 (struct sockaddr *) &RemoteAddress,\r
382 &LengthInBytes );\r
383 if ( -1 == Socket ) {\r
384 //\r
385 // Listen socket error\r
386 //\r
387 bListenError = TRUE;\r
388 bRemoveSocket = TRUE;\r
389 DEBUG (( DEBUG_ERROR,\r
390 "ERROR - Listen socket failure, errno: %d\r\n",\r
391 errno ));\r
392 }\r
393 else {\r
394 //\r
395 // Determine if there is room for this connection\r
396 //\r
397 if (( MAX_CONNECTIONS <= MaxPort )\r
398 || ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {\r
399 //\r
400 // Display the connection\r
401 //\r
402 Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",\r
403 RemoteAddress.sin_addr.s_addr & 0xff,\r
404 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
405 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
406 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
407 htons ( RemoteAddress.sin_port ));\r
408\r
409 //\r
410 // No room for this connection\r
411 // Close the connection\r
412 //\r
413 CloseStatus = close ( Socket );\r
414 if ( 0 == CloseStatus ) {\r
415 bRemoveSocket = TRUE;\r
416 DEBUG (( DEBUG_INFO,\r
417 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
59bc0593 418 PollFd[ Index ].fd,\r
4684b66f 419 RemoteAddress.sin_addr.s_addr & 0xff,\r
420 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
421 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
422 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
423 htons ( RemoteAddress.sin_port )));\r
424 }\r
425 else {\r
426 DEBUG (( DEBUG_ERROR,\r
427 "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",\r
59bc0593 428 PollFd[ Index ].fd,\r
4684b66f 429 errno ));\r
430 }\r
431\r
432 //\r
433 // Keep the application running\r
434 // No issue with the listen socket\r
435 //\r
436 Status = EFI_SUCCESS;\r
437 }\r
59bc0593 438 else {\r
4684b66f 439 //\r
440 // Display the connection\r
441 //\r
442 Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",\r
443 RemoteAddress.sin_addr.s_addr & 0xff,\r
444 ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
445 ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
446 ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
447 htons ( RemoteAddress.sin_port ));\r
448\r
449 //\r
450 // Allocate the client connection\r
451 //\r
452 Index = MaxPort++;\r
59bc0593 453 Port[ Index ].BytesAverage = 0;\r
454 Port[ Index ].BytesPrevious = 0;\r
455 Port[ Index ].BytesTotal = 0;\r
456 Port[ Index ].Samples = 0;\r
457 Port[ Index ].RemoteAddress.sin_len = RemoteAddress.sin_len;\r
458 Port[ Index ].RemoteAddress.sin_family = RemoteAddress.sin_family;\r
459 Port[ Index ].RemoteAddress.sin_port = RemoteAddress.sin_port;\r
460 Port[ Index ].RemoteAddress.sin_addr = RemoteAddress.sin_addr;\r
461 PollFd[ Index ].fd = Socket;\r
462 PollFd[ Index ].events = POLLRDNORM | POLLHUP;\r
463 PollFd[ Index ].revents = 0;\r
4684b66f 464 }\r
465 }\r
466 }\r
467 else {\r
468 //\r
469 // Data received\r
470 //\r
59bc0593 471 BytesReceived = read ( PollFd[ Index ].fd,\r
4684b66f 472 &Buffer,\r
473 sizeof ( Buffer ));\r
474 if ( 0 < BytesReceived ) {\r
475 //\r
476 // Display the amount of data received\r
477 //\r
478 DEBUG (( DEBUG_INFO,\r
479 "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",\r
59bc0593 480 PollFd[ Index ].fd,\r
4684b66f 481 BytesReceived,\r
59bc0593 482 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
483 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
484 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
485 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
486 htons ( Port[ Index ].RemoteAddress.sin_port )));\r
4684b66f 487\r
488 //\r
489 // Synchronize with the TimerCallback routine\r
490 //\r
491 TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );\r
492\r
493 //\r
494 // Account for the data received\r
495 //\r
59bc0593 496 Port[ Index ].BytesTotal += BytesReceived;\r
4684b66f 497\r
498 //\r
499 // Release the synchronization with the TimerCallback routine\r
500 //\r
501 gBS->RestoreTPL ( TplPrevious );\r
502 }\r
503 else if ( -1 == BytesReceived ) {\r
504 //\r
505 // Close the socket\r
506 //\r
507 DEBUG (( DEBUG_INFO,\r
508 "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",\r
59bc0593 509 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
510 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
511 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
512 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
513 htons ( Port[ Index ].RemoteAddress.sin_port ),\r
4684b66f 514 errno ));\r
59bc0593 515 CloseStatus = close ( PollFd[ Index ].fd );\r
4684b66f 516 if ( 0 == CloseStatus ) {\r
517 bRemoveSocket = TRUE;\r
518 DEBUG (( DEBUG_INFO,\r
519 "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",\r
59bc0593 520 PollFd[ Index ].fd,\r
521 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
522 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
523 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
524 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
525 htons ( Port[ Index ].RemoteAddress.sin_port )));\r
4684b66f 526 }\r
527 else {\r
528 DEBUG (( DEBUG_ERROR,\r
529 "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",\r
59bc0593 530 PollFd[ Index ].fd,\r
531 Port[ Index ].RemoteAddress.sin_addr.s_addr & 0xff,\r
532 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,\r
533 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,\r
534 ( Port[ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,\r
535 htons ( Port[ Index ].RemoteAddress.sin_port ),\r
4684b66f 536 errno ));\r
537 }\r
538 }\r
539\r
540 //\r
541 // Keep the application running\r
542 // No issue with the listen socket\r
543 //\r
544 Status = EFI_SUCCESS;\r
545 }\r
546 }\r
547\r
548 //\r
549 // Remove the socket if necessary\r
550 //\r
551 if ( bRemoveSocket ) {\r
552 DEBUG (( DEBUG_INFO,\r
553 "0x%08x: Socket removed from polling\r\n",\r
59bc0593 554 PollFd[ Index ].fd ));\r
4684b66f 555 MaxPort -= 1;\r
556 for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {\r
557 EntryPrevious = Entry;\r
59bc0593 558 Port[ EntryPrevious ].BytesAverage = Port[ Entry ].BytesAverage;\r
559 Port[ EntryPrevious ].BytesPrevious = Port[ Entry ].BytesPrevious;\r
560 Port[ EntryPrevious ].BytesTotal = Port[ Entry ].BytesTotal;\r
561 Port[ EntryPrevious ].RemoteAddress.sin_len = Port[ Entry ].RemoteAddress.sin_len;\r
562 Port[ EntryPrevious ].RemoteAddress.sin_family = Port[ Entry ].RemoteAddress.sin_family;\r
563 Port[ EntryPrevious ].RemoteAddress.sin_port = Port[ Entry ].RemoteAddress.sin_port;\r
564 Port[ EntryPrevious ].RemoteAddress.sin_addr.s_addr = Port[ Entry ].RemoteAddress.sin_addr.s_addr;\r
565 Port[ EntryPrevious ].Samples = Port[ Entry ].Samples;\r
566 PollFd[ EntryPrevious ].events = PollFd[ Entry ].events;\r
567 PollFd[ EntryPrevious ].fd = PollFd[ Entry ].fd;\r
568 PollFd[ EntryPrevious ].revents = PollFd[ Entry ].revents;\r
4684b66f 569 }\r
59bc0593 570 PollFd[ MaxPort ].fd = -1;\r
4684b66f 571 Index -= 1;\r
572 }\r
573\r
574 //\r
575 // Account for this socket\r
576 //\r
577 Index += 1;\r
578 }\r
579 }\r
580 }\r
581\r
582 //\r
583 // Return the listen failure if necessary\r
584 //\r
585 if (( !EFI_ERROR ( Status )) && bListenError ) {\r
586 Status = EFI_NOT_STARTED;\r
587 }\r
588\r
589 //\r
590 // Return the poll status\r
591 //\r
592 return Status;\r
593}\r
594\r
595\r
596/**\r
597 Handle the timer callback\r
598\r
599 @param [in] Event Event that caused this callback\r
600 @param [in] pContext Context for this routine\r
601**/\r
602VOID\r
603TimerCallback (\r
604 IN EFI_EVENT Event,\r
605 IN VOID * pContext\r
606 )\r
607{\r
608 UINT64 Average;\r
609 UINT64 BytesReceived;\r
610 UINT32 Delta;\r
611 UINT64 DeltaBytes;\r
612 nfds_t Index;\r
613\r
614 //\r
615 // Notify the other code of the timer tick\r
616 //\r
617 bTick = TRUE;\r
618\r
619 //\r
620 // Walk the list of ports\r
621 //\r
622 for ( Index = 0; MaxPort > Index; Index++ ) {\r
623 //\r
624 // Determine if any data was received\r
625 //\r
59bc0593 626 BytesReceived = Port[ Index ].BytesTotal;\r
627 if (( ListenSocket != PollFd[ Index ].fd )\r
4684b66f 628 && ( 0 != BytesReceived )) {\r
629 //\r
630 // Update the average bytes per second\r
631 //\r
59bc0593 632 DeltaBytes = Port[ Index ].BytesAverage >> AVERAGE_SHIFT_COUNT;\r
633 Port[ Index ].BytesAverage -= DeltaBytes;\r
634 DeltaBytes = BytesReceived - Port[ Index ].BytesPrevious;\r
635 Port[ Index ].BytesPrevious = BytesReceived;\r
636 Port[ Index ].BytesAverage += DeltaBytes;\r
4684b66f 637\r
638 //\r
639 // Separate the samples\r
640 //\r
59bc0593 641 if (( 2 << AVERAGE_SHIFT_COUNT ) == Port[ Index ].Samples ) {\r
4684b66f 642 Print ( L"---------- Stable average ----------\r\n" );\r
643 }\r
59bc0593 644 Port[ Index ].Samples += 1;\r
4684b66f 645\r
646 //\r
647 // Display the data rate\r
648 //\r
649 Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );\r
59bc0593 650 Average = Port[ Index ].BytesAverage >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );\r
4684b66f 651 if ( Average < RANGE_SWITCH ) {\r
652 Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",\r
653 Delta,\r
654 (UINT32) Average );\r
655 }\r
656 else {\r
657 Average >>= 10;\r
658 if ( Average < RANGE_SWITCH ) {\r
659 Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",\r
660 Delta,\r
661 (UINT32) Average );\r
662 }\r
663 else {\r
664 Average >>= 10;\r
665 if ( Average < RANGE_SWITCH ) {\r
666 Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",\r
667 Delta,\r
668 (UINT32) Average );\r
669 }\r
670 else {\r
671 Average >>= 10;\r
672 if ( Average < RANGE_SWITCH ) {\r
673 Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",\r
674 Delta,\r
675 (UINT32) Average );\r
676 }\r
677 else {\r
678 Average >>= 10;\r
679 if ( Average < RANGE_SWITCH ) {\r
680 Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",\r
681 Delta,\r
682 Average );\r
683 }\r
684 else {\r
685 Average >>= 10;\r
686 Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",\r
687 Delta,\r
688 (UINT32) Average );\r
689 }\r
690 }\r
691 }\r
692 }\r
693 }\r
694 }\r
695 }\r
696}\r
697\r
698\r
699/**\r
700 Create the timer\r
701\r
702 @retval EFI_SUCCESS The timer was successfully created\r
703 @retval Other Timer initialization failed\r
704**/\r
705EFI_STATUS\r
706TimerCreate (\r
707 )\r
708{\r
709 EFI_STATUS Status;\r
710\r
711 //\r
712 // Create the timer\r
713 //\r
714 Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
715 TPL_DATASINK,\r
716 TimerCallback,\r
717 NULL,\r
718 &pTimer );\r
719 if ( EFI_ERROR ( Status )) {\r
720 DEBUG (( DEBUG_ERROR,\r
721 "ERROR - Failed to allocate the timer event, Status: %r\r\n",\r
722 Status ));\r
723 }\r
724 else {\r
725 DEBUG (( DEBUG_INFO,\r
726 "0x%08x: Timer created\r\n",\r
727 pTimer ));\r
728 }\r
729\r
730 //\r
731 // Return the operation status\r
732 //\r
733 return Status;\r
734}\r
735\r
736\r
737/**\r
738 Stop the timer\r
739\r
740 @retval EFI_SUCCESS The timer was stopped successfully\r
741 @retval Other The timer failed to stop\r
742**/\r
743EFI_STATUS\r
744TimerStop (\r
745 )\r
746{\r
747 EFI_STATUS Status;\r
748\r
749 //\r
750 // Assume success\r
751 //\r
752 Status = EFI_SUCCESS;\r
753\r
754 //\r
755 // Determine if the timer is running\r
756 //\r
757 if ( bTimerRunning ) {\r
758 //\r
759 // Stop the timer\r
760 //\r
761 Status = gBS->SetTimer ( pTimer,\r
762 TimerCancel,\r
763 0 );\r
764 if ( EFI_ERROR ( Status )) {\r
765 DEBUG (( DEBUG_ERROR,\r
766 "ERROR - Failed to stop the timer, Status: %r\r\n",\r
767 Status ));\r
768 }\r
769 else {\r
770 //\r
771 // Timer timer is now stopped\r
772 //\r
773 bTimerRunning = FALSE;\r
774 DEBUG (( DEBUG_INFO,\r
775 "0x%08x: Timer stopped\r\n",\r
776 pTimer ));\r
777 }\r
778 }\r
779\r
780 //\r
781 // Return the operation status\r
782 //\r
783 return Status;\r
784}\r
785\r
786\r
787/**\r
788 Start the timer\r
789\r
790 @param [in] Milliseconds The number of milliseconds between timer callbacks\r
791\r
792 @retval EFI_SUCCESS The timer was successfully created\r
793 @retval Other Timer initialization failed\r
794**/\r
795EFI_STATUS\r
796TimerStart (\r
797 UINTN Milliseconds\r
798 )\r
799{\r
800 EFI_STATUS Status;\r
801 UINT64 TimeDelay;\r
802\r
803 //\r
804 // Stop the timer if necessary\r
805 //\r
806 Status = EFI_SUCCESS;\r
807 if ( bTimerRunning ) {\r
808 Status = TimerStop ( );\r
809 }\r
810 if ( !EFI_ERROR ( Status )) {\r
811 //\r
812 // Compute the new delay\r
813 //\r
814 TimeDelay = Milliseconds;\r
815 TimeDelay *= 1000 * 10;\r
816\r
817 //\r
818 // Start the timer\r
819 //\r
820 Status = gBS->SetTimer ( pTimer,\r
821 TimerPeriodic,\r
822 TimeDelay );\r
823 if ( EFI_ERROR ( Status )) {\r
824 DEBUG (( DEBUG_ERROR,\r
825 "ERROR - Failed to start the timer, Status: %r\r\n",\r
826 Status ));\r
827 }\r
828 else {\r
829 //\r
830 // The timer is now running\r
831 //\r
832 bTimerRunning = TRUE;\r
833 DEBUG (( DEBUG_INFO,\r
834 "0x%08x: Timer running\r\n",\r
835 pTimer ));\r
836 }\r
837 }\r
838\r
839 //\r
840 // Return the operation status\r
841 //\r
842 return Status;\r
843}\r
844\r
845\r
846/**\r
847 Destroy the timer\r
848\r
849 @retval EFI_SUCCESS The timer was destroyed successfully\r
850 @retval Other Failed to destroy the timer\r
851**/\r
852EFI_STATUS\r
853TimerDestroy (\r
854 )\r
855{\r
856 EFI_STATUS Status;\r
857\r
858 //\r
859 // Assume success\r
860 //\r
861 Status = EFI_SUCCESS;\r
862\r
863 //\r
864 // Determine if the timer is running\r
865 //\r
866 if ( bTimerRunning ) {\r
867 //\r
868 // Stop the timer\r
869 //\r
870 Status = TimerStop ( );\r
871 }\r
872 if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {\r
873 //\r
874 // Done with this timer\r
875 //\r
876 Status = gBS->CloseEvent ( pTimer );\r
877 if ( EFI_ERROR ( Status )) {\r
878 DEBUG (( DEBUG_ERROR,\r
879 "ERROR - Failed to free the timer event, Status: %r\r\n",\r
880 Status ));\r
881 }\r
882 else {\r
883 DEBUG (( DEBUG_INFO,\r
884 "0x%08x: Timer Destroyed\r\n",\r
885 pTimer ));\r
886 pTimer = NULL;\r
887 }\r
888 }\r
889\r
890 //\r
891 // Return the operation status\r
892 //\r
893 return Status;\r
894}\r
895\r
896\r
897/**\r
898 Receive data from the DataSource program to test a network's bandwidth.\r
899\r
900 @param [in] Argc The number of arguments\r
901 @param [in] Argv The argument value array\r
902\r
903 @retval 0 The application exited normally.\r
904 @retval Other An error occurred.\r
905**/\r
906int\r
907main (\r
908 IN int Argc,\r
909 IN char **Argv\r
910 )\r
911{\r
912 EFI_STATUS Status;\r
913\r
914 DEBUG (( DEBUG_INFO,\r
915 "DataSink starting\r\n" ));\r
916\r
917 //\r
918 // Use for/break instead of goto\r
919 //\r
59bc0593 920 for ( ; ; ) {\r
4684b66f 921 //\r
922 // Create the timer\r
923 //\r
924 bTick = TRUE;\r
925 Status = TimerCreate ( );\r
926 if ( EFI_ERROR ( Status )) {\r
927 break;\r
928 }\r
929\r
930 //\r
931 // Start a timer to perform network polling and display updates\r
932 //\r
933 Status = TimerStart ( 1 * 1000 );\r
934 if ( EFI_ERROR ( Status )) {\r
935 break;\r
936 }\r
937\r
938 //\r
939 // Loop forever waiting for abuse\r
940 //\r
941 do {\r
942 ListenSocket = -1;\r
943 do {\r
944 //\r
945 // Complete any client operations\r
946 //\r
947 Status = SocketPoll ( );\r
948 if ( EFI_ERROR ( Status )) {\r
949 //\r
950 // Control-C\r
951 //\r
952 break;\r
953 }\r
954 \r
955 //\r
956 // Wait for a while\r
957 //\r
958 } while ( !bTick );\r
959 if ( EFI_ERROR ( Status )) {\r
960 //\r
961 // Control-C\r
962 //\r
963 break;\r
964 }\r
965 \r
966 //\r
967 // Wait for the network layer to initialize\r
968 //\r
969 Status = SocketNew ( );\r
970 if ( EFI_ERROR ( Status )) {\r
971 continue;\r
972 }\r
973\r
974 //\r
975 // Wait for the remote network application to start\r
976 //\r
977 Status = SocketAccept ( );\r
978 if ( EFI_NOT_STARTED == Status ) {\r
979 Status = SocketClose ( );\r
980 continue;\r
981 }\r
982 else if ( EFI_SUCCESS != Status ) {\r
983 //\r
984 // Control-C\r
985 //\r
986 break;\r
987 }\r
988\r
989 //\r
990 // Send data until the connection breaks\r
991 //\r
992 do {\r
993 Status = SocketPoll ( );\r
994 } while ( !EFI_ERROR ( Status ));\r
995\r
996 //\r
997 // Done with the socket\r
998 //\r
999 Status = SocketClose ( );\r
1000 } while ( !EFI_ERROR ( Status ));\r
1001\r
1002 //\r
1003 // Close the socket if necessary\r
1004 //\r
1005 SocketClose ( );\r
1006\r
1007 //\r
1008 // All done\r
1009 //\r
1010 break;\r
1011 }\r
1012\r
1013 //\r
1014 // Stop the timer if necessary\r
1015 //\r
1016 TimerStop ( );\r
1017 TimerDestroy ( );\r
1018\r
1019 //\r
1020 // Return the operation status\r
1021 //\r
1022 DEBUG (( DEBUG_INFO,\r
1023 "DataSink exiting, Status: %r\r\n",\r
1024 Status ));\r
1025 return Status;\r
1026}\r