]>
Commit | Line | Data |
---|---|---|
9f7f5161 | 1 | /** |
2 | @file | |
3 | Web server application | |
4684b66f | 4 | |
9f7f5161 | 5 | Copyright (c) 2011-2012, Intel Corporation |
6 | All rights reserved. This program and the accompanying materials | |
7 | are licensed and made available under the terms and conditions of the BSD License | |
8 | which accompanies this distribution. The full text of the license may be found at | |
9 | http://opensource.org/licenses/bsd-license.php | |
4684b66f | 10 | |
9f7f5161 | 11 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
12 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
4684b66f | 13 | |
14 | **/ | |
15 | ||
16 | #include <WebServer.h> | |
17 | ||
18 | DT_WEB_SERVER mWebServer; ///< Web server's control structure | |
19 | ||
20 | ||
21 | /** | |
22 | Add a port to the list of ports to be polled. | |
23 | ||
24 | @param [in] pWebServer The web server control structure address. | |
25 | ||
26 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
27 | ||
28 | @retval EFI_SUCCESS The port was successfully added | |
29 | @retval EFI_NO_RESOURCES Insufficient memory to add the port | |
30 | ||
31 | **/ | |
32 | EFI_STATUS | |
33 | PortAdd ( | |
34 | IN DT_WEB_SERVER * pWebServer, | |
35 | IN int SocketFD | |
36 | ) | |
37 | { | |
38 | nfds_t Index; | |
39 | size_t LengthInBytes; | |
40 | nfds_t MaxEntries; | |
41 | nfds_t MaxEntriesNew; | |
42 | struct pollfd * pFdList; | |
43 | struct pollfd * pFdListNew; | |
44 | WSDT_PORT ** ppPortListNew; | |
45 | WSDT_PORT * pPort; | |
46 | EFI_STATUS Status; | |
47 | ||
48 | DBG_ENTER ( ); | |
49 | ||
50 | // | |
51 | // Use for/break instead of goto | |
52 | // | |
53 | for ( ; ; ) { | |
54 | // | |
55 | // Assume success | |
56 | // | |
57 | Status = EFI_SUCCESS; | |
58 | ||
59 | // | |
60 | // Create a new list if necessary | |
61 | // | |
62 | pFdList = pWebServer->pFdList; | |
63 | MaxEntries = pWebServer->MaxEntries; | |
64 | if ( pWebServer->Entries >= MaxEntries ) { | |
65 | MaxEntriesNew = 16 + MaxEntries; | |
66 | ||
67 | // | |
68 | // The current FD list is full | |
69 | // Allocate a new FD list | |
70 | // | |
71 | LengthInBytes = sizeof ( *pFdList ) * MaxEntriesNew; | |
72 | Status = gBS->AllocatePool ( EfiRuntimeServicesData, | |
73 | LengthInBytes, | |
74 | (VOID **)&pFdListNew ); | |
75 | if ( EFI_ERROR ( Status )) { | |
76 | DEBUG (( DEBUG_ERROR | DEBUG_POOL, | |
77 | "ERROR - Failed to allocate the FD list, Status: %r\r\n", | |
78 | Status )); | |
79 | break; | |
80 | } | |
81 | ||
82 | // | |
83 | // Allocate a new port list | |
84 | // | |
85 | LengthInBytes = sizeof ( *ppPortListNew ) * MaxEntriesNew; | |
86 | Status = gBS->AllocatePool ( EfiRuntimeServicesData, | |
87 | LengthInBytes, | |
88 | (VOID **) &ppPortListNew ); | |
89 | if ( EFI_ERROR ( Status )) { | |
90 | DEBUG (( DEBUG_ERROR | DEBUG_POOL, | |
91 | "ERROR - Failed to allocate the port list, Status: %r\r\n", | |
92 | Status )); | |
93 | ||
94 | // | |
95 | // Free the new FD list | |
96 | // | |
97 | gBS->FreePool ( pFdListNew ); | |
98 | break; | |
99 | } | |
100 | ||
101 | // | |
102 | // Duplicate the FD list | |
103 | // | |
104 | Index = MaxEntries; | |
105 | if ( NULL != pFdList ) { | |
106 | CopyMem ( pFdListNew, | |
107 | pFdList, | |
108 | Index * sizeof ( *pFdList )); | |
109 | } | |
110 | ||
111 | // | |
112 | // Initialize the new entries in the FD list | |
113 | // | |
114 | for ( ; MaxEntriesNew > Index; Index++ ) { | |
59bc0593 | 115 | pFdListNew[ Index ].fd = -1; |
116 | pFdListNew[ Index ].events = 0; | |
117 | pFdListNew[ Index ].revents = 0; | |
4684b66f | 118 | } |
119 | ||
120 | // | |
121 | // Free the old FD list | |
122 | // | |
123 | if ( NULL != pFdList ) { | |
124 | gBS->FreePool ( pFdList ); | |
125 | } | |
126 | ||
127 | // | |
128 | // Switch to the new FD list | |
129 | // | |
130 | pWebServer->pFdList = pFdListNew; | |
131 | pFdList = pWebServer->pFdList; | |
132 | ||
133 | // | |
134 | // Duplicate the port list | |
135 | // | |
136 | Index = MaxEntries; | |
137 | if ( NULL != pWebServer->ppPortList ) { | |
138 | CopyMem ( ppPortListNew, | |
139 | pWebServer->ppPortList, | |
140 | Index * sizeof ( *ppPortListNew )); | |
141 | } | |
142 | ||
143 | // | |
144 | // Initialize the new entries in the port list | |
145 | // | |
146 | for ( ; MaxEntriesNew > Index; Index++ ) { | |
59bc0593 | 147 | ppPortListNew[ Index ] = NULL; |
4684b66f | 148 | } |
149 | ||
150 | // | |
151 | // Free the old port list | |
152 | // | |
153 | if ( NULL != pWebServer->ppPortList ) { | |
154 | gBS->FreePool ( pWebServer->ppPortList ); | |
155 | } | |
156 | ||
157 | // | |
158 | // Switch to the new port list | |
159 | // | |
160 | pWebServer->ppPortList = ppPortListNew; | |
161 | ||
162 | // | |
163 | // Update the list size | |
164 | // | |
165 | pWebServer->MaxEntries = MaxEntriesNew; | |
166 | } | |
167 | ||
168 | // | |
169 | // Allocate a new port | |
170 | // | |
171 | LengthInBytes = sizeof ( *pPort ); | |
172 | Status = gBS->AllocatePool ( EfiRuntimeServicesData, | |
173 | LengthInBytes, | |
174 | (VOID **)&pPort ); | |
175 | if ( EFI_ERROR ( Status )) { | |
176 | DEBUG (( DEBUG_ERROR | DEBUG_POOL, | |
177 | "ERROR - Failed to allocate the port, Status: %r\r\n", | |
178 | Status )); | |
179 | break; | |
180 | } | |
181 | ||
182 | // | |
183 | // Initialize the port | |
184 | // | |
185 | pPort->RequestLength = 0; | |
186 | pPort->TxBytes = 0; | |
187 | ||
188 | // | |
189 | // Add the socket to the FD list | |
190 | // | |
59bc0593 | 191 | pFdList[ pWebServer->Entries ].fd = SocketFD; |
192 | pFdList[ pWebServer->Entries ].events = POLLRDNORM | |
4684b66f | 193 | | POLLHUP; |
59bc0593 | 194 | pFdList[ pWebServer->Entries ].revents = 0; |
4684b66f | 195 | |
196 | // | |
197 | // Add the port to the port list | |
198 | // | |
59bc0593 | 199 | pWebServer->ppPortList[ pWebServer->Entries ] = pPort; |
4684b66f | 200 | |
201 | // | |
202 | // Account for the new entry | |
203 | // | |
204 | pWebServer->Entries += 1; | |
205 | DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, | |
206 | "WebServer handling %d ports\r\n", | |
207 | pWebServer->Entries )); | |
208 | ||
209 | // | |
210 | // All done | |
211 | // | |
212 | break; | |
213 | } | |
214 | ||
215 | // | |
216 | // Return the operation status | |
217 | // | |
218 | DBG_EXIT_STATUS ( Status ); | |
219 | return Status; | |
220 | } | |
221 | ||
222 | ||
223 | /** | |
224 | Remove a port from the list of ports to be polled. | |
225 | ||
226 | @param [in] pWebServer The web server control structure address. | |
227 | ||
228 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
229 | ||
230 | **/ | |
231 | VOID | |
232 | PortRemove ( | |
233 | IN DT_WEB_SERVER * pWebServer, | |
234 | IN int SocketFD | |
235 | ) | |
236 | { | |
237 | nfds_t Entries; | |
238 | nfds_t Index; | |
239 | struct pollfd * pFdList; | |
240 | WSDT_PORT ** ppPortList; | |
241 | ||
242 | DBG_ENTER ( ); | |
243 | ||
244 | // | |
245 | // Attempt to remove the entry from the list | |
246 | // | |
247 | Entries = pWebServer->Entries; | |
248 | pFdList = pWebServer->pFdList; | |
249 | ppPortList = pWebServer->ppPortList; | |
250 | for ( Index = 0; Entries > Index; Index++ ) { | |
251 | // | |
252 | // Locate the specified socket file descriptor | |
253 | // | |
59bc0593 | 254 | if ( SocketFD == pFdList[ Index ].fd ) { |
4684b66f | 255 | // |
256 | // Determine if this is the listen port | |
257 | // | |
258 | if ( SocketFD == pWebServer->HttpListenPort ) { | |
259 | pWebServer->HttpListenPort = -1; | |
260 | } | |
261 | ||
262 | // | |
263 | // Close the socket | |
264 | // | |
265 | close ( SocketFD ); | |
266 | ||
267 | // | |
268 | // Free the port structure | |
269 | // | |
59bc0593 | 270 | gBS->FreePool ( ppPortList[ Index ]); |
4684b66f | 271 | |
272 | // | |
273 | // Remove this port from the list by copying | |
274 | // the rest of the list down one entry | |
275 | // | |
276 | Entries -= 1; | |
277 | for ( ; Entries > Index; Index++ ) { | |
59bc0593 | 278 | pFdList[ Index ] = pFdList[ Index + 1 ]; |
279 | ppPortList[ Index ] = ppPortList[ Index + 1 ]; | |
4684b66f | 280 | } |
59bc0593 | 281 | pFdList[ Index ].fd = -1; |
282 | pFdList[ Index ].events = 0; | |
283 | pFdList[ Index ].revents = 0; | |
284 | ppPortList[ Index ] = NULL; | |
4684b66f | 285 | |
286 | // | |
287 | // Update the number of entries in the list | |
288 | // | |
289 | pWebServer->Entries = Entries; | |
290 | DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, | |
291 | "WebServer handling %d ports\r\n", | |
292 | pWebServer->Entries )); | |
293 | break; | |
294 | } | |
295 | } | |
296 | ||
297 | DBG_EXIT ( ); | |
298 | } | |
299 | ||
300 | ||
301 | /** | |
302 | Process the work for the sockets. | |
303 | ||
304 | @param [in] pWebServer The web server control structure address. | |
305 | ||
306 | @param [in] SocketFD The socket's file descriptor to add to the list. | |
307 | ||
308 | @param [in] events everts is a bitmask of the work to be done | |
309 | ||
310 | @param [in] pPort The address of a WSDT_PORT structure | |
311 | ||
312 | @retval EFI_SUCCESS The operation was successful | |
313 | @retval EFI_DEVICE_ERROR Error, close the port | |
314 | ||
315 | **/ | |
316 | EFI_STATUS | |
317 | PortWork ( | |
318 | IN DT_WEB_SERVER * pWebServer, | |
319 | IN int SocketFD, | |
320 | IN INTN events, | |
321 | IN WSDT_PORT * pPort | |
322 | ) | |
323 | { | |
324 | BOOLEAN bDone; | |
325 | size_t LengthInBytes; | |
326 | int NewSocket; | |
327 | EFI_STATUS OpStatus; | |
f6e5cdd5 | 328 | struct sockaddr_in6 RemoteAddress; |
4684b66f | 329 | socklen_t RemoteAddressLength; |
330 | EFI_STATUS Status; | |
331 | ||
332 | DEBUG (( DEBUG_PORT_WORK, "Entering PortWork\r\n" )); | |
333 | ||
334 | // | |
335 | // Assume success | |
336 | // | |
337 | OpStatus = EFI_SUCCESS; | |
338 | ||
339 | // | |
340 | // Handle input events | |
341 | // | |
342 | if ( 0 != ( events & POLLRDNORM )) { | |
343 | // | |
344 | // Determine if this is a connection attempt | |
345 | // | |
f6e5cdd5 | 346 | if (( SocketFD == pWebServer->HttpListenPort ) |
347 | || ( SocketFD == pWebServer->HttpListenPort6 )) { | |
4684b66f | 348 | // |
349 | // Handle connection attempts | |
350 | // Accepts arrive as read events | |
351 | // | |
352 | RemoteAddressLength = sizeof ( RemoteAddress ); | |
353 | NewSocket = accept ( SocketFD, | |
f6e5cdd5 | 354 | (struct sockaddr *)&RemoteAddress, |
4684b66f | 355 | &RemoteAddressLength ); |
356 | if ( -1 != NewSocket ) { | |
357 | if ( 0 != NewSocket ) { | |
358 | // | |
359 | // Add this port to the list monitored by the web server | |
360 | // | |
361 | Status = PortAdd ( pWebServer, NewSocket ); | |
362 | if ( EFI_ERROR ( Status )) { | |
363 | DEBUG (( DEBUG_ERROR, | |
364 | "ERROR - Failed to add the port 0x%08x, Status: %r\r\n", | |
365 | NewSocket, | |
366 | Status )); | |
367 | ||
368 | // | |
369 | // Done with the new socket | |
370 | // | |
371 | close ( NewSocket ); | |
372 | } | |
373 | } | |
374 | else { | |
375 | DEBUG (( DEBUG_ERROR, | |
376 | "ERROR - Socket not available!\r\n" )); | |
377 | } | |
378 | ||
379 | // | |
380 | // Leave the listen port open | |
381 | // | |
382 | } | |
383 | else { | |
384 | // | |
385 | // Listen port error | |
386 | // Close the listen port by returning error status | |
387 | // | |
388 | OpStatus = EFI_DEVICE_ERROR; | |
389 | DEBUG (( DEBUG_ERROR, | |
390 | "ERROR - Failed to accept new connection, errno: 0x%08x\r\n", | |
391 | errno )); | |
392 | } | |
393 | } | |
394 | else { | |
395 | // | |
396 | // Handle the data received event | |
397 | // | |
398 | if ( 0 == pPort->RequestLength ) { | |
399 | // | |
400 | // Receive the page request | |
401 | // | |
402 | pPort->RequestLength = recv ( SocketFD, | |
403 | &pPort->Request[0], | |
404 | DIM ( pPort->Request ), | |
405 | 0 ); | |
406 | if ( -1 == pPort->RequestLength ) { | |
407 | // | |
408 | // Receive error detected | |
409 | // Close the port | |
410 | // | |
411 | OpStatus = EFI_DEVICE_ERROR; | |
412 | } | |
413 | else { | |
414 | DEBUG (( DEBUG_REQUEST, | |
415 | "0x%08x: Socket - Received %d bytes of HTTP request\r\n", | |
416 | SocketFD, | |
417 | pPort->RequestLength )); | |
418 | ||
419 | // | |
420 | // Process the request | |
421 | // | |
422 | OpStatus = HttpRequest ( SocketFD, pPort, &bDone ); | |
423 | if ( bDone ) { | |
424 | // | |
425 | // Notify the upper layer to close the socket | |
426 | // | |
427 | OpStatus = EFI_DEVICE_ERROR; | |
428 | } | |
429 | } | |
430 | } | |
59bc0593 | 431 | else { |
4684b66f | 432 | // |
433 | // Receive the file data | |
434 | // | |
435 | LengthInBytes = recv ( SocketFD, | |
436 | &pPort->RxBuffer[0], | |
437 | DIM ( pPort->RxBuffer ), | |
438 | 0 ); | |
439 | if ( -1 == LengthInBytes ) { | |
440 | // | |
441 | // Receive error detected | |
442 | // Close the port | |
443 | // | |
444 | OpStatus = EFI_DEVICE_ERROR; | |
445 | } | |
446 | else { | |
447 | DEBUG (( DEBUG_REQUEST, | |
448 | "0x%08x: Socket - Received %d bytes of file data\r\n", | |
449 | SocketFD, | |
450 | LengthInBytes )); | |
451 | ||
452 | // | |
453 | // TODO: Process the file data | |
454 | // | |
455 | } | |
456 | } | |
457 | } | |
458 | } | |
459 | ||
460 | // | |
461 | // Handle the close event | |
462 | // | |
463 | if ( 0 != ( events & POLLHUP )) { | |
464 | // | |
465 | // Close the port | |
466 | // | |
467 | OpStatus = EFI_DEVICE_ERROR; | |
468 | } | |
469 | ||
470 | // | |
471 | // Return the operation status | |
472 | // | |
473 | DEBUG (( DEBUG_PORT_WORK, | |
474 | "Exiting PortWork, Status: %r\r\n", | |
475 | OpStatus )); | |
476 | return OpStatus; | |
477 | } | |
478 | ||
479 | ||
480 | /** | |
481 | Scan the list of sockets and process any pending work | |
482 | ||
483 | @param [in] pWebServer The web server control structure address. | |
484 | ||
485 | **/ | |
486 | VOID | |
487 | SocketPoll ( | |
488 | IN DT_WEB_SERVER * pWebServer | |
489 | ) | |
490 | { | |
491 | int FDCount; | |
492 | struct pollfd * pPoll; | |
493 | WSDT_PORT ** ppPort; | |
494 | EFI_STATUS Status; | |
495 | ||
496 | DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" )); | |
497 | ||
498 | // | |
499 | // Determine if any ports are active | |
500 | // | |
501 | FDCount = poll ( pWebServer->pFdList, | |
502 | pWebServer->Entries, | |
503 | CLIENT_POLL_DELAY ); | |
504 | if ( -1 == FDCount ) { | |
505 | DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL, | |
506 | "ERROR - errno: %d\r\n", | |
507 | errno )); | |
508 | } | |
509 | ||
510 | pPoll = pWebServer->pFdList; | |
511 | ppPort = pWebServer->ppPortList; | |
512 | while ( 0 < FDCount ) { | |
513 | // | |
514 | // Walk the list of ports to determine what work needs to be done | |
515 | // | |
516 | if ( 0 != pPoll->revents ) { | |
517 | // | |
518 | // Process this port | |
519 | // | |
520 | Status = PortWork ( pWebServer, | |
521 | pPoll->fd, | |
522 | pPoll->revents, | |
523 | *ppPort ); | |
524 | pPoll->revents = 0; | |
525 | ||
526 | // | |
527 | // Close the port if necessary | |
528 | // | |
529 | if ( EFI_ERROR ( Status )) { | |
530 | PortRemove ( pWebServer, pPoll->fd ); | |
531 | pPoll -= 1; | |
532 | ppPort -= 1; | |
533 | } | |
534 | ||
535 | // | |
536 | // Account for this file descriptor | |
537 | // | |
538 | FDCount -= 1; | |
539 | } | |
540 | ||
541 | // | |
542 | // Set the next port | |
543 | // | |
544 | pPoll += 1; | |
545 | ppPort += 1; | |
546 | } | |
547 | ||
548 | DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" )); | |
549 | } | |
550 | ||
551 | ||
552 | /** | |
f6e5cdd5 | 553 | Create an HTTP port for the web server |
4684b66f | 554 | |
f6e5cdd5 | 555 | This routine polls the network layer to create an HTTP port for the |
4684b66f | 556 | web server. More than one attempt may be necessary since it may take |
557 | some time to get the IP address and initialize the upper layers of | |
558 | the network stack. | |
559 | ||
560 | After the HTTP port is created, the socket layer will manage the | |
561 | coming and going of the network connections until the last network | |
562 | connection is broken. | |
563 | ||
f6e5cdd5 | 564 | @param [in] pWebServer The web server control structure address. |
565 | @param [in] AddressFamily Address family for the network connection | |
566 | @param [in] Protocol Protocol to use for the network connection | |
567 | @param [in] HttpPort Port number for the HTTP connection | |
568 | @param [out] pPort Address of the port | |
4684b66f | 569 | |
570 | **/ | |
571 | VOID | |
f6e5cdd5 | 572 | WebServerListen ( |
573 | IN DT_WEB_SERVER * pWebServer, | |
574 | IN sa_family_t AddressFamily, | |
575 | IN int Protocol, | |
576 | IN UINT16 HttpPort, | |
577 | OUT int * pPort | |
4684b66f | 578 | ) |
579 | { | |
f6e5cdd5 | 580 | union { |
581 | struct sockaddr_in v4; | |
582 | struct sockaddr_in6 v6; | |
583 | } WebServerAddress; | |
4684b66f | 584 | int SocketStatus; |
585 | EFI_STATUS Status; | |
586 | ||
f6e5cdd5 | 587 | DEBUG (( DEBUG_SERVER_LISTEN, "Entering WebServerListen\r\n" )); |
4684b66f | 588 | |
589 | // | |
f6e5cdd5 | 590 | // Attempt to create the socket for the web server |
4684b66f | 591 | // |
f6e5cdd5 | 592 | * pPort = socket ( AddressFamily, SOCK_STREAM, Protocol ); |
593 | if ( -1 != *pPort ) { | |
4684b66f | 594 | // |
f6e5cdd5 | 595 | // Build the socket address |
4684b66f | 596 | // |
f6e5cdd5 | 597 | ZeroMem ( &WebServerAddress, sizeof ( WebServerAddress )); |
598 | if ( AF_INET == AddressFamily ) { | |
599 | WebServerAddress.v4.sin_len = sizeof ( WebServerAddress.v4 ); | |
600 | WebServerAddress.v4.sin_family = AddressFamily; | |
601 | WebServerAddress.v4.sin_port = htons ( HttpPort ); | |
602 | } | |
603 | else { | |
604 | WebServerAddress.v6.sin6_len = sizeof ( WebServerAddress.v6 ); | |
605 | WebServerAddress.v6.sin6_family = AddressFamily; | |
606 | WebServerAddress.v6.sin6_port = htons ( HttpPort ); | |
607 | WebServerAddress.v6.sin6_scope_id = __IPV6_ADDR_SCOPE_GLOBAL; | |
608 | } | |
4684b66f | 609 | |
f6e5cdd5 | 610 | // |
611 | // Bind the socket to the HTTP port | |
612 | // | |
613 | SocketStatus = bind ( *pPort, | |
614 | (struct sockaddr *) &WebServerAddress, | |
615 | WebServerAddress.v4.sin_len ); | |
616 | if ( -1 != SocketStatus ) { | |
4684b66f | 617 | // |
f6e5cdd5 | 618 | // Enable connections to the HTTP port |
4684b66f | 619 | // |
f6e5cdd5 | 620 | SocketStatus = listen ( *pPort, SOMAXCONN ); |
4684b66f | 621 | if ( -1 != SocketStatus ) { |
622 | // | |
f6e5cdd5 | 623 | // Add the HTTP port to the list of ports to poll |
4684b66f | 624 | // |
f6e5cdd5 | 625 | Status = PortAdd ( pWebServer, *pPort ); |
626 | if ( EFI_ERROR ( Status )) { | |
627 | SocketStatus = -1; | |
628 | } | |
629 | else { | |
630 | DEBUG (( DEBUG_PORT_WORK, | |
631 | "Listening on Tcp%d:%d\r\n", | |
632 | ( AF_INET == AddressFamily ) ? 4 : 6, | |
633 | HttpPort )); | |
634 | } | |
4684b66f | 635 | } |
636 | } | |
637 | ||
638 | // | |
f6e5cdd5 | 639 | // Release the socket if necessary |
4684b66f | 640 | // |
f6e5cdd5 | 641 | if ( -1 == SocketStatus ) { |
642 | close ( *pPort ); | |
643 | *pPort = -1; | |
4684b66f | 644 | } |
645 | } | |
646 | ||
f6e5cdd5 | 647 | DEBUG (( DEBUG_SERVER_LISTEN, "Exiting WebServerListen\r\n" )); |
4684b66f | 648 | } |
649 | ||
650 | ||
4684b66f | 651 | /** |
652 | Entry point for the web server application. | |
653 | ||
654 | @param [in] Argc The number of arguments | |
655 | @param [in] Argv The argument value array | |
656 | ||
657 | @retval 0 The application exited normally. | |
658 | @retval Other An error occurred. | |
659 | **/ | |
660 | int | |
661 | main ( | |
662 | IN int Argc, | |
663 | IN char **Argv | |
664 | ) | |
665 | { | |
f6e5cdd5 | 666 | UINT16 HttpPort; |
667 | UINTN Index; | |
4684b66f | 668 | DT_WEB_SERVER * pWebServer; |
669 | EFI_STATUS Status; | |
f6e5cdd5 | 670 | UINT64 TriggerTime; |
671 | ||
672 | // | |
673 | // Get the HTTP port | |
674 | // | |
675 | HttpPort = PcdGet16 ( WebServer_HttpPort ); | |
676 | DEBUG (( DEBUG_HTTP_PORT, | |
677 | "HTTP Port: %d\r\n", | |
678 | HttpPort )); | |
4684b66f | 679 | |
680 | // | |
681 | // Create a timer event to start HTTP port | |
682 | // | |
683 | pWebServer = &mWebServer; | |
684 | Status = gBS->CreateEvent ( EVT_TIMER, | |
685 | TPL_WEB_SERVER, | |
686 | NULL, | |
687 | NULL, | |
688 | &pWebServer->TimerEvent ); | |
689 | if ( !EFI_ERROR ( Status )) { | |
f6e5cdd5 | 690 | TriggerTime = HTTP_PORT_POLL_DELAY * ( 1000 * 10 ); |
691 | Status = gBS->SetTimer ( pWebServer->TimerEvent, | |
692 | TimerPeriodic, | |
693 | TriggerTime ); | |
4684b66f | 694 | if ( !EFI_ERROR ( Status )) { |
695 | // | |
696 | // Run the web server forever | |
697 | // | |
f6e5cdd5 | 698 | pWebServer->HttpListenPort = -1; |
699 | pWebServer->HttpListenPort6 = -1; | |
700 | pWebServer->bRunning = TRUE; | |
701 | do { | |
4684b66f | 702 | // |
703 | // Poll the network layer to create the HTTP port | |
704 | // for the web server. More than one attempt may | |
705 | // be necessary since it may take some time to get | |
706 | // the IP address and initialize the upper layers | |
707 | // of the network stack. | |
708 | // | |
f6e5cdd5 | 709 | if (( -1 == pWebServer->HttpListenPort ) |
710 | || ( -1 == pWebServer->HttpListenPort6 )) { | |
4684b66f | 711 | do { |
f6e5cdd5 | 712 | // |
713 | // Wait a while before polling for a connection | |
714 | // | |
715 | if ( EFI_SUCCESS != gBS->CheckEvent ( pWebServer->TimerEvent )) { | |
716 | if ( 0 != pWebServer->Entries ) { | |
717 | break; | |
718 | } | |
719 | gBS->WaitForEvent ( 1, &pWebServer->TimerEvent, &Index ); | |
720 | } | |
4684b66f | 721 | |
f6e5cdd5 | 722 | // |
723 | // Poll for a network connection | |
724 | // | |
725 | if ( -1 == pWebServer->HttpListenPort ) { | |
726 | WebServerListen ( pWebServer, | |
727 | AF_INET, | |
728 | IPPROTO_TCP, | |
729 | HttpPort, | |
730 | &pWebServer->HttpListenPort ); | |
731 | } | |
732 | if ( -1 == pWebServer->HttpListenPort6 ) { | |
733 | WebServerListen ( pWebServer, | |
734 | AF_INET6, | |
735 | IPPROTO_TCP, | |
736 | HttpPort, | |
737 | &pWebServer->HttpListenPort6 ); | |
738 | } | |
739 | ||
740 | // | |
741 | // Continue polling while both network connections are | |
742 | // not present | |
743 | // | |
744 | } while ( 0 == pWebServer->Entries ); | |
4684b66f | 745 | } |
746 | ||
747 | // | |
f6e5cdd5 | 748 | // Poll the sockets for activity while both network |
749 | // connections are connected | |
4684b66f | 750 | // |
f6e5cdd5 | 751 | do { |
752 | SocketPoll ( pWebServer ); | |
753 | } while ( pWebServer->bRunning | |
754 | && ( -1 != pWebServer->HttpListenPort ) | |
755 | && ( -1 != pWebServer->HttpListenPort6 )); | |
756 | ||
757 | // | |
758 | // Continue polling the network connections until both | |
759 | // TCP4 and TCP6 are connected | |
760 | // | |
761 | } while ( pWebServer->bRunning ); | |
4684b66f | 762 | |
763 | // | |
f6e5cdd5 | 764 | // Stop the timer |
4684b66f | 765 | // |
f6e5cdd5 | 766 | gBS->SetTimer ( pWebServer->TimerEvent, |
767 | TimerCancel, | |
768 | 0 ); | |
4684b66f | 769 | } |
f6e5cdd5 | 770 | |
771 | // | |
772 | // Done with the timer event | |
773 | // | |
774 | gBS->CloseEvent ( pWebServer->TimerEvent ); | |
4684b66f | 775 | } |
776 | ||
777 | // | |
778 | // Return the final status | |
779 | // | |
780 | DBG_EXIT_STATUS ( Status ); | |
781 | return Status; | |
782 | } |