See More

/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #if defined(__sun) #define _POSIX_PTHREAD_SEMANTICS #endif #include "tcp_cache_server.h" #include "cache_storage.h" #ifndef CPPCMS_WIN32 #include #include "daemonize.h" #endif #ifdef CPPCMS_WIN_NATIVE #include "winservice.h" #endif #include #include #include #include #include #include #include #include #include "base_cache.h" #include "logging.h" #include #include #include #include #ifdef CPPCMS_WIN_NATIVE #include "session_win32_file_storage.h" #include "winservice.h" #else #include "session_posix_file_storage.h" #endif #include "session_memory_storage.h" struct settings { std::string ip; int port; int threads; int gc; cppcms::json::value config; booster::shared_ptr<:sessions::session_storage_factory> sessions; booster::shared_object plugin; booster::intrusive_ptr<:impl::base_cache> cache; ~settings() { sessions.reset(); // ensure that sessions object is destroyed before shared object cache = 0; } settings(int argc,char **argv) { try { config = cppcms::service::load_settings(argc,argv); setup(config); } catch(cppcms::cppcms_error const &) { help(); throw; } } void help() { std::cerr << "usage: cppcms_scale [ -c config.js ] [ parameters ]\n" " -c config.js JSON, Configuration file, also parameters may\n" " be set via command line rather then the file\n" " --ip=IP IP to bind, default 0.0.0.0\n" " --port=N Port to bind, mandatory\n" " --threads=N Worker threads, default = # HW CPU\n" " --cache-limit=N The size of the cache in items\n" " --session-storage=(memory|files|external)\n" " Session storage module\n" " --session-gc=N The frequency of garbage collection\n" " --session-dir=/path The location of files for session storage\n" " --session-shared_object=/path\n" " The shared object/dll that is used as external\n" " storage" " --session-module=name\n" " The name of the module for example mymod for\n" " an external storage, renamed to shared object\n" " according to OS conventions, like libmymod.so\n" #ifndef CPPCMS_WIN32 " --daemon-enable=(true|false)\n" " Run the process as daemon, default false\n" " --daemon-lock=/path Location of the lock file that keeps process pid\n" " --daemon-user=user User that the daemon should run under\n" " --daemon-group=grp Group that the daemon should run under\n" " --daemon-chroot=/path\n" " Run the service in chroot jain\n" " --daemon-fdlimit=N The limit of file descriptors for the service\n" #endif #ifdef CPPCMS_WIN_NATIVE " --winservice-mode=(install|uninstall)\n" " Install or uninstall windows service\n" " --winservice-name=XXX\n" " Name of windows service\n" " --winservice-display_name=XXX\n" " The service name shown in the UI\n" " --winservice-start=(auto|demand)\n" " Windows service start mode\n" " --winservice-user=XXX\n" " --winservice-password=XXX\n" " The user and password the service would run under\n" #endif << std::endl; } void setup(cppcms::json::value const &v) { ip=v.get("ip","0.0.0.0"); port=v.get("port"); threads=v.get("threads",booster::thread::hardware_concurrency()); int items = v.get("cache.limit",-1); if(items!=-1){ cache = cppcms::impl::thread_cache_factory(items); } gc=v.get("session.gc",10); std::string stor = v.get("session.storage",""); if(!stor.empty()) { #ifndef CPPCMS_NO_GZIP if(stor == "files") { std::string dir = v.get("session.dir",""); #ifdef CPPCMS_WIN_NATIVE sessions.reset(new cppcms::sessions::session_file_storage_factory(dir)); #else sessions.reset(new cppcms::sessions::session_file_storage_factory(dir,threads,1,false)); #endif } else #endif //CPPCMS_NO_GZIP if(stor == "memory") { sessions.reset(new cppcms::sessions::session_memory_storage_factory()); } else if(stor == "external") { std::string so = v.get<:string>("session.shared_object",""); std::string module = v.get<:string>("session.module",""); std::string entry_point = v.get<:string>("session.entry_point","sessions_generator"); if(so.empty() && module.empty()) throw cppcms::cppcms_error( "session.storage=external " "and neither session.shared_object " "nor session.module is defined"); if(!so.empty() && !module.empty()) throw cppcms::cppcms_error( "both session.shared_object " "and session.module are defined"); if(so.empty()) { so = booster::shared_object::name(module); } std::string error; if(!plugin.open(so,error)) { throw cppcms::cppcms_error("sessions_pool: failed to load shared object " + so + ": " + error); } cppcms::sessions::cppcms_session_storage_generator_type f=0; plugin.symbol(f,entry_point); sessions.reset(f(v.find("session.settings"))); } else throw cppcms::cppcms_error("Unknown session.storage:"+stor); } if(!sessions && !cache) { throw cppcms::cppcms_error("Neither cache.limit nor session.storage is defined"); } } }; #if !defined(CPPCMS_WIN32) void main_posix(settings &par) { cppcms::impl::daemonizer demon(par.config); cppcms::impl::tcp_cache_service srv( par.cache, par.sessions, par.threads, par.ip, par.port, par.gc); // Wait for signals for exit sigset_t wait_mask; sigemptyset(&wait_mask); sigaddset(&wait_mask, SIGINT); sigaddset(&wait_mask, SIGQUIT); sigaddset(&wait_mask, SIGTERM); pthread_sigmask(SIG_BLOCK, &wait_mask, 0); int sig = 0; sigwait(&wait_mask, &sig); BOOSTER_NOTICE("cppcms_scale")<<"Catch signal: exiting..."; srv.stop(); } #elif defined(CPPCMS_WIN_NATIVE) static booster::shared_ptr<:impl::tcp_cache_service> the_server; static settings *the_settings; static booster::mutex done_lock; static booster::condition_variable done_cond; static bool done; static void win_prepare() { BOOSTER_NOTICE("cppcms_scale")<<"Starting service..."; settings &par = *the_settings; the_server.reset( new cppcms::impl::tcp_cache_service( par.cache, par.sessions, par.threads, par.ip, par.port, par.gc) ); } static void win_stop() { booster::unique_lock<:mutex> guard(done_lock); done = true; done_cond.notify_all(); } static void win_run() { { booster::unique_lock<:mutex> guard(done_lock); while(!done) { done_cond.wait(guard); } } BOOSTER_NOTICE("cppcms_scale")<<"Stopping service..."; the_server->stop(); the_server.reset(); the_settings = 0; } void main_win(settings &par,int argc,char **argv) { using cppcms::impl::winservice; the_settings = &par; winservice::instance().prepare(win_prepare); winservice::instance().stop(win_stop); winservice::instance().exec(win_run); winservice::instance().run(par.config,argc,argv); } #endif #ifdef CPPCMS_WIN32 void main_console(settings &par) { cppcms::impl::tcp_cache_service srv( par.cache, par.sessions, par.threads, par.ip, par.port, par.gc); std::cout << "Press any key to stop..." << std::flush; std::cin.get(); srv.stop(); } #endif int main(int argc,char **argv) { try { settings par(argc,argv); cppcms::impl::setup_logging(par.config); #ifndef CPPCMS_WIN32 main_posix(par); #elif defined CPPCMS_WIN_NATIVE if(cppcms::impl::winservice::is_console(par.config)) main_console(par); else main_win(par,argc,argv); #else // cygwin main_console(par); #endif } catch(std::exception const &e) { BOOSTER_ERROR("cppcms_scale")<