(file) Return to HTTPAcceptor.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/HTTPAcceptor.cpp between version 1.99 and 1.109

version 1.99, 2007/06/05 11:21:08 version 1.109, 2007/12/18 18:50:45
Line 40 
Line 40 
 #include "TLS.h" #include "TLS.h"
 #include "HTTPAcceptor.h" #include "HTTPAcceptor.h"
 #include "HTTPConnection.h" #include "HTTPConnection.h"
   #include "HostAddress.h"
 #include "Tracer.h" #include "Tracer.h"
 #include <Pegasus/Common/MessageLoader.h> #include <Pegasus/Common/MessageLoader.h>
  
   #ifdef PEGASUS_OS_PASE
   # include <as400_protos.h>
   # include <Pegasus/Common/PaseCcsid.h>
   #endif
   
 PEGASUS_USING_STD; PEGASUS_USING_STD;
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
  
 static int MAX_CONNECTION_QUEUE_LENGTH = -1;  static int _maxConnectionQueueLength = -1;
  
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
 // //
Line 59 
Line 65 
 class HTTPAcceptorRep class HTTPAcceptorRep
 { {
 public: public:
     HTTPAcceptorRep(Boolean local)      HTTPAcceptorRep(Uint16 connectionType)
     {     {
         if (local)          if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
         {         {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
             address =             address =
Line 71 
Line 77 
             PEGASUS_ASSERT(false);             PEGASUS_ASSERT(false);
 #endif #endif
         }         }
         else  #ifdef PEGASUS_ENABLE_IPV6
           else if (connectionType == HTTPAcceptor::IPV6_CONNECTION)
           {
               address =
                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in6);
               address_size = sizeof(struct sockaddr_in6);
           }
   #endif
           else if (connectionType == HTTPAcceptor::IPV4_CONNECTION)
         {         {
             address =             address =
                 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);                 reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
             address_size = sizeof(struct sockaddr_in);             address_size = sizeof(struct sockaddr_in);
         }         }
           else
           {
               PEGASUS_ASSERT(false);
       }
     }     }
   
     ~HTTPAcceptorRep()     ~HTTPAcceptorRep()
     {     {
         delete address;         delete address;
Line 100 
Line 119 
  
 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
                            MessageQueue* outputMessageQueue,                            MessageQueue* outputMessageQueue,
                            Boolean localConnection,                             Uint16 connectionType,
                            Uint32 portNumber,                            Uint32 portNumber,
                            SSLContext * sslcontext,                            SSLContext * sslcontext,
                            ReadWriteSem* sslContextObjectLock)                            ReadWriteSem* sslContextObjectLock)
Line 109 
Line 128 
      _outputMessageQueue(outputMessageQueue),      _outputMessageQueue(outputMessageQueue),
      _rep(0),      _rep(0),
      _entry_index(-1),      _entry_index(-1),
      _localConnection(localConnection),       _connectionType(connectionType),
      _portNumber(portNumber),      _portNumber(portNumber),
      _sslcontext(sslcontext),      _sslcontext(sslcontext),
      _sslContextObjectLock(sslContextObjectLock)       _sslContextObjectLock(sslContextObjectLock),
        _idleConnectionTimeoutSeconds(0)
 { {
    Socket::initializeInterface();    Socket::initializeInterface();
  
    /*    /*
         Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH          Platforms interpret the value of _maxConnectionQueueLength
         differently.  Some platforms interpret the value literally, while         differently.  Some platforms interpret the value literally, while
         others multiply a fudge factor. When the server is under stress from         others multiply a fudge factor. When the server is under stress from
         multiple clients with multiple requests, toggling this number may         multiple clients with multiple requests, toggling this number may
Line 125 
Line 145 
         value, we allow an environment variable to be set which specifies a         value, we allow an environment variable to be set which specifies a
         number greater than the maximum concurrent client connections         number greater than the maximum concurrent client connections
         possible.  If this environment var is not specified, then         possible.  If this environment var is not specified, then
         MAX_CONNECTION_QUEUE_LENGTH = 15.          _maxConnectionQueueLength = 15.
    */    */
  
 //To engage runtime backlog queue length: uncomment the following block AND //To engage runtime backlog queue length: uncomment the following block AND
 //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15  //comment out the line _maxConnectionQueueLength = 15
  
 /* /*
     if (MAX_CONNECTION_QUEUE_LENGTH == -1)      if (_maxConnectionQueueLength == -1)
     {     {
         const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");         const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
         if (!env)         if (!env)
         {         {
             MAX_CONNECTION_QUEUE_LENGTH = 15;              _maxConnectionQueueLength = 15;
         }         }
         else         else
         {         {
             char* end = NULL;             char* end = NULL;
             MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);              _maxConnectionQueueLength = strtol(env, &end, 10);
             if (*end)             if (*end)
                 MAX_CONNECTION_QUEUE_LENGTH = 15;                  _maxConnectionQueueLength = 15;
             cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<              cout << " _maxConnectionQueueLength = " <<
                 MAX_CONNECTION_QUEUE_LENGTH << endl;                  _maxConnectionQueueLength << endl;
         }         }
     }     }
 */ */
     MAX_CONNECTION_QUEUE_LENGTH = 15;  #ifdef PEGASUS_WMIMAPPER
       //The WMI Mapper can be used as a proxy to multiple WMI Servers.
       //If a client application simultaneously initiates connections
       //to many Windows systems, many of these connections may be routed
       //to a single WMI Mapper. A larger _maxConnectionQueueLength
       //value is required to allow these connections to be initiated
       //successfully.
       _maxConnectionQueueLength = 40;
   #else
       _maxConnectionQueueLength = 15;
   #endif
 } }
  
 HTTPAcceptor::~HTTPAcceptor() HTTPAcceptor::~HTTPAcceptor()
Line 252 
Line 282 
         throw BindFailedException(parms);         throw BindFailedException(parms);
     }     }
  
     _rep = new HTTPAcceptorRep(_localConnection);      _rep = new HTTPAcceptorRep(_connectionType);
  
     // bind address     // bind address
     _bind();     _bind();
Line 265 
Line 295 
 */ */
 void HTTPAcceptor::_bind() void HTTPAcceptor::_bind()
 { {
   #ifdef PEGASUS_OS_PASE
       // bind need ccsid is 819
       int orig_ccsid;
       orig_ccsid = _SETCCSID(-1);
       if (orig_ccsid == -1)
       {
           PEG_TRACE_STRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               String("HTTPAcceptor::_bind: Can not get current PASE CCSID."));
           orig_ccsid = 1208;
       }
       PaseCcsid ccsid(819, orig_ccsid);
   #endif
   
     PEGASUS_ASSERT(_rep != 0);     PEGASUS_ASSERT(_rep != 0);
     // Create address:     // Create address:
       memset(_rep->address, 0, _rep->address_size);
  
     memset(_rep->address, 0, sizeof(*_rep->address));      if (_connectionType == LOCAL_CONNECTION)
   
     if (_localConnection)  
     {     {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
           //
           // Make sure the local domain socket can be owned by the cimserver
           // user.  Otherwise, the bind may fail with a vague "bind failed"
           // error.
           //
           if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
           {
               if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
               {
                   throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
               }
           }
   
         reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =         reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
             AF_UNIX;             AF_UNIX;
         strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,         strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
             PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);             PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
         ::unlink(  
             reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);  
 #else #else
         PEGASUS_ASSERT(false);         PEGASUS_ASSERT(false);
 #endif #endif
     }     }
     else  #ifdef PEGASUS_ENABLE_IPV6
       else if (_connectionType == IPV6_CONNECTION)
       {
           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
               in6addr_any;
           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_family =
               AF_INET6;
           reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_port =
               htons(_portNumber);
       }
   #endif
       else if(_connectionType == IPV4_CONNECTION)
     {     {
         reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =         reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_addr.s_addr =
             INADDR_ANY;             INADDR_ANY;
Line 292 
Line 356 
         reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =         reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
             htons(_portNumber);             htons(_portNumber);
     }     }
       else
       {
           PEGASUS_ASSERT(false);
       }
  
     // Create socket:     // Create socket:
  
     if (_localConnection)      if (_connectionType == LOCAL_CONNECTION)
     {     {
         _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);         _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
     }     }
     else  #ifdef PEGASUS_ENABLE_IPV6
       else if (_connectionType == IPV6_CONNECTION)
       {
           _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
       }
   #endif
       else if (_connectionType == IPV4_CONNECTION)
     {     {
         _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);         _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     }     }
       else
       {
           PEGASUS_ASSERT(false);
       }
  
     if (_rep->socket < 0)     if (_rep->socket < 0)
     {     {
Line 315 
Line 393 
         throw BindFailedException(parms);         throw BindFailedException(parms);
     }     }
  
       Socket::disableBlocking(_rep->socket);
  
 // set the close-on-exec bit for this file handle. // set the close-on-exec bit for this file handle.
 // any unix that forks needs this bit set. // any unix that forks needs this bit set.
Line 396 
Line 475 
 #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \ #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
      (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \      (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
       defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))       defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
     if (_localConnection)      if (_connectionType == LOCAL_CONNECTION)
     {     {
         if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,         if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
                 S_IRUSR | S_IWUSR | S_IXUSR |                 S_IRUSR | S_IWUSR | S_IXUSR |
Line 418 
Line 497 
  
     // Set up listening on the given socket:     // Set up listening on the given socket:
  
     //int const MAX_CONNECTION_QUEUE_LENGTH = 15;      //int const _maxConnectionQueueLength = 15;
  
     if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)      if (listen(_rep->socket, _maxConnectionQueueLength) < 0)
     {     {
         Socket::close(_rep->socket);         Socket::close(_rep->socket);
         delete _rep;         delete _rep;
Line 438 
Line 517 
             _rep->socket,             _rep->socket,
             SocketMessage::READ | SocketMessage::EXCEPTION,             SocketMessage::READ | SocketMessage::EXCEPTION,
             getQueueId(),             getQueueId(),
             Monitor::ACCEPTOR)))              MonitorEntry::TYPE_ACCEPTOR)))
     {     {
         Socket::close(_rep->socket);         Socket::close(_rep->socket);
         delete _rep;         delete _rep;
Line 468 
Line 547 
         // close the socket         // close the socket
         Socket::close(_rep->socket);         Socket::close(_rep->socket);
         // Unlink Local Domain Socket Bug# 3312         // Unlink Local Domain Socket Bug# 3312
         if (_localConnection)          if (_connectionType == LOCAL_CONNECTION)
         {         {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
Line 517 
Line 596 
         // close the socket         // close the socket
         Socket::close(_rep->socket);         Socket::close(_rep->socket);
         // Unlink Local Domain Socket Bug# 3312         // Unlink Local Domain Socket Bug# 3312
         if (_localConnection)          if (_connectionType == LOCAL_CONNECTION)
         {         {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,             PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
Line 571 
Line 650 
     _socketWriteTimeout = socketWriteTimeout;     _socketWriteTimeout = socketWriteTimeout;
 } }
  
   void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
   {
       _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
   }
   
 void HTTPAcceptor::unbind() void HTTPAcceptor::unbind()
 { {
     if (_rep)     if (_rep)
Line 578 
Line 662 
         _portNumber = 0;         _portNumber = 0;
         Socket::close(_rep->socket);         Socket::close(_rep->socket);
  
         if (_localConnection)          if (_connectionType == LOCAL_CONNECTION)
         {         {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
             ::unlink(             ::unlink(
Line 635 
Line 719 
     struct sockaddr* accept_address;     struct sockaddr* accept_address;
     SocketLength address_size;     SocketLength address_size;
  
     if (_localConnection)      if (_connectionType == LOCAL_CONNECTION)
     {     {
 #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
         accept_address =         accept_address =
Line 647 
Line 731 
     }     }
     else     else
     {     {
   #ifdef PEGASUS_ENABLE_IPV6
           accept_address =
              reinterpret_cast<struct sockaddr*>
              (new struct sockaddr_storage);
           address_size = sizeof(struct sockaddr_storage);
   #else
         accept_address =         accept_address =
             reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);             reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
         address_size = sizeof(struct sockaddr_in);         address_size = sizeof(struct sockaddr_in);
   #endif
     }     }
  
     SocketHandle socket;      // It is not necessary to handle EINTR errors from this accept() call.
 #ifdef PEGASUS_OS_TYPE_WINDOWS      // An EINTR error should not occur on a non-blocking socket.  If the
     socket = accept(_rep->socket, accept_address, &address_size);      // listen socket is blocking and EINTR occurs, the new socket connection
 #else      // is not accepted here.
     while (  
         ((socket = accept(_rep->socket, accept_address, &address_size)) == -1)      // EAGAIN errors are also not handled here.  An EAGAIN error should not
         && (errno == EINTR))      // occur after select() indicates that the listen socket is available for
         ;      // reading.  If the accept() fails with an EAGAIN error code, a new
 #endif      // connection is not accepted here.
   
       SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
  
     if (socket == PEGASUS_SOCKET_ERROR)     if (socket == PEGASUS_SOCKET_ERROR)
     {     {
Line 688 
Line 781 
  
     String ipAddress;     String ipAddress;
  
     if (_localConnection)      if (_connectionType == LOCAL_CONNECTION)
     {     {
         ipAddress = "localhost";         ipAddress = "localhost";
     }     }
     else     else
     {     {
   #ifdef PEGASUS_ENABLE_IPV6
           char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
           int rc;
           if ((rc = System::getNameInfo(accept_address,
                   address_size,
                   ipBuffer,
                   PEGASUS_INET6_ADDRSTR_LEN,
                   0,
                   0,
                   NI_NUMERICHOST)))
           {
               Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
                   "HTTPAcceptor - getnameinfo() failure.  rc: $0", rc);
   
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                   "HTTPAcceptor: getnameinfo() failed");
               delete accept_address;
               Socket::close(socket);
               return;
           }
           ipAddress = ipBuffer;
   #else
         unsigned char* sa = reinterpret_cast<unsigned char*>(         unsigned char* sa = reinterpret_cast<unsigned char*>(
             &reinterpret_cast<struct sockaddr_in*>(             &reinterpret_cast<struct sockaddr_in*>(
                 accept_address)->sin_addr.s_addr);                 accept_address)->sin_addr.s_addr);
         char ipBuffer[32];         char ipBuffer[32];
         sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);         sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
         ipAddress = ipBuffer;         ipAddress = ipBuffer;
   #endif
     }     }
  
     delete accept_address;     delete accept_address;
Line 730 
Line 846 
     SharedPtr<MP_Socket> mp_socket(new MP_Socket(     SharedPtr<MP_Socket> mp_socket(new MP_Socket(
         socket, _sslcontext, _sslContextObjectLock, ipAddress));         socket, _sslcontext, _sslContextObjectLock, ipAddress));
  
       mp_socket->disableBlocking();
     mp_socket->setSocketWriteTimeout(_socketWriteTimeout);     mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
  
     // Perform the SSL handshake, if applicable.  Make the socket non-blocking      // Perform the SSL handshake, if applicable.
     // for this operation so we can send it back to the Monitor's select() loop  
     // if it takes a while.  
  
     mp_socket->disableBlocking();  
     Sint32 socketAcceptStatus = mp_socket->accept();     Sint32 socketAcceptStatus = mp_socket->accept();
     mp_socket->enableBlocking();  
  
     if (socketAcceptStatus < 0)     if (socketAcceptStatus < 0)
     {     {
Line 753 
Line 866 
     HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,     HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
         ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));         ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
  
       if (_idleConnectionTimeoutSeconds)
       {
           connection->_idleConnectionTimeoutSeconds =
               _idleConnectionTimeoutSeconds;
           Time::gettimeofday(&connection->_idleStartTime);
       }
   
     if (socketAcceptStatus == 0)     if (socketAcceptStatus == 0)
     {     {
         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,         PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
             "HTTPAcceptor: SSL_accept() pending");             "HTTPAcceptor: SSL_accept() pending");
         connection->_acceptPending = true;         connection->_acceptPending = true;
           Time::gettimeofday(&connection->_acceptPendingStartTime);
     }     }
  
     // Solicit events on this new connection's socket:     // Solicit events on this new connection's socket:
Line 766 
Line 887 
     if (-1 ==  (index = _monitor->solicitSocketMessages(     if (-1 ==  (index = _monitor->solicitSocketMessages(
             connection->getSocket(),             connection->getSocket(),
             SocketMessage::READ | SocketMessage::EXCEPTION,             SocketMessage::READ | SocketMessage::EXCEPTION,
             connection->getQueueId(), Monitor::CONNECTION)) )              connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
     {     {
         // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return         // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
         // an error message to Client application.         // an error message to Client application.


Legend:
Removed from v.1.99  
changed lines
  Added in v.1.109

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2