00001
00002
00003
00004
00005
00006
00007
00008
00009 static const char rcsid[] __attribute__((used)) = "$Id: httpd.cpp 1197 2014-10-14 22:26:11Z sella $";
00010
00011 #include "test.h"
00012
00013 #include <stdio.h>
00014 #include <signal.h>
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <pthread.h>
00018
00019 #include <mutex>
00020 #include <condition_variable>
00021
00022 #include "alias.h"
00023 #include "version.h"
00024 #include "sella/util/Log.h"
00025 #include "sella/util/String.h"
00026 #include "sella/server/HTTP.h"
00027 #include "sella/server/callbacks.h"
00028 #include "sella/util/CommandLine.h"
00029 #include "sella/net/IPAddressPort.h"
00030
00031 namespace sella {
00032 namespace httpd {
00033 bool running = true, restart = false;
00034 size_t workers = sella::server::HTTP::MinimumWorkersDefault;
00035 std::string listeners = "0.0.0.0:1080, [::]:1080";
00036 std::string root = sella::server::HTTP::RootDefault;
00037 std::mutex mutex;
00038 std::condition_variable cv;
00039 enum Mode { NonBlock, Block, Async } mode = Block;
00040 int debug = 0;
00041 }
00042 }
00043
00044 using namespace sella::httpd;
00045 using namespace sella::util;
00046 using namespace sella::net;
00047 using namespace sella::server;
00048
00049 bool init_config(int argc, char **argv);
00050 bool init_signals(void);
00051 void sighandler(int sig);
00052
00053 bool acl_callback(HTTPConnection::shared connection) {
00054 return true;
00055 }
00056
00057 bool authentication_callback(HTTPConnection::shared connection) {
00058 return true;
00059 }
00060
00061 bool request_callback(HTTPConnection::shared connection) {
00062 return http::request_callback(connection);
00063 }
00064
00065 bool error_callback(HTTPConnection::shared connection, int code, const std::string &detail = std::string()) {
00066 return http::error_callback(connection, code, detail);
00067 }
00068
00069 int main(int argc, char **argv) {
00070 SET_FORMAT(SimpleLogFormat());
00071 SET_IDENTIFIER("httpd");
00072 SET_OPTION(Log::WithStderrOption);
00073
00074 init_config(argc, argv);
00075 init_signals();
00076
00077 INFO("Using %s v%s", libutilxx__package(), libutilxx__version());
00078
00079 HTTP http;
00080
00081 http.setListeners(listeners);
00082 http.setRoot(root);
00083 http.setCustomHeaders(std::vector<std::string>({ "X-Powered-By: unicorn tears", "Age: 0" }));
00084
00085
00086 http.setACLCallback(acl_callback);
00087 http.setAuthenticationCallback(authentication_callback);
00088 http.setRequestCallback(request_callback);
00089 http.setErrorCallback(error_callback);
00090
00091 if (IS_TRACE("print")) {
00092 http.print();
00093 }
00094
00095 try {
00096 while (running) {
00097 std::unique_lock<std::mutex> lock(mutex);
00098
00099 INFO("Starting up on port(s): %s", http.getListenersString().c_str());
00100
00101 if (mode == Block) {
00102 http.run(workers);
00103 } else if (mode == NonBlock) {
00104 http.start(workers);
00105
00106 INFO("%s - Startup complete", http.getBanner().c_str());
00107
00108 while (running) {
00109 cv.wait(lock);
00110 }
00111
00112 http.stop();
00113 } else if (mode == Async) {
00114 while (running) {
00115 http.receive();
00116
00117 INFO("Doing something else...");
00118 usleep(500000);
00119 }
00120 } else {
00121 WARNING("Guru Meditation #00000004.0000AAC0");
00122
00123 running = false;
00124 }
00125
00126 if (restart) {
00127 running = true;
00128 restart = false;
00129 }
00130 }
00131
00132 INFO("%s - Shutdown complete", http.getBanner().c_str());
00133 } catch (ServerException &e) {
00134 INFO(e.what());
00135
00136 return EXIT_FAILURE;
00137 }
00138
00139 return EXIT_SUCCESS;
00140 }
00141
00142 bool init_config(int argc, char **argv) {
00143 std::string m;
00144 sella::util::CommandLine cmdln(argc, argv);
00145
00146 cmdln.add('m', "mode", "use MODE block, nonblock or async", "MODE", "block");
00147 cmdln.add('r', "root", "use DIR as root directory", "DIR", root);
00148 cmdln.add('l', "listeners", "use LIST as addresses/ports to listen", "LIST", listeners);
00149 cmdln.add('w', "workers", "use INT workers", "INT", workers, 1, 256);
00150 cmdln.add('d', "debug", "set debug level to INT", "INT", debug, 0, 9);
00151 cmdln.add();
00152 cmdln.add('h', "help", "display this help screen");
00153 cmdln.add('v', "version", "display version information");
00154
00155 std::map<std::string, std::string> conf = cmdln.parse(stdin);
00156
00157 if (conf.find("help") != conf.end()) {
00158 printf("%s v%s\n", libutilxx__package(), libutilxx__version());
00159 cmdln.usage(stdout, EXIT_SUCCESS);
00160 } else if (conf.find("version") != conf.end()) {
00161 printf("%s v%s\n", libutilxx__package(), libutilxx__version());
00162
00163 exit(EXIT_SUCCESS);
00164 }
00165
00166 if (conf.find("mode") != conf.end()) {
00167 if (conf["mode"] == "block") {
00168 mode = Block;
00169 } else if (conf["mode"] == "nonblock") {
00170 mode = NonBlock;
00171 } else if (conf["mode"] == "async") {
00172 mode = Async;
00173 }
00174 }
00175
00176 if (conf.find("listeners") != conf.end()) {
00177 listeners = conf["listeners"];
00178 }
00179
00180 if (conf.find("root") != conf.end()) {
00181 root = conf["root"];
00182 }
00183
00184 if (conf.find("workers") != conf.end()) {
00185 workers = atoi(conf["workers"].c_str());
00186 }
00187
00188 if (conf.find("debug") != conf.end()) {
00189 debug = atoi(conf["debug"].c_str());
00190
00191 switch (debug) {
00192 case 9:
00193 SET_TRACE("all");
00194 SET_LOGMASK(LOG_UPTO(LOG_DEBUG));
00195
00196 case 3:
00197 SET_TRACE(PACKAGE "-detail");
00198
00199 case 2:
00200 SET_TRACE(PACKAGE);
00201
00202 case 1:
00203 SET_TRACE("print");
00204 }
00205 }
00206
00207 return true;
00208 }
00209
00210 bool init_signals(void) {
00211 struct sigaction act, old;
00212
00213 act.sa_handler = sighandler;
00214 sigemptyset(&act.sa_mask);
00215 act.sa_flags = SA_RESTART;
00216
00217 if (sigaction(SIGINT, NULL, &old) < 0) {
00218 fprintf(stderr, "Failed to retrieve signal handler for SIGINT.\n");
00219 } else if (old.sa_handler == SIG_DFL) {
00220 if (sigaction(SIGINT, &act, NULL) < 0) {
00221 fprintf(stderr, "Failed to install signal handler for SIGINT.\n");
00222 }
00223 }
00224
00225 if (sigaction(SIGTERM, NULL, &old) < 0) {
00226 fprintf(stderr, "Failed to retrieve signal handler for SIGTERM.\n");
00227 } else if (old.sa_handler == SIG_DFL) {
00228 if (sigaction(SIGTERM, &act, NULL) < 0) {
00229 fprintf(stderr, "Failed to install signal handler for SIGTERM.\n");
00230 }
00231 }
00232
00233 if (sigaction(SIGHUP, NULL, &old) < 0) {
00234 fprintf(stderr, "Failed to retrieve signal handler for SIGHUP.\n");
00235 } else if (old.sa_handler == SIG_DFL) {
00236 if (sigaction(SIGHUP, &act, NULL) < 0) {
00237 fprintf(stderr, "Failed to install signal handler for SIGHUP.\n");
00238 }
00239 }
00240
00241 if (sigaction(SIGUSR1, NULL, &old) < 0) {
00242 fprintf(stderr, "Failed to retrieve signal handler for SIGUSR1.\n");
00243 } else if (old.sa_handler == SIG_DFL) {
00244 if (sigaction(SIGUSR1, &act, NULL) < 0) {
00245 fprintf(stderr, "Failed to install signal handler for SIGUSR1.\n");
00246 }
00247 }
00248
00249 if (sigaction(SIGUSR2, NULL, &old) < 0) {
00250 fprintf(stderr, "Failed to retrieve signal handler for SIGUSR2.\n");
00251 } else if (old.sa_handler == SIG_DFL) {
00252 if (sigaction(SIGUSR2, &act, NULL) < 0) {
00253 fprintf(stderr, "Failed to install signal handler for SIGUSR2.\n");
00254 }
00255 }
00256
00257 if (sigaction(SIGPIPE, NULL, &old) < 0) {
00258 fprintf(stderr, "Failed to retrieve signal handler for SIGPIPE.\n");
00259 } else if (old.sa_handler == SIG_DFL) {
00260 if (sigaction(SIGPIPE, &act, NULL) < 0) {
00261 fprintf(stderr, "Failed to install signal handler for SIGPIPE.\n");
00262 }
00263 }
00264
00265 return true;
00266 }
00267
00268 void sighandler(int sig) {
00269 switch (sig) {
00270 case SIGINT:
00271 case SIGTERM:
00272 running = false;
00273 cv.notify_one();
00274
00275 break;
00276
00277 case SIGHUP:
00278 restart = true;
00279 running = false;
00280
00281 break;
00282
00283 case SIGUSR1:
00284 break;
00285
00286 case SIGUSR2:
00287 break;
00288
00289 case SIGPIPE:
00290 break;
00291
00292 default:
00293 break;
00294 }
00295 }
00296
00297
00298
00299