(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.20 and 1.135

version 1.20, 2002/06/01 00:56:32 version 1.135, 2012/12/13 14:38:55
Line 1 
Line 1 
 //%/////////////////////////////////////////////////////////////////////////////  //%LICENSE////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Company, IBM,  // Licensed to The Open Group (TOG) under one or more contributor license
 // The Open Group, Tivoli Systems  // agreements.  Refer to the OpenPegasusNOTICE.txt file distributed with
   // this work for additional information regarding copyright ownership.
   // Each contributor licenses this file to you under the OpenPegasus Open
   // Source License; you may not use this file except in compliance with the
   // License.
   //
   // Permission is hereby granted, free of charge, to any person obtaining a
   // copy of this software and associated documentation files (the "Software"),
   // to deal in the Software without restriction, including without limitation
   // the rights to use, copy, modify, merge, publish, distribute, sublicense,
   // and/or sell copies of the Software, and to permit persons to whom the
   // Software is furnished to do so, subject to the following conditions:
   //
   // The above copyright notice and this permission notice shall be included
   // in all copies or substantial portions of the Software.
   //
   // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
   // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy  //////////////////////////////////////////////////////////////////////////
 // of this software and associated documentation files (the "Software"), to  
 // deal in the Software without restriction, including without limitation the  
 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  
 // sell copies of the Software, and to permit persons to whom the Software is  
 // furnished to do so, subject to the following conditions:  
 //  
 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN  
 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED  
 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT  
 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR  
 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT  
 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN  
 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
 //  
 //==============================================================================  
 //  
 // 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_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 _maxConnectionQueueLength = -1;
   
   Uint32 HTTPAcceptor::_socketWriteTimeout =
       PEGASUS_DEFAULT_SOCKETWRITE_TIMEOUT_SECONDS;
   
   #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
   Mutex HTTPAcceptor::_socketWriteTimeoutMutex;
   #endif
   
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
 // //
 // HTTPAcceptorRep // HTTPAcceptorRep
 // //
 //////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
  
 struct HTTPAcceptorRep  class HTTPAcceptorRep
   {
   public:
       HTTPAcceptorRep(Uint16 connectionType)
 { {
 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET          if (connectionType == HTTPAcceptor::LOCAL_CONNECTION)
       struct sockaddr_un address;          {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               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
       Sint32 socket;          }
   #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()
       {
           closeSocket();
           delete address;
       }
   
       void closeSocket()
       {
           Socket::close(socket);
       }
   
       struct sockaddr* address;
   
       SocketLength address_size;
       Mutex _connection_mut;
   
       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)                             Uint32 portNumber,
                              SSLContext * sslcontext,
                              ReadWriteSem* sslContextObjectLock,
                              HostAddress *listenOn)
      : Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),  // ATTN: Need unique names?
        _monitor(monitor),
        _outputMessageQueue(outputMessageQueue),
        _rep(0),
        _entry_index(-1),
        _connectionType(connectionType),
        _portNumber(portNumber),
        _sslcontext(sslcontext),
       _sslContextObjectLock(sslContextObjectLock),
       _listenAddress(listenOn)
 { {
      PEGASUS_ASSERT(!_sslcontext == !_sslContextObjectLock);
    Socket::initializeInterface();    Socket::initializeInterface();
 }  
  
 HTTPAcceptor::HTTPAcceptor(Monitor* monitor, MessageQueue* outputMessageQueue,     /*
                            SSLContext * sslcontext)          Platforms interpret the value of _maxConnectionQueueLength
    :       Base(PEGASUS_QUEUENAME_HTTPACCEPTOR),          differently.  Some platforms interpret the value literally, while
            _monitor(monitor), _outputMessageQueue(outputMessageQueue),          others multiply a fudge factor. When the server is under stress from
            _rep(0),          multiple clients with multiple requests, toggling this number may
            _sslcontext(sslcontext)          prevent clients from being dropped.  Instead of hard coding the
           value, we allow an environment variable to be set which specifies a
           number greater than the maximum concurrent client connections
           possible.  If this environment var is not specified, then
           _maxConnectionQueueLength = 15.
      */
   
   //To engage runtime backlog queue length: uncomment the following block AND
   //comment out the line _maxConnectionQueueLength = 15
   
   /*
       if (_maxConnectionQueueLength == -1)
 { {
    Socket::initializeInterface();          const char* env = getenv("PEGASUS_MAX_BACKLOG_CONNECTION_QUEUE");
           if (!env)
           {
               _maxConnectionQueueLength = 15;
           }
           else
           {
               char* end = NULL;
               _maxConnectionQueueLength = strtol(env, &end, 10);
               if (*end)
                   _maxConnectionQueueLength = 15;
               cout << " _maxConnectionQueueLength = " <<
                   _maxConnectionQueueLength << endl;
           }
       }
   */
   #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()
 { {
       destroyConnections();
    unbind();    unbind();
       // ATTN: Is this correct in a multi-HTTPAcceptor server?
    Socket::uninitializeInterface();    Socket::uninitializeInterface();
 } }
  
Line 114 
Line 210 
    if (! message)    if (! message)
       return;       return;
  
       PEGASUS_ASSERT(_rep != 0);
    switch (message->getType())    switch (message->getType())
    {    {
       case SOCKET_MESSAGE:       case SOCKET_MESSAGE:
Line 121 
Line 218 
          SocketMessage* socketMessage = (SocketMessage*)message;          SocketMessage* socketMessage = (SocketMessage*)message;
  
          // If this is a connection request:          // If this is a connection request:
               PEGASUS_ASSERT(socketMessage->socket == _rep->socket);
   
               PEGASUS_ASSERT(socketMessage->events & SocketMessage::READ);
  
          if (socketMessage->socket == _rep->socket &&  
              socketMessage->events | SocketMessage::READ)  
          {  
             _acceptConnection();             _acceptConnection();
          }  
          else  
          {  
             // ATTN! this can't happen!  
          }  
  
          break;          break;
       }       }
  
       case CLOSE_CONNECTION_MESSAGE:       case CLOSE_CONNECTION_MESSAGE:
       {       {
          CloseConnectionMessage* closeConnectionMessage             CloseConnectionMessage* closeConnectionMessage =
             = (CloseConnectionMessage*)message;                 (CloseConnectionMessage*)message;
   
              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);
                while (connection->refcount.value()) { }  
                delete connection;                delete connection;
                break;                break;
             }             }
          }          }
   
              break;
       }       }
  
       default:       default:
       // ATTN: need unexpected message error!             PEGASUS_ASSERT(false);
       break;       break;
    };      }
  
    delete message;    delete message;
 } }
Line 168 
Line 263 
 void HTTPAcceptor::handleEnqueue() void HTTPAcceptor::handleEnqueue()
 { {
    Message* message = dequeue();    Message* message = dequeue();
   
    if (!message)  
       return;  
   
    handleEnqueue(message);    handleEnqueue(message);
   
 } }
  
 void HTTPAcceptor::bind(Uint32 portNumber)  void HTTPAcceptor::bind()
 { {
    if (_rep)    if (_rep)
       throw BindFailed("HTTPAcceptor already bound");      {
           MessageLoaderParms parms("Common.HTTPAcceptor.ALREADY_BOUND",
    _rep = new HTTPAcceptorRep;              "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()
 { {
   #ifdef PEGASUS_OS_PASE
       AutoPtr<PaseCcsid> ccsid;
   #endif
  
       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)
       {
   #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.
           //
   #ifdef PEGASUS_OS_PASE
           // PASE domain socket needs ccsid 819
           int orig_ccsid;
           orig_ccsid = _SETCCSID(-1);
           if (orig_ccsid == -1)
           {
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
                       "HTTPAcceptor::_bind: Can not get current PASE CCSID.");
               orig_ccsid = 1208;
           }
           ccsid.reset(new PaseCcsid(819, orig_ccsid));
   #endif
           if (System::exists(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
           {
               if (!System::removeFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH))
               {
                   throw CannotRemoveFile(PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
               }
           }
  
 #ifdef PEGASUS_LOCAL_DOMAIN_SOCKET          reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_family =
    _rep->address.sun_family = AF_UNIX;              AF_UNIX;
    strcpy(_rep->address.sun_path, "/var/opt/wbem/cimxml.socket");          strcpy(reinterpret_cast<struct sockaddr_un*>(_rep->address)->sun_path,
    ::unlink(_rep->address.sun_path);              PEGASUS_LOCAL_DOMAIN_SOCKET_PATH);
 #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 #endif
       }
   #ifdef PEGASUS_ENABLE_IPV6
       else if (_connectionType == IPV6_CONNECTION)
       {
           if(_listenAddress)
           {
               String hostAdd = _listenAddress->getHost();
               CString ip = hostAdd.getCString();
   
               struct sockaddr_in6 in6addr;
               memset(&in6addr, 0, sizeof(sockaddr_in6));
               if(_listenAddress ->isHostAddLinkLocal())
               {
                   HostAddress::convertTextToBinary(AF_INET6,
                   (const char*)ip,
                   &in6addr.sin6_addr);
                   reinterpret_cast<struct sockaddr_in6*>(
                       _rep->address)->sin6_addr = in6addr.sin6_addr;
                   reinterpret_cast<struct sockaddr_in6*>(
                       _rep->address)->sin6_scope_id =
                           _listenAddress->getScopeID();
               }
               else
               {
                   HostAddress::convertTextToBinary(AF_INET6,
                   (const char*)ip,
                   &in6addr.sin6_addr);
                   reinterpret_cast<struct sockaddr_in6*>(
                       _rep->address)->sin6_addr = in6addr.sin6_addr;
               }
           }
           else
           {
           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)
       {
           if(_listenAddress)
           {
               String hostAdd = _listenAddress->getHost();
               CString ip = hostAdd.getCString();
               struct sockaddr_in addrs;
               HostAddress::convertTextToBinary(
                   AF_INET,
                   (const char*)ip,
                   &addrs.sin_addr);
               reinterpret_cast<struct sockaddr_in*>(
                   _rep->address)->sin_addr.s_addr = addrs.sin_addr.s_addr;
           }
           else
           {
               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
       {
           PEGASUS_ASSERT(false);
       }
  
    // 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 BindFailed("Failed to create socket");          MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_CREATE_SOCKET",
               "Failed to create socket");
           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::LEVEL1,
               "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::LEVEL1,
                   "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
    // that we can rebind to a new socket using the same address when we    // that we can rebind to a new socket using the same address when we
Line 240 
Line 468 
    {    {
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailed("Failed to set socket option");          MessageLoaderParms parms("Common.HTTPAcceptor.FAILED_SET_SOCKET_OPTION",
               "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)
       {
           MessageLoaderParms parms(
               "Common.HTTPAcceptor.FAILED_BIND_SOCKET_DETAIL",
               "Failed to bind socket on port $0: $1.",
               _portNumber, PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS);
   
           delete _rep;
           _rep = 0;
           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),      // Change permissions on Linux local domain socket to allow writes by
               sizeof(_rep->address)) < 0)      // others.
       //
   #if !defined(PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET) && \
        (defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU) || \
         defined(PEGASUS_OS_ZOS) || \
         defined(PEGASUS_OS_PASE))
       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);              MessageLoaderParms parms(
                   "Common.HTTPAcceptor.FAILED_SET_LDS_FILE_OPTION",
                   "Failed to set permission on local domain socket $0: $1.",
                   PEGASUS_LOCAL_DOMAIN_SOCKET_PATH,
                   PEGASUS_SYSTEM_ERRORMSG_NLS );
   
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailed("Failed to bind socket");              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 _maxConnectionQueueLength = 15;
  
    if (listen(_rep->socket, MAX_CONNECTION_QUEUE_LENGTH) < 0)      if (::listen(_rep->socket, _maxConnectionQueueLength) < 0)
    {    {
       Socket::close(_rep->socket);          MessageLoaderParms parms(
               "Common.HTTPAcceptor.FAILED_LISTEN_SOCKET",
               "Failed to listen on socket $0: $1.",
               (int)_rep->socket,PEGASUS_SYSTEM_NETWORK_ERRORMSG_NLS );
   
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailed("Failed to bind socket");          throw BindFailedException(parms);
    }    }
  
    // Register to receive SocketMessages on this socket:    // Register to receive SocketMessages on this socket:
  
    if (!_monitor->solicitSocketMessages(      if (-1 == ( _entry_index = _monitor->solicitSocketMessages(
           _rep->socket,           _rep->socket,
           SocketMessage::READ | SocketMessage::EXCEPTION,  
           getQueueId(),           getQueueId(),
           Monitor::ACCEPTOR))              MonitorEntry::TYPE_ACCEPTOR)))
    {    {
       Socket::close(_rep->socket);  
       delete _rep;       delete _rep;
       _rep = 0;       _rep = 0;
       throw BindFailed("Failed to solicit socket messaeges");          MessageLoaderParms parms(
               "Common.HTTPAcceptor.FAILED_SOLICIT_SOCKET_MESSAGES",
               "Failed to solicit socket messaeges");
           throw BindFailedException(parms);
    }    }
 } }
  
Line 291 
Line 574 
    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);          _rep->closeSocket();
           // Unlink Local Domain Socket Bug# 3312
           if (_connectionType == LOCAL_CONNECTION)
           {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
                   "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_HTTP, Tracer::LEVEL2,
               "HTTPAcceptor::closeConnectionSocket failure _rep is null.");
    }    }
 } }
  
Line 307 
Line 611 
    {    {
       _bind();       _bind();
    }    }
       else
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
               "HTTPAcceptor::reopenConnectionSocket failure _rep is null.");
       }
 } }
  
   
 /** /**
    getOutstandingRequestCount - returns the number of outstanding requests.     reconnectConnectionSocket - creates a new server socket.
 */ */
 Uint32 HTTPAcceptor::getOutstandingRequestCount()  void HTTPAcceptor::reconnectConnectionSocket()
 { {
    if (_rep->connections.size() > 0)      if (_rep)
    {    {
       HTTPConnection* connection = _rep->connections[0];          // unregister the socket
       return(connection->getRequestCount());          _monitor->unsolicitSocketMessages(_rep->socket);
           // close the socket
           _rep->closeSocket();
           // Unlink Local Domain Socket
           if (_connectionType == LOCAL_CONNECTION)
           {
   #ifndef PEGASUS_DISABLE_LOCAL_DOMAIN_SOCKET
               PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL3,
                   "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    else
    {    {
       return(0);          PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
               "HTTPAcceptor::reconnectConnectionSocket failure _rep is null.");
    }    }
 } }
  
   /**
       getOutstandingRequestCount - returns the number of outstanding requests.
   */
   Uint32 HTTPAcceptor::getOutstandingRequestCount() const
   {
       Uint32 count = 0;
       if (_rep)
       {
           AutoMutex autoMut(_rep->_connection_mut);
           for (Uint32 i = 0, n = _rep->connections.size(); i < n; i++)
           {
               HTTPConnection* connection = _rep->connections[i];
               if (connection->isResponsePending())
               {
                   count++;
               }
           }
       }
       return count;
   }
   
   
   /**
       getPortNumber - returns the port number used for the connection
   */
   Uint32 HTTPAcceptor::getPortNumber() const
   {
       return _portNumber;
   }
   
   void HTTPAcceptor::setSocketWriteTimeout(Uint32 socketWriteTimeout)
   {
   #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
       AutoMutex lock(_socketWriteTimeoutMutex);
   #endif
       _socketWriteTimeout = socketWriteTimeout;
   }
   
 void HTTPAcceptor::unbind() void HTTPAcceptor::unbind()
 { {
    if (_rep)    if (_rep)
    {    {
       Socket::close(_rep->socket);          _portNumber = 0;
           _rep->closeSocket();
   
           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_HTTP, Tracer::LEVEL1,
               "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:
  
           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 350 
Line 738 
  
       // 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();
 } }
   }
  
 void HTTPAcceptor::_acceptConnection() void HTTPAcceptor::_acceptConnection()
 { {
Line 363 
Line 752 
  
    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
       }
 #if defined(PEGASUS_PLATFORM_LINUX_IX86_GNU) || defined(PEGASUS_PLATFORM_LINUX_GENERIC_GNU)      else
    Sint32 socket = accept(      {
       _rep->socket, (struct sockaddr*)&address, (socklen_t *)&n);  #ifdef PEGASUS_ENABLE_IPV6
           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
       }
  
    if (socket < 0)      // 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.
   
       SocketHandle socket = accept(_rep->socket, accept_address, &address_size);
   
       if (socket == PEGASUS_SOCKET_ERROR)
    {    {
        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,          // the remote connection is invalid, destroy client address.
                         "HTTPAcceptor: accept() failed");          delete accept_address;
   
           // TCPIP is down reconnect this acceptor
           if (getSocketError() == PEGASUS_NETWORK_TCPIP_STOPPED)
           {
               PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
                   "Socket has an IO error. TCP/IP down. Try to reconnect.");
   
               reconnectConnectionSocket();
   
               return;
           }
           PEG_TRACE((
               TRC_DISCARDED_DATA,
               Tracer::LEVEL1,
               "HTTPAcceptor: accept() failed.  errno: %u",
               errno));
       return;       return;
    }    }
  
    // Create a new conection and add it to the connection list:      // Use an AutoPtr to ensure the socket handle is closed on exception
       AutoPtr<SocketHandle, CloseSocketHandle> socketPtr(&socket);
  
    MP_Socket * mp_socket = new MP_Socket(socket, _sslcontext);  #ifndef PEGASUS_OS_TYPE_WINDOWS
    if (mp_socket->accept() < 0)      // We need to ensure that the socket number is not higher than
       // 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;
   
           PEG_TRACE(
               (TRC_DISCARDED_DATA,
                Tracer::LEVEL1,
                "HTTPAcceptor out of available sockets."
                    "accept() returned too large socket number %u."
                    "Closing connection to the new client.",
                socket));
   
           return;
       }
   #endif
   
       String ipAddress;
   
       if (_connectionType == LOCAL_CONNECTION)
       {
           ipAddress = "localhost";
       }
       else
       {
   #ifdef PEGASUS_ENABLE_IPV6
           char ipBuffer[PEGASUS_INET6_ADDRSTR_LEN];
           if (System::getNameInfo(accept_address,
                   address_size,
                   ipBuffer,
                   PEGASUS_INET6_ADDRSTR_LEN,
                   0,
                   0,
                   NI_NUMERICHOST))
    {    {
        PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2,              delete accept_address;
               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::LEVEL1,
               "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::LEVEL1,
                   "HTTPAcceptor: fcntl(F_SETFD) failed");
           }
       }
   #endif
   
   
       PEG_TRACE((
           TRC_HTTP,
           Tracer::LEVEL3,
           "HTTPAcceptor - accept() success.  Socket: %u",
           socket));
   
       SharedPtr<MP_Socket> mp_socket(new MP_Socket(
           socket, _sslcontext, _sslContextObjectLock, ipAddress));
       // mp_socket now has responsibility for closing the socket handle
       socketPtr.release();
   
       mp_socket->disableBlocking();
   
       {
   #ifndef PEGASUS_INTEGERS_BOUNDARY_ALIGNED
           AutoMutex lock(_socketWriteTimeoutMutex);
   #endif
           mp_socket->setSocketWriteTimeout(_socketWriteTimeout);
       }
   
       // Perform the SSL handshake, if applicable.
   
       Sint32 socketAcceptStatus = mp_socket->accept();
   
       if (socketAcceptStatus < 0)
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
                         "HTTPAcceptor: SSL_accept() failed");                         "HTTPAcceptor: SSL_accept() failed");
       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));  
  
    // Solicit events on this new connection's socket:      AutoPtr<HTTPConnection> connection(new HTTPConnection(
           _monitor,
           mp_socket,
           ipAddress,
           this,
           _outputMessageQueue));
  
    if (!_monitor->solicitSocketMessages(      if (HTTPConnection::getIdleConnectionTimeout())
           socket,  
           SocketMessage::READ | SocketMessage::EXCEPTION,  
           connection->getQueueId(), Monitor::CONNECTION))  
    {    {
       delete connection;          Time::gettimeofday(&connection->_idleStartTime);
       Socket::close(socket);      }
   
       if (socketAcceptStatus == 0)
       {
           PEG_TRACE_CSTRING(TRC_HTTP, Tracer::LEVEL1,
               "HTTPAcceptor: SSL_accept() pending");
           connection->_acceptPending = true;
           Time::gettimeofday(&connection->_acceptPendingStartTime);
    }    }
  
    // Save the socket for cleanup later:      // Solicit events on this new connection's socket:
       int index;
   
       if (-1 ==  (index = _monitor->solicitSocketMessages(
               connection->getSocket(),
               connection->getQueueId(), MonitorEntry::TYPE_CONNECTION)) )
       {
           PEG_TRACE_CSTRING(TRC_DISCARDED_DATA, Tracer::LEVEL1,
               "HTTPAcceptor::_acceptConnection: Attempt to allocate entry in "
                   "_entries table failed.");
           return;
       }
  
    _rep->connections.append(connection);      connection->_entry_index = index;
       AutoMutex autoMut(_rep->_connection_mut);
       _rep->connections.append(connection.get());
       connection.release();
 } }
  
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END


Legend:
Removed from v.1.20  
changed lines
  Added in v.1.135

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2