OW_HTTPServer.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2001-2004 Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2004 Novell, Inc. All rights reserved.
00004 *
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 *
00008 *  - Redistributions of source code must retain the above copyright notice,
00009 *    this list of conditions and the following disclaimer.
00010 *
00011 *  - Redistributions in binary form must reproduce the above copyright notice,
00012 *    this list of conditions and the following disclaimer in the documentation
00013 *    and/or other materials provided with the distribution.
00014 *
00015 *  - Neither the name of Vintela, Inc., Novell, Inc. nor the names of its
00016 *    contributors may be used to endorse or promote products derived from this
00017 *    software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00023 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029 * POSSIBILITY OF SUCH DAMAGE.
00030 *******************************************************************************/
00031 
00037 #include "OW_config.h"
00038 #include "OW_HTTPServer.hpp"
00039 #include "OW_HTTPSvrConnection.hpp"
00040 #include "OW_ServerSocket.hpp"
00041 #include "OW_IOException.hpp"
00042 #include "OW_Socket.hpp"
00043 #include "OW_Format.hpp"
00044 #include "OW_SelectableIFC.hpp"
00045 #include "OW_Assertion.hpp"
00046 #include "OW_ConfigOpts.hpp"
00047 #include "OW_HTTPUtils.hpp"
00048 #ifndef OW_DISABLE_DIGEST
00049 #include "OW_DigestAuthentication.hpp"
00050 #endif
00051 #include "OW_CIMOMHandleIFC.hpp"
00052 #include "OW_SocketBaseImpl.hpp" // for setDumpFiles()
00053 #include "OW_Runnable.hpp"
00054 #include "OW_ThreadCancelledException.hpp"
00055 #include "OW_ThreadPool.hpp"
00056 #include "OW_ExceptionIds.hpp"
00057 #ifndef OW_WIN32
00058 #include "OW_UnnamedPipe.hpp"
00059 #include "OW_LocalAuthentication.hpp"
00060 #endif
00061 #include "OW_SSLException.hpp"
00062 #include "OW_SSLCtxMgr.hpp"
00063 #include "OW_AuthenticationException.hpp"
00064 #include "OW_OperationContext.hpp"
00065 #include "OW_ServiceIFCNames.hpp"
00066 #include "OW_Thread.hpp" // for ThreadException
00067 
00068 namespace OW_NAMESPACE
00069 {
00070 
00071 OW_DEFINE_EXCEPTION_WITH_ID(HTTPServer)
00072 
00073 namespace
00074 {
00075    const String COMPONENT_NAME("ow.httpserver");
00076 
00077 #ifdef OW_HAVE_OPENSSL
00078    class X509Freer
00079    {
00080    public:
00081       X509Freer(X509* x509)
00082          : m_x509(x509)
00083       {
00084       }
00085       ~X509Freer()
00086       {
00087          if (m_x509 != 0)
00088          {
00089             X509_free(m_x509);
00090          }
00091       }
00092    private:
00093       X509* m_x509;
00094    };
00095 #endif
00096 
00097 }
00098 
00100 HTTPServer::HTTPServer()
00101 #ifdef OW_WIN32
00102    : m_event(NULL)
00103 #else
00104    : m_upipe(UnnamedPipe::createUnnamedPipe())
00105 #endif
00106    , m_allowAllUsers(false)
00107    , m_sslCtx(0)
00108    , m_shuttingDown(false)
00109 #ifndef OW_NO_SSL
00110    , m_trustStore(0)
00111 #endif
00112 {
00113 #ifdef OW_WIN32
00114    m_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00115 #else
00116    m_upipe->setBlocking(UnnamedPipe::E_NONBLOCKING);
00117 #endif
00118 }
00120 HTTPServer::~HTTPServer()
00121 {
00122 }
00123 
00124 
00126 String
00127 HTTPServer::getName() const
00128 {
00129    return ServiceIFCNames::HTTPServer;
00130 }
00131 
00133 StringArray
00134 HTTPServer::getDependencies() const
00135 {
00136    StringArray rv;
00137    rv.push_back(ServiceIFCNames::CIMServer);
00138    rv.push_back(ServiceIFCNames::AuthManager);
00139    return rv;
00140 }
00141 
00143 bool HTTPServer::isAllowedUser(const String& user) const
00144 {
00145    return m_allowedUsers.count(user) != 0 || m_allowAllUsers;
00146 }
00147 
00149 bool
00150 HTTPServer::authenticate(HTTPSvrConnection* pconn,
00151    String& userName, const String& info, OperationContext& context,
00152    const Socket& socket)
00153 {
00154    MutexLock lock(m_authGuard);
00155    String scheme; 
00156    if (!info.empty())
00157    {
00158       scheme = info.tokenize()[0]; 
00159       scheme.toLowerCase(); 
00160    }
00161 
00162    
00163    // user supplied creds.  Find out what type of auth they're using.  We currently support Basic, Digest & OWLocal
00164 #ifndef OW_WIN32
00165    if (m_options.allowLocalAuthentication && scheme.equals("owlocal"))
00166    {
00167       OW_LOG_DEBUG(getEnvironment()->getLogger(COMPONENT_NAME), "HTTPServer::authenticate: processing OWLocal");
00168       bool rv = m_localAuthentication->authenticate(userName, info, pconn) && isAllowedUser(userName);
00169       if (rv)
00170       {
00171          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authenticated %1", userName));
00172       }
00173       else
00174       {
00175          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authentication failed for: %1", userName));
00176       }
00177       return rv;
00178    }
00179 #endif
00180 
00181 #ifndef OW_NO_SSL
00182    if (m_sslopts.verifyMode != SSLOpts::MODE_DISABLED)
00183    {
00184       if (socket.peerCertVerified())
00185       {
00186          SSL* ssl = socket.getSSL();
00187          OW_ASSERT(ssl);
00188          X509* cert = SSL_get_peer_certificate(ssl);
00189          OW_ASSERT(cert);
00190          X509Freer x509Freer(cert);
00191          String hash = SSLTrustStore::getCertMD5Fingerprint(cert);
00192          String uid;
00193          if (!m_trustStore->getUser(hash, userName, uid))
00194          {
00195             OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authentication failed for: %1.  (Cert verified, but unknown user)", userName));
00196             return false;
00197          }
00198          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authenticated %1", userName));
00199          if (!uid.empty())
00200          {
00201             context.setStringData(OperationContext::CURUSER_UIDKEY, uid);
00202          }
00203          return true;
00204       }
00205    }
00206 #endif
00207    bool rv = false;
00208    if (m_options.allowDigestAuthentication && scheme.equals("digest"))
00209    {
00210 #ifndef OW_DISABLE_DIGEST
00211       OW_LOG_DEBUG(getEnvironment()->getLogger(COMPONENT_NAME), "HTTPServer::authenticate: processing Digest");
00212       rv = m_digestAuthentication->authenticate(userName, info, pconn) && isAllowedUser(userName);
00213       if (rv)
00214       {
00215          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authenticated %1", userName));
00216       }
00217       else
00218       {
00219          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authentication failed for: %1", userName));
00220       }
00221 #endif
00222    }
00223    else if (m_options.allowBasicAuthentication && scheme.equals("basic"))
00224    {
00225       OW_LOG_DEBUG(getEnvironment()->getLogger(COMPONENT_NAME), "HTTPServer::authenticate: processing Basic");
00226       String authChallenge = "Basic realm=\"" + pconn->getHostName() + "\"";
00227       String password;
00228       // info is a username:password string that is base64 encoded. decode it.
00229       try
00230       {
00231          HTTPUtils::decodeBasicCreds(info, userName, password);
00232       }
00233       catch (const AuthenticationException& e)
00234       {
00235          // decoding failed
00236          pconn->setErrorDetails("Problem decoding credentials");
00237          pconn->addHeader("WWW-Authenticate", authChallenge);
00238          OW_LOG_DEBUG(getEnvironment()->getLogger(COMPONENT_NAME), "HTTPServer::authenticate: Problem decoding credentials");
00239          return false;
00240       }
00241       String details;
00242       rv = m_options.env->authenticate(userName, password, details, context) && isAllowedUser(userName);
00243       if (!rv)
00244       {
00245          pconn->setErrorDetails(details);
00246          pconn->addHeader("WWW-Authenticate", authChallenge);
00247          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: failed: %1", details));
00248       }
00249       else
00250       {
00251          OW_LOG_INFO(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: authenticated %1", userName));
00252       }
00253    }
00254    else
00255    {
00256       // We don't handle whatever they sent, so send the default challenge
00257       String hostname = pconn->getHostName();
00258       pconn->setErrorDetails("You must authenticate to access this"
00259          " resource");
00260       String authChallenge;
00261       switch (m_options.defaultAuthChallenge)
00262       {
00263 #ifndef OW_DISABLE_DIGEST
00264          case E_DIGEST:
00265             authChallenge = m_digestAuthentication->getChallenge(hostname);
00266             break;
00267 #endif
00268          case E_BASIC:
00269             authChallenge = "Basic realm=\"" + pconn->getHostName() + "\"";
00270             break;
00271 
00272          default:
00273             OW_ASSERT("Internal implementation error! m_options.defaultAuthChallenge is invalid!" == 0);
00274       }
00275       OW_LOG_DEBUG(getEnvironment()->getLogger(COMPONENT_NAME), Format("HTTPServer::authenticate: Returning WWW-Authenticate: %1", authChallenge));
00276       pconn->addHeader("WWW-Authenticate", authChallenge);
00277       return false;
00278    }
00279 
00280 #ifndef OW_NO_SSL
00281    if (rv && m_sslopts.verifyMode == SSLOpts::MODE_AUTOUPDATE)
00282    {
00283       SSL* ssl = socket.getSSL();
00284       if (ssl)
00285       {
00286          X509* cert = SSL_get_peer_certificate(ssl);
00287          if (cert)
00288          {
00289             X509Freer x509Freer(cert);
00290             try
00291             {
00292                String uid = context.getStringDataWithDefault(OperationContext::CURUSER_UIDKEY);
00293                m_trustStore->addCertificate(cert, userName, uid);
00294             }
00295             catch (SSLException& e)
00296             {
00297                OW_LOG_ERROR(getEnvironment()->getLogger(COMPONENT_NAME), e.getMessage());
00298             }
00299          }
00300       }
00301    }
00302 #endif
00303    return rv;
00304 }
00305 
00307 void
00308 HTTPServer::init(const ServiceEnvironmentIFCRef& env)
00309 {
00310    try
00311    {
00312       String item = env->getConfigItem(ConfigOpts::HTTP_SERVER_HTTP_PORT_opt, OW_DEFAULT_HTTP_SERVER_HTTP_PORT);
00313       m_options.httpPort = item.toInt32();
00314       
00315       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_HTTPS_PORT_opt, OW_DEFAULT_HTTP_SERVER_HTTPS_PORT);
00316       m_options.httpsPort = item.toInt32();
00317 
00318       m_options.defaultContentLanguage = env->getConfigItem(
00319          ConfigOpts::HTTP_SERVER_DEFAULT_CONTENT_LANGUAGE_opt, OW_DEFAULT_HTTP_SERVER_DEFAULT_CONTENT_LANGUAGE);
00320    
00321 #ifndef OW_WIN32
00322       m_options.UDSFilename = env->getConfigItem(ConfigOpts::HTTP_SERVER_UDS_FILENAME_opt, OW_DEFAULT_HTTP_SERVER_UDS_FILENAME);
00323 #endif
00324       
00325       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_USE_UDS_opt, OW_DEFAULT_HTTP_SERVER_USE_UDS);
00326       m_options.useUDS = item.equalsIgnoreCase("true");
00327       
00328       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_MAX_CONNECTIONS_opt, OW_DEFAULT_HTTP_SERVER_MAX_CONNECTIONS);
00329       m_options.maxConnections = item.toInt32();
00330       // TODO: Make the type of pool and the size of the queue be separate config options.
00331       m_threadPool = ThreadPoolRef(new ThreadPool(ThreadPool::DYNAMIC_SIZE, m_options.maxConnections, m_options.maxConnections * 100, env->getLogger(COMPONENT_NAME), "HTTPServer"));
00332       
00333       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_SINGLE_THREAD_opt, OW_DEFAULT_HTTP_SERVER_SINGLE_THREAD);
00334       m_options.isSepThread = !item.equalsIgnoreCase("true");
00335       
00336       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_ENABLE_DEFLATE_opt, OW_DEFAULT_HTTP_SERVER_ENABLE_DEFLATE);
00337       m_options.enableDeflate = !item.equalsIgnoreCase("false");
00338       
00339       item = env->getConfigItem(ConfigOpts::ALLOW_ANONYMOUS_opt, OW_DEFAULT_ALLOW_ANONYMOUS);
00340       m_options.allowAnonymous = item.equalsIgnoreCase("true");
00341       m_options.env = env;
00342       
00343       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_USE_DIGEST_opt, OW_DEFAULT_HTTP_SERVER_USE_DIGEST);
00344       m_options.allowDigestAuthentication = !item.equalsIgnoreCase("false");
00345       if (m_options.allowDigestAuthentication)
00346       {
00347 #ifndef OW_DISABLE_DIGEST
00348          String passwdFile = env->getConfigItem(
00349             ConfigOpts::HTTP_SERVER_DIGEST_PASSWORD_FILE_opt, OW_DEFAULT_HTTP_SERVER_DIGEST_PASSWORD_FILE);
00350          m_digestAuthentication = IntrusiveReference<DigestAuthentication>(
00351             new DigestAuthentication(passwdFile));
00352          m_options.defaultAuthChallenge = E_DIGEST;
00353 #else
00354          OW_THROW(HTTPServerException, "Unable to initialize HTTP Server because"
00355             " digest is enabled in the config file, but the digest code has been disabled");
00356 #endif
00357       }
00358       else
00359       {
00360          // TODO: deprecate ConfigOpts::HTTP_USE_DIGEST_opt and create a new option for the default auth challenge
00361          // If OWLocal is desired for the default, set defaultAuthChallenge to E_OWLOCAL
00362          m_options.defaultAuthChallenge = E_BASIC;
00363       }
00364       // TODO: right now basic and digest are mutually exclusive because of the config file setup.
00365       // When possible deprecate the existing config items and make them independent.
00366       m_options.allowBasicAuthentication = !m_options.allowDigestAuthentication;
00367    
00368 #ifndef OW_WIN32
00369       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_ALLOW_LOCAL_AUTHENTICATION_opt, OW_DEFAULT_HTTP_SERVER_ALLOW_LOCAL_AUTHENTICATION);
00370       m_options.allowLocalAuthentication = !item.equalsIgnoreCase("false");
00371       if (m_options.allowLocalAuthentication)
00372       {
00373          m_localAuthentication = IntrusiveReference<LocalAuthentication>(
00374             new LocalAuthentication(env->getLogger(COMPONENT_NAME)));
00375       }
00376 #endif
00377 
00378       String dumpPrefix = env->getConfigItem(ConfigOpts::DUMP_SOCKET_IO_opt);
00379       if (!dumpPrefix.empty())
00380       {
00381          SocketBaseImpl::setDumpFiles(
00382             dumpPrefix + "/owHTTPSockDumpIn",
00383             dumpPrefix + "/owHTTPSockDumpOut");
00384       }
00385       
00386       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_REUSE_ADDR_opt, OW_DEFAULT_HTTP_SERVER_REUSE_ADDR);
00387       m_options.reuseAddr = !item.equalsIgnoreCase("false");
00388       
00389       item = env->getConfigItem(ConfigOpts::HTTP_SERVER_TIMEOUT_opt, OW_DEFAULT_HTTP_SERVER_TIMEOUT);
00390       m_options.timeout = item.toInt32();
00391 
00392       StringArray users = env->getMultiConfigItem(ConfigOpts::ALLOWED_USERS_opt, 
00393          String(OW_DEFAULT_ALLOWED_USERS).tokenize(" \t"),
00394          " \t");
00395       if (users.size() == 1 && users[0] == "*")
00396       {
00397          m_allowAllUsers = true;
00398       }
00399       else
00400       {
00401          m_allowAllUsers = false;
00402          m_allowedUsers.insert(users.begin(), users.end());
00403       }
00404    }
00405    catch (const StringConversionException& e)
00406    {
00407       OW_THROW(HTTPServerException, Format("Unable to initialize HTTP Server because"
00408          " of invalid config item. %1", e.getMessage()).c_str());
00409    }
00410 }
00412 class HTTPServerSelectableCallback : public SelectableCallbackIFC
00413 {
00414 public:
00415    HTTPServerSelectableCallback(bool isHTTPS,
00416       HTTPServer* httpServer, bool isIPC)
00417       : SelectableCallbackIFC()
00418       , m_isHTTPS(isHTTPS)
00419       , m_HTTPServer(httpServer)
00420       , m_isIPC(isIPC)
00421    {
00422    }
00423    virtual ~HTTPServerSelectableCallback() {}
00424    virtual void doSelected(SelectableIFCRef& selectedObject)
00425    {
00426       try
00427       {
00428          IntrusiveReference<ServerSocket> pServerSocket;
00429          if (m_isIPC)
00430          {
00431             pServerSocket = m_HTTPServer->m_pUDSServerSocket;
00432          }
00433          else if (m_isHTTPS)
00434          {
00435             pServerSocket = m_HTTPServer->m_pHttpsServerSocket;
00436          }
00437          else
00438          {
00439             pServerSocket = m_HTTPServer->m_pHttpServerSocket;
00440          }
00441          Socket socket = pServerSocket->accept(2);
00442          LoggerRef logger = m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME);
00443          OW_LOG_INFO(logger,
00444              Format("Received connection on %1 from %2",
00445              socket.getLocalAddress().toString(),
00446              socket.getPeerAddress().toString()));
00447          HTTPServer::Options newOpts = m_HTTPServer->m_options;
00448          if (m_isIPC)
00449          {
00450             newOpts.enableDeflate = false;
00451          }
00452 #ifdef OW_WIN32
00453          RunnableRef rref(new HTTPSvrConnection(socket,
00454              m_HTTPServer, m_HTTPServer->m_event, newOpts));
00455 #else
00456          RunnableRef rref(new HTTPSvrConnection(socket,
00457              m_HTTPServer, m_HTTPServer->m_upipe, newOpts));
00458 #endif
00459          if (!m_HTTPServer->m_threadPool->tryAddWork(rref))
00460          {
00461             OW_LOG_INFO(logger, "Server too busy, closing connection");
00462             // main thread can't block, set the socket timeout to 0
00463             socket.setTimeouts(0);
00464             std::ostream& socketOstr(socket.getOutputStream());
00465             socketOstr << "HTTP/1.1 503 Service unavailable: connection queue full\r\n";
00466             socketOstr << "Connection: close\r\n";
00467             socketOstr << "Content-Length: 0\r\n\r\n";
00468             socketOstr.flush();
00469             socket.disconnect();
00470          }
00471       }
00472       catch (SSLException& se)
00473       {
00474          OW_LOG_INFO(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME),
00475             Format("SSL Handshake failed: %1", se.getMessage()).c_str());
00476       }
00477       catch (SocketTimeoutException &e)
00478       {
00479          OW_LOG_INFO(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME), Format(
00480             "Socket TimeOut in HTTPServer: %1", e));
00481       }
00482       catch (SocketException &e)
00483       {
00484          OW_LOG_INFO(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME), Format(
00485             "Socket Exception in HTTPServer: %1", e));
00486       }
00487       catch (IOException &e)
00488       {
00489          OW_LOG_ERROR(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME), Format(
00490             "IO Exception in HTTPServer: %1", e));
00491       }
00492       catch (ThreadException& e)
00493       {
00494          OW_LOG_ERROR(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME), Format(
00495             "ThreadException in HTTPServer: %1", e));
00496       }
00497       catch (Exception& e)
00498       {
00499          OW_LOG_ERROR(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME), Format(
00500             "Exception in HTTPServer: %1", e));
00501          // since it's something we don't expect, it's probably a bad problem, and we'll
00502          // just throw.
00503          throw;
00504       }
00505       catch (ThreadCancelledException&)
00506       {
00507          throw;
00508       }
00509       catch (...)
00510       {
00511          OW_LOG_ERROR(m_HTTPServer->m_options.env->getLogger(COMPONENT_NAME),
00512             "Unknown exception in HTTPServer.");
00513          throw;
00514       }
00515    }
00516 private:
00517    bool m_isHTTPS;
00518    HTTPServer* m_HTTPServer;
00519    bool m_isIPC;
00520 };
00522 void
00523 HTTPServer::start()
00524 {
00525    ServiceEnvironmentIFCRef env = m_options.env;
00526    LoggerRef lgr = env->getLogger(COMPONENT_NAME);
00527    OW_LOG_DEBUG(lgr, "HTTP Service is starting...");
00528    if (m_options.httpPort < 0 && m_options.httpsPort < 0 && !m_options.useUDS)
00529    {
00530       OW_THROW(SocketException, "No ports to listen on and use_UDS set to false");
00531    }
00532 #ifndef OW_WIN32
00533    if (m_options.useUDS)
00534    {
00535       try
00536       {
00537          m_pUDSServerSocket = new ServerSocket;
00538          m_pUDSServerSocket->doListen(m_options.UDSFilename, 1000, m_options.reuseAddr);
00539          OW_LOG_INFO(lgr, "HTTP server listening on Unix Domain Socket");
00540          String theURL = "ipc://localhost/cimom";
00541          addURL(URL(theURL));
00542          
00543          SelectableCallbackIFCRef cb(new HTTPServerSelectableCallback(
00544             false, this, true));
00545          env->addSelectable(m_pUDSServerSocket, cb);
00546       }
00547       catch (SocketException& e)
00548       {
00549          OW_LOG_ERROR(lgr, Format("HTTP Server failed to listen on UDS: %1", e));
00550          throw;
00551       }
00552    }
00553 #endif
00554    StringArray listenAddresses = env->getMultiConfigItem(
00555       ConfigOpts::HTTP_SERVER_LISTEN_ADDRESSES_opt, 
00556       String(OW_DEFAULT_HTTP_SERVER_LISTEN_ADDRESSES).tokenize(" \t"),
00557       " \t");
00558 
00559    if (listenAddresses.empty())
00560    {
00561       OW_THROW(HTTPServerException, "http_server.listen_addresses config item malformed");
00562    }
00563    for (size_t i = 0; i < listenAddresses.size(); ++i)
00564    {
00565       const String& curAddress = listenAddresses[i];
00566       if (m_options.httpPort >= 0)
00567       {
00568          try
00569          {
00570             UInt16 lport = static_cast<UInt16>(m_options.httpPort);
00571             m_pHttpServerSocket = new ServerSocket;
00572             m_pHttpServerSocket->doListen(lport,
00573                1000, curAddress,
00574                m_options.reuseAddr ? SocketFlags::E_REUSE_ADDR : SocketFlags::E_DONT_REUSE_ADDR);
00575             m_options.httpPort = m_pHttpServerSocket->getLocalAddress().getPort();
00576             OW_LOG_INFO(lgr, Format("HTTP server listening on: %1:%2",
00577                curAddress, m_options.httpPort));
00578             String theURL = "http://" + SocketAddress::getAnyLocalHost().getName()
00579                + ":" + String(m_options.httpPort) + "/cimom";
00580             addURL(URL(theURL));
00581 
00582             SelectableCallbackIFCRef cb(new HTTPServerSelectableCallback(
00583                false, this, false));
00584             env->addSelectable(m_pHttpServerSocket, cb);
00585          }
00586          catch (SocketException& e)
00587          {
00588             OW_LOG_ERROR(lgr, Format("HTTP Server failed to listen on: %1:%2.  Msg: %3", curAddress, m_options.httpPort, e));
00589             throw;
00590          }
00591       }
00592       if (m_options.httpsPort >= 0)
00593       {
00594 #ifdef OW_NO_SSL
00595          if (m_options.httpPort < 0 && !m_options.useUDS)
00596          {
00597             OW_THROW(HTTPServerException, "No ports to listen on.  "
00598                   "SSL unavailable (OpenWBEM not built with SSL support) "
00599                   "and no http port defined.");
00600          }
00601          else
00602          {
00603             String msg = Format("Unable to listen on %1:%2.  "
00604                   "OpenWBEM not built with SSL support.", curAddress, m_options.httpsPort);
00605             OW_LOG_ERROR(lgr, msg);
00606             OW_THROW(HTTPServerException, msg.c_str());
00607          }
00608 #else
00609          try
00610          {
00611             m_sslopts.certfile = env->getConfigItem(ConfigOpts::HTTP_SERVER_SSL_CERT_opt);
00612             m_sslopts.keyfile = env->getConfigItem(ConfigOpts::HTTP_SERVER_SSL_KEY_opt);
00613             if (m_sslopts.keyfile.empty())
00614             {
00615                m_sslopts.keyfile = m_sslopts.certfile;
00616             }
00617             m_sslopts.trustStore = env->getConfigItem(ConfigOpts::HTTP_SERVER_SSL_TRUST_STORE,
00618                                           OW_DEFAULT_HTTP_SERVER_SSL_TRUST_STORE);
00619             String verifyMode = env->getConfigItem(ConfigOpts::HTTP_SERVER_SSL_CLIENT_VERIFICATION_opt,
00620                                           OW_DEFAULT_HTTP_SERVER_SSL_CLIENT_VERIFICATION);
00621             verifyMode.toLowerCase();
00622             if (verifyMode == "disabled")
00623             {
00624                m_sslopts.verifyMode = SSLOpts::MODE_DISABLED;
00625             }
00626             else if (verifyMode == "optional")
00627             {
00628                m_sslopts.verifyMode = SSLOpts::MODE_OPTIONAL;
00629             }
00630             else if (verifyMode == "required")
00631             {
00632                m_sslopts.verifyMode = SSLOpts::MODE_REQUIRED;
00633             }
00634             else if (verifyMode == "autoupdate")
00635             {
00636                m_sslopts.verifyMode = SSLOpts::MODE_AUTOUPDATE;
00637             }
00638             else
00639             {
00640                OW_THROW(HTTPServerException, Format("Bad value (%1) for configuration item %2",
00641                                            verifyMode,
00642                                            ConfigOpts::HTTP_SERVER_SSL_CLIENT_VERIFICATION_opt).c_str());
00643             }
00644             //SSLCtxMgr::initServer(certfile, keyfile);
00645             m_sslCtx = SSLServerCtxRef(new SSLServerCtx(m_sslopts));
00646             if (m_sslopts.verifyMode != SSLOpts::MODE_DISABLED)
00647             {
00648                m_trustStore = SSLTrustStoreRef(new SSLTrustStore(m_sslopts.trustStore));
00649             }
00650          }
00651          catch (SSLException& e)
00652          {
00653             OW_LOG_ERROR(lgr, Format("HTTP Service: Error initializing SSL: %1",
00654                e.getMessage()));
00655             throw;
00656          }
00657 
00658          UInt16 lport = static_cast<UInt16>(m_options.httpsPort);
00659          //if (SSLCtxMgr::isServer())
00660          if (m_sslCtx)
00661          {
00662             try
00663             {
00664                m_pHttpsServerSocket = new ServerSocket(m_sslCtx);
00665                m_pHttpsServerSocket->doListen(lport,
00666                   1000, curAddress,
00667                   m_options.reuseAddr ? SocketFlags::E_REUSE_ADDR : SocketFlags::E_DONT_REUSE_ADDR);
00668                m_options.httpsPort =
00669                   m_pHttpsServerSocket->getLocalAddress().getPort();
00670                OW_LOG_INFO(lgr, Format("HTTPS server listening on: %1:%2",
00671                   curAddress, m_options.httpsPort));
00672                String theURL = "https://" +
00673                   SocketAddress::getAnyLocalHost().getName() + ":" +
00674                   String(m_options.httpsPort) + "/cimom";
00675                addURL(URL(theURL));
00676                SelectableCallbackIFCRef cb(new HTTPServerSelectableCallback(
00677                   true, this, false));
00678                env->addSelectable(m_pHttpsServerSocket, cb);
00679             }
00680             catch (SocketException& e)
00681             {
00682                OW_LOG_ERROR(lgr, Format("HTTP Server failed to listen on: %1:%2.  Msg: %3", curAddress, m_options.httpPort, e));
00683                throw;
00684             }
00685          }
00686          else
00687 #endif // #ifndef OW_NO_SSL
00688          {
00689             if (m_options.httpPort < 0 && !m_options.useUDS)
00690             {
00691                OW_THROW(HTTPServerException, "No ports to listen on.  "
00692                   "SSL unavailable (SSL not initialized in server mode) "
00693                   "and no http port defined.");
00694             }
00695             String msg = Format("Unable to listen on: %1:%2.  "
00696                "SSL not initialized in server mode.", curAddress, m_options.httpsPort);
00697             OW_LOG_ERROR(lgr, msg);
00698             OW_THROW(HTTPServerException, msg.c_str());
00699 
00700          }
00701       } // if (m_httpsPort > 0)
00702    }
00703    OW_LOG_DEBUG(lgr, "HTTP Service has started");
00704 }
00706 void
00707 HTTPServer::addURL(const URL& url)
00708 {
00709    m_urls.push_back(url);
00710 }
00712 Array<URL>
00713 HTTPServer::getURLs() const
00714 {
00715    return m_urls;
00716 }
00718 SocketAddress
00719 HTTPServer::getLocalHTTPAddress()
00720 {
00721    if (m_pHttpServerSocket)
00722    {
00723       return m_pHttpServerSocket->getLocalAddress();
00724    }
00725    else
00726    {
00727       return SocketAddress::allocEmptyAddress(SocketAddress::INET);
00728    }
00729 }
00731 SocketAddress
00732 HTTPServer::getLocalHTTPSAddress()
00733 {
00734    if (m_pHttpsServerSocket)
00735    {
00736       return m_pHttpsServerSocket->getLocalAddress();
00737    }
00738    else
00739    {
00740       return SocketAddress::allocEmptyAddress(SocketAddress::INET);
00741    }
00742 }
00744 bool
00745 HTTPServer::isShuttingDown()
00746 {
00747    MutexLock lock(m_shutdownGuard);
00748    return m_shuttingDown;
00749 }
00751 void
00752 HTTPServer::shutdown()
00753 {
00754    {
00755       MutexLock lock(m_shutdownGuard);
00756       m_shuttingDown = true;
00757    }
00758    OW_LOG_DEBUG(m_options.env->getLogger(COMPONENT_NAME), "HTTP Service is shutting down...");
00759    // first stop all new connections
00760    m_options.env->removeSelectable(m_pHttpServerSocket);
00761    m_options.env->removeSelectable(m_pHttpsServerSocket);
00762    m_options.env->removeSelectable(m_pUDSServerSocket);
00763 
00764    // now stop all current connections
00765 #ifdef OW_WIN32
00766    if (!::SetEvent(m_event))
00767    {
00768       OW_THROW(IOException,
00769          "Failed signaling event for HTTP server shutdown");
00770    }
00771 #else
00772    if (m_upipe->writeString("shutdown") == -1)
00773    {
00774       OW_THROW_ERRNO_MSG(IOException, "Failed writing to HTTPServer shutdown pipe");
00775    }
00776 #endif
00777    // not going to finish off what's in the queue, and we'll give the threads 60 seconds to exit before they're clobbered.
00778    m_threadPool->shutdown(ThreadPool::E_DISCARD_WORK_IN_QUEUE, 60);
00779    m_pHttpServerSocket = 0;
00780    m_pHttpsServerSocket = 0;
00781    m_pUDSServerSocket = 0;
00782    OW_LOG_DEBUG(m_options.env->getLogger(COMPONENT_NAME), "HTTP Service has shut down");
00783 
00784    // clear out variables to avoid circular reference counts.
00785    m_options.env = 0;
00786 }
00787 
00788 } // end namespace OW_NAMESPACE
00789 
00791 // This allows the http server to be dynamically loaded
00792 OW_SERVICE_FACTORY(OW_NAMESPACE::HTTPServer,HTTPServer)
00793 

Generated on Thu Feb 9 08:47:59 2006 for openwbem by  doxygen 1.4.6