(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.24.2.2 and 1.93.4.5

version 1.24.2.2, 2002/10/30 21:20:03 version 1.93.4.5, 2008/01/23 10:09:50
Line 1 
Line 1 
 //%/////////////////////////////////////////////////////////////////////////////  //%2006////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
 // The Open Group, Tivoli Systems  // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
   // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation, The Open Group.
   // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; Symantec Corporation; The Open Group.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 21 
Line 29 
 // //
 //============================================================================== //==============================================================================
 // //
 // Author: Mike Brasher (mbrasher@bmc.com)  
 //  
 // Modified By:  
 //         Jenny Yu, Hewlett-Packard Company (jenny_yu@hp.com)  
 //         Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)  
 //  
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
 #include "Config.h" #include "Config.h"
 #include "Constants.h" #include "Constants.h"
 #include <iostream> #include <iostream>
 #include "Socket.h"  
   
 #ifdef PEGASUS_PLATFORM_WIN32_IX86_MSVC  
 #include <windows.h>  
 #else  
 # include <cctype>  
 # include <unistd.h>  
 # include <cstdlib>  
 # include <errno.h>  
 # include <fcntl.h>  
 # include <netdb.h>  
 # include <netinet/in.h>  
 # include <arpa/inet.h>  
 # include <sys/socket.h>  
 # ifdef PEGASUS_LOCAL_DOMAIN_SOCKET  
 #  include <sys/un.h>  
 # endif  
 #endif  
  
   #include "Network.h"
 #include "Socket.h" #include "Socket.h"
 #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>
   
   #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
   #include "EBCDIC_OS400.h"
   #endif
   
  
 PEGASUS_USING_STD; PEGASUS_USING_STD;
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
  
   
   static int MAX_CONNECTION_QUEUE_LENGTH = -1;
   
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
 // //
 // HTTPAcceptorRep // HTTPAcceptorRep
 // //
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
  
 struct HTTPAcceptorRep  class HTTPAcceptorRep
   {
   public:
       HTTPAcceptorRep(Uint16 connectionType)
       {
           if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
 { {
 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
       struct sockaddr_un address;              address =
                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
               address_size = sizeof(struct sockaddr_un);
 #else #else
       struct sockaddr_in address;              PEGASUS_ASSERT(false);
 #endif #endif
           }
   #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 =
                   reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
               address_size = sizeof(struct sockaddr_in);
           }
           else
           {
               PEGASUS_ASSERT(false);
       }
       }
   
       ~HTTPAcceptorRep()
       {
           delete address;
       }
       struct sockaddr* address;
   
       SocketLength address_size;
       Mutex _connection_mut;       Mutex _connection_mut;
  
       Sint32 socket;      SocketHandle socket;
       Array<HTTPConnection*> connections;       Array<HTTPConnection*> connections;
 }; };
  
   
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
 // //
 // HTTPAcceptor // HTTPAcceptor
 // //
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
  
 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue)  HTTPAcceptor::HTTPAcceptor(Monitor* monitor,
    : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),                             MessageQueue* outputMessageQueue,
      _monitor(monitor), _outputMessageQueue(outputMessageQueue),                             Uint16 connectionType,
      _rep(0), _sslcontext(NULL), _entry_index(-1)                             Uint32 portNumber,
 {                             SSLContext * sslcontext,
                              ReadWriteSem* sslContextObjectLock)
    _inet_address[0] = 0x00;     : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
    Socket::initializeInterface();       _monitor(monitor),
 }       _outputMessageQueue(outputMessageQueue),
   
 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,  
                            SSLContext * sslcontext)  
    :       Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  
            _monitor(monitor), _outputMessageQueue(outputMessageQueue),  
            _rep(0),            _rep(0),
        _entry_index(-1),
        _connectionType(connectionType),
        _portNumber(portNumber),
            _sslcontext(sslcontext),            _sslcontext(sslcontext),
            _entry_index(-1)       _sslContextObjectLock(sslContextObjectLock),
        _idleConnectionTimeoutSeconds(0)
 { {
    _inet_address[0] = 0x00;  
    Socket::initializeInterface();    Socket::initializeInterface();
 }  
  
 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,     /*
                            SSLContext * sslcontext,          Platforms interpret the value of MAX_CONNECTION_QUEUE_LENGTH
                            char *inet_address)          differently.  Some platforms interpret the value literally, while
    :       Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),          others multiply a fudge factor. When the server is under stress from
            _monitor(monitor), _outputMessageQueue(outputMessageQueue),          multiple clients with multiple requests, toggling this number may
            _rep(0),          prevent clients from being dropped.  Instead of hard coding the
            _sslcontext(sslcontext),          value, we allow an environment variable to be set which specifies a
            _entry_index(-1)          number greater than the maximum concurrent client connections
           possible.  If this environment var is not specified, then
           MAX_CONNECTION_QUEUE_LENGTH = 15.
      */
   
   //To engage runtime backlog queue length: uncomment the following block AND
   //comment out the line MAX_CONNECTION_QUEUE_LENGTH = 15
   
   /*
       if (MAX_CONNECTION_QUEUE_LENGTH == -1)
 { {
    strncpy(_inet_address, inet_address, 16);  #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
    _inet_address[16] = 0x00;  #pragma convert(37)
    Socket::initializeInterface();          const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
           EtoA(env);
   #pragma convert(0)
   #else
           const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
   #endif
           if (!env)
           {
               MAX_CONNECTION_QUEUE_LENGTH = 15;
           }
           else
           {
               char* end = NULL;
               MAX_CONNECTION_QUEUE_LENGTH = strtol(env, &end, 10);
               if (*end)
                   MAX_CONNECTION_QUEUE_LENGTH = 15;
               cout << " MAX_CONNECTION_QUEUE_LENGTH = " <<
                   MAX_CONNECTION_QUEUE_LENGTH << endl;
           }
       }
   */
       MAX_CONNECTION_QUEUE_LENGTH = 15;
 } }
  
 HTTPAcceptor::~HTTPAcceptor() HTTPAcceptor::~HTTPAcceptor()
 { {
       destroyConnections();
    unbind();    unbind();
       // ATTN: Is this correct in a multi-HTTPAcceptor server?
    Socket::uninitializeInterface();    Socket::uninitializeInterface();
 } }
  
Line 133 
Line 193 
    if (! message)    if (! message)
       return;       return;
  
       PEGASUS_ASSERT(_rep != 0);
    switch (message->getType())    switch (message->getType())
    {    {
       case SOCKET_MESSAGE:       case SOCKET_MESSAGE:
Line 142 
Line 203 
          // If this is a connection request:          // If this is a connection request:
  
          if (socketMessage->socket == _rep->socket &&          if (socketMessage->socket == _rep->socket &&
              socketMessage->events | SocketMessage::READ)                  socketMessage->events & SocketMessage::READ)
          {          {
             _acceptConnection();             _acceptConnection();
          }          }
          else          else
          {          {
             // ATTN! this can't happen!             // ATTN! this can't happen!
                   PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                       "HTTPAcceptor::handleEnqueue: Invalid SOCKET_MESSAGE "
                           "received.");
          }          }
  
          break;          break;
Line 156 
Line 220 
  
       case CLOSE_CONNECTION_MESSAGE:       case CLOSE_CONNECTION_MESSAGE:
       {       {
          CloseConnectionMessage* closeConnectionMessage             CloseConnectionMessage* closeConnectionMessage =
             = (CloseConnectionMessage*)message;                 (CloseConnectionMessage*)message;
  
          _rep->_connection_mut.lock(pegasus_thread_self());             AutoMutex autoMut(_rep->_connection_mut);
  
          for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)          for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
          {          {
             HTTPConnection* connection = _rep->connections[i];             HTTPConnection* connection = _rep->connections[i];
             Sint32 socket = connection->getSocket();                 SocketHandle socket = connection->getSocket();
  
             if (socket == closeConnectionMessage->socket)             if (socket == closeConnectionMessage->socket)
             {             {
                _monitor->unsolicitSocketMessages(socket);                _monitor->unsolicitSocketMessages(socket);
                _rep->connections.remove(i);                _rep->connections.remove(i);
                delete connection;                delete connection;
                PEGASUS_STD(cout) << "Closing HTTP Connection; Current Connection Table Size: " <<  
                _rep->connections.size() << PEGASUS_STD(endl);  
                break;                break;
             }             }
          }          }
          _rep->_connection_mut.unlock();  
              break;
       }       }
  
       default:       default:
       // ATTN: need unexpected message error!       // ATTN: need unexpected message error!
              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                  "HTTPAcceptor::handleEnqueue: Invalid MESSAGE received.");
       break;       break;
    };      }
  
    delete message;    delete message;
 } }
Line 193 
Line 258 
    Message* message = dequeue();    Message* message = dequeue();
  
    if (!message)    if (!message)
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::handleEnqueue(): No message on queue.");
       return;       return;
       }
  
    handleEnqueue(message);    handleEnqueue(message);
   
 } }
  
 void HTTPAcceptor::bind(Uint32 portNumber)  void HTTPAcceptor::bind()
 { {
    if (_rep)    if (_rep)
       throw BindFailedException("HTTPAcceptor already bound");      {
           MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
               "HTTPAcceptor already bound");
  
    _rep = new HTTPAcceptorRep;          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::bind: HTTPAcceptor already bound.");
           throw BindFailedException(parms);
       }
  
    _portNumber = portNumber;      _rep = new HTTPAcceptorRep(_connectionType);
  
    // bind address    // bind address
    _bind();    _bind();
   
    return;  
 } }
  
 /** /**
    _bind - creates a new server socket and bind socket to the port address.    _bind - creates a new server socket and bind socket to the port address.
    If PEGASUS_LOCAL_DOMAIN_SOCKET is defined, the port number is ignored and      If PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET is not defined, the port number is
    a domain socket is bound.      ignored and a domain socket is bound.
 */ */
 void HTTPAcceptor::_bind() void HTTPAcceptor::_bind()
 { {
       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)
       {
 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET  #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
    _rep->address.sun_family = AF_UNIX;          reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
    strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");              AF_UNIX;
    ::unlink(_rep->address.sun_path);          strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
               PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
   #ifdef PEGASUS_PLATFORM_OS400_ISERIES_IBM
           AtoE(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
   #endif
           ::unlink(
               reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
 #else #else
    if(_inet_address[0] != 0x00)          PEGASUS_ASSERT(false);
   #endif
       }
   #ifdef PEGASUS_ENABLE_IPV6
       else if (_connectionType == IPV6_CONNECTION)
    {    {
       _rep->address.sin_addr.s_addr = inet_addr(_inet_address);          reinterpret_cast<struct sockaddr_in6*>(_rep->address)->sin6_addr =
       cout << "binding to " << _inet_address << endl;              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 =
               INADDR_ANY;
           reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_family =
               AF_INET;
           reinterpret_cast<struct sockaddr_in*>(_rep->address)->sin_port =
               htons(_portNumber);
    }    }
    else    else
    {    {
       _rep->address.sin_addr.s_addr = INADDR_ANY;          PEGASUS_ASSERT(false);
    }    }
  
    _rep->address.sin_family = AF_INET;  
    _rep->address.sin_port = htons(_portNumber);  
 #endif  
   
    // Create socket:    // Create socket:
  
 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET      if (_connectionType == LOCAL_CONNECTION)
    _rep->socket = socket(AF_UNIX, SOCK_STREAM, 0);      {
 #else          _rep->socket = Socket::createSocket(AF_UNIX, SOCK_STREAM, 0);
    _rep->socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);      }
   #ifdef PEGASUS_ENABLE_IPV6
       else if (_connectionType == IPV6_CONNECTION)
       {
           _rep->socket = Socket::createSocket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
       }
 #endif #endif
       else if (_connectionType == IPV4_CONNECTION)
       {
           _rep->socket = Socket::createSocket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
       }
       else
       {
           PEGASUS_ASSERT(false);
       }
  
    if (_rep->socket < 0)    if (_rep->socket < 0)
    {    {
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailedException("Failed to create socket");          MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
               "Failed to create socket");
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind _rep->socket < 0");
           throw BindFailedException(parms);
       }
   
       Socket::disableBlocking(_rep->socket);
   
   // set the close-on-exec bit for this file handle.
   // any unix that forks needs this bit set.
   #if !defined PEGASUS_OS_TYPE_WINDOWS && !defined(PEGASUS_OS_VMS)
       int sock_flags;
       if ((sock_flags = fcntl(_rep->socket, F_GETFD, 0)) < 0)
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind: fcntl(F_GETFD) failed");
       }
       else
       {
           sock_flags |= FD_CLOEXEC;
           if (fcntl(_rep->socket, F_SETFD, sock_flags) < 0)
           {
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                   "HTTPAcceptor::_bind: fcntl(F_SETFD) failed");
    }    }
       }
   #endif
   
  
    //    //
    // Set the socket option SO_REUSEADDR to reuse the socket address so    // Set the socket option SO_REUSEADDR to reuse the socket address so
Line 271 
Line 402 
    if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,    if (setsockopt(_rep->socket, SOL_SOCKET, SO_REUSEADDR,
                   (char *)&opt, sizeof(opt)) < 0)                   (char *)&opt, sizeof(opt)) < 0)
    {    {
           Socket::close(_rep->socket);
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailedException("Failed to set socket option");          MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
               "Failed to set socket option");
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind: Failed to set socket option.");
           throw BindFailedException(parms);
    }    }
  
   
       //
    // Bind socket to port:    // Bind socket to port:
       //
       if (::bind(_rep->socket, _rep->address, _rep->address_size) < 0)
       {
           Socket::close(_rep->socket);
           delete _rep;
           _rep = 0;
           MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
               "Failed to bind socket");
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind: Failed to bind socket.");
           throw BindFailedException(parms);
       }
   
   
       //
       // Get the actual port value used if the caller specified a port value of 0.
       //
       if (_portNumber == 0)
       {
           sockaddr_in buf;
           SocketLength bufSize = sizeof(buf);
           if (getsockname(_rep->socket, reinterpret_cast<sockaddr *>(&buf),
                   &bufSize) == 0 )
           {
               _portNumber = ntohs(buf.sin_port);
           }
       }
  
    if (::bind(_rep->socket,  
               reinterpret_cast<struct sockaddr*>(&_rep->address),      //
               sizeof(_rep->address)) < 0)      // Change permissions on Linux local domain socket to allow writes by
       // others.
       //
   #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
        (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
         defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM))
       if (_connectionType == LOCAL_CONNECTION)
       {
           if (::chmod(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
                   S_IRUSR | S_IWUSR | S_IXUSR |
                   S_IRGRP | S_IWGRP | S_IXGRP |
                   S_IROTH | S_IWOTH | S_IXOTH ) < 0 )
    {    {
       Socket::close(_rep->socket);       Socket::close(_rep->socket);
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailedException("Failed to bind socket");              MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
                   "Failed to bind socket");
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                   "HTTPAcceptor::_bind: Failed to set domain socket "
                       "permissions.");
               throw BindFailedException(parms);
           }
    }    }
   #endif
  
    // Set up listening on the given socket:    // Set up listening on the given socket:
  
    int const MAX_CONNECTION_QUEUE_LENGTH = 5;      //int const MAX_CONNECTION_QUEUE_LENGTH = 15;
  
    if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)    if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)
    {    {
       Socket::close(_rep->socket);       Socket::close(_rep->socket);
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailedException("Failed to bind socket");          MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_BIND_SOCKET",
               "Failed to bind socket");
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind: Failed to bind socket(1).");
           throw BindFailedException(parms);
    }    }
  
    // Register to receive SocketMessages on this socket:    // Register to receive SocketMessages on this socket:
Line 311 
Line 498 
       Socket::close(_rep->socket);       Socket::close(_rep->socket);
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailedException("Failed to solicit socket messaeges");          MessageLoaderParms parms(
               "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
               "Failed to solicit socket messaeges");
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_bind: Failed to solicit socket messages(2).");
           throw BindFailedException(parms);
    }    }
 } }
  
Line 324 
Line 516 
    if (_rep)    if (_rep)
    {    {
       // unregister the socket       // unregister the socket
       _monitor->unsolicitSocketMessages(_rep->socket);  
           // ATTN - comment out - see CIMServer::stopClientConnection()
           //_monitor->unsolicitSocketMessages(_rep->socket);
  
       // close the socket       // close the socket
       Socket::close(_rep->socket);       Socket::close(_rep->socket);
           // Unlink Local Domain Socket Bug# 3312
           if (_connectionType == LOCAL_CONNECTION)
           {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
                   "HTTPAcceptor::closeConnectionSocket Unlinking local "
                       "connection.");
               ::unlink(
                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
   #else
               PEGASUS_ASSERT(false);
   #endif
           }
       }
       else
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
    }    }
 } }
  
Line 340 
Line 552 
    {    {
       _bind();       _bind();
    }    }
       else
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
       }
   }
   
   
   /**
      reconnectConnectionSocket - creates a new server socket.
   */
   void HTTPAcceptor::reconnectConnectionSocket()
   {
       if (_rep)
       {
           // unregister the socket
           _monitor->unsolicitSocketMessages(_rep->socket);
           // close the socket
           Socket::close(_rep->socket);
           // Unlink Local Domain Socket Bug# 3312
           if (_connectionType == LOCAL_CONNECTION)
           {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
                   "HTTPAcceptor::reconnectConnectionSocket Unlinking local "
                       "connection." );
               ::unlink(
                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
   #else
               PEGASUS_ASSERT(false);
   #endif
           }
           // open the socket
           _bind();
       }
       else
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
       }
 } }
  
 /** /**
    getOutstandingRequestCount - returns the number of outstanding requests.    getOutstandingRequestCount - returns the number of outstanding requests.
 */ */
 Uint32 HTTPAcceptor::getOutstandingRequestCount()  Uint32 HTTPAcceptor::getOutstandingRequestCount() const
 { {
    Uint32 count = 0;    Uint32 count = 0;
       if (_rep)
    _rep->_connection_mut.lock(pegasus_thread_self());      {
           AutoMutex autoMut(_rep->_connection_mut);
    if (_rep->connections.size() > 0)    if (_rep->connections.size() > 0)
    {    {
       HTTPConnection* connection = _rep->connections[0];       HTTPConnection* connection = _rep->connections[0];
       count = connection->getRequestCount();       count = connection->getRequestCount();
    }    }
    _rep->_connection_mut.unlock();      }
    return count;    return count;
   }
  
   
   /**
       getPortNumber - returns the port number used for the connection
   */
   Uint32 HTTPAcceptor::getPortNumber() const
   {
       return _portNumber;
   }
   
   void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
   {
       _socketWriteTimeout = socketWriteTimeout;
   }
   
   void HTTPAcceptor::setIdleConnectionTimeout(Uint32 idleConnectionTimeoutSeconds)
   {
       _idleConnectionTimeoutSeconds = idleConnectionTimeoutSeconds;
 } }
  
 void HTTPAcceptor::unbind() void HTTPAcceptor::unbind()
 { {
    if (_rep)    if (_rep)
    {    {
           _portNumber = 0;
       Socket::close(_rep->socket);       Socket::close(_rep->socket);
   
           if (_connectionType == LOCAL_CONNECTION)
           {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               ::unlink(
                   reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path);
   #else
               PEGASUS_ASSERT(false);
   #endif
           }
   
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
    }    }
       else
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::unbind failure _rep is null." );
       }
 } }
  
 void HTTPAcceptor::destroyConnections() void HTTPAcceptor::destroyConnections()
 { {
       if (_rep)
       {
    // For each connection created by this object:    // For each connection created by this object:
  
    _rep->_connection_mut.lock(pegasus_thread_self());          AutoMutex autoMut(_rep->_connection_mut);
    for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)    for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
    {    {
       HTTPConnection* connection = _rep->connections[i];       HTTPConnection* connection = _rep->connections[i];
       Sint32 socket = connection->getSocket();              SocketHandle socket = connection->getSocket();
  
       // Unsolicit SocketMessages:       // Unsolicit SocketMessages:
  
Line 386 
Line 676 
  
       // Destroy the connection (causing it to close):       // Destroy the connection (causing it to close):
  
       while (connection->refcount.value()) { }              while (connection->refcount.get()) { }
       delete connection;       delete connection;
    }    }
  
    _rep->connections.clear();    _rep->connections.clear();
    _rep->_connection_mut.unlock();      }
 } }
  
 void HTTPAcceptor::_acceptConnection() void HTTPAcceptor::_acceptConnection()
Line 400 
Line 690 
  
    PEGASUS_ASSERT(_rep != 0);    PEGASUS_ASSERT(_rep != 0);
  
    if (!_rep)  
       return;  
   
    // Accept the connection (populate the address):    // Accept the connection (populate the address):
  
    sockaddr_in address;      struct sockaddr* accept_address;
       SocketLength address_size;
  
 #if defined(PEGASUS_PLATFORM_ZOS_ZSERIES_IBM) || defined(PEGASUS_PLATFORM_AIX_RS_IBMCXX)      if (_connectionType == LOCAL_CONNECTION)
    size_t n = sizeof(address);      {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
           accept_address =
               reinterpret_cast<struct sockaddr*>(new struct sockaddr_un);
           address_size = sizeof(struct sockaddr_un);
 #else #else
    int n = sizeof(address);          PEGASUS_ASSERT(false);
 #endif #endif
       }
       else
 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)      {
    Sint32 socket = accept(  #ifdef PEGASUS_ENABLE_IPV6
       _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);          accept_address =
              reinterpret_cast<struct sockaddr*>
              (new struct sockaddr_storage);
           address_size = sizeof(struct sockaddr_storage);
 #else #else
    Sint32 socket = accept(_rep->socket, reinterpret_cast<struct sockaddr*>(&address), &n);          accept_address =
               reinterpret_cast<struct sockaddr*>(new struct sockaddr_in);
           address_size = sizeof(struct sockaddr_in);
 #endif #endif
       }
  
       // It is not necessary to handle EINTR errors from this accept() call.
       // An EINTR error should not occur on a non-blocking socket.  If the
       // listen socket is blocking and EINTR occurs, the new socket connection
       // is not accepted here.
  
       // EAGAIN errors are also not handled here.  An EAGAIN error should not
       // occur after select() indicates that the listen socket is available for
       // reading.  If the accept() fails with an EAGAIN error code, a new
       // connection is not accepted here.
  
    if (socket < 0)      SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
   
       if (socket == PEGASUS_SOCKET_ERROR)
       {
           // the remote connection is invalid, destroy client address.
           delete accept_address;
   
           // TCPIP is down reconnect this acceptor
           if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
    {    {
        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,              PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                   "Socket has an IO error. TCP/IP down. Try to reconnect.");
   
               reconnectConnectionSocket();
   
               return;
           }
   
           Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
               "HTTPAcceptor - accept() failure.  errno: $0", errno);
   
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                         "HTTPAcceptor: accept() failed");                         "HTTPAcceptor: accept() failed");
       return;       return;
    }    }
 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)      // We need to ensure that the socket number is not higher than
    if( _inet_address[0] != 0x00)      // what fits into FD_SETSIZE, because we else won't be able to select on it
       // and won't ever communicate correct on that socket.
       if (socket >= FD_SETSIZE)
       {
           // the remote connection is invalid, destroy client address.
           delete accept_address;
   
           Logger::put(Logger::STANDARD_LOG, System::CIMSERVER, Logger::TRACE,
               "HTTPAcceptor out of available sockets. "
                   "Closing connection to the new client.");
   
           PEG_TRACE(
               (TRC_DISCARDED_DATA,
                Tracer::LEVEL2,
                "accept() returned too large socket number %d.",
                socket));
   
           // close the connection
           Socket::close(socket);
           return;
       }
   
   
       String ipAddress;
   
       if (_connectionType == LOCAL_CONNECTION)
    {    {
       if( 1023 < htons(address.sin_port) )          ipAddress = "localhost";
       }
       else
       {       {
          shutdown(socket, 2);  #ifdef PEGASUS_ENABLE_IPV6
           char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
           int rc;
           while ((rc = getnameinfo(accept_address, address_size, ipBuffer,
               PEGASUS_INET6_ADDRSTR_LEN, 0, 0, NI_NUMERICHOST)) == EAI_AGAIN)
               ;
           if (rc)
           {
               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);          Socket::close(socket);
          return;          return;
       }       }
           ipAddress = ipBuffer;
   #else
           unsigned char* sa = reinterpret_cast<unsigned char*>(
               &reinterpret_cast<struct sockaddr_in*>(
                   accept_address)->sin_addr.s_addr);
           char ipBuffer[32];
           sprintf(ipBuffer, "%u.%u.%u.%u", sa[0], sa[1], sa[2], sa[3]);
           ipAddress = ipBuffer;
   #endif
    }    }
  
       delete accept_address;
   
   // set the close on exec flag
   #if !defined(PEGASUS_OS_TYPE_WINDOWS) && !defined(PEGASUS_OS_VMS)
       int sock_flags;
       if ((sock_flags = fcntl(socket, F_GETFD, 0)) < 0)
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor: fcntl(F_GETFD) failed");
       }
       else
       {
           sock_flags |= FD_CLOEXEC;
           if (fcntl(socket, F_SETFD, sock_flags) < 0)
           {
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                   "HTTPAcceptor: fcntl(F_SETFD) failed");
           }
       }
 #endif #endif
    // Create a new conection and add it to the connection list:  
  
    MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);  
    if (mp_socket->accept() < 0)      PEG_LOGGER_TRACE((Logger::STANDARD_LOG, System::CIMSERVER, 0,
           "HTTPAcceptor - accept() success.  Socket: $1" ,socket));
   
       AutoPtr<MP_Socket> mp_socket(new MP_Socket(
           socket, _sslcontext, _sslContextObjectLock));
   
       mp_socket->disableBlocking();
       mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
   
       // Perform the SSL handshake, if applicable.
   
       Sint32 socketAcceptStatus = mp_socket->accept();
   
       if (socketAcceptStatus < 0)
    {    {
        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
                         "HTTPAcceptor: SSL_accept() failed");                         "HTTPAcceptor: SSL_accept() failed");
           mp_socket->close();
       return;       return;
    }    }
  
    HTTPConnection* connection = new HTTPConnection(      // Create a new connection and add it to the connection list:
       _monitor, mp_socket, this, static_cast<MessageQueue *>(_outputMessageQueue));  
       HTTPConnection* connection = new HTTPConnection(_monitor, mp_socket,
           ipAddress, this, static_cast<MessageQueue *>(_outputMessageQueue));
   
       if (_idleConnectionTimeoutSeconds)
       {
           connection->_idleConnectionTimeoutSeconds =
               _idleConnectionTimeoutSeconds;
           Time::gettimeofday(&connection->_idleStartTime);
       }
   
       if (socketAcceptStatus == 0)
       {
           PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL2,
               "HTTPAcceptor: SSL_accept() pending");
           connection->_acceptPending = true;
           Time::gettimeofday(&connection->_acceptPendingStartTime);
       }
  
    // Solicit events on this new connection's socket:    // Solicit events on this new connection's socket:
    int index;    int index;
  
    if (! (index = _monitor->solicitSocketMessages(      if (-1 ==  (index = _monitor->solicitSocketMessages(
           socket,              connection->getSocket(),
           SocketMessage::READ | SocketMessage::EXCEPTION,           SocketMessage::READ | SocketMessage::EXCEPTION,
           connection->getQueueId(), Monitor::CONNECTION)) )           connection->getQueueId(), Monitor::CONNECTION)) )
    {    {
           // ATTN-DE-P2-2003100503::TODO::Need to enhance code to return
           // an error message to Client application.
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL2,
               "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
                   "_entries table failed.");
       delete connection;       delete connection;
       Socket::close(socket);       Socket::close(socket);
           return;
    }    }
  
    // Save the socket for cleanup later:    // Save the socket for cleanup later:
    connection->_entry_index = index;    connection->_entry_index = index;
    _rep->_connection_mut.lock(pegasus_thread_self());      AutoMutex autoMut(_rep->_connection_mut);
    _rep->connections.append(connection);    _rep->connections.append(connection);
    _rep->_connection_mut.unlock();  
    PEGASUS_STD(cout) << "Creating new HTTP Connection; Current Connection Table Size: " <<  
    _rep->connections.size() << " entries" << endl;  
   
 } }
  
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END


Legend:
Removed from v.1.24.2.2  
changed lines
  Added in v.1.93.4.5

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2