core.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "core.hpp"
  4. #include <cstdlib>
  5. #include <csignal>
  6. #include <config/core.hpp>
  7. #ifndef MINICORE
  8. #include "database.hpp"
  9. #include "ers.hpp"
  10. #include "socket.hpp"
  11. #include "timer.hpp"
  12. #include "sql.hpp"
  13. #endif
  14. #ifndef _WIN32
  15. #include <unistd.h>
  16. #else
  17. #include "winapi.hpp" // Console close event handling
  18. #include <direct.h> // _chdir
  19. #endif
  20. #include "cbasetypes.hpp"
  21. #include "malloc.hpp"
  22. #include "mmo.hpp"
  23. #include "showmsg.hpp"
  24. #include "strlib.hpp"
  25. #ifndef DEPRECATED_COMPILER_SUPPORT
  26. #if defined( _MSC_VER ) && _MSC_VER < 1914
  27. #error "Visual Studio versions older than Visual Studio 2017 are not officially supported anymore"
  28. #elif defined( __clang__ ) && __clang_major__ < 13
  29. #error "clang versions older than clang 13.0 are not officially supported anymore"
  30. #elif !defined( __clang__ ) && defined( __GNUC__ ) && __GNUC__ < 6
  31. #error "GCC versions older than GCC 6 are not officially supported anymore"
  32. #endif
  33. #endif
  34. using namespace rathena::server_core;
  35. Core* global_core = nullptr;
  36. #if defined(BUILDBOT)
  37. int32 buildbotflag = 0;
  38. #endif
  39. char db_path[12] = "db"; /// relative path for db from server
  40. char conf_path[12] = "conf"; /// relative path for conf from server
  41. char *SERVER_NAME = nullptr;
  42. #ifndef MINICORE // minimalist Core
  43. // Added by Gabuzomeu
  44. //
  45. // This is an implementation of signal() using sigaction() for portability.
  46. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced
  47. // Programming in the UNIX Environment_.
  48. //
  49. #ifdef WIN32 // windows don't have SIGPIPE
  50. #define SIGPIPE SIGINT
  51. #endif
  52. #ifndef POSIX
  53. #define compat_signal(signo, func) signal(signo, func)
  54. #else
  55. sigfunc *compat_signal(int32 signo, sigfunc *func) {
  56. struct sigaction sact, oact;
  57. sact.sa_handler = func;
  58. sigemptyset(&sact.sa_mask);
  59. sact.sa_flags = 0;
  60. #ifdef SA_INTERRUPT
  61. sact.sa_flags |= SA_INTERRUPT; /* SunOS */
  62. #endif
  63. if (sigaction(signo, &sact, &oact) < 0)
  64. return (SIG_ERR);
  65. return (oact.sa_handler);
  66. }
  67. #endif
  68. /*======================================
  69. * CORE : Console events for Windows
  70. *--------------------------------------*/
  71. #ifdef _WIN32
  72. static BOOL WINAPI console_handler(DWORD c_event) {
  73. switch(c_event) {
  74. case CTRL_CLOSE_EVENT:
  75. case CTRL_LOGOFF_EVENT:
  76. case CTRL_SHUTDOWN_EVENT:
  77. if( global_core != nullptr ){
  78. global_core->signal_shutdown();
  79. }
  80. break;
  81. default:
  82. return FALSE;
  83. }
  84. return TRUE;
  85. }
  86. static void cevents_init() {
  87. if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE)
  88. ShowWarning ("Unable to install the console handler!\n");
  89. }
  90. #endif
  91. /*======================================
  92. * CORE : Signal Sub Function
  93. *--------------------------------------*/
  94. static void sig_proc(int32 sn) {
  95. static int32 is_called = 0;
  96. switch (sn) {
  97. case SIGINT:
  98. case SIGTERM:
  99. if (++is_called > 3)
  100. exit(EXIT_SUCCESS);
  101. if( global_core != nullptr ){
  102. global_core->signal_shutdown();
  103. }
  104. break;
  105. case SIGSEGV:
  106. case SIGFPE:
  107. if( global_core != nullptr ){
  108. global_core->signal_crash();
  109. }
  110. // Pass the signal to the system's default handler
  111. compat_signal(sn, SIG_DFL);
  112. raise(sn);
  113. break;
  114. #ifndef _WIN32
  115. case SIGXFSZ:
  116. // ignore and allow it to set errno to EFBIG
  117. ShowWarning ("Max file size reached!\n");
  118. //run_flag = 0; // should we quit?
  119. break;
  120. case SIGPIPE:
  121. //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.cpp
  122. break; // does nothing here
  123. #endif
  124. }
  125. }
  126. void signals_init (void) {
  127. compat_signal(SIGTERM, sig_proc);
  128. compat_signal(SIGINT, sig_proc);
  129. #ifndef _DEBUG // need unhandled exceptions to debug on Windows
  130. compat_signal(SIGSEGV, sig_proc);
  131. compat_signal(SIGFPE, sig_proc);
  132. #endif
  133. #ifndef _WIN32
  134. compat_signal(SIGILL, SIG_DFL);
  135. compat_signal(SIGXFSZ, sig_proc);
  136. compat_signal(SIGPIPE, sig_proc);
  137. compat_signal(SIGBUS, SIG_DFL);
  138. compat_signal(SIGTRAP, SIG_DFL);
  139. #endif
  140. }
  141. #endif
  142. const char* get_svn_revision(void) {
  143. #ifdef SVNVERSION
  144. return EXPAND_AND_QUOTE(SVNVERSION);
  145. #else// not SVNVERSION
  146. static char svn_version_buffer[16] = "";
  147. FILE *fp;
  148. if( svn_version_buffer[0] != '\0' )
  149. return svn_version_buffer;
  150. // subversion 1.7 uses a sqlite3 database
  151. // FIXME this is hackish at best...
  152. // - ignores database file structure
  153. // - assumes the data in NODES.dav_cache column ends with "!svn/ver/<revision>/<path>)"
  154. // - since it's a cache column, the data might not even exist
  155. if( (fp = fopen(".svn" PATHSEP_STR "wc.db", "rb")) != nullptr || (fp = fopen(".." PATHSEP_STR ".svn" PATHSEP_STR "wc.db", "rb")) != nullptr )
  156. {
  157. #ifndef SVNNODEPATH
  158. //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up
  159. #define SVNNODEPATH trunk
  160. #endif
  161. const char* prefix = "!svn/ver/";
  162. const char* postfix = "/" EXPAND_AND_QUOTE(SVNNODEPATH) ")"; // there should exist only 1 entry like this
  163. size_t prefix_len = strlen(prefix);
  164. size_t postfix_len = strlen(postfix);
  165. size_t i,j,len;
  166. char* buffer;
  167. // read file to buffer
  168. fseek(fp, 0, SEEK_END);
  169. len = ftell(fp);
  170. buffer = (char*)aMalloc(len + 1);
  171. fseek(fp, 0, SEEK_SET);
  172. len = fread(buffer, 1, len, fp);
  173. buffer[len] = '\0';
  174. fclose(fp);
  175. // parse buffer
  176. for( i = prefix_len + 1; i + postfix_len <= len; ++i ) {
  177. if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 )
  178. continue; // postfix missmatch
  179. for( j = i; j > 0; --j ) {// skip digits
  180. if( !ISDIGIT(buffer[j - 1]) )
  181. break;
  182. }
  183. if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 )
  184. continue; // prefix missmatch
  185. // done
  186. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j));
  187. break;
  188. }
  189. aFree(buffer);
  190. if( svn_version_buffer[0] != '\0' )
  191. return svn_version_buffer;
  192. }
  193. // subversion 1.6 and older?
  194. if ((fp = fopen(".svn/entries", "r")) != nullptr)
  195. {
  196. char line[1024];
  197. int32 rev;
  198. // Check the version
  199. if (fgets(line, sizeof(line), fp))
  200. {
  201. if(!ISDIGIT(line[0]))
  202. {
  203. // XML File format
  204. while (fgets(line,sizeof(line),fp))
  205. if (strstr(line,"revision=")) break;
  206. if (sscanf(line," %*[^\"]\"%11d%*[^\n]", &rev) == 1) {
  207. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev);
  208. }
  209. }
  210. else
  211. {
  212. // Bin File format
  213. if ( fgets(line, sizeof(line), fp) == nullptr ) { printf("Can't get bin name\n"); } // Get the name
  214. if ( fgets(line, sizeof(line), fp) == nullptr ) { printf("Can't get entries kind\n"); } // Get the entries kind
  215. if(fgets(line, sizeof(line), fp)) // Get the rev numver
  216. {
  217. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line));
  218. }
  219. }
  220. }
  221. fclose(fp);
  222. if( svn_version_buffer[0] != '\0' )
  223. return svn_version_buffer;
  224. }
  225. // fallback
  226. svn_version_buffer[0] = UNKNOWN_VERSION;
  227. return svn_version_buffer;
  228. #endif
  229. }
  230. // Grabs the hash from the last time the user updated their working copy (last pull)
  231. const char *get_git_hash (void) {
  232. static char GitHash[41] = ""; //Sha(40) + 1
  233. FILE *fp;
  234. if( GitHash[0] != '\0' )
  235. return GitHash;
  236. if( (fp = fopen(".git/refs/remotes/origin/master", "r")) != nullptr || // Already pulled once
  237. (fp = fopen(".git/refs/heads/master", "r")) != nullptr ) { // Cloned only
  238. char line[64];
  239. char *rev = (char*)malloc(sizeof(char) * 50);
  240. if (fgets(line, sizeof(line), fp) != nullptr && sscanf(line, "%40s", rev) == 1)
  241. snprintf(GitHash, sizeof(GitHash), "%s", rev);
  242. free(rev);
  243. fclose(fp);
  244. } else {
  245. GitHash[0] = UNKNOWN_VERSION;
  246. }
  247. if ( !(*GitHash) ) {
  248. GitHash[0] = UNKNOWN_VERSION;
  249. }
  250. return GitHash;
  251. }
  252. /*======================================
  253. * CORE : Display title
  254. * ASCII By CalciumKid 1/12/2011
  255. *--------------------------------------*/
  256. static void display_title(void) {
  257. const char* svn = get_svn_revision();
  258. const char* git = get_git_hash();
  259. ShowMessage("\n");
  260. ShowMessage("" CL_PASS " " CL_BOLD " " CL_PASS"" CL_CLL "" CL_NORMAL "\n");
  261. ShowMessage("" CL_PASS " " CL_BT_WHITE " rAthena Development Team presents " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  262. ShowMessage("" CL_PASS " " CL_BOLD " ___ __ __ " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  263. ShowMessage("" CL_PASS " " CL_BOLD " _____/ | / /_/ /_ ___ ____ ____ _ " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  264. ShowMessage("" CL_PASS " " CL_BOLD " / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  265. ShowMessage("" CL_PASS " " CL_BOLD " / / / ___ / /_/ / / / __/ / / / /_/ / " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  266. ShowMessage("" CL_PASS " " CL_BOLD " /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  267. ShowMessage("" CL_PASS " " CL_BOLD " " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  268. ShowMessage("" CL_PASS " " CL_GREEN " http://rathena.org/board/ " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  269. ShowMessage("" CL_PASS " " CL_BOLD " " CL_PASS "" CL_CLL "" CL_NORMAL "\n");
  270. if( svn[0] != UNKNOWN_VERSION )
  271. ShowInfo("SVN Revision: '" CL_WHITE "%s" CL_RESET "'\n", svn);
  272. else if( git[0] != UNKNOWN_VERSION )
  273. ShowInfo("Git Hash: '" CL_WHITE "%s" CL_RESET "'\n", git);
  274. }
  275. // Warning if executed as superuser (root)
  276. void usercheck(void)
  277. {
  278. #if !defined(BUILDBOT)
  279. #ifdef _WIN32
  280. if (IsCurrentUserLocalAdministrator()) {
  281. ShowWarning("You are running rAthena with admin privileges, it is not necessary.\n");
  282. }
  283. #else
  284. if (geteuid() == 0) {
  285. ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n");
  286. }
  287. #endif
  288. #endif
  289. }
  290. int32 Core::start( int32 argc, char **argv ){
  291. if( this->get_status() != e_core_status::NOT_STARTED) {
  292. ShowFatalError( "Core was already started and cannot be started again!\n" );
  293. return EXIT_FAILURE;
  294. }
  295. this->set_status( e_core_status::CORE_INITIALIZING );
  296. {// initialize program arguments
  297. char *p1;
  298. if((p1 = strrchr(argv[0], '/')) != nullptr || (p1 = strrchr(argv[0], '\\')) != nullptr ){
  299. char *pwd = nullptr; //path working directory
  300. SERVER_NAME = ++p1;
  301. size_t n = p1-argv[0]; //calc dir name len
  302. pwd = safestrncpy((char*)malloc(n + 1), argv[0], n);
  303. if(chdir(pwd) != 0)
  304. ShowError("Couldn't change working directory to %s for %s, runtime will probably fail",pwd,SERVER_NAME);
  305. free(pwd);
  306. }else{
  307. // On Windows the .bat files have the executeable names as parameters without any path seperator [Lemongrass]
  308. SERVER_NAME = argv[0];
  309. }
  310. }
  311. malloc_init();// needed for Show* in display_title() [FlavioJS]
  312. display_title();
  313. usercheck();
  314. #ifndef MINICORE
  315. Sql_Init();
  316. db_init();
  317. signals_init();
  318. do_init_database();
  319. #ifdef _WIN32
  320. cevents_init();
  321. #endif
  322. timer_init();
  323. socket_init();
  324. #endif
  325. this->set_status( e_core_status::CORE_INITIALIZED );
  326. this->set_status( e_core_status::SERVER_INITIALIZING );
  327. if( !this->initialize( argc, argv ) ){
  328. return EXIT_FAILURE;
  329. }
  330. // If initialization did not trigger shutdown
  331. if( this->m_status != e_core_status::STOPPING ){
  332. this->set_status( e_core_status::SERVER_INITIALIZED );
  333. this->set_status( e_core_status::RUNNING );
  334. #ifndef MINICORE
  335. if( !this->m_run_once ){
  336. // Main runtime cycle
  337. while( this->get_status() == e_core_status::RUNNING ){
  338. t_tick next = do_timer( gettick_nocache() );
  339. this->handle_main( next );
  340. }
  341. }
  342. #endif
  343. this->set_status( e_core_status::STOPPING );
  344. }
  345. this->set_status( e_core_status::SERVER_FINALIZING );
  346. this->finalize();
  347. this->set_status( e_core_status::SERVER_FINALIZED );
  348. this->set_status( e_core_status::CORE_FINALIZING );
  349. #ifndef MINICORE
  350. timer_final();
  351. socket_final();
  352. db_final();
  353. ers_final();
  354. #endif
  355. malloc_final();
  356. this->set_status( e_core_status::CORE_FINALIZED );
  357. #if defined(BUILDBOT)
  358. if( buildbotflag ){
  359. exit(EXIT_FAILURE);
  360. }
  361. #endif
  362. this->set_status( e_core_status::STOPPED );
  363. return EXIT_SUCCESS;
  364. }
  365. bool Core::initialize( int32 argc, char* argv[] ){
  366. // Do nothing
  367. return true;
  368. }
  369. void Core::handle_main( t_tick next ){
  370. #ifndef MINICORE
  371. // By default we handle all socket packets
  372. do_sockets( next );
  373. #endif
  374. }
  375. void Core::handle_crash(){
  376. // Do nothing
  377. }
  378. void Core::handle_shutdown(){
  379. // Do nothing
  380. }
  381. void Core::finalize(){
  382. // Do nothing
  383. }
  384. void Core::set_status( e_core_status status ){
  385. this->m_status = status;
  386. }
  387. e_core_status Core::get_status(){
  388. return this->m_status;
  389. }
  390. e_core_type Core::get_type(){
  391. return this->m_type;
  392. }
  393. bool Core::is_running(){
  394. return this->get_status() == e_core_status::RUNNING;
  395. }
  396. void Core::set_run_once( bool run_once ){
  397. this->m_run_once = run_once;
  398. }
  399. void Core::signal_crash(){
  400. this->set_status( e_core_status::STOPPING );
  401. if( this->m_crashed ){
  402. ShowFatalError( "Received another crash signal, while trying to handle the last crash!\n" );
  403. }else{
  404. ShowFatalError( "Received a crash signal, trying to handle it as good as possible!\n" );
  405. this->m_crashed = true;
  406. this->handle_crash();
  407. }
  408. }
  409. void Core::signal_shutdown(){
  410. this->set_status( e_core_status::STOPPING );
  411. this->handle_shutdown();
  412. }