pion-net  4.0.9
PionWebServer.cpp
1 // ------------------------------------------------------------------
2 // pion-net: a C++ framework for building lightweight HTTP interfaces
3 // ------------------------------------------------------------------
4 // Copyright (C) 2007-2008 Atomic Labs, Inc. (http://www.atomiclabs.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #include <vector>
11 #include <iostream>
12 #include <boost/asio.hpp>
13 #include <pion/PionPlugin.hpp>
14 #include <pion/net/WebServer.hpp>
15 #include "ShutdownManager.hpp"
16 
17 // these are used only when linking to static web service libraries
18 // #ifdef PION_STATIC_LINKING
19 PION_DECLARE_PLUGIN(EchoService)
20 PION_DECLARE_PLUGIN(FileService)
21 PION_DECLARE_PLUGIN(HelloService)
22 PION_DECLARE_PLUGIN(LogService)
23 PION_DECLARE_PLUGIN(CookieService)
24 
25 using namespace std;
26 using namespace pion;
27 using namespace pion::net;
28 
29 
31 void argument_error(void)
32 {
33  std::cerr << "usage: PionWebServer [OPTIONS] RESOURCE WEBSERVICE" << std::endl
34  << " PionWebServer [OPTIONS] -c SERVICE_CONFIG_FILE" << std::endl
35  << "options: [-ssl PEM_FILE] [-i IP] [-p PORT] [-d PLUGINS_DIR] [-o OPTION=VALUE]" << std::endl;
36 }
37 
38 
40 int main (int argc, char *argv[])
41 {
42  static const unsigned int DEFAULT_PORT = 8080;
43 
44  // used to keep track of web service name=value options
45  typedef std::vector<std::pair<std::string, std::string> > ServiceOptionsType;
46  ServiceOptionsType service_options;
47 
48  // parse command line: determine port number, RESOURCE and WEBSERVICE
49  boost::asio::ip::tcp::endpoint cfg_endpoint(boost::asio::ip::tcp::v4(), DEFAULT_PORT);
50  std::string service_config_file;
51  std::string resource_name;
52  std::string service_name;
53  std::string ssl_pem_file;
54  bool ssl_flag = false;
55 
56  for (int argnum=1; argnum < argc; ++argnum) {
57  if (argv[argnum][0] == '-') {
58  if (argv[argnum][1] == 'p' && argv[argnum][2] == '\0' && argnum+1 < argc) {
59  // set port number
60  ++argnum;
61  cfg_endpoint.port(strtoul(argv[argnum], 0, 10));
62  if (cfg_endpoint.port() == 0) cfg_endpoint.port(DEFAULT_PORT);
63  } else if (argv[argnum][1] == 'i' && argv[argnum][2] == '\0' && argnum+1 < argc) {
64  // set ip address
65  cfg_endpoint.address(boost::asio::ip::address::from_string(argv[++argnum]));
66  } else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
67  service_config_file = argv[++argnum];
68  } else if (argv[argnum][1] == 'd' && argv[argnum][2] == '\0' && argnum+1 < argc) {
69  // add the service plug-ins directory to the search path
70  try { PionPlugin::addPluginDirectory(argv[++argnum]); }
72  std::cerr << "PionWebServer: Web service plug-ins directory does not exist: "
73  << argv[argnum] << std::endl;
74  return 1;
75  }
76  } else if (argv[argnum][1] == 'o' && argv[argnum][2] == '\0' && argnum+1 < argc) {
77  std::string option_name(argv[++argnum]);
78  std::string::size_type pos = option_name.find('=');
79  if (pos == std::string::npos) {
80  argument_error();
81  return 1;
82  }
83  std::string option_value(option_name, pos + 1);
84  option_name.resize(pos);
85  service_options.push_back( std::make_pair(option_name, option_value) );
86  } else if (argv[argnum][1] == 's' && argv[argnum][2] == 's' &&
87  argv[argnum][3] == 'l' && argv[argnum][4] == '\0' && argnum+1 < argc) {
88  ssl_flag = true;
89  ssl_pem_file = argv[++argnum];
90  } else {
91  argument_error();
92  return 1;
93  }
94  } else if (argnum+2 == argc) {
95  // second to last argument = RESOURCE
96  resource_name = argv[argnum];
97  } else if (argnum+1 == argc) {
98  // last argument = WEBSERVICE
99  service_name = argv[argnum];
100  } else {
101  argument_error();
102  return 1;
103  }
104  }
105 
106  if (service_config_file.empty() && (resource_name.empty() || service_name.empty())) {
107  argument_error();
108  return 1;
109  }
110 
111  // setup signal handler
112 #ifdef PION_WIN32
113  SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
114 #else
115  signal(SIGINT, handle_signal);
116 #endif
117 
118  // initialize log system (use simple configuration)
119  PionLogger main_log(PION_GET_LOGGER("PionWebServer"));
120  PionLogger pion_log(PION_GET_LOGGER("pion"));
121  PION_LOG_SETLEVEL_INFO(main_log);
122  PION_LOG_SETLEVEL_INFO(pion_log);
123  PION_LOG_CONFIG_BASIC;
124 
125  try {
126  // add the Pion plug-ins installation directory to our path
127  try { PionPlugin::addPluginDirectory(PION_PLUGINS_DIRECTORY); }
129  PION_LOG_WARN(main_log, "Default plug-ins directory does not exist: "
130  << PION_PLUGINS_DIRECTORY);
131  }
132 
133  // add the directory of the program we're running to our path
134  try { PionPlugin::addPluginDirectory(boost::filesystem::path(argv[0]).branch_path().string()); }
136  PION_LOG_WARN(main_log, "Directory of current executable does not exist: "
137  << boost::filesystem::path(argv[0]).branch_path());
138  }
139 
140  // create a server for HTTP & add the Hello Service
141  WebServer web_server(cfg_endpoint);
142 
143  if (ssl_flag) {
144 #ifdef PION_HAVE_SSL
145  // configure server for SSL
146  web_server.setSSLKeyFile(ssl_pem_file);
147  PION_LOG_INFO(main_log, "SSL support enabled using key file: " << ssl_pem_file);
148 #else
149  PION_LOG_ERROR(main_log, "SSL support is not enabled");
150 #endif
151  }
152 
153  if (service_config_file.empty()) {
154  // load a single web service using the command line arguments
155  web_server.loadService(resource_name, service_name);
156 
157  // set web service options if any are defined
158  for (ServiceOptionsType::iterator i = service_options.begin();
159  i != service_options.end(); ++i)
160  {
161  web_server.setServiceOption(resource_name, i->first, i->second);
162  }
163  } else {
164  // load services using the configuration file
165  web_server.loadServiceConfig(service_config_file);
166  }
167 
168  // startup the server
169  web_server.start();
170  main_shutdown_manager.wait();
171 
172  } catch (std::exception& e) {
173  PION_LOG_FATAL(main_log, e.what());
174  }
175 
176  return 0;
177 }