pion-net  4.0.9
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 }