# net/utils/PionWebServer.cpp

    00001 // ------------------------------------------------------------------
    00002 // pion-net: a C++ framework for building lightweight HTTP interfaces
    00003 // ------------------------------------------------------------------
    00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
    00005 //
    00006 // Distributed under the Boost Software License, Version 1.0.
    00007 // See http://www.boost.org/LICENSE_1_0.txt
    00008 //
    00009
    00010 #include <vector>
    00011 #include <iostream>
    00012 #include <boost/asio.hpp>
    00013 #include <pion/PionPlugin.hpp>
    00014 #include <pion/net/WebServer.hpp>
    00015 #include "ShutdownManager.hpp"
    00016
    00017 // these are used only when linking to static web service libraries
    00018 // #ifdef PION_STATIC_LINKING
    00019 PION_DECLARE_PLUGIN(EchoService)
    00020 PION_DECLARE_PLUGIN(FileService)
    00021 PION_DECLARE_PLUGIN(HelloService)
    00022 PION_DECLARE_PLUGIN(LogService)
    00023 PION_DECLARE_PLUGIN(CookieService)
    00024
    00025 using namespace std;
    00026 using namespace pion;
    00027 using namespace pion::net;
    00028
    00029
    00031 void argument_error(void)
    00032 {
    00033     std::cerr << "usage:   PionWebServer [OPTIONS] RESOURCE WEBSERVICE" << std::endl
    00034               << "         PionWebServer [OPTIONS] -c SERVICE_CONFIG_FILE" << std::endl
    00035               << "options: [-ssl PEM_FILE] [-i IP] [-p PORT] [-d PLUGINS_DIR] [-o OPTION=VALUE]" << std::endl;
    00036 }
    00037
    00038
    00040 int main (int argc, char *argv[])
    00041 {
    00042     static const unsigned int DEFAULT_PORT = 8080;
    00043
    00044     // used to keep track of web service name=value options
    00045     typedef std::vector<std::pair<std::string, std::string> >   ServiceOptionsType;
    00046     ServiceOptionsType service_options;
    00047
    00048     // parse command line: determine port number, RESOURCE and WEBSERVICE
    00049     boost::asio::ip::tcp::endpoint cfg_endpoint(boost::asio::ip::tcp::v4(), DEFAULT_PORT);
    00050     std::string service_config_file;
    00051     std::string resource_name;
    00052     std::string service_name;
    00053     std::string ssl_pem_file;
    00054     bool ssl_flag = false;
    00055
    00056     for (int argnum=1; argnum < argc; ++argnum) {
    00057         if (argv[argnum][0] == '-') {
    00058             if (argv[argnum][1] == 'p' && argv[argnum][2] == '\0' && argnum+1 < argc) {
    00059                 // set port number
    00060                 ++argnum;
    00061                 cfg_endpoint.port(strtoul(argv[argnum], 0, 10));
    00062                 if (cfg_endpoint.port() == 0) cfg_endpoint.port(DEFAULT_PORT);
    00063             } else if (argv[argnum][1] == 'i' && argv[argnum][2] == '\0' && argnum+1 < argc) {
    00064                 // set ip address
    00065                 cfg_endpoint.address(boost::asio::ip::address::from_string(argv[++argnum]));
    00066             } else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
    00067                 service_config_file = argv[++argnum];
    00068             } else if (argv[argnum][1] == 'd' && argv[argnum][2] == '\0' && argnum+1 < argc) {
    00069                 // add the service plug-ins directory to the search path
    00070                 try { PionPlugin::addPluginDirectory(argv[++argnum]); }
    00071                 catch (PionPlugin::DirectoryNotFoundException&) {
    00072                     std::cerr << "PionWebServer: Web service plug-ins directory does not exist: "
    00073                         << argv[argnum] << std::endl;
    00074                     return 1;
    00075                 }
    00076             } else if (argv[argnum][1] == 'o' && argv[argnum][2] == '\0' && argnum+1 < argc) {
    00077                 std::string option_name(argv[++argnum]);
    00078                 std::string::size_type pos = option_name.find('=');
    00079                 if (pos == std::string::npos) {
    00080                     argument_error();
    00081                     return 1;
    00082                 }
    00083                 std::string option_value(option_name, pos + 1);
    00084                 option_name.resize(pos);
    00085                 service_options.push_back( std::make_pair(option_name, option_value) );
    00086             } else if (argv[argnum][1] == 's' && argv[argnum][2] == 's' &&
    00087                        argv[argnum][3] == 'l' && argv[argnum][4] == '\0' && argnum+1 < argc) {
    00088                 ssl_flag = true;
    00089                 ssl_pem_file = argv[++argnum];
    00090             } else {
    00091                 argument_error();
    00092                 return 1;
    00093             }
    00094         } else if (argnum+2 == argc) {
    00095             // second to last argument = RESOURCE
    00096             resource_name = argv[argnum];
    00097         } else if (argnum+1 == argc) {
    00098             // last argument = WEBSERVICE
    00099             service_name = argv[argnum];
    00100         } else {
    00101             argument_error();
    00102             return 1;
    00103         }
    00104     }
    00105
    00106     if (service_config_file.empty() && (resource_name.empty() || service_name.empty())) {
    00107         argument_error();
    00108         return 1;
    00109     }
    00110
    00111     // setup signal handler
    00112 #ifdef PION_WIN32
    00113     SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
    00114 #else
    00115     signal(SIGINT, handle_signal);
    00116 #endif
    00117
    00118     // initialize log system (use simple configuration)
    00119     PionLogger main_log(PION_GET_LOGGER("PionWebServer"));
    00120     PionLogger pion_log(PION_GET_LOGGER("pion"));
    00121     PION_LOG_SETLEVEL_INFO(main_log);
    00122     PION_LOG_SETLEVEL_INFO(pion_log);
    00123     PION_LOG_CONFIG_BASIC;
    00124
    00125     try {
    00126         // add the Pion plug-ins installation directory to our path
    00127         try { PionPlugin::addPluginDirectory(PION_PLUGINS_DIRECTORY); }
    00128         catch (PionPlugin::DirectoryNotFoundException&) {
    00129             PION_LOG_WARN(main_log, "Default plug-ins directory does not exist: "
    00130                 << PION_PLUGINS_DIRECTORY);
    00131         }
    00132
    00133         // add the directory of the program we're running to our path
    00134         try { PionPlugin::addPluginDirectory(boost::filesystem::path(argv[0]).branch_path().string()); }
    00135         catch (PionPlugin::DirectoryNotFoundException&) {
    00136             PION_LOG_WARN(main_log, "Directory of current executable does not exist: "
    00137                 << boost::filesystem::path(argv[0]).branch_path());
    00138         }
    00139
    00140         // create a server for HTTP & add the Hello Service
    00141         WebServer  web_server(cfg_endpoint);
    00142
    00143         if (ssl_flag) {
    00144 #ifdef PION_HAVE_SSL
    00145             // configure server for SSL
    00146             web_server.setSSLKeyFile(ssl_pem_file);
    00147             PION_LOG_INFO(main_log, "SSL support enabled using key file: " << ssl_pem_file);
    00148 #else
    00149             PION_LOG_ERROR(main_log, "SSL support is not enabled");
    00150 #endif
    00151         }
    00152
    00153         if (service_config_file.empty()) {
    00154             // load a single web service using the command line arguments
    00155             web_server.loadService(resource_name, service_name);
    00156
    00157             // set web service options if any are defined
    00158             for (ServiceOptionsType::iterator i = service_options.begin();
    00159                  i != service_options.end(); ++i)
    00160             {
    00161                 web_server.setServiceOption(resource_name, i->first, i->second);
    00162             }
    00163         } else {
    00164             // load services using the configuration file
    00165             web_server.loadServiceConfig(service_config_file);
    00166         }
    00167
    00168         // startup the server
    00169         web_server.start();
    00170         main_shutdown_manager.wait();
    00171
    00172     } catch (std::exception& e) {
    00173         PION_LOG_FATAL(main_log, e.what());
    00174     }
    00175
    00176     return 0;
    00177 }