Changeset 104205 in vbox for trunk/src/VBox/Main
- Timestamp:
- Apr 5, 2024 5:38:51 PM (10 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/webservice/vboxweb.cpp
r99739 r104205 140 140 static const char *g_pcszBindToHost = NULL; // host; NULL = localhost 141 141 static unsigned int g_uBindToPort = 18083; // port 142 static unsigned int g_uBacklog = 100; // backlog = max queue size for requests142 static unsigned int g_uBacklog = 100; // backlog = max queue size for connections 143 143 144 144 #ifdef WITH_OPENSSL … … 307 307 308 308 case 'k': 309 pcszDescr = "Maximum number of requests before a socketwill be closed (100).";309 pcszDescr = "Maximum number of requests before a connection will be closed (100)."; 310 310 break; 311 311 … … 362 362 * @param u Thread number. (So we can count from 1 and be readable.) 363 363 * @param q SoapQ instance which has the queue to process. 364 * @param soap struct soap instance from main() which we copy here.365 364 */ 366 365 SoapThread(size_t u, 367 SoapQ &q, 368 const struct soap *soap) 366 SoapQ &q) 369 367 : m_u(u), 370 m_strThread(com::Utf8StrFmt("SQW%02d", m_u)),371 368 m_pQ(&q) 372 369 { 373 // make a copy of the soap struct for the new thread 374 m_soap = soap_copy(soap); 375 m_soap->fget = fnHttpGet; 376 377 /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed, 378 * which is important to avoid a client from holding a thread indefinitely. 379 * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive 380 * 381 * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is 382 * possible by enabling the SOAP_C_UTFSTRING flag. 383 */ 384 soap_set_omode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); 385 soap_set_imode(m_soap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); 386 m_soap->max_keep_alive = g_cMaxKeepAlive; 387 370 m_strThread = com::Utf8StrFmt("SQW%02d", m_u); 388 371 int vrc = RTThreadCreate(&m_pThread, 389 372 fntWrapper, … … 432 415 com::Utf8Str m_strThread; // thread name ("SoapQWrkXX") 433 416 SoapQ *m_pQ; // the single SOAP queue that all the threads service 434 struct soap *m_soap; // copy of the soap structure for this thread (from soap_copy())435 417 RTTHREAD m_pThread; // IPRT thread struct for this thread 436 418 }; … … 447 429 /** 448 430 * Constructor. Creates the soap queue. 449 * @param pSoap450 431 */ 451 SoapQ(const struct soap *pSoap) 452 : m_soap(pSoap), 453 m_mutex(util::LOCKCLASS_OBJECTSTATE), // lowest lock order, no other may be held while this is held 432 SoapQ() 433 : m_mutex(util::LOCKCLASS_OBJECTSTATE), // lowest lock order, no other may be held while this is held 454 434 m_cIdleThreads(0) 455 435 { … … 475 455 476 456 RTSemEventMultiDestroy(m_event); 457 458 while (!m_llSocketsQ.empty()) 459 { 460 struct soap *pSoap = m_llSocketsQ.front(); 461 m_llSocketsQ.pop_front(); 462 463 if (pSoap == NULL || !soap_valid_socket(pSoap->socket)) 464 continue; 465 466 soap_destroy(pSoap); // clean up class instances 467 soap_end(pSoap); // clean up everything and close socket 468 soap_free(pSoap); // free soap connection 469 } 477 470 } 478 471 479 472 /** 480 * Adds the given so cketto the SOAP queue and posts the473 * Adds the given soap connection to the SOAP queue and posts the 481 474 * member event sem to wake up the workers. Called on the main thread 482 * whenever a socket has work to do. Creates a new SOAP thread on the475 * whenever a connection comes in. Creates a new SOAP thread on the 483 476 * first call or when all existing threads are busy. 484 * @param s Socket from soap_accept() which has work to do.477 * @param pSoap connection 485 478 */ 486 size_t add( SOAP_SOCKET s)479 size_t add(const struct soap *pSoap) 487 480 { 488 481 size_t cItems; … … 497 490 { 498 491 SoapThread *pst = new SoapThread(m_llAllThreads.size() + 1, 499 *this, 500 m_soap); 492 *this); 501 493 m_llAllThreads.push_back(pst); 502 494 util::AutoWriteLock thrLock(g_pThreadsLockHandle COMMA_LOCKVAL_SRC_POS); … … 505 497 } 506 498 507 // enqueue th e socket of this connection and post eventsem so that508 // one of the threads(possibly the one just created) can pick it up509 m_llSocketsQ.push_back(s );499 // enqueue this connection and post eventsem so that one of the threads 500 // (possibly the one just created) can pick it up 501 m_llSocketsQ.push_back(soap_copy(pSoap)); 510 502 cItems = m_llSocketsQ.size(); 511 503 qlock.release(); … … 519 511 /** 520 512 * Blocks the current thread until work comes in; then returns 521 * the SOAP socketwhich has work to do. This reduces m_cIdleThreads513 * the SOAP connection which has work to do. This reduces m_cIdleThreads 522 514 * by one, and the caller MUST call done() when it's done processing. 523 515 * Called from the worker threads. … … 526 518 * @return 527 519 */ 528 SOAP_SOCKETget(size_t &cIdleThreads, size_t &cThreads)520 struct soap *get(size_t &cIdleThreads, size_t &cThreads) 529 521 { 530 522 while (g_fKeepRunning) … … 539 531 if (!m_llSocketsQ.empty()) 540 532 { 541 SOAP_SOCKET socket= m_llSocketsQ.front();533 struct soap *pSoap = m_llSocketsQ.front(); 542 534 m_llSocketsQ.pop_front(); 543 535 cIdleThreads = --m_cIdleThreads; … … 552 544 qlock.release(); 553 545 554 return socket;546 return pSoap; 555 547 } 556 548 557 549 // nothing to do: keep looping 558 550 } 559 return SOAP_INVALID_SOCKET;551 return NULL; 560 552 } 561 553 … … 572 564 /** 573 565 * To be called by a worker thread when signing off, i.e. no longer 574 * willing to process requests.566 * willing to process SOAP connections. 575 567 */ 576 568 void signoff(SoapThread *th) … … 588 580 } 589 581 590 const struct soap *m_soap; // soap structure created by main(), passed to constructor591 592 582 util::WriteLockHandle m_mutex; 593 583 RTSEMEVENTMULTI m_event; // posted by add(), blocked on by get() … … 597 587 598 588 // A std::list abused as a queue; this contains the actual jobs to do, 599 // each int being a socket from soap_accept()600 std::list< SOAP_SOCKET> m_llSocketsQ;589 // each entry being a connection from soap_accept() passed through SoapQ::add. 590 std::list<struct soap *> m_llSocketsQ; 601 591 }; 602 592 … … 604 594 * Thread function for each of the SOAP queue worker threads. This keeps 605 595 * running, blocks on the event semaphore in SoapThread.SoapQ and picks 606 * up a socketfrom the queue therein, which has been put there by607 * beginProcessing().596 * up a connection from the queue therein, which has been put there by 597 * SoapQ::add(). 608 598 */ 609 599 void SoapThread::process() … … 613 603 while (g_fKeepRunning) 614 604 { 615 // wait for a socketto arrive on the queue605 // wait for a job to arrive on the queue 616 606 size_t cIdleThreads = 0, cThreads = 0; 617 m_soap->socket= m_pQ->get(cIdleThreads, cThreads);618 619 if ( !soap_valid_socket(m_soap->socket))607 struct soap *pSoap = m_pQ->get(cIdleThreads, cThreads); 608 609 if (pSoap == NULL || !soap_valid_socket(pSoap->socket)) 620 610 continue; 621 611 612 pSoap->fget = fnHttpGet; 613 614 /* The soap.max_keep_alive value can be set to the maximum keep-alive calls allowed, 615 * which is important to avoid a client from holding a thread indefinitely. 616 * http://www.cs.fsu.edu/~engelen/soapdoc2.html#sec:keepalive 617 * 618 * Strings with 8-bit content can hold ASCII (default) or UTF8. The latter is 619 * possible by enabling the SOAP_C_UTFSTRING flag. 620 */ 621 soap_set_omode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); 622 soap_set_imode(pSoap, SOAP_IO_KEEPALIVE | SOAP_C_UTFSTRING); 623 pSoap->max_keep_alive = g_cMaxKeepAlive; 624 622 625 LogRel(("Processing connection from IP=%RTnaipv4 socket=%d (%d out of %d threads idle)\n", 623 RT_H2N_U32( m_soap->ip), m_soap->socket, cIdleThreads, cThreads));626 RT_H2N_U32(pSoap->ip), pSoap->socket, cIdleThreads, cThreads)); 624 627 625 628 // Ensure that we don't get stuck indefinitely for connections using 626 629 // keepalive, otherwise stale connections tie up worker threads. 627 m_soap->send_timeout = 60;628 m_soap->recv_timeout = 60;630 pSoap->send_timeout = 60; 631 pSoap->recv_timeout = 60; 629 632 // Limit the maximum SOAP request size to a generous amount, just to 630 633 // be on the safe side (SOAP is quite wordy when representing arrays, 631 634 // and some API uses need to deal with large arrays). Good that binary 632 635 // data is no longer represented by byte arrays... 633 m_soap->recv_maxlength = _16M;636 pSoap->recv_maxlength = _16M; 634 637 // process the request; this goes into the COM code in methodmaps.cpp 638 635 639 do { 636 640 #ifdef WITH_OPENSSL 637 if (g_fSSL && soap_ssl_accept( m_soap))641 if (g_fSSL && soap_ssl_accept(pSoap)) 638 642 { 639 WebLogSoapError( m_soap);643 WebLogSoapError(pSoap); 640 644 break; 641 645 } 642 646 #endif /* WITH_OPENSSL */ 643 soap_serve( m_soap);647 soap_serve(pSoap); 644 648 } while (0); 645 649 646 soap_destroy(m_soap); // clean up class instances 647 soap_end(m_soap); // clean up everything and close socket 650 soap_destroy(pSoap); // clean up class instances 651 soap_end(pSoap); // clean up everything and close connection 652 soap_free(pSoap); // free soap connection 648 653 649 654 // tell the queue we're idle again … … 909 914 #endif /* WITH_OPENSSL */ 910 915 916 soap.accept_timeout = 60; 911 917 soap.bind_flags |= SO_REUSEADDR; 912 918 // avoid EADDRINUSE on bind() … … 916 922 g_pcszBindToHost ? g_pcszBindToHost : "localhost", // safe default host 917 923 g_uBindToPort, // port 918 g_uBacklog); // backlog = max queue size for requests924 g_uBacklog); // backlog = max queue size for connections 919 925 if (m == SOAP_INVALID_SOCKET) 920 926 WebLogSoapError(&soap); … … 931 937 932 938 // initialize thread queue, mutex and eventsem 933 g_pSoapQ = new SoapQ( &soap);939 g_pSoapQ = new SoapQ(); 934 940 935 941 uint64_t cAccepted = 1; 936 942 while (g_fKeepRunning) 937 943 { 938 struct timeval timeout;939 fd_set ReadFds, WriteFds, XcptFds;940 int rv;941 for (;;)942 {943 timeout.tv_sec = 60;944 timeout.tv_usec = 0;945 FD_ZERO(&ReadFds);946 FD_SET(soap.master, &ReadFds);947 FD_ZERO(&WriteFds);948 FD_SET(soap.master, &WriteFds);949 FD_ZERO(&XcptFds);950 FD_SET(soap.master, &XcptFds);951 rv = select((int)soap.master + 1, &ReadFds, &WriteFds, &XcptFds, &timeout);952 if (rv > 0)953 break; // work is waiting954 if (rv == 0)955 continue; // timeout, not necessary to bother gsoap956 // r < 0, errno957 #if GSOAP_VERSION >= 208103958 if (soap_socket_errno == SOAP_EINTR)959 #else960 if (soap_socket_errno(soap.master) == SOAP_EINTR)961 #endif962 rv = 0; // re-check if we should terminate963 break;964 }965 if (rv == 0)966 continue;967 968 // call gSOAP to handle incoming SOAP connection969 soap.accept_timeout = -1; // 1usec timeout, actual waiting is above970 944 s = soap_accept(&soap); 971 945 if (!soap_valid_socket(s)) 972 946 { 973 if (soap.errnum )947 if (soap.errnum != SOAP_EINTR) 974 948 WebLogSoapError(&soap); 975 949 continue; 976 950 } 977 951 978 // add the socketto the queue and tell worker threads to952 // add the connection to the queue and tell worker threads to 979 953 // pick up the job 980 size_t cItemsOnQ = g_pSoapQ->add( s);981 LogRel((" Request%llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ));954 size_t cItemsOnQ = g_pSoapQ->add(&soap); 955 LogRel(("Connection %llu on socket %d queued for processing (%d items on Q)\n", cAccepted, s, cItemsOnQ)); 982 956 cAccepted++; 983 957 } … … 986 960 g_pSoapQ = NULL; 987 961 988 LogRel(("ending SOAP request handling\n")); 989 990 delete g_pSoapQ; 991 g_pSoapQ = NULL; 962 LogRel(("Ending SOAP connection handling\n")); 992 963 993 964 } … … 1002 973 /** 1003 974 * Thread function for the "queue pumper" thread started from main(). This implements 1004 * the loop that takes SOAP calls from HTTP and serves them by handing sockets to the975 * the loop that takes SOAP calls from HTTP and serves them by handing connections to the 1005 976 * SOAP queue worker threads. 1006 977 */
Note:
See TracChangeset
for help on using the changeset viewer.