summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/HPM.c10
-rw-r--r--src/common/HPMDataCheck.h34
-rw-r--r--src/common/HPMSymbols.inc.h38
-rw-r--r--src/common/console.c38
-rw-r--r--src/common/console.h16
-rw-r--r--src/common/core.c97
-rw-r--r--src/common/db.h10
-rw-r--r--src/common/des.c155
-rw-r--r--src/common/des.h45
-rw-r--r--src/common/grfio.c493
-rw-r--r--src/common/grfio.h108
-rw-r--r--src/common/md5calc.c156
-rw-r--r--src/common/md5calc.h44
-rw-r--r--src/common/mmo.h77
-rw-r--r--src/common/mutex.c158
-rw-r--r--src/common/mutex.h168
-rw-r--r--src/common/random.c62
-rw-r--r--src/common/random.h84
-rw-r--r--src/common/showmsg.c4
-rw-r--r--src/common/showmsg.h4
-rw-r--r--src/common/socket.c280
-rw-r--r--src/common/spinlock.h89
-rw-r--r--src/common/strlib.c1
-rw-r--r--src/common/thread.c250
-rw-r--r--src/common/thread.h232
25 files changed, 1751 insertions, 902 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c
index 02b675704..8e0bbe992 100644
--- a/src/common/HPM.c
+++ b/src/common/HPM.c
@@ -389,12 +389,12 @@ bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecF
ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), i, strcmp(VECTOR_INDEX(cmdline->args_data, i).name, name) == 0);
- if (i != VECTOR_LENGTH(cmdline->args_data)) {
- ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
- return false;
- }
+ if (i != VECTOR_LENGTH(cmdline->args_data)) {
+ ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
+ return false;
+ }
- return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL);
+ return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL);
}
/**
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 3d25d7330..d0e23811c 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -23,6 +23,8 @@
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+
#ifndef HPM_DATA_CHECK_H
#define HPM_DATA_CHECK_H
@@ -148,7 +150,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#define COMMON_DB_H
#endif // COMMON_DB_H
#ifdef COMMON_DES_H
- { "BIT64", sizeof(struct BIT64), SERVER_TYPE_ALL },
+ { "des_bit64", sizeof(struct des_bit64), SERVER_TYPE_ALL },
+ { "des_interface", sizeof(struct des_interface), SERVER_TYPE_ALL },
#else
#define COMMON_DES_H
#endif // COMMON_DES_H
@@ -157,6 +160,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_ERS_H
#endif // COMMON_ERS_H
+ #ifdef COMMON_GRFIO_H
+ { "grfio_interface", sizeof(struct grfio_interface), SERVER_TYPE_MAP },
+ #else
+ #define COMMON_GRFIO_H
+ #endif // COMMON_GRFIO_H
#ifdef COMMON_HPMI_H
{ "HPMi_interface", sizeof(struct HPMi_interface), SERVER_TYPE_ALL },
{ "hplugin_info", sizeof(struct hplugin_info), SERVER_TYPE_ALL },
@@ -169,6 +177,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_MAPINDEX_H
#endif // COMMON_MAPINDEX_H
+ #ifdef COMMON_MD5CALC_H
+ { "md5_interface", sizeof(struct md5_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_MD5CALC_H
+ #endif // COMMON_MD5CALC_H
#ifdef COMMON_MEMMGR_H
{ "malloc_interface", sizeof(struct malloc_interface), SERVER_TYPE_ALL },
#else
@@ -208,11 +221,21 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_MMO_H
#endif // COMMON_MMO_H
+ #ifdef COMMON_MUTEX_H
+ { "mutex_interface", sizeof(struct mutex_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_MUTEX_H
+ #endif // COMMON_MUTEX_H
#ifdef COMMON_NULLPO_H
{ "nullpo_interface", sizeof(struct nullpo_interface), SERVER_TYPE_ALL },
#else
#define COMMON_NULLPO_H
#endif // COMMON_NULLPO_H
+ #ifdef COMMON_RANDOM_H
+ { "rnd_interface", sizeof(struct rnd_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_RANDOM_H
+ #endif // COMMON_RANDOM_H
#ifdef COMMON_SHOWMSG_H
{ "showmsg_interface", sizeof(struct showmsg_interface), SERVER_TYPE_ALL },
#else
@@ -228,7 +251,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#define COMMON_SOCKET_H
#endif // COMMON_SOCKET_H
#ifdef COMMON_SPINLOCK_H
- { "SPIN_LOCK", sizeof(struct SPIN_LOCK), SERVER_TYPE_ALL },
+ { "spin_lock", sizeof(struct spin_lock), SERVER_TYPE_ALL },
#else
#define COMMON_SPINLOCK_H
#endif // COMMON_SPINLOCK_H
@@ -251,6 +274,11 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#else
#define COMMON_SYSINFO_H
#endif // COMMON_SYSINFO_H
+ #ifdef COMMON_THREAD_H
+ { "thread_interface", sizeof(struct thread_interface), SERVER_TYPE_ALL },
+ #else
+ #define COMMON_THREAD_H
+ #endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H
{ "TimerData", sizeof(struct TimerData), SERVER_TYPE_ALL },
{ "timer_interface", sizeof(struct timer_interface), SERVER_TYPE_ALL },
@@ -648,6 +676,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "casecheck_data", sizeof(struct casecheck_data), SERVER_TYPE_MAP },
{ "reg_db", sizeof(struct reg_db), SERVER_TYPE_MAP },
{ "script_array", sizeof(struct script_array), SERVER_TYPE_MAP },
+ { "script_buf", sizeof(struct script_buf), SERVER_TYPE_MAP },
{ "script_code", sizeof(struct script_code), SERVER_TYPE_MAP },
{ "script_data", sizeof(struct script_data), SERVER_TYPE_MAP },
{ "script_function", sizeof(struct script_function), SERVER_TYPE_MAP },
@@ -662,6 +691,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "script_syntax_data", sizeof(struct script_syntax_data), SERVER_TYPE_MAP },
{ "str_data_struct", sizeof(struct str_data_struct), SERVER_TYPE_MAP },
{ "string_translation", sizeof(struct string_translation), SERVER_TYPE_MAP },
+ { "string_translation_entry", sizeof(struct string_translation_entry), SERVER_TYPE_MAP },
#else
#define MAP_SCRIPT_H
#endif // MAP_SCRIPT_H
diff --git a/src/common/HPMSymbols.inc.h b/src/common/HPMSymbols.inc.h
index a6bf1622b..7ccb960de 100644
--- a/src/common/HPMSymbols.inc.h
+++ b/src/common/HPMSymbols.inc.h
@@ -23,6 +23,8 @@
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+
#if !defined(HERCULES_CORE)
#ifdef COMMON_UTILS_H /* HCache */
struct HCache_interface *HCache;
@@ -66,6 +68,9 @@ struct core_interface *core;
#ifdef COMMON_DB_H /* DB */
struct db_interface *DB;
#endif // COMMON_DB_H
+#ifdef COMMON_DES_H /* des */
+struct des_interface *des;
+#endif // COMMON_DES_H
#ifdef MAP_DUEL_H /* duel */
struct duel_interface *duel;
#endif // MAP_DUEL_H
@@ -75,6 +80,9 @@ struct elemental_interface *elemental;
#ifdef CHAR_GEOIP_H /* geoip */
struct geoip_interface *geoip;
#endif // CHAR_GEOIP_H
+#ifdef COMMON_GRFIO_H /* grfio */
+struct grfio_interface *grfio;
+#endif // COMMON_GRFIO_H
#ifdef MAP_GUILD_H /* guild */
struct guild_interface *guild;
#endif // MAP_GUILD_H
@@ -165,12 +173,18 @@ struct mapit_interface *mapit;
#ifdef MAP_MAPREG_H /* mapreg */
struct mapreg_interface *mapreg;
#endif // MAP_MAPREG_H
+#ifdef COMMON_MD5CALC_H /* md5 */
+struct md5_interface *md5;
+#endif // COMMON_MD5CALC_H
#ifdef MAP_MERCENARY_H /* mercenary */
struct mercenary_interface *mercenary;
#endif // MAP_MERCENARY_H
#ifdef MAP_MOB_H /* mob */
struct mob_interface *mob;
#endif // MAP_MOB_H
+#ifdef COMMON_MUTEX_H /* mutex */
+struct mutex_interface *mutex;
+#endif // COMMON_MUTEX_H
#ifdef MAP_NPC_H /* npc_chat */
struct npc_chat_interface *npc_chat;
#endif // MAP_NPC_H
@@ -204,6 +218,9 @@ struct pincode_interface *pincode;
#ifdef MAP_QUEST_H /* quest */
struct quest_interface *quest;
#endif // MAP_QUEST_H
+#ifdef COMMON_RANDOM_H /* rnd */
+struct rnd_interface *rnd;
+#endif // COMMON_RANDOM_H
#ifdef MAP_SCRIPT_H /* script */
struct script_interface *script;
#endif // MAP_SCRIPT_H
@@ -240,6 +257,9 @@ struct sv_interface *sv;
#ifdef COMMON_SYSINFO_H /* sysinfo */
struct sysinfo_interface *sysinfo;
#endif // COMMON_SYSINFO_H
+#ifdef COMMON_THREAD_H /* thread */
+struct thread_interface *thread;
+#endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H /* timer */
struct timer_interface *timer;
#endif // COMMON_TIMER_H
@@ -298,6 +318,9 @@ if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("core", core)) return "core";
#ifdef COMMON_DB_H /* DB */
if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("DB", DB)) return "DB";
#endif // COMMON_DB_H
+#ifdef COMMON_DES_H /* des */
+if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("des", des)) return "des";
+#endif // COMMON_DES_H
#ifdef MAP_DUEL_H /* duel */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("duel", duel)) return "duel";
#endif // MAP_DUEL_H
@@ -307,6 +330,9 @@ if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("elemental", elemental)) retu
#ifdef CHAR_GEOIP_H /* geoip */
if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("geoip", geoip)) return "geoip";
#endif // CHAR_GEOIP_H
+#ifdef COMMON_GRFIO_H /* grfio */
+if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("grfio", grfio)) return "grfio";
+#endif // COMMON_GRFIO_H
#ifdef MAP_GUILD_H /* guild */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("guild", guild)) return "guild";
#endif // MAP_GUILD_H
@@ -397,12 +423,18 @@ if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mapit", mapit)) return "mapi
#ifdef MAP_MAPREG_H /* mapreg */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mapreg", mapreg)) return "mapreg";
#endif // MAP_MAPREG_H
+#ifdef COMMON_MD5CALC_H /* md5 */
+if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("md5", md5)) return "md5";
+#endif // COMMON_MD5CALC_H
#ifdef MAP_MERCENARY_H /* mercenary */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mercenary", mercenary)) return "mercenary";
#endif // MAP_MERCENARY_H
#ifdef MAP_MOB_H /* mob */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("mob", mob)) return "mob";
#endif // MAP_MOB_H
+#ifdef COMMON_MUTEX_H /* mutex */
+if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("mutex", mutex)) return "mutex";
+#endif // COMMON_MUTEX_H
#ifdef MAP_NPC_H /* npc_chat */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("npc_chat", npc_chat)) return "npc_chat";
#endif // MAP_NPC_H
@@ -436,6 +468,9 @@ if ((server_type&(SERVER_TYPE_CHAR)) && !HPM_SYMBOL("pincode", pincode)) return
#ifdef MAP_QUEST_H /* quest */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("quest", quest)) return "quest";
#endif // MAP_QUEST_H
+#ifdef COMMON_RANDOM_H /* rnd */
+if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("rnd", rnd)) return "rnd";
+#endif // COMMON_RANDOM_H
#ifdef MAP_SCRIPT_H /* script */
if ((server_type&(SERVER_TYPE_MAP)) && !HPM_SYMBOL("script", script)) return "script";
#endif // MAP_SCRIPT_H
@@ -472,6 +507,9 @@ if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("sv", sv)) return "sv";
#ifdef COMMON_SYSINFO_H /* sysinfo */
if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("sysinfo", sysinfo)) return "sysinfo";
#endif // COMMON_SYSINFO_H
+#ifdef COMMON_THREAD_H /* thread */
+if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("thread", thread)) return "thread";
+#endif // COMMON_THREAD_H
#ifdef COMMON_TIMER_H /* timer */
if ((server_type&(SERVER_TYPE_ALL)) && !HPM_SYMBOL("timer", timer)) return "timer";
#endif // COMMON_TIMER_H
diff --git a/src/common/console.c b/src/common/console.c
index 0be33e5c3..f1b4523e2 100644
--- a/src/common/console.c
+++ b/src/common/console.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -57,6 +57,7 @@ struct console_interface console_s;
struct console_interface *console;
#ifdef CONSOLE_INPUT
struct console_input_interface console_input_s;
+struct spin_lock console_ptlock_s;
struct {
char queue[CONSOLE_PARSE_SIZE][MAX_CONSOLE_INPUT];
@@ -464,45 +465,45 @@ void *cThread_main(void *x) {
console->input->parse(input);
if( input[0] != '\0' ) {/* did we get something? */
- EnterSpinLock(&console->input->ptlock);
+ EnterSpinLock(console->input->ptlock);
if( cinput.count == CONSOLE_PARSE_SIZE ) {
- LeaveSpinLock(&console->input->ptlock);
+ LeaveSpinLock(console->input->ptlock);
continue;/* drop */
}
safestrncpy(cinput.queue[cinput.count++],input,MAX_CONSOLE_INPUT);
- LeaveSpinLock(&console->input->ptlock);
+ LeaveSpinLock(console->input->ptlock);
}
}
- ramutex_lock( console->input->ptmutex );
- racond_wait( console->input->ptcond, console->input->ptmutex, -1 );
- ramutex_unlock( console->input->ptmutex );
+ mutex->lock(console->input->ptmutex);
+ mutex->cond_wait(console->input->ptcond, console->input->ptmutex, -1);
+ mutex->unlock(console->input->ptmutex);
}
return NULL;
}
int console_parse_timer(int tid, int64 tick, int id, intptr_t data) {
int i;
- EnterSpinLock(&console->input->ptlock);
+ EnterSpinLock(console->input->ptlock);
for(i = 0; i < cinput.count; i++) {
console->input->parse_sub(cinput.queue[i]);
}
cinput.count = 0;
- LeaveSpinLock(&console->input->ptlock);
- racond_signal(console->input->ptcond);
+ LeaveSpinLock(console->input->ptlock);
+ mutex->cond_signal(console->input->ptcond);
return 0;
}
void console_parse_final(void) {
if( console->input->ptstate ) {
InterlockedDecrement(&console->input->ptstate);
- racond_signal(console->input->ptcond);
+ mutex->cond_signal(console->input->ptcond);
/* wait for thread to close */
- rathread_wait(console->input->pthread, NULL);
+ thread->wait(console->input->pthread, NULL);
- racond_destroy(console->input->ptcond);
- ramutex_destroy(console->input->ptmutex);
+ mutex->cond_destroy(console->input->ptcond);
+ mutex->destroy(console->input->ptmutex);
}
}
void console_parse_init(void) {
@@ -510,12 +511,12 @@ void console_parse_init(void) {
console->input->ptstate = 1;
- InitializeSpinLock(&console->input->ptlock);
+ InitializeSpinLock(console->input->ptlock);
- console->input->ptmutex = ramutex_create();
- console->input->ptcond = racond_create();
+ console->input->ptmutex = mutex->create();
+ console->input->ptcond = mutex->cond_create();
- if( (console->input->pthread = rathread_create(console->input->pthread_main, NULL)) == NULL ){
+ if( (console->input->pthread = thread->create(console->input->pthread_main, NULL)) == NULL ){
ShowFatalError("console_parse_init: failed to spawn console_parse thread.\n");
exit(EXIT_FAILURE);
}
@@ -563,6 +564,7 @@ void console_defaults(void)
console->display_gplnotice = display_gplnotice;
#ifdef CONSOLE_INPUT
console->input = &console_input_s;
+ console->input->ptlock = &console_ptlock_s;
console->input->parse_init = console_parse_init;
console->input->parse_final = console_parse_final;
console->input->parse_timer = console_parse_timer;
diff --git a/src/common/console.h b/src/common/console.h
index 57c750a7d..dd3a9cf2e 100644
--- a/src/common/console.h
+++ b/src/common/console.h
@@ -22,12 +22,14 @@
#include "common/hercules.h"
#include "common/db.h"
-#include "common/mutex.h"
#include "common/spinlock.h"
-#include "common/thread.h"
/* Forward Declarations */
struct Sql; // common/sql.h
+struct cond_data;
+struct mutex_data;
+struct spin_lock;
+struct thread_handle;
/**
* Queue Max
@@ -71,11 +73,11 @@ struct CParseEntry {
struct console_input_interface {
#ifdef CONSOLE_INPUT
/* vars */
- SPIN_LOCK ptlock;/* parse thread lock */
- rAthread *pthread;/* parse thread */
- volatile int32 ptstate;/* parse thread state */
- ramutex *ptmutex;/* parse thread mutex */
- racond *ptcond;/* parse thread cond */
+ struct spin_lock *ptlock; ///< parse thread lock.
+ struct thread_handle *pthread; ///< parse thread.
+ volatile int32 ptstate; ///< parse thread state.
+ struct mutex_data *ptmutex; ///< parse thread mutex.
+ struct cond_data *ptcond; ///< parse thread conditional variable.
/* */
VECTOR_DECL(struct CParseEntry *) command_list;
VECTOR_DECL(struct CParseEntry *) commands;
diff --git a/src/common/core.c b/src/common/core.c
index ccd80c44b..63123dfea 100644
--- a/src/common/core.c
+++ b/src/common/core.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -26,23 +26,27 @@
#include "common/cbasetypes.h"
#include "common/console.h"
#include "common/db.h"
+#include "common/des.h"
+#include "common/grfio.h"
#include "common/memmgr.h"
#include "common/mmo.h"
-#include "common/random.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
#include "common/sysinfo.h"
-#include "common/nullpo.h"
+#include "common/timer.h"
+#include "common/utils.h"
#ifndef MINICORE
# include "common/HPM.h"
# include "common/conf.h"
# include "common/ers.h"
+# include "common/md5calc.h"
+# include "common/mutex.h"
+# include "common/random.h"
# include "common/socket.h"
# include "common/sql.h"
# include "common/thread.h"
-# include "common/timer.h"
-# include "common/utils.h"
#endif
#ifndef _WIN32
@@ -54,6 +58,28 @@
#include <stdio.h>
#include <stdlib.h>
+/*
+ * Uncomment the line below if you want to silence the root warning on startup
+ * (not recommended, as it opens the machine to security risks. You should
+ * never ever run software as root unless it requires the extra privileges
+ * (which Hercules does not.)
+ * More info:
+ * http://www.tldp.org/HOWTO/Security-HOWTO/local-security.html
+ * http://www.gentoo.org/doc/en/security/security-handbook.xml?style=printable&part=1&chap=1#doc_chap4
+ * http://wiki.centos.org/TipsAndTricks/BecomingRoot
+ * http://fedoraproject.org/wiki/Configuring_Sudo
+ * https://help.ubuntu.com/community/RootSudo
+ * http://www.freebsdwiki.net/index.php/Root
+ *
+ * If your service provider forces (or encourages) you to run server software
+ * as root, please complain to them before and after uncommenting this line,
+ * since it is a very bad idea.
+ * Please note that NO SUPPORT will be given if you uncomment the following line.
+ */
+//#define I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+// And don't complain to us if the XYZ plugin you installed wiped your hard disk, or worse.
+// Note: This feature is deprecated, and should not be used.
+
/// Called when a terminate signal is received.
void (*shutdown_callback)(void) = NULL;
@@ -172,11 +198,51 @@ void signals_init (void) {
/**
* Warns the user if executed as superuser (root)
+ *
+ * @retval false if the check didn't pass and the program should be terminated.
*/
-void usercheck(void) {
+bool usercheck(void)
+{
+#ifndef _WIN32
if (sysinfo->is_superuser()) {
- ShowWarning("You are running Hercules with root privileges, it is not necessary.\n");
+ if (!isatty(fileno(stdin))) {
+#ifdef BUILDBOT
+ return true;
+#else // BUILDBOT
+ ShowFatalError("You are running Hercules with root privileges, it is not necessary, nor recommended. "
+ "Aborting.\n");
+ return false; // Don't allow noninteractive execution regardless.
+#endif // BUILDBOT
+ }
+ ShowError("You are running Hercules with root privileges, it is not necessary, nor recommended.\n");
+#ifdef I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+#ifndef BUILDBOT
+#warning This Hercules build is not eligible to obtain support by the developers.
+#warning The setting I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT is deprecated and should not be used.
+#endif // BUILDBOT
+#else // not I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
+ ShowNotice("Execution will be paused for 60 seconds. Press Ctrl-C if you wish to quit.\n");
+ ShowNotice("If you want to get rid of this message, please open %s and uncomment, near the top, the line saying:\n"
+ "\t\"//#define I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT\"\n", __FILE__);
+ ShowNotice("Note: In a near future, this courtesy notice will go away. "
+ "Please update your infrastructure not to require root privileges before then.\n");
+ ShowWarning("It's recommended that you " CL_WHITE "press CTRL-C now!" CL_RESET "\n");
+ {
+ int i;
+ for (i = 0; i < 60; i++) {
+ ShowMessage("\a *");
+ HSleep(1);
+ }
+ }
+ ShowMessage("\n");
+ ShowNotice("Resuming operations with root privileges. "
+ CL_RED "If anything breaks, you get to keep the pieces, "
+ "and the Hercules developers won't be able to help you."
+ CL_RESET "\n");
+#endif // I_AM_AWARE_OF_THE_RISK_AND_STILL_WANT_TO_RUN_HERCULES_AS_ROOT
}
+#endif // not _WIN32
+ return true;
}
void core_defaults(void) {
@@ -191,12 +257,18 @@ void core_defaults(void) {
malloc_defaults();
showmsg_defaults();
cmdline_defaults();
+ des_defaults();
+ grfio_defaults(); // Note: grfio is lazily loaded. grfio->init() and grfio->final() are not automatically called.
#ifndef MINICORE
+ mutex_defaults();
libconfig_defaults();
sql_defaults();
timer_defaults();
db_defaults();
socket_defaults();
+ rnd_defaults();
+ md5_defaults();
+ thread_defaults();
#endif
}
/**
@@ -426,7 +498,8 @@ int main (int argc, char **argv) {
if (!(showmsg->silent&0x1))
console->display_title();
- usercheck();
+ if (!usercheck())
+ return EXIT_FAILURE;
#ifdef MINICORE // minimalist Core
do_init(argc,argv);
@@ -435,7 +508,7 @@ int main (int argc, char **argv) {
set_server_type();
Sql_Init();
- rathread_init();
+ thread->init();
DB->init();
signals_init();
@@ -446,8 +519,7 @@ int main (int argc, char **argv) {
timer->init();
/* timer first */
- rnd_init();
- srand((unsigned int)timer->gettick());
+ rnd->init();
console->init();
@@ -472,8 +544,9 @@ int main (int argc, char **argv) {
timer->final();
sockt->final();
DB->final();
- rathread_final();
+ thread->final();
ers_final();
+ rnd->final();
#endif
cmdline->final();
//sysinfo->final(); Called by iMalloc->final()
diff --git a/src/common/db.h b/src/common/db.h
index d7d111c86..1c0955221 100644
--- a/src/common/db.h
+++ b/src/common/db.h
@@ -1395,6 +1395,16 @@ HPShared struct db_interface *DB;
} while(false)
/**
+ * Removes all values from the vector.
+ *
+ * Does not free the allocated data.
+ */
+#define VECTOR_TRUNCATE(_vec) \
+ do { \
+ VECTOR_LENGTH(_vec) = 0; \
+ } while (false)
+
+/**
* Clears the vector, freeing allocated data.
*
* @param _vec Vector.
diff --git a/src/common/des.c b/src/common/des.c
index ce64309f3..c680610e9 100644
--- a/src/common/des.c
+++ b/src/common/des.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -24,23 +24,23 @@
#include "common/cbasetypes.h"
-/// DES (Data Encryption Standard) algorithm, modified version.
-/// @see http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=5099.
-/// @see http://en.wikipedia.org/wiki/Data_Encryption_Standard
-/// @see http://en.wikipedia.org/wiki/DES_supplementary_material
+/** @file
+ * Implementation of the des interface.
+ */
+struct des_interface des_s;
+struct des_interface *des;
/// Bitmask for accessing individual bits of a byte.
static const uint8_t mask[8] = {
0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};
-
-/// Initial permutation (IP).
-static void IP(BIT64* src)
+/**
+ * Initial permutation (IP).
+ */
+static void des_IP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t ip_table[64] = {
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
@@ -51,24 +51,23 @@ static void IP(BIT64* src)
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(ip_table); ++i )
- {
+ for(i = 0; i < ARRAYLENGTH(ip_table); ++i) {
uint8_t j = ip_table[i] - 1;
- if( src->b[(j >> 3) & 7] & mask[j & 7] )
- tmp .b[(i >> 3) & 7] |= mask[i & 7];
+ if (src->b[(j >> 3) & 7] & mask[j & 7])
+ tmp.b[(i >> 3) & 7] |= mask[i & 7];
}
*src = tmp;
}
-
-/// Final permutation (IP^-1).
-static void FP(BIT64* src)
+/**
+ * Final permutation (IP^-1).
+ */
+static void des_FP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t fp_table[64] = {
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
@@ -79,24 +78,26 @@ static void FP(BIT64* src)
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(fp_table); ++i )
- {
+ for (i = 0; i < ARRAYLENGTH(fp_table); ++i) {
uint8_t j = fp_table[i] - 1;
- if( src->b[(j >> 3) & 7] & mask[j & 7] )
- tmp .b[(i >> 3) & 7] |= mask[i & 7];
+ if (src->b[(j >> 3) & 7] & mask[j & 7])
+ tmp.b[(i >> 3) & 7] |= mask[i & 7];
}
*src = tmp;
}
-
-/// Expansion (E).
-/// Expands upper four 8-bits (32b) into eight 6-bits (48b).
-static void E(BIT64* src)
+/**
+ * Expansion (E).
+ *
+ * Expands upper four 8-bits (32b) into eight 6-bits (48b).
+ */
+static void des_E(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
+ struct des_bit64 tmp = {{0}};
#if 0
// original
@@ -110,13 +111,12 @@ static void E(BIT64* src)
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1,
};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(expand_table); ++i )
- {
+ for (i = 0; i < ARRAYLENGTH(expand_table); ++i) {
uint8_t j = expand_table[i] - 1;
- if( src->b[j / 8 + 4] & mask[j % 8] )
- tmp .b[i / 6 + 0] |= mask[i % 6];
+ if (src->b[j / 8 + 4] & mask[j % 8])
+ tmp.b[i / 6 + 0] |= mask[i % 6];
}
#endif
// optimized
@@ -132,12 +132,11 @@ static void E(BIT64* src)
*src = tmp;
}
-
-/// Transposition (P-BOX).
-static void TP(BIT64* src)
+/**
+ * Transposition (P-BOX).
+ */
+static void des_TP(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t tp_table[32] = {
16, 7, 20, 21,
29, 12, 28, 17,
@@ -148,25 +147,27 @@ static void TP(BIT64* src)
19, 13, 30, 6,
22, 11, 4, 25,
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(tp_table); ++i )
- {
+ for (i = 0; i < ARRAYLENGTH(tp_table); ++i) {
uint8_t j = tp_table[i] - 1;
- if( src->b[(j >> 3) + 0] & mask[j & 7] )
- tmp .b[(i >> 3) + 4] |= mask[i & 7];
+ if (src->b[(j >> 3) + 0] & mask[j & 7])
+ tmp.b[(i >> 3) + 4] |= mask[i & 7];
}
*src = tmp;
}
-/// Substitution boxes (S-boxes).
-/// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast).
-static void SBOX(BIT64* src)
+/**
+ * Substitution boxes (S-boxes).
+ *
+ * This implementation was optimized to process two nibbles in one step (twice
+ * as fast).
+ */
+static void des_SBOX(struct des_bit64 *src)
{
- BIT64 tmp = {{0}};
-
static const uint8_t s_table[4][64] = {
{
0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e,
@@ -190,10 +191,10 @@ static void SBOX(BIT64* src)
0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb,
}
};
+ struct des_bit64 tmp = {{0}};
+ int i;
- size_t i;
- for( i = 0; i < ARRAYLENGTH(s_table); ++i )
- {
+ for (i = 0; i < ARRAYLENGTH(s_table); ++i) {
tmp.b[i] = (s_table[i][src->b[i*2+0]] & 0xf0)
| (s_table[i][src->b[i*2+1]] & 0x0f);
}
@@ -201,15 +202,17 @@ static void SBOX(BIT64* src)
*src = tmp;
}
-
-/// DES round function.
-/// XORs src[0..3] with TP(SBOX(E(src[4..7]))).
-static void RoundFunction(BIT64* src)
+/**
+ * DES round function.
+ *
+ * XORs src[0..3] with TP(SBOX(E(src[4..7]))).
+ */
+static void des_RoundFunction(struct des_bit64 *src)
{
- BIT64 tmp = *src;
- E(&tmp);
- SBOX(&tmp);
- TP(&tmp);
+ struct des_bit64 tmp = *src;
+ des_E(&tmp);
+ des_SBOX(&tmp);
+ des_TP(&tmp);
src->b[0] ^= tmp.b[4];
src->b[1] ^= tmp.b[5];
@@ -217,20 +220,30 @@ static void RoundFunction(BIT64* src)
src->b[3] ^= tmp.b[7];
}
-
-void des_decrypt_block(BIT64* block)
+/// @copydoc des_interface::decrypt_block()
+void des_decrypt_block(struct des_bit64 *block)
{
- IP(block);
- RoundFunction(block);
- FP(block);
+ des_IP(block);
+ des_RoundFunction(block);
+ des_FP(block);
}
-
-void des_decrypt(unsigned char* data, size_t size)
+/// @copydoc des_interface::decrypt()
+void des_decrypt(unsigned char *data, size_t size)
{
- BIT64* p = (BIT64*)data;
+ struct des_bit64 *p = (struct des_bit64 *)data;
size_t i;
- for( i = 0; i*8 < size; i += 8 )
- des_decrypt_block(p);
+ for (i = 0; i*8 < size; i += 8)
+ des->decrypt_block(p);
+}
+
+/**
+ * Interface base initialization.
+ */
+void des_defaults(void)
+{
+ des = &des_s;
+ des->decrypt = des_decrypt;
+ des->decrypt_block = des_decrypt_block;
}
diff --git a/src/common/des.h b/src/common/des.h
index d62b5cc49..9924a044b 100644
--- a/src/common/des.h
+++ b/src/common/des.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,14 +21,49 @@
#ifndef COMMON_DES_H
#define COMMON_DES_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
+
+/**
+ * @file
+ *
+ * DES (Data Encryption Standard) algorithm, modified version.
+ *
+ * @see http://www.eathena.ws/board/index.php?autocom=bugtracker&showbug=5099
+ * @see http://en.wikipedia.org/wiki/Data_Encryption_Standard
+ * @see http://en.wikipedia.org/wiki/DES_supplementary_material
+ */
+
+/* Struct definitions */
/// One 64-bit block.
-typedef struct BIT64 { uint8_t b[8]; } BIT64;
+struct des_bit64 {
+ uint8_t b[8];
+};
+
+/* Interface */
+
+/// The des interface.
+struct des_interface {
+ /**
+ * Decrypts a block.
+ *
+ * @param[in,out] block The block to decrypt (in-place).
+ */
+ void (*decrypt_block) (struct des_bit64 *block);
+
+ /**
+ * Decrypts a buffer.
+ *
+ * @param [in,out] data The buffer to decrypt (in-place).
+ * @param [in] size The size of the data.
+ */
+ void (*decrypt) (unsigned char *data, size_t size);
+};
#ifdef HERCULES_CORE
-void des_decrypt_block(BIT64* block);
-void des_decrypt(unsigned char* data, size_t size);
+void des_defaults(void);
#endif // HERCULES_CORE
+HPShared struct des_interface *des; ///< Pointer to the des interface implementation.
+
#endif // COMMON_DES_H
diff --git a/src/common/grfio.c b/src/common/grfio.c
index c6e47d357..0a9708f17 100644
--- a/src/common/grfio.c
+++ b/src/common/grfio.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -35,10 +35,12 @@
#include <sys/stat.h>
#include <zlib.h>
-//----------------------------
-// file entry table struct
-//----------------------------
-typedef struct FILELIST {
+/** @file
+ * Implementation of the GRF I/O interface.
+ */
+
+/// File entry table struct.
+struct grf_filelist {
int srclen; ///< compressed size
int srclen_aligned;
int declen; ///< original size
@@ -48,11 +50,13 @@ typedef struct FILELIST {
char fn[128-4*5]; ///< file name
char *fnd; ///< if the file was cloned, contains name of original file
int8 gentry; ///< read grf file select
-} FILELIST;
+};
-#define FILELIST_TYPE_FILE 0x01 // entry is a file
-#define FILELIST_TYPE_ENCRYPT_MIXED 0x02 // encryption mode 0 (header DES + periodic DES/shuffle)
-#define FILELIST_TYPE_ENCRYPT_HEADER 0x04 // encryption mode 1 (header DES only)
+enum grf_filelist_type {
+ FILELIST_TYPE_FILE = 0x01, ///< entry is a file
+ FILELIST_TYPE_ENCRYPT_MIXED = 0x02, ///< encryption mode 0 (header DES + periodic DES/shuffle)
+ FILELIST_TYPE_ENCRYPT_HEADER = 0x04, ///< encryption mode 1 (header DES only)
+};
//gentry ... > 0 : data read from a grf file (gentry_table[gentry-1])
//gentry ... 0 : data read from a local file (data directory)
@@ -64,7 +68,7 @@ typedef struct FILELIST {
//#define GRFIO_LOCAL
// stores info about every loaded file
-FILELIST* filelist = NULL;
+struct grf_filelist *filelist = NULL;
int filelist_entrys = 0;
int filelist_maxentry = 0;
@@ -76,24 +80,30 @@ int gentry_maxentry = 0;
// the path to the data directory
char data_dir[1024] = "";
+struct grfio_interface grfio_s;
+struct grfio_interface *grfio;
+
// little endian char array to uint conversion
-static unsigned int getlong(unsigned char* p)
+static unsigned int getlong(unsigned char *p)
{
return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24);
}
-static void NibbleSwap(unsigned char* src, int len)
+static void NibbleSwap(unsigned char *src, int len)
{
- while( len > 0 )
- {
+ while (len > 0) {
*src = (*src >> 4) | (*src << 4);
++src;
--len;
}
}
-/// Substitutes some specific values for others, leaves rest intact. Obfuscation.
-/// NOTE: Operation is symmetric (calling it twice gives back the original input).
+/**
+ * (De)-obfuscates data.
+ *
+ * Substitutes some specific values for others, leaves rest intact.
+ * NOTE: Operation is symmetric (calling it twice gives back the original input).
+ */
static uint8_t grf_substitution(uint8_t in)
{
uint8_t out;
@@ -121,9 +131,9 @@ static uint8_t grf_substitution(uint8_t in)
}
#if 0 /* this is not used anywhere, is it ok to delete? */
-static void grf_shuffle_enc(BIT64* src)
+static void grf_shuffle_enc(struct des_bit64 *src)
{
- BIT64 out;
+ struct des_bit64 out;
out.b[0] = src->b[3];
out.b[1] = src->b[4];
@@ -138,9 +148,9 @@ static void grf_shuffle_enc(BIT64* src)
}
#endif // 0
-static void grf_shuffle_dec(BIT64* src)
+static void grf_shuffle_dec(struct des_bit64 *src)
{
- BIT64 out;
+ struct des_bit64 out;
out.b[0] = src->b[3];
out.b[1] = src->b[4];
@@ -154,29 +164,42 @@ static void grf_shuffle_dec(BIT64* src)
*src = out;
}
-static void grf_decode_header(unsigned char* buf, size_t len)
+/**
+ * Decodes header-encrypted grf data.
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data.
+ */
+static void grf_decode_header(unsigned char *buf, size_t len)
{
- BIT64* p = (BIT64*)buf;
- size_t nblocks = len / sizeof(BIT64);
+ struct des_bit64 *p = (struct des_bit64 *)buf;
+ size_t nblocks = len / sizeof(struct des_bit64);
size_t i;
// first 20 blocks are all des-encrypted
- for( i = 0; i < 20 && i < nblocks; ++i )
- des_decrypt_block(&p[i]);
+ for (i = 0; i < 20 && i < nblocks; ++i)
+ des->decrypt_block(&p[i]);
// the rest is plaintext, done.
}
-static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
+/**
+ * Decodes fully encrypted grf data
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data.
+ * @param[in] cycle The current decoding cycle.
+ */
+static void grf_decode_full(unsigned char *buf, size_t len, int cycle)
{
- BIT64* p = (BIT64*)buf;
- size_t nblocks = len / sizeof(BIT64);
+ struct des_bit64 *p = (struct des_bit64 *)buf;
+ size_t nblocks = len / sizeof(struct des_bit64);
int dcycle, scycle;
size_t i, j;
// first 20 blocks are all des-encrypted
- for( i = 0; i < 20 && i < nblocks; ++i )
- des_decrypt_block(&p[i]);
+ for (i = 0; i < 20 && i < nblocks; ++i)
+ des->decrypt_block(&p[i]);
// after that only one of every 'dcycle' blocks is des-encrypted
dcycle = cycle;
@@ -186,17 +209,16 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
// so decrypt/de-shuffle periodically
j = (size_t)-1; // 0, adjusted to fit the ++j step
- for( i = 20; i < nblocks; ++i )
- {
- if( i % dcycle == 0 )
- {// decrypt block
- des_decrypt_block(&p[i]);
+ for (i = 20; i < nblocks; ++i) {
+ if (i % dcycle == 0) {
+ // decrypt block
+ des->decrypt_block(&p[i]);
continue;
}
++j;
- if( j % scycle == 0 && j != 0 )
- {// de-shuffle block
+ if (j % scycle == 0 && j != 0) {
+ // de-shuffle block
grf_shuffle_dec(&p[i]);
continue;
}
@@ -205,22 +227,25 @@ static void grf_decode_full(unsigned char* buf, size_t len, int cycle)
}
}
-/// Decodes grf data.
-/// @param buf data to decode (in-place)
-/// @param len length of the data
-/// @param entry_type flags associated with the data
-/// @param entry_len true (unaligned) length of the data
-static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entry_len)
+/**
+ * Decodes grf data.
+ *
+ * @param[in,out] buf Data to decode (in-place).
+ * @param[in] len Length of the data
+ * @param[in] entry_type Flags associated with the data.
+ * @param[in] entry_len True (unaligned) length of the data.
+ */
+static void grf_decode(unsigned char *buf, size_t len, char entry_type, int entry_len)
{
- if( entry_type & FILELIST_TYPE_ENCRYPT_MIXED )
- {// fully encrypted
+ if (entry_type & FILELIST_TYPE_ENCRYPT_MIXED) {
+ // fully encrypted
int digits;
int cycle;
int i;
// compute number of digits of the entry length
digits = 1;
- for( i = 10; i <= entry_len; i *= 10 )
+ for (i = 10; i <= entry_len; i *= 10)
++digits;
// choose size of gap between two encrypted blocks
@@ -232,51 +257,47 @@ static void grf_decode(unsigned char* buf, size_t len, char entry_type, int entr
: digits + 15;
grf_decode_full(buf, len, cycle);
- }
- else
- if( entry_type & FILELIST_TYPE_ENCRYPT_HEADER )
- {// header encrypted
+ } else if (entry_type & FILELIST_TYPE_ENCRYPT_HEADER) {
+ // header encrypted
grf_decode_header(buf, len);
}
- else
- {// plaintext
- ;
- }
+ /* else plaintext */
}
-/******************************************************
- *** Zlib Subroutines ***
- ******************************************************/
+/* Zlib Subroutines */
-/// zlib crc32
-unsigned long grfio_crc32(const unsigned char* buf, unsigned int len)
+/// @copydoc grfio_interface::crc32()
+unsigned long grfio_crc32(const unsigned char *buf, unsigned int len)
{
return crc32(crc32(0L, Z_NULL, 0), buf, len);
}
-/// zlib uncompress
-int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen)
+/// @copydoc grfio_interface::decode_zip
+int grfio_decode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len)
{
- return uncompress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen);
+ return uncompress(dest, dest_len, source, source_len);
}
-/// zlib compress
-int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen) {
- if( *destLen == 0 ) /* [Ind/Hercules] */
- *destLen = compressBound(sourceLen);
- if( dest == NULL ) { /* [Ind/Hercules] */
- CREATE(dest, unsigned char, *destLen);
+/// @copydoc grfio_interface::encode_zip
+int grfio_encode_zip(void *dest, unsigned long *dest_len, const void *source, unsigned long source_len)
+{
+ if (*dest_len == 0) /* [Ind/Hercules] */
+ *dest_len = compressBound(source_len);
+ if (dest == NULL) {
+ /* [Ind/Hercules] */
+ CREATE(dest, unsigned char, *dest_len);
}
- return compress((Bytef*)dest, destLen, (const Bytef*)source, sourceLen);
+ return compress(dest, dest_len, source, source_len);
}
-/***********************************************************
- *** File List Subroutines ***
- ***********************************************************/
-// file list hash table
+/* File List Subroutines */
+
+/// File list hash table
int filelist_hash[256];
-// initializes the table that holds the first elements of all hash chains
+/**
+ * Initializes the table that holds the first elements of all hash chains
+ */
static void hashinit(void)
{
int i;
@@ -284,26 +305,37 @@ static void hashinit(void)
filelist_hash[i] = -1;
}
-// hashes a filename string into a number from {0..255}
-static int filehash(const char* fname)
+/**
+ * Hashes a filename string into a number from {0..255}
+ *
+ * @param fname The filename to hash.
+ * @return The hash.
+ */
+static int grf_filehash(const char *fname)
{
- unsigned int hash = 0;
- while(*fname) {
+ uint32 hash = 0;
+ while (*fname != '\0') {
hash = (hash<<1) + (hash>>7)*9 + TOLOWER(*fname);
fname++;
}
return hash & 255;
}
-// finds a FILELIST entry with the specified file name
-static FILELIST* filelist_find(const char* fname)
+/**
+ * Finds a grf_filelist entry with the specified file name
+ *
+ * @param fname The file to find.
+ * @return The file entry.
+ * @retval NULL if the file wasn't found.
+ */
+static struct grf_filelist *grfio_filelist_find(const char *fname)
{
int hash, index;
- if (!filelist)
+ if (filelist == NULL)
return NULL;
- hash = filelist_hash[filehash(fname)];
+ hash = filelist_hash[grf_filehash(fname)];
for (index = hash; index != -1; index = filelist[index].next)
if(!strcmpi(filelist[index].fn, fname))
break;
@@ -311,16 +343,23 @@ static FILELIST* filelist_find(const char* fname)
return (index >= 0) ? &filelist[index] : NULL;
}
-// returns the original file name
-char* grfio_find_file(const char* fname)
+/// @copydoc grfio_interface::find_file()
+const char *grfio_find_file(const char *fname)
{
- FILELIST *flist = filelist_find(fname);
- if (!flist) return NULL;
+ struct grf_filelist *flist = grfio_filelist_find(fname);
+ if (flist == NULL)
+ return NULL;
return (!flist->fnd ? flist->fn : flist->fnd);
}
-// adds a FILELIST entry into the list of loaded files
-static FILELIST* filelist_add(FILELIST* entry) {
+/**
+ * Adds a grf_filelist entry into the list of loaded files.
+ *
+ * @param entry The entry to add.
+ * @return A pointer to the added entry.
+ */
+static struct grf_filelist *grfio_filelist_add(struct grf_filelist *entry)
+{
int hash;
nullpo_ret(entry);
#ifdef __clang_analyzer__
@@ -331,16 +370,16 @@ static FILELIST* filelist_add(FILELIST* entry) {
#define FILELIST_ADDS 1024 // number increment of file lists `
if (filelist_entrys >= filelist_maxentry) {
- filelist = (FILELIST *)aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(FILELIST));
- memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(FILELIST));
+ filelist = aRealloc(filelist, (filelist_maxentry + FILELIST_ADDS) * sizeof(struct grf_filelist));
+ memset(filelist + filelist_maxentry, '\0', FILELIST_ADDS * sizeof(struct grf_filelist));
filelist_maxentry += FILELIST_ADDS;
}
#undef FILELIST_ADDS
- memcpy(&filelist[filelist_entrys], entry, sizeof(FILELIST));
+ memcpy(&filelist[filelist_entrys], entry, sizeof(struct grf_filelist));
- hash = filehash(entry->fn);
+ hash = grf_filehash(entry->fn);
filelist[filelist_entrys].next = filelist_hash[hash];
filelist_hash[hash] = filelist_entrys;
@@ -349,63 +388,69 @@ static FILELIST* filelist_add(FILELIST* entry) {
return &filelist[filelist_entrys - 1];
}
-// adds a new FILELIST entry or overwrites an existing one
-static FILELIST* filelist_modify(FILELIST* entry)
+/**
+ * Adds a new grf_filelist entry or overwrites an existing one.
+ *
+ * @param entry The entry to add.
+ * @return A pointer to the added entry.
+ */
+static struct grf_filelist *grfio_filelist_modify(struct grf_filelist *entry)
{
- FILELIST* fentry = filelist_find(entry->fn);
+ struct grf_filelist *fentry = grfio_filelist_find(entry->fn);
if (fentry != NULL) {
int tmp = fentry->next;
- memcpy(fentry, entry, sizeof(FILELIST));
+ memcpy(fentry, entry, sizeof(struct grf_filelist));
fentry->next = tmp;
} else {
- fentry = filelist_add(entry);
+ fentry = grfio_filelist_add(entry);
}
return fentry;
}
-// shrinks the file list array if too long
-static void filelist_compact(void)
+/// Shrinks the file list array if too long.
+static void grfio_filelist_compact(void)
{
if (filelist == NULL)
return;
if (filelist_entrys < filelist_maxentry) {
- filelist = (FILELIST *)aRealloc(filelist, filelist_entrys * sizeof(FILELIST));
+ filelist = aRealloc(filelist, filelist_entrys * sizeof(struct grf_filelist));
filelist_maxentry = filelist_entrys;
}
}
-/***********************************************************
- *** Grfio Subroutines ***
- ***********************************************************/
+/* GRF I/O Subroutines */
-/// Combines are resource path with the data folder location to create local resource path.
-static void grfio_localpath_create(char* buffer, size_t size, const char* filename)
+/**
+ * Combines a resource path with the data folder location to create local
+ * resource path.
+ *
+ * @param[out] buffer The output buffer.
+ * @param[in] size The size of the output buffer.
+ * @param[in] filename Resource path.
+ */
+static void grfio_localpath_create(char *buffer, size_t size, const char *filename)
{
- unsigned int i;
+ int i;
size_t len;
len = strlen(data_dir);
- if( data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\' )
- {
+ if (data_dir[0] == '\0' || data_dir[len-1] == '/' || data_dir[len-1] == '\\')
safesnprintf(buffer, size, "%s%s", data_dir, filename);
- }
else
- {
safesnprintf(buffer, size, "%s/%s", data_dir, filename);
- }
// normalize path
- for( i = 0; buffer[i] != '\0'; ++i )
- if( buffer[i] == '\\' )
+ for (i = 0; buffer[i] != '\0'; ++i)
+ if (buffer[i] == '\\')
buffer[i] = '/';
}
-/// Reads a file into a newly allocated buffer (from grf or data directory).
+/// @copydoc grfio_interface::reads()
void *grfio_reads(const char *fname, int *size)
{
- FILELIST* entry = filelist_find(fname);
+ struct grf_filelist *entry = grfio_filelist_find(fname);
if (entry == NULL || entry->gentry <= 0) {
// LocalFileCheck
char lfname[256];
@@ -424,7 +469,7 @@ void *grfio_reads(const char *fname, int *size)
return NULL;
}
fseek(in,0,SEEK_SET);
- buf = (unsigned char *)aMalloc(declen+1); // +1 for resnametable zero-termination
+ buf = aMalloc(declen+1); // +1 for resnametable zero-termination
buf[declen] = '\0';
if (fread(buf, 1, declen, in) != (size_t)declen) {
ShowError("An error occurred in fread grfio_reads, fname=%s \n",fname);
@@ -454,7 +499,7 @@ void *grfio_reads(const char *fname, int *size)
if (in != NULL) {
int fsize = entry->srclen_aligned;
- unsigned char *buf = (unsigned char *)aMalloc(fsize);
+ unsigned char *buf = aMalloc(fsize);
unsigned char *buf2 = NULL;
if (fseek(in, entry->srcpos, SEEK_SET) != 0
|| fread(buf, 1, fsize, in) != (size_t)fsize) {
@@ -465,14 +510,14 @@ void *grfio_reads(const char *fname, int *size)
}
fclose(in);
- buf2 = (unsigned char *)aMalloc(entry->declen+1); // +1 for resnametable zero-termination
+ buf2 = aMalloc(entry->declen+1); // +1 for resnametable zero-termination
buf2[entry->declen] = '\0';
if (entry->type & FILELIST_TYPE_FILE) {
// file
uLongf len;
grf_decode(buf, fsize, entry->type, entry->srclen);
len = entry->declen;
- decode_zip(buf2, &len, buf, entry->srclen);
+ grfio->decode_zip(buf2, &len, buf, entry->srclen);
if (len != (uLong)entry->declen) {
ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen);
aFree(buf);
@@ -498,35 +543,51 @@ void *grfio_reads(const char *fname, int *size)
return NULL;
}
-/// Decodes encrypted filename from a version 01xx grf index.
-static char* decode_filename(unsigned char* buf, int len)
+/**
+ * Decodes encrypted filename from a version 01xx grf index.
+ *
+ * @param[in,out] buf The encrypted filename (decrypted in-place).
+ * @param[in] len The filename length.
+ * @return A pointer to the decrypted filename.
+ */
+static char *grfio_decode_filename(unsigned char *buf, int len)
{
- int lop;
- for(lop=0;lop<len;lop+=8) {
- NibbleSwap(&buf[lop],8);
- des_decrypt(&buf[lop],8);
+ int i;
+ for (i = 0; i < len; i += 8) {
+ NibbleSwap(&buf[i],8);
+ des->decrypt(&buf[i],8);
}
return (char*)buf;
}
-/// Compares file extension against known large file types.
-/// @return true if the file should undergo full mode 0 decryption, and true otherwise.
-static bool isFullEncrypt(const char* fname)
+/**
+ * Compares file extension against known large file types.
+ *
+ * @param fname The file name.
+ * @return true if the file should undergo full mode 0 decryption, and true otherwise.
+ */
+static bool grfio_is_full_encrypt(const char *fname)
{
- const char* ext = strrchr(fname, '.');
- if( ext != NULL ) {
- static const char extensions[4][5] = { ".gnd", ".gat", ".act", ".str" };
- size_t i;
- for( i = 0; i < ARRAYLENGTH(extensions); ++i )
- if( strcmpi(ext, extensions[i]) == 0 )
+ const char *ext = strrchr(fname, '.');
+ if (ext != NULL) {
+ static const char *extensions[] = { ".gnd", ".gat", ".act", ".str" };
+ int i;
+ for (i = 0; i < ARRAYLENGTH(extensions); ++i)
+ if (strcmpi(ext, extensions[i]) == 0)
return false;
}
return true;
}
-/// Loads all entries in the specified grf file into the filelist.
-/// @param gentry index of the grf file name in the gentry_table
+/**
+ * Loads all entries in the specified grf file into the filelist.
+ *
+ * @param grfname Name of the grf file.
+ * @param gentry Index of the grf file name in the gentry_table.
+ * @return Error code.
+ * @retval 0 in case of success.
+ */
static int grfio_entryread(const char *grfname, int gentry)
{
long grf_size;
@@ -535,12 +596,11 @@ static int grfio_entryread(const char *grfname, int gentry)
unsigned char *grf_filelist;
FILE *fp = fopen(grfname, "rb");
- if( fp == NULL ) {
- ShowWarning("GRF data file not found: '%s'\n",grfname);
+ if (fp == NULL) {
+ ShowWarning("GRF data file not found: '%s'\n", grfname);
return 1; // 1:not found error
- } else {
- ShowInfo("GRF data file found: '%s'\n",grfname);
}
+ ShowInfo("GRF data file found: '%s'\n", grfname);
fseek(fp,0,SEEK_END);
grf_size = ftell(fp);
@@ -551,7 +611,7 @@ static int grfio_entryread(const char *grfname, int gentry)
fclose(fp);
return 2; // 2:file format error
}
- if (strcmp((const char*)grf_header,"Master of Magic") != 0 || fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0) {
+ if (strcmp((const char*)grf_header, "Master of Magic") != 0 || fseek(fp, getlong(grf_header+0x1e), SEEK_CUR) != 0) {
fclose(fp);
ShowError("GRF %s read error\n", grfname);
return 2; // 2:file format error
@@ -561,9 +621,8 @@ static int grfio_entryread(const char *grfname, int gentry)
if (grf_version == 0x01) {
// ****** Grf version 01xx ******
- long list_size;
- list_size = grf_size - ftell(fp);
- grf_filelist = (unsigned char *)aMalloc(list_size);
+ long list_size = grf_size - ftell(fp);
+ grf_filelist = aMalloc(list_size);
if (fread(grf_filelist,1,list_size,fp) != (size_t)list_size) {
ShowError("Couldn't read all grf_filelist element of %s \n", grfname);
aFree(grf_filelist);
@@ -576,11 +635,11 @@ static int grfio_entryread(const char *grfname, int gentry)
// Get an entry
for (entry = 0, ofs = 0; entry < entrys; ++entry) {
- FILELIST aentry;
+ struct grf_filelist aentry = { 0 };
int ofs2 = ofs+getlong(grf_filelist+ofs)+4;
unsigned char type = grf_filelist[ofs2+12];
if (type&FILELIST_TYPE_FILE) {
- char *fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6);
+ char *fname = grfio_decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6);
int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715;
if (strlen(fname) > sizeof(aentry.fn) - 1) {
@@ -589,7 +648,7 @@ static int grfio_entryread(const char *grfname, int gentry)
return 5; // 5: file name too long
}
- type |= isFullEncrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER;
+ type |= grfio_is_full_encrypt(fname) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER;
aentry.srclen = srclen;
aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579;
@@ -603,7 +662,7 @@ static int grfio_entryread(const char *grfname, int gentry)
#else
aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck
#endif
- filelist_modify(&aentry);
+ grfio_filelist_modify(&aentry);
}
ofs = ofs2 + 17;
@@ -630,7 +689,7 @@ static int grfio_entryread(const char *grfname, int gentry)
return 4;
}
- rBuf = (unsigned char *)aMalloc(rSize); // Get a Read Size
+ rBuf = aMalloc(rSize); // Get a Read Size
if (fread(rBuf,1,rSize,fp) != rSize) {
ShowError("An error occurred in fread \n");
fclose(fp);
@@ -638,8 +697,8 @@ static int grfio_entryread(const char *grfname, int gentry)
return 4;
}
fclose(fp);
- grf_filelist = (unsigned char *)aMalloc(eSize); // Get a Extend Size
- decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function
+ grf_filelist = aMalloc(eSize); // Get a Extend Size
+ grfio->decode_zip(grf_filelist, &eSize, rBuf, rSize); // Decode function
aFree(rBuf);
entrys = getlong(grf_header+0x26) - 7;
@@ -647,7 +706,7 @@ static int grfio_entryread(const char *grfname, int gentry)
// Get an entry
for (entry = 0, ofs = 0; entry < entrys; ++entry) {
- FILELIST aentry;
+ struct grf_filelist aentry;
char *fname = (char*)(grf_filelist+ofs);
int ofs2 = ofs + (int)strlen(fname)+1;
int type = grf_filelist[ofs2+12];
@@ -672,84 +731,89 @@ static int grfio_entryread(const char *grfname, int gentry)
#else
aentry.gentry = (char)(gentry+1); // With no first time LocalFileCheck
#endif
- filelist_modify(&aentry);
+ grfio_filelist_modify(&aentry);
}
ofs = ofs2 + 17;
}
aFree(grf_filelist);
- } else {// ****** Grf Other version ******
+ } else {
+ // ****** Grf Other version ******
fclose(fp);
ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a));
return 4;
}
- filelist_compact(); // Unnecessary area release of filelist
+ grfio_filelist_compact(); // Unnecessary area release of filelist
return 0; // 0:no error
}
-static bool grfio_parse_restable_row(const char* row)
+/**
+ * Parses a Resource file table row.
+ *
+ * @param row The row data.
+ * @return success state.
+ * @retval true in case of success.
+ */
+static bool grfio_parse_restable_row(const char *row)
{
char w1[256], w2[256];
char src[256], dst[256];
char local[256];
- FILELIST* entry;
+ struct grf_filelist *entry = NULL;
if (sscanf(row, "%255[^#\r\n]#%255[^#\r\n]#", w1, w2) != 2)
return false;
- if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL )
+ if (strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL)
return false; // we only need the maps' GAT and RSW files
sprintf(src, "data\\%s", w1);
sprintf(dst, "data\\%s", w2);
- entry = filelist_find(dst);
- if( entry != NULL )
- {// alias for GRF resource
- FILELIST fentry;
- memcpy(&fentry, entry, sizeof(FILELIST));
+ entry = grfio_filelist_find(dst);
+ if (entry != NULL) {
+ // alias for GRF resource
+ struct grf_filelist fentry = *entry;
safestrncpy(fentry.fn, src, sizeof(fentry.fn));
fentry.fnd = aStrdup(dst);
- filelist_modify(&fentry);
+ grfio_filelist_modify(&fentry);
return true;
}
grfio_localpath_create(local, sizeof(local), dst);
- if( exists(local) )
- {// alias for local resource
- FILELIST fentry;
- memset(&fentry, 0, sizeof(fentry));
+ if (exists(local)) {
+ // alias for local resource
+ struct grf_filelist fentry = { 0 };
safestrncpy(fentry.fn, src, sizeof(fentry.fn));
fentry.fnd = aStrdup(dst);
- filelist_modify(&fentry);
+ grfio_filelist_modify(&fentry);
return true;
}
return false;
}
-/// Grfio Resource file check.
+/**
+ * Grfio Resource file check.
+ */
static void grfio_resourcecheck(void)
{
char restable[256];
- char *buf;
- int size;
- FILE* fp;
- int i = 0;
+ char *buf = NULL;
+ FILE *fp = NULL;
+ int size = 0, i = 0;
// read resnametable from data directory and return if successful
grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt");
fp = fopen(restable, "rb");
- if( fp != NULL )
- {
+ if (fp != NULL) {
char line[256];
- while( fgets(line, sizeof(line), fp) )
- {
- if( grfio_parse_restable_row(line) )
+ while (fgets(line, sizeof(line), fp)) {
+ if (grfio_parse_restable_row(line))
++i;
}
@@ -759,20 +823,19 @@ static void grfio_resourcecheck(void)
}
// read resnametable from loaded GRF's, only if it cannot be loaded from the data directory
- buf = (char *)grfio_reads("data\\resnametable.txt", &size);
- if( buf != NULL )
- {
- char *ptr;
+ buf = grfio->reads("data\\resnametable.txt", &size);
+ if (buf != NULL) {
+ char *ptr = NULL;
buf[size] = '\0';
ptr = buf;
- while( ptr - buf < size )
- {
- if( grfio_parse_restable_row(ptr) )
+ while (ptr - buf < size) {
+ if (grfio_parse_restable_row(ptr))
++i;
ptr = strchr(ptr, '\n');
- if( ptr == NULL ) break;
+ if (ptr == NULL)
+ break;
ptr++;
}
@@ -782,13 +845,19 @@ static void grfio_resourcecheck(void)
}
}
-/// Reads a grf file and adds it to the list.
-static int grfio_add(const char* fname)
+/**
+ * Reads a grf file and adds it to the list.
+ *
+ * @param fname The file name to read.
+ * @return Error code.
+ * @retval 0 in case of success.
+ */
+static int grfio_add(const char *fname)
{
if (gentry_entrys >= gentry_maxentry) {
#define GENTRY_ADDS 4 // The number increment of gentry_table entries
gentry_maxentry += GENTRY_ADDS;
- gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*));
+ gentry_table = aRealloc(gentry_table, gentry_maxentry * sizeof(char*));
memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS);
#undef GENTRY_ADDS
}
@@ -798,7 +867,7 @@ static int grfio_add(const char* fname)
return grfio_entryread(fname, gentry_entrys - 1);
}
-/// Finalizes grfio.
+/// @copydoc grfio_interface::final()
void grfio_final(void)
{
if (filelist != NULL) {
@@ -824,36 +893,33 @@ void grfio_final(void)
gentry_entrys = gentry_maxentry = 0;
}
-/// Initializes grfio.
-void grfio_init(const char* fname)
+/// @copydoc grfio_interface::init()
+void grfio_init(const char *fname)
{
- FILE* data_conf;
+ FILE *data_conf;
int grf_num = 0;
hashinit(); // hash table initialization
data_conf = fopen(fname, "r");
- if( data_conf != NULL )
- {
+ if (data_conf != NULL) {
char line[1024];
- while( fgets(line, sizeof(line), data_conf) )
- {
+ while (fgets(line, sizeof(line), data_conf)) {
char w1[1024], w2[1024];
- if( line[0] == '/' && line[1] == '/' )
+ if (line[0] == '/' && line[1] == '/')
continue; // skip comments
if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
continue; // skip unrecognized lines
// Entry table reading
- if( strcmp(w1, "grf") == 0 ) // GRF file
- {
- if( grfio_add(w2) == 0 )
+ if (strcmp(w1, "grf") == 0) {
+ // GRF file
+ if (grfio_add(w2) == 0)
++grf_num;
- }
- else if( strcmp(w1,"data_dir") == 0 ) // Data directory
- {
+ } else if (strcmp(w1,"data_dir") == 0) {
+ // Data directory
safestrncpy(data_dir, w2, sizeof(data_dir));
}
}
@@ -862,12 +928,25 @@ void grfio_init(const char* fname)
ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname);
}
- if( grf_num == 0 )
+ if (grf_num == 0)
ShowInfo("No GRF loaded, using default data directory\n");
// Unnecessary area release of filelist
- filelist_compact();
+ grfio_filelist_compact();
// Resource check
grfio_resourcecheck();
}
+
+/// Interface base initialization.
+void grfio_defaults(void)
+{
+ grfio = &grfio_s;
+ grfio->init = grfio_init;
+ grfio->final = grfio_final;
+ grfio->reads = grfio_reads;
+ grfio->find_file = grfio_find_file;
+ grfio->crc32 = grfio_crc32;
+ grfio->decode_zip = grfio_decode_zip;
+ grfio->encode_zip = grfio_encode_zip;
+}
diff --git a/src/common/grfio.h b/src/common/grfio.h
index 36ed8fb39..857bc507e 100644
--- a/src/common/grfio.h
+++ b/src/common/grfio.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,16 +21,104 @@
#ifndef COMMON_GRFIO_H
#define COMMON_GRFIO_H
+#include "common/hercules.h"
+
+/** @file
+ * GRF I/O library.
+ */
+
+/// The GRF I/O interface.
+struct grfio_interface {
+ /**
+ * Interface initialization.
+ *
+ * @param fname Name of the configuration file.
+ */
+ void (*init) (const char *fname);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Reads a file into a newly allocated buffer (from grf or data directory).
+ *
+ * @param[in] fname Name of the file to read.
+ * @param[out] size Buffer to return the size of the read file (optional).
+ * @return The file data.
+ * @retval NULL in case of error.
+ */
+ void *(*reads) (const char *fname, int *size);
+
+ /**
+ * Finds a file in the grf or data directory
+ *
+ * @param fname The file to find.
+ * @return The original file name.
+ * @retval NULL if the file wasn't found.
+ */
+ const char *(*find_file) (const char *fname);
+
+ /**
+ * Calculates a CRC32 hash.
+ *
+ * @param buf The data to hash.
+ * @param len Data length.
+ *
+ * @return The CRC32 hash.
+ */
+ unsigned long (*crc32) (const unsigned char *buf, unsigned int len);
+
+ /**
+ * Decompresses ZIP data.
+ *
+ * Decompresses the source buffer into the destination buffer.
+ * source_len is the byte length of the source buffer. Upon entry,
+ * dest_len is the total size of the destination buffer, which must be
+ * large enough to hold the entire uncompressed data. (The size of the
+ * uncompressed data must have been saved previously by the compressor
+ * and transmitted to the decompressor by some mechanism outside the
+ * scope of this compression library.) Upon exit, dest_len is the
+ * actual size of the uncompressed buffer.
+ *
+ * @param[in,out] dest The destination (uncompressed) buffer.
+ * @param[in,out] dest_len Max length of the destination buffer, returns length of the decompressed data.
+ * @param[in] source The source (compressed) buffer.
+ * @param[in] source_len Source data length.
+ * @return error code.
+ * @retval Z_OK in case of success.
+ */
+ int (*decode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len);
+
+ /**
+ * Compresses data to ZIP format.
+ *
+ * Compresses the source buffer into the destination buffer.
+ * source_len is the byte length of the source buffer. Upon entry,
+ * dest_len is the total size of the destination buffer, which must be
+ * at least the value returned by compressBound(source_len). Upon
+ * exit, dest_len is the actual size of the compressed buffer.
+ *
+ * @param[in,out] dest The destination (compressed) buffer (if NULL, a new buffer will be created).
+ * @param[in,out] dest_len Max length of the destination buffer (if 0, it will be calculated).
+ * @param[in] source The source (uncompressed) buffer.
+ * @param[in] source_len Source data length.
+ */
+ int (*encode_zip) (void *dest, unsigned long *dest_len, const void *source, unsigned long source_len);
+};
+
+/**
+ * Reads a file into a newly allocated buffer (from grf or data directory)
+ *
+ * @param fn The filename to read.
+ *
+ * @see grfio_interface::reads()
+ * @related grfio_interface
+ */
+#define grfio_read(fn) grfio->reads((fn), NULL)
+
#ifdef HERCULES_CORE
-void grfio_init(const char* fname);
-void grfio_final(void);
-void* grfio_reads(const char* fname, int* size);
-char* grfio_find_file(const char* fname);
-#define grfio_read(fn) grfio_reads((fn), NULL)
-
-unsigned long grfio_crc32(const unsigned char *buf, unsigned int len);
-int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
-int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen);
+void grfio_defaults(void);
#endif // HERCULES_CORE
+HPShared struct grfio_interface *grfio; ///< Pointer to the grfio interface.
#endif /* COMMON_GRFIO_H */
diff --git a/src/common/md5calc.c b/src/common/md5calc.c
index d346c8aa4..bd6b48f10 100644
--- a/src/common/md5calc.c
+++ b/src/common/md5calc.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -20,27 +20,27 @@
*/
#define HERCULES_CORE
-/***********************************************************
- * md5 calculation algorithm
- *
- * The source code referred to the following URL.
- * http://www.geocities.co.jp/SiliconValley-Oakland/8878/lab17/lab17.html
- *
- ***********************************************************/
-
#include "md5calc.h"
#include "common/cbasetypes.h"
+#include "common/nullpo.h"
#include "common/random.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-// Global variable
+/** @file
+ * Implementation of the md5 interface.
+ */
+
+struct md5_interface md5_s;
+struct md5_interface *md5;
+
+/// Global variable
static unsigned int *pX;
-// String Table
+/// String Table
static const unsigned int T[] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4
@@ -60,99 +60,102 @@ static const unsigned int T[] = {
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 //60
};
-// ROTATE_LEFT The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC.
+/// The left is made to rotate x [ n-bit ]. This is diverted as it is from RFC.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// The function used for other calculation
-static unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)
+static unsigned int md5_F(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Y) | (~X & Z);
}
-static unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_G(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Z) | (Y & ~Z);
}
-static unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_H(unsigned int X, unsigned int Y, unsigned int Z)
{
return X ^ Y ^ Z;
}
-static unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)
+
+static unsigned int md5_I(unsigned int X, unsigned int Y, unsigned int Z)
{
return Y ^ (X | ~Z);
}
-static unsigned int Round(unsigned int a, unsigned int b, unsigned int FGHI,
+static unsigned int md5_Round(unsigned int a, unsigned int b, unsigned int FGHI,
unsigned int k, unsigned int s, unsigned int i)
{
return b + ROTATE_LEFT(a + FGHI + pX[k] + T[i], s);
}
-static void Round1(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round1(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, F(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_F(b,c,d), k, s, i);
}
-static void Round2(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round2(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, G(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_G(b,c,d), k, s, i);
}
-static void Round3(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round3(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, H(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_H(b,c,d), k, s, i);
}
-static void Round4(unsigned int *a, unsigned int b, unsigned int c,
+static void md5_Round4(unsigned int *a, unsigned int b, unsigned int c,
unsigned int d,unsigned int k, unsigned int s, unsigned int i)
{
- *a = Round(*a, b, I(b,c,d), k, s, i);
+ *a = md5_Round(*a, b, md5_I(b,c,d), k, s, i);
}
-static void MD5_Round_Calculate(const unsigned char *block,
+static void md5_Round_Calculate(const unsigned char *block,
unsigned int *A2, unsigned int *B2, unsigned int *C2, unsigned int *D2)
{
//create X It is since it is required.
unsigned int X[16]; //512bit 64byte
- int j,k;
+ int j, k;
//Save A as AA, B as BB, C as CC, and and D as DD (saving of A, B, C, and D)
- unsigned int A=*A2, B=*B2, C=*C2, D=*D2;
- unsigned int AA = A,BB = B,CC = C,DD = D;
+ unsigned int A = *A2, B = *B2, C = *C2, D = *D2;
+ unsigned int AA = A, BB = B, CC = C, DD = D;
//It is a large region variable reluctantly because of calculation of a round. . . for Round1...4
pX = X;
//Copy block(padding_message) i into X
- for (j=0,k=0; j<64; j+=4,k++)
- X[k] = ( (unsigned int )block[j] ) // 8byte*4 -> 32byte conversion
- | ( ((unsigned int )block[j+1]) << 8 ) // A function called Decode as used in the field of RFC
- | ( ((unsigned int )block[j+2]) << 16 )
- | ( ((unsigned int )block[j+3]) << 24 );
-
+ for (j = 0, k = 0; j < 64; j += 4, k++) {
+ X[k] = ((unsigned int)block[j]) // 8byte*4 -> 32byte conversion
+ | (((unsigned int)block[j+1]) << 8) // A function called Decode as used in the field of RFC
+ | (((unsigned int)block[j+2]) << 16)
+ | (((unsigned int)block[j+3]) << 24);
+ }
//Round 1
- Round1(&A,B,C,D, 0, 7, 0); Round1(&D,A,B,C, 1, 12, 1); Round1(&C,D,A,B, 2, 17, 2); Round1(&B,C,D,A, 3, 22, 3);
- Round1(&A,B,C,D, 4, 7, 4); Round1(&D,A,B,C, 5, 12, 5); Round1(&C,D,A,B, 6, 17, 6); Round1(&B,C,D,A, 7, 22, 7);
- Round1(&A,B,C,D, 8, 7, 8); Round1(&D,A,B,C, 9, 12, 9); Round1(&C,D,A,B, 10, 17, 10); Round1(&B,C,D,A, 11, 22, 11);
- Round1(&A,B,C,D, 12, 7, 12); Round1(&D,A,B,C, 13, 12, 13); Round1(&C,D,A,B, 14, 17, 14); Round1(&B,C,D,A, 15, 22, 15);
+ md5_Round1(&A,B,C,D, 0, 7, 0); md5_Round1(&D,A,B,C, 1, 12, 1); md5_Round1(&C,D,A,B, 2, 17, 2); md5_Round1(&B,C,D,A, 3, 22, 3);
+ md5_Round1(&A,B,C,D, 4, 7, 4); md5_Round1(&D,A,B,C, 5, 12, 5); md5_Round1(&C,D,A,B, 6, 17, 6); md5_Round1(&B,C,D,A, 7, 22, 7);
+ md5_Round1(&A,B,C,D, 8, 7, 8); md5_Round1(&D,A,B,C, 9, 12, 9); md5_Round1(&C,D,A,B, 10, 17, 10); md5_Round1(&B,C,D,A, 11, 22, 11);
+ md5_Round1(&A,B,C,D, 12, 7, 12); md5_Round1(&D,A,B,C, 13, 12, 13); md5_Round1(&C,D,A,B, 14, 17, 14); md5_Round1(&B,C,D,A, 15, 22, 15);
//Round 2
- Round2(&A,B,C,D, 1, 5, 16); Round2(&D,A,B,C, 6, 9, 17); Round2(&C,D,A,B, 11, 14, 18); Round2(&B,C,D,A, 0, 20, 19);
- Round2(&A,B,C,D, 5, 5, 20); Round2(&D,A,B,C, 10, 9, 21); Round2(&C,D,A,B, 15, 14, 22); Round2(&B,C,D,A, 4, 20, 23);
- Round2(&A,B,C,D, 9, 5, 24); Round2(&D,A,B,C, 14, 9, 25); Round2(&C,D,A,B, 3, 14, 26); Round2(&B,C,D,A, 8, 20, 27);
- Round2(&A,B,C,D, 13, 5, 28); Round2(&D,A,B,C, 2, 9, 29); Round2(&C,D,A,B, 7, 14, 30); Round2(&B,C,D,A, 12, 20, 31);
+ md5_Round2(&A,B,C,D, 1, 5, 16); md5_Round2(&D,A,B,C, 6, 9, 17); md5_Round2(&C,D,A,B, 11, 14, 18); md5_Round2(&B,C,D,A, 0, 20, 19);
+ md5_Round2(&A,B,C,D, 5, 5, 20); md5_Round2(&D,A,B,C, 10, 9, 21); md5_Round2(&C,D,A,B, 15, 14, 22); md5_Round2(&B,C,D,A, 4, 20, 23);
+ md5_Round2(&A,B,C,D, 9, 5, 24); md5_Round2(&D,A,B,C, 14, 9, 25); md5_Round2(&C,D,A,B, 3, 14, 26); md5_Round2(&B,C,D,A, 8, 20, 27);
+ md5_Round2(&A,B,C,D, 13, 5, 28); md5_Round2(&D,A,B,C, 2, 9, 29); md5_Round2(&C,D,A,B, 7, 14, 30); md5_Round2(&B,C,D,A, 12, 20, 31);
//Round 3
- Round3(&A,B,C,D, 5, 4, 32); Round3(&D,A,B,C, 8, 11, 33); Round3(&C,D,A,B, 11, 16, 34); Round3(&B,C,D,A, 14, 23, 35);
- Round3(&A,B,C,D, 1, 4, 36); Round3(&D,A,B,C, 4, 11, 37); Round3(&C,D,A,B, 7, 16, 38); Round3(&B,C,D,A, 10, 23, 39);
- Round3(&A,B,C,D, 13, 4, 40); Round3(&D,A,B,C, 0, 11, 41); Round3(&C,D,A,B, 3, 16, 42); Round3(&B,C,D,A, 6, 23, 43);
- Round3(&A,B,C,D, 9, 4, 44); Round3(&D,A,B,C, 12, 11, 45); Round3(&C,D,A,B, 15, 16, 46); Round3(&B,C,D,A, 2, 23, 47);
+ md5_Round3(&A,B,C,D, 5, 4, 32); md5_Round3(&D,A,B,C, 8, 11, 33); md5_Round3(&C,D,A,B, 11, 16, 34); md5_Round3(&B,C,D,A, 14, 23, 35);
+ md5_Round3(&A,B,C,D, 1, 4, 36); md5_Round3(&D,A,B,C, 4, 11, 37); md5_Round3(&C,D,A,B, 7, 16, 38); md5_Round3(&B,C,D,A, 10, 23, 39);
+ md5_Round3(&A,B,C,D, 13, 4, 40); md5_Round3(&D,A,B,C, 0, 11, 41); md5_Round3(&C,D,A,B, 3, 16, 42); md5_Round3(&B,C,D,A, 6, 23, 43);
+ md5_Round3(&A,B,C,D, 9, 4, 44); md5_Round3(&D,A,B,C, 12, 11, 45); md5_Round3(&C,D,A,B, 15, 16, 46); md5_Round3(&B,C,D,A, 2, 23, 47);
//Round 4
- Round4(&A,B,C,D, 0, 6, 48); Round4(&D,A,B,C, 7, 10, 49); Round4(&C,D,A,B, 14, 15, 50); Round4(&B,C,D,A, 5, 21, 51);
- Round4(&A,B,C,D, 12, 6, 52); Round4(&D,A,B,C, 3, 10, 53); Round4(&C,D,A,B, 10, 15, 54); Round4(&B,C,D,A, 1, 21, 55);
- Round4(&A,B,C,D, 8, 6, 56); Round4(&D,A,B,C, 15, 10, 57); Round4(&C,D,A,B, 6, 15, 58); Round4(&B,C,D,A, 13, 21, 59);
- Round4(&A,B,C,D, 4, 6, 60); Round4(&D,A,B,C, 11, 10, 61); Round4(&C,D,A,B, 2, 15, 62); Round4(&B,C,D,A, 9, 21, 63);
+ md5_Round4(&A,B,C,D, 0, 6, 48); md5_Round4(&D,A,B,C, 7, 10, 49); md5_Round4(&C,D,A,B, 14, 15, 50); md5_Round4(&B,C,D,A, 5, 21, 51);
+ md5_Round4(&A,B,C,D, 12, 6, 52); md5_Round4(&D,A,B,C, 3, 10, 53); md5_Round4(&C,D,A,B, 10, 15, 54); md5_Round4(&B,C,D,A, 1, 21, 55);
+ md5_Round4(&A,B,C,D, 8, 6, 56); md5_Round4(&D,A,B,C, 15, 10, 57); md5_Round4(&C,D,A,B, 6, 15, 58); md5_Round4(&B,C,D,A, 13, 21, 59);
+ md5_Round4(&A,B,C,D, 4, 6, 60); md5_Round4(&D,A,B,C, 11, 10, 61); md5_Round4(&C,D,A,B, 2, 15, 62); md5_Round4(&B,C,D,A, 9, 21, 63);
// Then perform the following additions. (let's add)
*A2 = A + AA;
@@ -164,7 +167,8 @@ static void MD5_Round_Calculate(const unsigned char *block,
memset(pX, 0, sizeof(X));
}
-static void MD5_String2binary(const char * string, unsigned char * output)
+/// @copydoc md5_interface::binary()
+static void md5_string2binary(const char *string, unsigned char *output)
{
//var
/*8bit*/
@@ -196,7 +200,7 @@ static void MD5_String2binary(const char * string, unsigned char * output)
//1-2 Repeat calculation until length becomes less than 64 bytes.
for (i=string_byte_len; 64<=i; i-=64,pstring+=64)
- MD5_Round_Calculate(pstring, A,B,C,D);
+ md5_Round_Calculate(pstring, A,B,C,D);
//1-3
copy_len = string_byte_len % 64; //The number of bytes which remained is computed.
@@ -207,7 +211,7 @@ static void MD5_String2binary(const char * string, unsigned char * output)
//1-4
//If 56 bytes or more (less than 64 bytes) of remainder becomes, it will calculate by extending to 64 bytes.
if (56 <= copy_len) {
- MD5_Round_Calculate(padding_message, A,B,C,D);
+ md5_Round_Calculate(padding_message, A,B,C,D);
memset(padding_message, 0, 56); //56 bytes is newly fill uped with 0.
}
@@ -219,31 +223,26 @@ static void MD5_String2binary(const char * string, unsigned char * output)
if (UINT_MAX / 8 < string_byte_len) {
unsigned int high = (string_byte_len - UINT_MAX / 8) * 8;
memcpy(&padding_message[60], &high, 4);
- } else
+ } else {
memset(&padding_message[60], 0, 4); //In this case, it is good for a higher rank at 0.
+ }
//Step 4.Process Message in 16-Word Blocks (calculation of MD5)
- MD5_Round_Calculate(padding_message, A,B,C,D);
+ md5_Round_Calculate(padding_message, A,B,C,D);
//Step 5.Output (output)
memcpy(output,msg_digest,16);
}
-//-------------------------------------------------------------------
-// The function for the exteriors
-
-/** output is the coded binary in the character sequence which wants to code string. */
-void MD5_Binary(const char * string, unsigned char * output)
-{
- MD5_String2binary(string,output);
-}
-
-/** output is the coded character sequence in the character sequence which wants to code string. */
-void MD5_String(const char *string, char *output)
+/// @copydoc md5_interface::string()
+void md5_string(const char *string, char *output)
{
unsigned char digest[16];
- MD5_String2binary(string,digest);
+ nullpo_retv(string);
+ nullpo_retv(output);
+
+ md5->binary(string,digest);
snprintf(output, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[ 0], digest[ 1], digest[ 2], digest[ 3],
digest[ 4], digest[ 5], digest[ 6], digest[ 7],
@@ -251,11 +250,24 @@ void MD5_String(const char *string, char *output)
digest[12], digest[13], digest[14], digest[15]);
}
-/** output is a sequence of non-zero characters to be used as password salt. */
-void MD5_Salt(unsigned int len, char * output)
+/// @copydoc md5_interface::salt();
+void md5_salt(int len, char *output)
{
- unsigned int i;
- for( i = 0; i < len; ++i )
+ int i;
+ Assert_retv(len > 0);
+
+ for (i = 0; i < len; ++i)
output[i] = (char)(1 + rnd() % 255);
}
+
+/**
+ * Interface base initialization.
+ */
+void md5_defaults(void)
+{
+ md5 = &md5_s;
+ md5->binary = md5_string2binary;
+ md5->string = md5_string;
+ md5->salt = md5_salt;
+}
diff --git a/src/common/md5calc.h b/src/common/md5calc.h
index 0294c3ca1..b4d4995f9 100644
--- a/src/common/md5calc.h
+++ b/src/common/md5calc.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,10 +21,46 @@
#ifndef COMMON_MD5CALC_H
#define COMMON_MD5CALC_H
+#include "common/hercules.h"
+
+/** @file
+ * md5 calculation algorithm.
+ *
+ * The source code referred to the following URL.
+ * http://www.geocities.co.jp/SiliconValley-Oakland/8878/lab17/lab17.html
+ */
+
+/// The md5 interface
+struct md5_interface {
+ /**
+ * Hashes a string, returning the hash in string format.
+ *
+ * @param[in] string The source string (NUL terminated).
+ * @param[out] output Output buffer (at least 33 bytes available).
+ */
+ void (*string) (const char *string, char *output);
+
+ /**
+ * Hashes a string, returning the buffer in binary format.
+ *
+ * @param[in] string The source string.
+ * @param[out] output Output buffer (at least 16 bytes available).
+ */
+ void (*binary) (const char *string, unsigned char *output);
+
+ /**
+ * Generates a random salt.
+ *
+ * @param[in] len The desired salt length.
+ * @param[out] output The output buffer (at least len bytes available).
+ */
+ void (*salt) (int len, char *output);
+};
+
#ifdef HERCULES_CORE
-void MD5_String(const char * string, char * output);
-void MD5_Binary(const char * string, unsigned char * output);
-void MD5_Salt(unsigned int len, char * output);
+void md5_defaults(void);
#endif // HERCULES_CORE
+HPShared struct md5_interface *md5; ///< Pointer to the md5 interface.
+
#endif /* COMMON_MD5CALC_H */
diff --git a/src/common/mmo.h b/src/common/mmo.h
index a2080d900..0a5d9d053 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -125,29 +125,69 @@
//Official Limit: 2.1b ( the var that stores the money doesn't go much higher than this by default )
#define MAX_BANK_ZENY INT_MAX
+#ifndef MAX_LEVEL
#define MAX_LEVEL 175
+#endif
#define MAX_FAME 1000000000
#define MAX_CART 100
+#ifndef MAX_SKILL
#define MAX_SKILL 1478
+#endif
+#ifndef MAX_SKILL_ID
#define MAX_SKILL_ID 10015 // [Ind/Hercules] max used skill ID
+#endif
+#ifndef MAX_SKILL_TREE
// Update this max as necessary. 86 is the value needed for Expanded Super Novice.
#define MAX_SKILL_TREE 86
+#endif
+#ifndef DEFAULT_WALK_SPEED
#define DEFAULT_WALK_SPEED 150
+#endif
+#ifndef MIN_WALK_SPEED
#define MIN_WALK_SPEED 20 /* below 20 clips animation */
+#endif
+#ifndef MAX_WALK_SPEED
#define MAX_WALK_SPEED 1000
+#endif
+#ifndef MAX_STORAGE
#define MAX_STORAGE 600
+#endif
+#ifndef MAX_GUILD_STORAGE
#define MAX_GUILD_STORAGE 600
+#endif
+#ifndef MAX_PARTY
#define MAX_PARTY 12
+#endif
+#ifndef BASE_GUILD_SIZE
#define BASE_GUILD_SIZE 16 // Base guild members (without GD_EXTENSION)
+#endif
+#ifndef MAX_GUILD
#define MAX_GUILD (BASE_GUILD_SIZE+10*6) // Increased max guild members +6 per 1 extension levels [Lupus]
+#endif
+#ifndef MAX_GUILDPOSITION
#define MAX_GUILDPOSITION 20 // Increased max guild positions to accomodate for all members [Valaris] (removed) [PoW]
+#endif
+#ifndef MAX_GUILDEXPULSION
#define MAX_GUILDEXPULSION 32
+#endif
+#ifndef MAX_GUILDALLIANCE
#define MAX_GUILDALLIANCE 16
+#endif
+#ifndef MAX_GUILDSKILL
#define MAX_GUILDSKILL 15 // Increased max guild skills because of new skills [Sara-chan]
+#endif
+#ifndef MAX_GUILDLEVEL
#define MAX_GUILDLEVEL 50
+#endif
+#ifndef MAX_GUARDIANS
#define MAX_GUARDIANS 8 // Local max per castle. [Skotlex]
+#endif
+#ifndef MAX_QUEST_OBJECTIVES
#define MAX_QUEST_OBJECTIVES 3 // Max quest objectives for a quest
+#endif
+#ifndef MAX_START_ITEMS
#define MAX_START_ITEMS 32 // Max number of items allowed to be given to a char whenever it's created. [mkbu95]
+#endif
// for produce
#define MIN_ATTRIBUTE 0
@@ -170,7 +210,9 @@
#define MAP_NAME_LENGTH (11 + 1)
#define MAP_NAME_LENGTH_EXT (MAP_NAME_LENGTH + 4)
+#ifndef MAX_FRIENDS
#define MAX_FRIENDS 40
+#endif
#define MAX_MEMOPOINTS 3
// Size of the fame list arrays.
@@ -186,8 +228,12 @@
#define MAX_GUILDMES2 120
// Base Homun skill.
+#ifndef HM_SKILLBASE
#define HM_SKILLBASE 8001
+#endif
+#ifndef MAX_HOMUNSKILL
#define MAX_HOMUNSKILL 43
+#endif
// Mail System
#define MAIL_MAX_INBOX 30
@@ -195,13 +241,23 @@
#define MAIL_BODY_LENGTH 200
// Mercenary System
+#ifndef MC_SKILLBASE
#define MC_SKILLBASE 8201
+#endif
+#ifndef MAX_MERCSKILL
#define MAX_MERCSKILL 40
+#endif
// Elemental System
+#ifndef MAX_ELEMENTALSKILL
#define MAX_ELEMENTALSKILL 42
+#endif
+#ifndef EL_SKILLBASE
#define EL_SKILLBASE 8401
+#endif
+#ifndef MAX_ELESKILLTREE
#define MAX_ELESKILLTREE 3
+#endif
// The following system marks a different job ID system used by the map server,
// which makes a lot more sense than the normal one. [Skotlex]
@@ -233,7 +289,9 @@ enum item_types {
IT_AMMO, //10
IT_DELAYCONSUME,//11
IT_CASH = 18,
+#ifndef IT_MAX
IT_MAX
+#endif
};
#define INDEX_NOT_FOUND (-1) ///< Used as invalid/failure value in various functions that return an index
@@ -253,6 +311,11 @@ struct quest {
enum quest_state state; ///< Current quest state
};
+enum attribute_flag {
+ ATTR_NONE = 0,
+ ATTR_BROKEN = 1,
+};
+
struct item {
int id;
short nameid;
@@ -325,7 +388,9 @@ enum e_item_bound_type {
IBT_GUILD = 0x2,
IBT_PARTY = 0x3,
IBT_CHARACTER = 0x4,
+#ifndef IBT_MAX
IBT_MAX = 0x4,
+#endif
};
enum {
@@ -505,7 +570,7 @@ struct mmo_charstatus {
int bank_vault;
short class_;
- unsigned int status_point,skill_point;
+ int status_point, skill_point;
int hp,max_hp,sp,max_sp;
unsigned int option;
short manner; // Defines how many minutes a char will be muted, each negative point is equivalent to a minute.
@@ -525,7 +590,7 @@ struct mmo_charstatus {
short robe;
char name[NAME_LENGTH];
- unsigned int base_level,job_level;
+ int base_level, job_level;
short str,agi,vit,int_,dex,luk;
unsigned char slot,sex;
@@ -772,7 +837,9 @@ enum {
GD_RESTORE=10012,
GD_EMERGENCYCALL=10013,
GD_DEVELOPMENT=10014,
+#ifndef GD_MAX
GD_MAX,
+#endif
};
//These mark the ID of the jobs, as expected by the client. [Skotlex]
@@ -929,7 +996,9 @@ enum {
JOB_OBORO,
JOB_REBELLION = 4215,
+#ifndef JOB_MAX
JOB_MAX,
+#endif
};
//Total number of classes (for data storage)
@@ -966,7 +1035,9 @@ enum weapon_type {
W_GRENADE, //21
W_HUUMA, //22
W_2HSTAFF, //23
+#ifndef MAX_SINGLE_WEAPON_TYPE
MAX_SINGLE_WEAPON_TYPE,
+#endif
// dual-wield constants
W_DOUBLE_DD, ///< 2 daggers
W_DOUBLE_SS, ///< 2 swords
@@ -974,7 +1045,9 @@ enum weapon_type {
W_DOUBLE_DS, ///< dagger + sword
W_DOUBLE_DA, ///< dagger + axe
W_DOUBLE_SA, ///< sword + axe
+#ifndef MAX_WEAPON_TYPE
MAX_WEAPON_TYPE,
+#endif
};
enum ammo_type {
diff --git a/src/common/mutex.c b/src/common/mutex.c
index 0f02b153f..bdc2fb4dc 100644
--- a/src/common/mutex.c
+++ b/src/common/mutex.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -34,7 +34,14 @@
#include <sys/time.h>
#endif
-struct ramutex{
+/** @file
+ * Implementation of the mutex interface.
+ */
+
+struct mutex_interface mutex_s;
+struct mutex_interface *mutex;
+
+struct mutex_data {
#ifdef WIN32
CRITICAL_SECTION hMutex;
#else
@@ -42,32 +49,26 @@ struct ramutex{
#endif
};
-struct racond{
+struct cond_data {
#ifdef WIN32
HANDLE events[2];
ra_align(8) volatile LONG nWaiters;
CRITICAL_SECTION waiters_lock;
-
#define EVENT_COND_SIGNAL 0
#define EVENT_COND_BROADCAST 1
-
#else
pthread_cond_t hCond;
#endif
};
-////////////////////
-// Mutex
-//
-// Implementation:
-//
+/* Mutex */
-ramutex *ramutex_create(void) {
- struct ramutex *m;
-
- m = (struct ramutex*)aMalloc( sizeof(struct ramutex) );
+/// @copydoc mutex_interface::create()
+struct mutex_data *mutex_create(void)
+{
+ struct mutex_data *m = aMalloc(sizeof(struct mutex_data));
if (m == NULL) {
- ShowFatalError("ramutex_create: OOM while allocating %"PRIuS" bytes.\n", sizeof(struct ramutex));
+ ShowFatalError("ramutex_create: OOM while allocating %"PRIuS" bytes.\n", sizeof(struct mutex_data));
return NULL;
}
@@ -78,10 +79,11 @@ ramutex *ramutex_create(void) {
#endif
return m;
-}//end: ramutex_create()
-
-void ramutex_destroy(ramutex *m) {
+}
+/// @copydoc mutex_interface::destroy()
+void mutex_destroy(struct mutex_data *m)
+{
#ifdef WIN32
DeleteCriticalSection(&m->hMutex);
#else
@@ -89,53 +91,49 @@ void ramutex_destroy(ramutex *m) {
#endif
aFree(m);
+}
-}//end: ramutex_destroy()
-
-void ramutex_lock(ramutex *m) {
-
+/// @copydoc mutex_interface::lock()
+void mutex_lock(struct mutex_data *m)
+{
#ifdef WIN32
EnterCriticalSection(&m->hMutex);
#else
pthread_mutex_lock(&m->hMutex);
#endif
-}//end: ramutex_lock
+}
-bool ramutex_trylock(ramutex *m) {
+/// @copydoc mutex_interface::trylock()
+bool mutex_trylock(struct mutex_data *m)
+{
#ifdef WIN32
- if(TryEnterCriticalSection(&m->hMutex) != FALSE)
+ if (TryEnterCriticalSection(&m->hMutex) != FALSE)
return true;
-
- return false;
#else
- if(pthread_mutex_trylock(&m->hMutex) == 0)
+ if (pthread_mutex_trylock(&m->hMutex) == 0)
return true;
-
- return false;
#endif
-}//end: ramutex_trylock()
+ return false;
+}
-void ramutex_unlock(ramutex *m) {
+/// @copydoc mutex_interface::unlock()
+void mutex_unlock(struct mutex_data *m)
+{
#ifdef WIN32
LeaveCriticalSection(&m->hMutex);
#else
pthread_mutex_unlock(&m->hMutex);
#endif
+}
-}//end: ramutex_unlock()
-
-///////////////
-// Condition Variables
-//
-// Implementation:
-//
+/* Conditional variable */
-racond *racond_create(void) {
- struct racond *c;
-
- c = (struct racond*)aMalloc( sizeof(struct racond) );
+/// @copydoc mutex_interface::cond_create()
+struct cond_data *cond_create(void)
+{
+ struct cond_data *c = aMalloc(sizeof(struct cond_data));
if (c == NULL) {
- ShowFatalError("racond_create: OOM while allocating %"PRIuS" bytes\n", sizeof(struct racond));
+ ShowFatalError("racond_create: OOM while allocating %"PRIuS" bytes\n", sizeof(struct cond_data));
return NULL;
}
@@ -149,21 +147,25 @@ racond *racond_create(void) {
#endif
return c;
-}//end: racond_create()
+}
-void racond_destroy(racond *c) {
+/// @copydoc mutex_interface::cond_destroy()
+void cond_destroy(struct cond_data *c)
+{
#ifdef WIN32
- CloseHandle( c->events[ EVENT_COND_SIGNAL ] );
- CloseHandle( c->events[ EVENT_COND_BROADCAST ] );
- DeleteCriticalSection( &c->waiters_lock );
+ CloseHandle(c->events[EVENT_COND_SIGNAL]);
+ CloseHandle(c->events[EVENT_COND_BROADCAST]);
+ DeleteCriticalSection(&c->waiters_lock);
#else
pthread_cond_destroy(&c->hCond);
#endif
aFree(c);
-}//end: racond_destroy()
+}
-void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
+/// @copydoc mutex_interface::cond_wait()
+void cond_wait(struct cond_data *c, struct mutex_data *m, sysint timeout_ticks)
+{
#ifdef WIN32
register DWORD ms;
int result;
@@ -173,7 +175,7 @@ void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
c->nWaiters++;
LeaveCriticalSection(&c->waiters_lock);
- if(timeout_ticks < 0)
+ if (timeout_ticks < 0)
ms = INFINITE;
else
ms = (timeout_ticks > MAXDWORD) ? (MAXDWORD - 1) : (DWORD)timeout_ticks;
@@ -181,27 +183,27 @@ void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
// we can release the mutex (m) here, cause win's
// manual reset events maintain state when used with
// SetEvent()
- ramutex_unlock(m);
+ mutex->unlock(m);
result = WaitForMultipleObjects(2, c->events, FALSE, ms);
EnterCriticalSection(&c->waiters_lock);
c->nWaiters--;
- if( (result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0) )
+ if ((result == WAIT_OBJECT_0 + EVENT_COND_BROADCAST) && (c->nWaiters == 0))
is_last = true; // Broadcast called!
LeaveCriticalSection(&c->waiters_lock);
// we are the last waiter that has to be notified, or to stop waiting
// so we have to do a manual reset
- if(is_last == true)
+ if (is_last == true)
ResetEvent( c->events[EVENT_COND_BROADCAST] );
- ramutex_lock(m);
+ mutex->lock(m);
#else
- if(timeout_ticks < 0){
- pthread_cond_wait( &c->hCond, &m->hMutex );
- }else{
+ if (timeout_ticks < 0) {
+ pthread_cond_wait(&c->hCond, &m->hMutex);
+ } else {
struct timespec wtime;
int64 exact_timeout = timer->gettick() + timeout_ticks;
@@ -210,11 +212,12 @@ void racond_wait(racond *c, ramutex *m, sysint timeout_ticks) {
pthread_cond_timedwait( &c->hCond, &m->hMutex, &wtime);
}
-
#endif
-}//end: racond_wait()
+}
-void racond_signal(racond *c) {
+/// @copydoc mutex_interface::cond_signal()
+void cond_signal(struct cond_data *c)
+{
#ifdef WIN32
# if 0
bool has_waiters = false;
@@ -225,13 +228,15 @@ void racond_signal(racond *c) {
if(has_waiters == true)
# endif // 0
- SetEvent( c->events[ EVENT_COND_SIGNAL ] );
+ SetEvent(c->events[EVENT_COND_SIGNAL]);
#else
pthread_cond_signal(&c->hCond);
#endif
-}//end: racond_signal()
+}
-void racond_broadcast(racond *c) {
+/// @copydoc mutex_interface::cond_broadcast()
+void cond_broadcast(struct cond_data *c)
+{
#ifdef WIN32
# if 0
bool has_waiters = false;
@@ -242,8 +247,27 @@ void racond_broadcast(racond *c) {
if(has_waiters == true)
# endif // 0
- SetEvent( c->events[ EVENT_COND_BROADCAST ] );
+ SetEvent(c->events[EVENT_COND_BROADCAST]);
#else
pthread_cond_broadcast(&c->hCond);
#endif
-}//end: racond_broadcast()
+}
+
+/**
+ * Interface base initialization.
+ */
+void mutex_defaults(void)
+{
+ mutex = &mutex_s;
+ mutex->create = mutex_create;
+ mutex->destroy = mutex_destroy;
+ mutex->lock = mutex_lock;
+ mutex->trylock = mutex_trylock;
+ mutex->unlock = mutex_unlock;
+
+ mutex->cond_create = cond_create;
+ mutex->cond_destroy = cond_destroy;
+ mutex->cond_wait = cond_wait;
+ mutex->cond_signal = cond_signal;
+ mutex->cond_broadcast = cond_broadcast;
+}
diff --git a/src/common/mutex.h b/src/common/mutex.h
index e49791493..0569fb0da 100644
--- a/src/common/mutex.h
+++ b/src/common/mutex.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,91 +21,111 @@
#ifndef COMMON_MUTEX_H
#define COMMON_MUTEX_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
-typedef struct ramutex ramutex; // Mutex
-typedef struct racond racond; // Condition Var
-
-#ifdef HERCULES_CORE
-/**
- * Creates a Mutex
- *
- * @return not NULL
+/** @file
+ * Mutex and conditional variables implementation for Hercules.
*/
-ramutex *ramutex_create(void);
-/**
- * Destroys a Mutex
- *
- * @param m - the mutex to destroy
- */
-void ramutex_destroy(ramutex *m);
+/* Opaque types */
-/**
- * Gets a lock
- *
- * @param m - the mutex to lock
- */
-void ramutex_lock(ramutex *m);
+struct mutex_data; ///< Mutex
+struct cond_data; ///< Conditional variable
-/**
- * Trys to get the Lock
- *
- * @param m - the mutex try to lock
- *
- * @return boolean (true = got the lock)
- */
-bool ramutex_trylock(ramutex *m);
+/* Interface */
-/**
- * Unlocks a mutex
- *
- * @param m - the mutex to unlock
- */
-void ramutex_unlock(ramutex *m);
+/// The mutex interface.
+struct mutex_interface {
+ /**
+ * Creates a mutex.
+ *
+ * @return The created mutex.
+ */
+ struct mutex_data *(*create) (void);
+ /**
+ * Destroys a mutex.
+ *
+ * @param m the mutex to destroy.
+ */
+ void (*destroy) (struct mutex_data *m);
-/**
- * Creates a Condition variable
- *
- * @return not NULL
- */
-racond *racond_create(void);
+ /**
+ * Gets a lock.
+ *
+ * This function blocks until the lock can be acquired.
+ *
+ * @param m The mutex to lock.
+ */
+ void (*lock) (struct mutex_data *m);
-/**
- * Destroy a Condition variable
- *
- * @param c - the condition variable to destroy
- */
-void racond_destroy(racond *c);
+ /**
+ * Tries to get a lock.
+ *
+ * This function returns immediately.
+ *
+ * @param m The mutex to try to lock.
+ * @return success status.
+ * @retval true if the lock was acquired.
+ * @retval false if the mutex couldn't be locked.
+ */
+ bool (*trylock) (struct mutex_data *m);
-/**
- * Waits Until state is signaled
- *
- * @param c - the condition var to wait for signaled state
- * @param m - the mutex used for synchronization
- * @param timeout_ticks - timeout in ticks ( -1 = INFINITE )
- */
-void racond_wait(racond *c, ramutex *m, sysint timeout_ticks);
+ /**
+ * Unlocks a mutex.
+ *
+ * @param m The mutex to unlock.
+ */
+ void (*unlock) (struct mutex_data *m);
-/**
- * Sets the given condition var to signaled state
- *
- * @param c - condition var to set in signaled state.
- *
- * @note:
- * Only one waiter gets notified.
- */
-void racond_signal(racond *c);
+ /**
+ * Creates a conditional variable.
+ *
+ * @return the created conditional variable.
+ */
+ struct cond_data *(*cond_create) (void);
-/**
- * Sets notifies all waiting threads thats signaled.
- * @param c - condition var to set in signaled state
- *
- * @note:
- * All Waiters getting notified.
- */
-void racond_broadcast(racond *c);
+ /**
+ * Destroys a conditional variable.
+ *
+ * @param c the conditional variable to destroy.
+ */
+ void (*cond_destroy) (struct cond_data *c);
+
+ /**
+ * Waits Until state is signaled.
+ *
+ * @param c The condition var to wait for signaled state.
+ * @param m The mutex used for synchronization.
+ * @param timeout_ticks Timeout in ticks (-1 = INFINITE)
+ */
+ void (*cond_wait) (struct cond_data *c, struct mutex_data *m, sysint timeout_ticks);
+
+ /**
+ * Sets the given condition var to signaled state.
+ *
+ * @remark
+ * Only one waiter gets notified.
+ *
+ * @param c Condition var to set in signaled state.
+ */
+ void (*cond_signal) (struct cond_data *c);
+
+ /**
+ * Sets notifies all waiting threads thats signaled.
+ *
+ * @remark
+ * All Waiters getting notified.
+ *
+ * @param c Condition var to set in signaled state.
+ */
+ void (*cond_broadcast) (struct cond_data *c);
+};
+
+#ifdef HERCULES_CORE
+void mutex_defaults(void);
#endif // HERCULES_CORE
+HPShared struct mutex_interface *mutex; ///< Pointer to the mutex interface.
+
#endif /* COMMON_MUTEX_H */
diff --git a/src/common/random.c b/src/common/random.c
index ba70a5c1d..b3a13e054 100644
--- a/src/common/random.c
+++ b/src/common/random.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "common/timer.h" // gettick
#include <mt19937ar/mt19937ar.h> // init_genrand, genrand_int32, genrand_res53
+#include <stdlib.h>
#if defined(WIN32)
# include "common/winapi.h"
@@ -35,8 +36,14 @@
# include <unistd.h>
#endif
+/** @file
+ * Implementation of the random number generator interface.
+ */
+
+struct rnd_interface rnd_s;
+struct rnd_interface *rnd;
-/// Initializes the random number generator with an appropriate seed.
+/// @copydoc rnd_interface::init()
void rnd_init(void)
{
unsigned long seed = (unsigned long)timer->gettick();
@@ -53,53 +60,64 @@ void rnd_init(void)
#endif // HAVE_GETTID
#endif
init_genrand(seed);
+
+ // Also initialize the stdlib rng, just in case it's used somewhere.
+ srand((unsigned int)seed);
}
+/// @copydoc rnd_interface::final()
+void rnd_final(void)
+{
+}
-/// Initializes the random number generator.
+/// @copydoc rnd_interface::seed()
void rnd_seed(uint32 seed)
{
init_genrand(seed);
}
-
-/// Generates a random number in the interval [0, SINT32_MAX]
-int32 rnd(void)
+/// @copydoc rnd_interface::random()
+int32 rnd_random(void)
{
return (int32)genrand_int31();
}
-
-/// Generates a random number in the interval [0, dice_faces)
-/// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0)
+/// @copydoc rnd_interface::roll()
uint32 rnd_roll(uint32 dice_faces)
{
- return (uint32)(rnd_uniform()*dice_faces);
+ return (uint32)(rnd->uniform()*dice_faces);
}
-
-/// Generates a random number in the interval [min, max]
-/// Returns min if range is invalid.
+/// @copydoc rnd_interface::value()
int32 rnd_value(int32 min, int32 max)
{
- if( min >= max )
+ if (min >= max)
return min;
- return min + (int32)(rnd_uniform()*(max-min+1));
+ return min + (int32)(rnd->uniform()*(max-min+1));
}
-
-/// Generates a random number in the interval [0.0, 1.0)
-/// NOTE: interval is open ended, so 1.0 is excluded
+/// @copydoc rnd_interface::uniform()
double rnd_uniform(void)
{
return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32
}
-
-/// Generates a random number in the interval [0.0, 1.0) with 53-bit resolution
-/// NOTE: interval is open ended, so 1.0 is excluded
-/// NOTE: 53 bits is the maximum precision of a double
+/// @copydoc rnd_interface::uniform53()
double rnd_uniform53(void)
{
return genrand_res53();
}
+
+/// Interface base initialization.
+void rnd_defaults(void)
+{
+ rnd = &rnd_s;
+ rnd->init = rnd_init;
+ rnd->final = rnd_final;
+ rnd->seed = rnd_seed;
+ rnd->random = rnd_random;
+ rnd->roll = rnd_roll;
+ rnd->value = rnd_value;
+ rnd->uniform = rnd_uniform;
+ rnd->uniform53 = rnd_uniform53;
+}
diff --git a/src/common/random.h b/src/common/random.h
index 0b5abbcdc..1b249ef19 100644
--- a/src/common/random.h
+++ b/src/common/random.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,17 +21,81 @@
#ifndef COMMON_RANDOM_H
#define COMMON_RANDOM_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
+
+/** @file
+ * The random number generator interface.
+ */
+
+/// Random interface.
+struct rnd_interface {
+ /**
+ * Interface initialization.
+ *
+ * During initialization, the RNG is seeded with a random seed.
+ */
+ void (*init) (void);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Re-seeds the random number generator.
+ *
+ * @param seed The new seed.
+ */
+ void (*seed) (uint32 seed);
+
+ /**
+ * Generates a random number in the interval [0, SINT32_MAX].
+ */
+ int32 (*random) (void);
+
+ /**
+ * Generates a random number in the interval [0, dice_faces).
+ *
+ * @remark
+ * interval is open ended, so dice_faces is excluded (unless it's 0)
+ */
+ uint32 (*roll) (uint32 dice_faces);
+
+ /**
+ * Generates a random number in the interval [min, max].
+ *
+ * @retval min if range is invalid.
+ */
+ int32 (*value) (int32 min, int32 max);
+
+ /**
+ * Generates a random number in the interval [0.0, 1.0)
+ *
+ * @remark
+ * interval is open ended, so 1.0 is excluded
+ */
+ double (*uniform) (void);
+
+ /**
+ * Generates a random number in the interval [0.0, 1.0) with 53-bit resolution.
+ *
+ * 53 bits is the maximum precision of a double.
+ *
+ * @remark
+ * interval is open ended, so 1.0 is excluded
+ */
+ double (*uniform53) (void);
+};
+
+/**
+ * Utlity macro to call the frequently used rnd_interface#random().
+ *
+ * @related rnd_interface.
+ */
+#define rnd() rnd->random()
#ifdef HERCULES_CORE
-void rnd_init(void);
-void rnd_seed(uint32);
-
-int32 rnd(void);// [0, SINT32_MAX]
-uint32 rnd_roll(uint32 dice_faces);// [0, dice_faces)
-int32 rnd_value(int32 min, int32 max);// [min, max]
-double rnd_uniform(void);// [0.0, 1.0)
-double rnd_uniform53(void);// [0.0, 1.0)
+void rnd_defaults(void);
#endif // HERCULES_CORE
+HPShared struct rnd_interface *rnd; ///< Pointer to the random interface.
+
#endif /* COMMON_RANDOM_H */
diff --git a/src/common/showmsg.c b/src/common/showmsg.c
index 8ed8efc1d..d8864684d 100644
--- a/src/common/showmsg.c
+++ b/src/common/showmsg.c
@@ -804,7 +804,11 @@ void showmsg_showConfigWarning(struct config_setting_t *config, const char *stri
StrBuf->AppendStr(&buf, string);
StrBuf->Printf(&buf, " (%s:%u)\n", config_setting_source_file(config), config_setting_source_line(config));
va_start(ap, string);
+#ifdef BUILDBOT
+ vShowMessage_(MSG_ERROR, StrBuf->Value(&buf), ap);
+#else // BUILDBOT
vShowMessage_(MSG_WARNING, StrBuf->Value(&buf), ap);
+#endif // BUILDBOT
va_end(ap);
StrBuf->Destroy(&buf);
}
diff --git a/src/common/showmsg.h b/src/common/showmsg.h
index 7b48d0df2..303c8dd28 100644
--- a/src/common/showmsg.h
+++ b/src/common/showmsg.h
@@ -130,7 +130,11 @@ struct showmsg_interface {
#define ShowSQL(fmt, ...) (showmsg->showSQL((fmt), ##__VA_ARGS__))
#define ShowInfo(fmt, ...) (showmsg->showInfo((fmt), ##__VA_ARGS__))
#define ShowNotice(fmt, ...) (showmsg->showNotice((fmt), ##__VA_ARGS__))
+#ifdef BUILDBOT
+#define ShowWarning(fmt, ...) (showmsg->showError((fmt), ##__VA_ARGS__))
+#else // BUILDBOT
#define ShowWarning(fmt, ...) (showmsg->showWarning((fmt), ##__VA_ARGS__))
+#endif // BUILDBOT
#define ShowDebug(fmt, ...) (showmsg->showDebug((fmt), ##__VA_ARGS__))
#define ShowError(fmt, ...) (showmsg->showError((fmt), ##__VA_ARGS__))
#define ShowFatalError(fmt, ...) (showmsg->showFatalError((fmt), ##__VA_ARGS__))
diff --git a/src/common/socket.c b/src/common/socket.c
index 5d4ea06a0..af5e8aa73 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -38,35 +38,39 @@
#include <stdlib.h>
#include <sys/types.h>
+#ifdef SOCKET_EPOLL
+#include <sys/epoll.h>
+#endif // SOCKET_EPOLL
+
#ifdef WIN32
# include "common/winapi.h"
-#else
+#else // WIN32
# include <arpa/inet.h>
# include <errno.h>
# include <net/if.h>
# include <netdb.h>
#if defined __linux__ || defined __linux
# include <linux/tcp.h>
-#else
+#else // defined __linux__ || defined __linux
# include <netinet/in.h>
# include <netinet/tcp.h>
-#endif
+#endif // defined __linux__ || defined __linux
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <unistd.h>
-# ifndef SIOCGIFCONF
-# include <sys/sockio.h> // SIOCGIFCONF on Solaris, maybe others? [Shinomori]
-# endif
-# ifndef FIONBIO
-# include <sys/filio.h> // FIONBIO on Solaris [FlavioJS]
-# endif
+#ifndef SIOCGIFCONF
+# include <sys/sockio.h> // SIOCGIFCONF on Solaris, maybe others? [Shinomori]
+#endif // SIOCGIFCONF
+#ifndef FIONBIO
+# include <sys/filio.h> // FIONBIO on Solaris [FlavioJS]
+#endif // FIONBIO
-# ifdef HAVE_SETRLIMIT
-# include <sys/resource.h>
-# endif
-#endif
+#ifdef HAVE_SETRLIMIT
+# include <sys/resource.h>
+#endif // HAVE_SETRLIMIT
+#endif // WIN32
/**
* Socket Interface Source
@@ -82,7 +86,7 @@ struct socket_data **session;
void send_shortlist_add_fd(int fd);
// Do pending network sends (and eof handling) from the shortlist.
void send_shortlist_do_sends(void);
-#endif
+#endif // SEND_SHORTLIST
/////////////////////////////////////////////////////////////////////
#if defined(WIN32)
@@ -212,7 +216,7 @@ char* sErr(int code)
#define sFD_ZERO FD_ZERO
/////////////////////////////////////////////////////////////////////
-#else
+#else // defined(WIN32)
/////////////////////////////////////////////////////////////////////
// nix portability layer
@@ -244,29 +248,40 @@ char* sErr(int code)
#define sFD_ZERO FD_ZERO
/////////////////////////////////////////////////////////////////////
-#endif
+#endif // defined(WIN32)
/////////////////////////////////////////////////////////////////////
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
-#endif
+#endif // MSG_NOSIGNAL
+#ifndef SOCKET_EPOLL
+// Select based Event Dispatcher:
fd_set readfds;
+#else // SOCKET_EPOLL
+// Epoll based Event Dispatcher:
+static int epoll_maxevents = (FD_SETSIZE / 2);
+static int epfd = SOCKET_ERROR;
+static struct epoll_event epevent;
+static struct epoll_event *epevents = NULL;
+
+#endif // SOCKET_EPOLL
+
// Maximum packet size in bytes, which the client is able to handle.
// Larger packets cause a buffer overflow and stack corruption.
#if PACKETVER >= 20131223
static size_t socket_max_client_packet = 0xFFFF;
-#else
+#else // PACKETVER >= 20131223
static size_t socket_max_client_packet = 0x6000;
-#endif
+#endif // PACKETVER >= 20131223
#ifdef SHOW_SERVER_STATS
// Data I/O statistics
static size_t socket_data_i = 0, socket_data_ci = 0, socket_data_qi = 0;
static size_t socket_data_o = 0, socket_data_co = 0, socket_data_qo = 0;
static time_t socket_data_last_tick = 0;
-#endif
+#endif // SHOW_SERVER_STATS
// initial recv buffer size (this will also be the max. size)
// biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes)
@@ -282,14 +297,14 @@ static time_t socket_data_last_tick = 0;
int send_shortlist_array[FD_SETSIZE];// we only support FD_SETSIZE sockets, limit the array to that
int send_shortlist_count = 0;// how many fd's are in the shortlist
uint32 send_shortlist_set[(FD_SETSIZE+31)/32];// to know if specific fd's are already in the shortlist
-#endif
+#endif // SEND_SHORTLIST
static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse);
#ifndef MINICORE
int ip_rules = 1;
static int connect_check(uint32 ip);
-#endif
+#endif // MINICORE
const char* error_msg(void)
{
@@ -380,13 +395,13 @@ void setsocketopts(int fd, struct hSockOpt *opt)
ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd);
#ifdef TCP_THIN_LINEAR_TIMEOUTS
- if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, (char *)&yes, sizeof(yes)))
- ShowWarning("setsocketopts: Unable to set TCP_THIN_LINEAR_TIMEOUTS mode for connection #%d!\n", fd);
-#endif
+ if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, (char *)&yes, sizeof(yes)))
+ ShowWarning("setsocketopts: Unable to set TCP_THIN_LINEAR_TIMEOUTS mode for connection #%d!\n", fd);
+#endif // TCP_THIN_LINEAR_TIMEOUTS
#ifdef TCP_THIN_DUPACK
- if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, (char *)&yes, sizeof(yes)))
- ShowWarning("setsocketopts: Unable to set TCP_THIN_DUPACK mode for connection #%d!\n", fd);
-#endif
+ if (sSetsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, (char *)&yes, sizeof(yes)))
+ ShowWarning("setsocketopts: Unable to set TCP_THIN_DUPACK mode for connection #%d!\n", fd);
+#endif // TCP_THIN_DUPACK
}
/*======================================
@@ -398,7 +413,7 @@ void set_eof(int fd)
#ifdef SEND_SHORTLIST
// Add this socket to the shortlist for eof handling.
send_shortlist_add_fd(fd);
-#endif
+#endif // SEND_SHORTLIST
sockt->session[fd]->flag.eof = 1;
}
}
@@ -436,7 +451,7 @@ int recv_to_fifo(int fd)
{
socket_data_ci += len;
}
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -453,12 +468,12 @@ int send_from_fifo(int fd)
len = sSend(fd, (const char *) sockt->session[fd]->wdata, (int)sockt->session[fd]->wdata_size, MSG_NOSIGNAL);
if( len == SOCKET_ERROR )
- {//An exception has occurred
+ { //An exception has occurred
if( sErrno != S_EWOULDBLOCK ) {
//ShowDebug("send_from_fifo: %s, ending connection #%d\n", error_msg(), fd);
#ifdef SHOW_SERVER_STATS
socket_data_qo -= sockt->session[fd]->wdata_size;
-#endif
+#endif // SHOW_SERVER_STATS
sockt->session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex]
sockt->eof(fd);
}
@@ -480,7 +495,7 @@ int send_from_fifo(int fd)
{
socket_data_co += len;
}
-#endif
+#endif // SHOW_SERVER_STATS
}
return 0;
@@ -534,11 +549,27 @@ int connect_client(int listen_fd) {
sockt->close(fd);
return -1;
}
-#endif
+#endif // MINICORE
- if( sockt->fd_max <= fd ) sockt->fd_max = fd + 1;
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
sFD_SET(fd,&readfds);
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("connect_client: New Socket #%d failed to add to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ return -1;
+ }
+
+#endif // SOCKET_EPOLL
+
+ if( sockt->fd_max <= fd ) sockt->fd_max = fd + 1;
+
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
sockt->session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr);
@@ -586,8 +617,26 @@ int make_listen_bind(uint32 ip, uint16 port)
exit(EXIT_FAILURE);
}
+
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
+ sFD_SET(fd,&readfds);
+
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("make_listen_bind: failed to add listener socket #%d to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ exit(EXIT_FAILURE);
+ }
+
+#endif // SOCKET_EPOLL
+
if(sockt->fd_max <= fd) sockt->fd_max = fd + 1;
- sFD_SET(fd, &readfds);
+
create_session(fd, connect_client, null_send, null_parse);
sockt->session[fd]->client_addr = 0; // just listens
@@ -637,9 +686,26 @@ int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
//Now the socket can be made non-blocking. [Skotlex]
sockt->set_nonblocking(fd, 1);
- if (sockt->fd_max <= fd) sockt->fd_max = fd + 1;
+
+#ifndef SOCKET_EPOLL
+ // Select Based Event Dispatcher
sFD_SET(fd,&readfds);
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+
+ if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &epevent) == SOCKET_ERROR){
+ ShowError("make_connection: failed to add socket #%d to epoll event dispatcher: %s\n", fd, error_msg());
+ sClose(fd);
+ return -1;
+ }
+
+#endif // SOCKET_EPOLL
+
+ if(sockt->fd_max <= fd) sockt->fd_max = fd + 1;
+
create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse);
sockt->session[fd]->client_addr = ntohl(remote_address.sin_addr.s_addr);
@@ -668,7 +734,7 @@ static void delete_session(int fd)
#ifdef SHOW_SERVER_STATS
socket_data_qi -= sockt->session[fd]->rdata_size - sockt->session[fd]->rdata_pos;
socket_data_qo -= sockt->session[fd]->wdata_size;
-#endif
+#endif // SHOW_SERVER_STATS
aFree(sockt->session[fd]->rdata);
aFree(sockt->session[fd]->wdata);
if( sockt->session[fd]->session_data )
@@ -741,7 +807,7 @@ int rfifoskip(int fd, size_t len)
s->rdata_pos = s->rdata_pos + len;
#ifdef SHOW_SERVER_STATS
socket_data_qi -= len;
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -792,7 +858,7 @@ int wfifoset(int fd, size_t len)
s->wdata_size += len;
#ifdef SHOW_SERVER_STATS
socket_data_qo += len;
-#endif
+#endif // SHOW_SERVER_STATS
//If the interserver has 200% of its normal size full, flush the data.
if( s->flag.server && s->wdata_size >= 2*FIFOSIZE_SERVERLINK )
sockt->flush(fd);
@@ -806,22 +872,24 @@ int wfifoset(int fd, size_t len)
#ifdef SEND_SHORTLIST
send_shortlist_add_fd(fd);
-#endif
+#endif // SEND_SHORTLIST
return 0;
}
int do_sockets(int next)
{
+#ifndef SOCKET_EPOLL
fd_set rfd;
struct timeval timeout;
+#endif // SOCKET_EPOLL
int ret,i;
// PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof.
// Send remaining data and process client-side disconnects here.
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
-#else
+#else // SEND_SHORTLIST
for (i = 1; i < sockt->fd_max; i++)
{
if(!sockt->session[fd]
@@ -830,7 +898,10 @@ int do_sockets(int next)
if(sockt->session[fd]>wdata_size)
sockt->session[fd]>func_send(i);
}
-#endif
+#endif // SEND_SHORTLIST
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher:
// can timeout until the next tick
timeout.tv_sec = next/1000;
@@ -848,6 +919,20 @@ int do_sockets(int next)
}
return 0; // interrupted by a signal, just loop and try again
}
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+
+ ret = epoll_wait(epfd, epevents, epoll_maxevents, next);
+ if(ret == SOCKET_ERROR)
+ {
+ if( sErrno != S_EINTR )
+ {
+ ShowFatalError("do_sockets: epoll_wait() failed, %s!\n", error_msg());
+ exit(EXIT_FAILURE);
+ }
+ return 0; // interrupted by a signal, just loop and try again
+ }
+#endif // SOCKET_EPOLL
sockt->last_tick = time(NULL);
@@ -859,7 +944,33 @@ int do_sockets(int next)
if( sockt->session[fd] )
sockt->session[fd]->func_recv(fd);
}
-#else
+#elif defined(SOCKET_EPOLL)
+ // epoll based selection
+
+ for( i = 0; i < ret; i++ )
+ {
+ struct epoll_event *it = &epevents[i];
+ struct socket_data *sock = sockt->session[ it->data.fd ];
+
+ if(!sock)
+ continue;
+
+ if ((it->events & EPOLLERR) ||
+ (it->events & EPOLLHUP) ||
+ (!(it->events & EPOLLIN)))
+ {
+ // Got Error on this connection
+ sockt->eof( it->data.fd );
+
+ } else if (it->events & EPOLLIN) {
+ // data wainting
+ sock->func_recv( it->data.fd );
+
+ }
+
+ }
+
+#else // defined(SOCKET_EPOLL)
// otherwise assume that the fd_set is a bit-array and enumerate it in a standard way
for( i = 1; ret && i < sockt->fd_max; ++i )
{
@@ -869,12 +980,12 @@ int do_sockets(int next)
--ret;
}
}
-#endif
+#endif // defined(SOCKET_EPOLL)
// POSTSEND Send remaining data and handle eof sessions.
#ifdef SEND_SHORTLIST
send_shortlist_do_sends();
-#else
+#else // SEND_SHORTLIST
for (i = 1; i < sockt->fd_max; i++)
{
if(!sockt->session[i])
@@ -888,7 +999,7 @@ int do_sockets(int next)
sockt->session[i]->func_parse(i); //This should close the session immediately.
}
}
-#endif
+#endif // SEND_SHORTLIST
// parse input data on each socket
for(i = 1; i < sockt->fd_max; i++)
@@ -931,14 +1042,14 @@ int do_sockets(int next)
sprintf(buf, "In: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | Out: %.03f kB/s (%.03f kB/s, Q: %.03f kB) | RAM: %.03f MB", socket_data_i/1024., socket_data_ci/1024., socket_data_qi/1024., socket_data_o/1024., socket_data_co/1024., socket_data_qo/1024., iMalloc->usage()/1024.);
#ifdef _WIN32
SetConsoleTitle(buf);
-#else
+#else // _WIN32
ShowMessage("\033[s\033[1;1H\033[2K%s\033[u", buf);
-#endif
+#endif // _WIN32
socket_data_last_tick = sockt->last_tick;
socket_data_i = socket_data_ci = 0;
socket_data_o = socket_data_co = 0;
}
-#endif
+#endif // SHOW_SERVER_STATS
return 0;
}
@@ -1160,7 +1271,7 @@ int access_ipmask(const char* str, AccessControl* acc)
return 1;
}
//////////////////////////////
-#endif
+#endif // MINICORE
//////////////////////////////
int socket_config_read(const char* cfgName)
@@ -1184,7 +1295,15 @@ int socket_config_read(const char* cfgName)
sockt->stall_time = atoi(w2);
if( sockt->stall_time < 3 )
sockt->stall_time = 3;/* a minimum is required to refrain it from killing itself */
+ }
+#ifdef SOCKET_EPOLL
+ else if(!strcmpi(w1, "epoll_maxevents")) {
+ epoll_maxevents = atoi(w2);
+ if(epoll_maxevents < 16){
+ epoll_maxevents = 16; // minimum that seems to be useful
+ }
}
+#endif // SOCKET_EPOLL
#ifndef MINICORE
else if (!strcmpi(w1, "enable_ip_rules")) {
ip_rules = config_switch(w2);
@@ -1218,7 +1337,7 @@ int socket_config_read(const char* cfgName)
access_debug = config_switch(w2);
else if (!strcmpi(w1,"socket_max_client_packet"))
socket_max_client_packet = strtoul(w2, NULL, 0);
-#endif
+#endif // MINICORE
else if (!strcmpi(w1, "import"))
socket_config_read(w2);
else
@@ -1239,7 +1358,7 @@ void socket_final(void)
aFree(access_allow);
if( access_deny )
aFree(access_deny);
-#endif
+#endif // MINICORE
for( i = 1; i < sockt->fd_max; i++ )
if(sockt->session[i])
@@ -1255,6 +1374,18 @@ void socket_final(void)
VECTOR_CLEAR(sockt->lan_subnets);
VECTOR_CLEAR(sockt->allowed_ips);
VECTOR_CLEAR(sockt->trusted_ips);
+
+#ifdef SOCKET_EPOLL
+ if(epfd != SOCKET_ERROR){
+ close(epfd);
+ epfd = SOCKET_ERROR;
+ }
+ if(epevents != NULL){
+ aFree(epevents);
+ epevents = NULL;
+ }
+#endif // SOCKET_EPOLL
+
}
/// Closes a socket.
@@ -1264,7 +1395,17 @@ void socket_close(int fd)
return;// invalid
sockt->flush(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket)
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher
sFD_CLR(fd, &readfds);// this needs to be done before closing the socket
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher
+ epevent.data.fd = fd;
+ epevent.events = EPOLLIN;
+ epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &epevent); // removing the socket from epoll when it's being closed is not required but recommended
+#endif // SOCKET_EPOLL
+
sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes
sClose(fd); // We don't really care if these closing functions return an error, we are just shutting down and not reusing this socket.
if (sockt->session[fd]) delete_session(fd);
@@ -1401,20 +1542,39 @@ void socket_init(void)
}
}
}
-#endif
+#endif // defined(HAVE_SETRLIMIT) && !defined(CYGWIN)
// Get initial local ips
sockt->naddr_ = sockt->getips(sockt->addr_,16);
+ socket_config_read(SOCKET_CONF_FILENAME);
+
+#ifndef SOCKET_EPOLL
+ // Select based Event Dispatcher:
sFD_ZERO(&readfds);
+ ShowInfo("Server uses '" CL_WHITE "select" CL_RESET "' as event dispatcher\n");
+
+#else // SOCKET_EPOLL
+ // Epoll based Event Dispatcher:
+ epfd = epoll_create(FD_SETSIZE); // 2.6.8 or newer ignores the expected socket amount argument
+ if(epfd == SOCKET_ERROR){
+ ShowError("Failed to Create Epoll Event Dispatcher: %s\n", error_msg());
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&epevent, 0x00, sizeof(struct epoll_event));
+ epevents = aCalloc(epoll_maxevents, sizeof(struct epoll_event));
+
+ ShowInfo("Server uses '" CL_WHITE "epoll" CL_RESET "' with up to " CL_WHITE "%d" CL_RESET " events per cycle as event dispatcher\n", epoll_maxevents);
+
+#endif // SOCKET_EPOLL
+
#if defined(SEND_SHORTLIST)
memset(send_shortlist_set, 0, sizeof(send_shortlist_set));
-#endif
+#endif // defined(SEND_SHORTLIST)
CREATE(sockt->session, struct socket_data *, FD_SETSIZE);
- socket_config_read(SOCKET_CONF_FILENAME);
-
// initialize last send-receive tick
sockt->last_tick = time(NULL);
@@ -1427,7 +1587,7 @@ void socket_init(void)
connect_history = uidb_alloc(DB_OPT_RELEASE_DATA);
timer->add_func_list(connect_check_clear, "connect_check_clear");
timer->add_interval(timer->gettick()+1000, connect_check_clear, 0, 0, 5*60*1000);
-#endif
+#endif // MINICORE
ShowInfo("Server supports up to '"CL_WHITE"%"PRIu64""CL_RESET"' concurrent connections.\n", rlim_cur);
}
@@ -1617,7 +1777,7 @@ void send_shortlist_do_sends(void)
}
}
}
-#endif
+#endif // SEND_SHORTLIST
/**
* Checks whether the given IP comes from LAN or WAN.
@@ -1752,10 +1912,12 @@ void socket_net_config_read(const char *filename)
ShowError("No allowed server IP ranges configured. This server won't be able to accept connections from any char servers.\n");
}
ARR_FIND(0, VECTOR_LENGTH(sockt->allowed_ips), i, SUBNET_MATCH(0, VECTOR_INDEX(sockt->allowed_ips, i).ip, VECTOR_INDEX(sockt->allowed_ips, i).mask));
+#ifndef BUILDBOT
if (i != VECTOR_LENGTH(sockt->allowed_ips)) {
ShowWarning("Using a wildcard IP range in the allowed server IPs is NOT RECOMMENDED.\n");
ShowNotice("Please edit your '%s' allowed list to fit your network configuration.\n", filename);
}
+#endif // BUILDBOT
libconfig->destroy(&network_config);
return;
}
diff --git a/src/common/spinlock.h b/src/common/spinlock.h
index 4d9c4c668..c04416285 100644
--- a/src/common/spinlock.h
+++ b/src/common/spinlock.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -37,74 +37,75 @@
#endif
#ifdef WIN32
-
-typedef struct __declspec( align(64) ) SPIN_LOCK{
+struct __declspec(align(64)) spin_lock {
volatile LONG lock;
volatile LONG nest;
volatile LONG sync_lock;
-} SPIN_LOCK;
+};
#else
-typedef struct SPIN_LOCK{
- volatile int32 lock;
- volatile int32 nest; // nesting level.
-
- volatile int32 sync_lock;
-} __attribute__((aligned(64))) SPIN_LOCK;
+struct spin_lock {
+ volatile int32 lock;
+ volatile int32 nest; // nesting level.
+ volatile int32 sync_lock;
+} __attribute__((aligned(64)));
#endif
-
#ifdef HERCULES_CORE
-static forceinline void InitializeSpinLock(SPIN_LOCK *lck){
- lck->lock = 0;
- lck->nest = 0;
- lck->sync_lock = 0;
+static forceinline void InitializeSpinLock(struct spin_lock *lck)
+{
+ lck->lock = 0;
+ lck->nest = 0;
+ lck->sync_lock = 0;
}
-static forceinline void FinalizeSpinLock(SPIN_LOCK *lck){
+static forceinline void FinalizeSpinLock(struct spin_lock *lck)
+{
return;
}
-#define getsynclock(l) do { if(InterlockedCompareExchange((l), 1, 0) == 0) break; rathread_yield(); } while(/*always*/1)
+#define getsynclock(l) do { if(InterlockedCompareExchange((l), 1, 0) == 0) break; thread->yield(); } while(/*always*/1)
#define dropsynclock(l) do { InterlockedExchange((l), 0); } while(0)
-static forceinline void EnterSpinLock(SPIN_LOCK *lck){
- int tid = rathread_get_tid();
+static forceinline void EnterSpinLock(struct spin_lock *lck)
+{
+ int tid = thread->get_tid();
- // Get Sync Lock && Check if the requester thread already owns the lock.
- // if it owns, increase nesting level
- getsynclock(&lck->sync_lock);
- if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){
- InterlockedIncrement(&lck->nest);
- dropsynclock(&lck->sync_lock);
- return; // Got Lock
- }
- // drop sync lock
+ // Get Sync Lock && Check if the requester thread already owns the lock.
+ // if it owns, increase nesting level
+ getsynclock(&lck->sync_lock);
+ if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) {
+ InterlockedIncrement(&lck->nest);
dropsynclock(&lck->sync_lock);
-
- // Spin until we've got it !
- while(1){
- if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){
- InterlockedIncrement(&lck->nest);
- return; // Got Lock
- }
- rathread_yield(); // Force ctxswitch to another thread.
+ return; // Got Lock
+ }
+ // drop sync lock
+ dropsynclock(&lck->sync_lock);
+
+ // Spin until we've got it !
+ while (true) {
+ if (InterlockedCompareExchange(&lck->lock, tid, 0) == 0) {
+ InterlockedIncrement(&lck->nest);
+ return; // Got Lock
}
+ thread->yield(); // Force ctxswitch to another thread.
+ }
}
-static forceinline void LeaveSpinLock(SPIN_LOCK *lck){
- int tid = rathread_get_tid();
+static forceinline void LeaveSpinLock(struct spin_lock *lck)
+{
+ int tid = thread->get_tid();
- getsynclock(&lck->sync_lock);
+ getsynclock(&lck->sync_lock);
- if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock.
- if(InterlockedDecrement(&lck->nest) == 0)
- InterlockedExchange(&lck->lock, 0); // Unlock!
- }
+ if (InterlockedCompareExchange(&lck->lock, tid, tid) == tid) { // this thread owns the lock.
+ if (InterlockedDecrement(&lck->nest) == 0)
+ InterlockedExchange(&lck->lock, 0); // Unlock!
+ }
- dropsynclock(&lck->sync_lock);
+ dropsynclock(&lck->sync_lock);
}
#endif // HERCULES_CORE
diff --git a/src/common/strlib.c b/src/common/strlib.c
index 9690151b4..b67adb63c 100644
--- a/src/common/strlib.c
+++ b/src/common/strlib.c
@@ -772,6 +772,7 @@ size_t sv_escape_c(char* out_dest, const char* src, size_t len, const char* esca
case '\v': out_dest[j++] = 'v'; break;
case '\f': out_dest[j++] = 'f'; break;
case '\?': out_dest[j++] = '?'; break;
+ case '\"': out_dest[j++] = '"'; break;
default:// to octal
out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0700)>>6));
out_dest[j++] = '0'+((char)(((unsigned char)src[i]&0070)>>3));
diff --git a/src/common/thread.c b/src/common/thread.c
index b724344e6..aaafab943 100644
--- a/src/common/thread.c
+++ b/src/common/thread.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -20,10 +20,6 @@
*/
#define HERCULES_CORE
-// Basic Threading abstraction (for pthread / win32 based systems)
-//
-// Author: Florian Wilkemeyer <fw@f-ws.de>
-
#include "thread.h"
#include "common/cbasetypes.h"
@@ -48,13 +44,22 @@
#define HAS_TLS
#endif
-#define RA_THREADS_MAX 64
+/** @file
+ * Thread interface implementation.
+ * @author Florian Wilkemeyer <fw@f-ws.de>
+ */
+
+struct thread_interface thread_s;
+struct thread_interface *thread;
-struct rAthread {
+/// The maximum amount of threads.
+#define THREADS_MAX 64
+
+struct thread_handle {
unsigned int myID;
- RATHREAD_PRIO prio;
- rAthreadProc proc;
+ enum thread_priority prio;
+ threadFunc proc;
void *param;
#ifdef WIN32
@@ -68,16 +73,17 @@ struct rAthread {
__thread int g_rathread_ID = -1;
#endif
-///
-/// Subystem Code
-///
-static struct rAthread l_threads[RA_THREADS_MAX];
+// Subystem Code
+
+static struct thread_handle l_threads[THREADS_MAX];
-void rathread_init(void) {
- register unsigned int i;
- memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) );
+/// @copydoc thread_interface::init()
+void thread_init(void)
+{
+ register int i;
+ memset(&l_threads, 0x00, THREADS_MAX * sizeof(struct thread_handle));
- for(i = 0; i < RA_THREADS_MAX; i++){
+ for (i = 0; i < THREADS_MAX; i++) {
l_threads[i].myID = i;
}
@@ -85,46 +91,53 @@ void rathread_init(void) {
#ifdef HAS_TLS
g_rathread_ID = 0;
#endif
- l_threads[0].prio = RAT_PRIO_NORMAL;
- l_threads[0].proc = (rAthreadProc)0xDEADCAFE;
+ l_threads[0].prio = THREADPRIO_NORMAL;
+ l_threads[0].proc = (threadFunc)0xDEADCAFE;
-}//end: rathread_init()
+}
-void rathread_final(void) {
- register unsigned int i;
+/// @copydoc thread_interface::final()
+void thread_final(void)
+{
+ register int i;
// Unterminated Threads Left?
- // Shouldn't happen ..
- // Kill 'em all!
- //
- for(i = 1; i < RA_THREADS_MAX; i++){
- if(l_threads[i].proc != NULL){
- ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
- rathread_destroy(&l_threads[i]);
+ // Shouldn't happen ... Kill 'em all!
+ for (i = 1; i < THREADS_MAX; i++) {
+ if (l_threads[i].proc != NULL){
+ ShowWarning("thread_final: unterminated Thread (tid %d entry_point %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
+ thread->destroy(&l_threads[i]);
}
}
+}
-}//end: rathread_final()
-
-// gets called whenever a thread terminated ..
-static void rat_thread_terminated(rAthread *handle) {
+/**
+ * Gets called whenever a thread terminated.
+ *
+ * @param handle The terminated thread's handle.
+ */
+static void thread_terminated(struct thread_handle *handle)
+{
// Preserve handle->myID and handle->hThread, set everything else to its default value
handle->param = NULL;
handle->proc = NULL;
- handle->prio = RAT_PRIO_NORMAL;
-}//end: rat_thread_terminated()
+ handle->prio = THREADPRIO_NORMAL;
+}
#ifdef WIN32
-DWORD WINAPI raThreadMainRedirector(LPVOID p){
+DWORD WINAPI thread_main_redirector(LPVOID p)
+{
#else
-static void *raThreadMainRedirector( void *p ){
+static void *thread_main_redirector(void *p)
+{
sigset_t set; // on Posix Thread platforms
#endif
void *ret;
+ struct thread_handle *self = p;
// Update myID @ TLS to right id.
#ifdef HAS_TLS
- g_rathread_ID = ((rAthread*)p)->myID;
+ g_rathread_ID = self->myID;
#endif
#ifndef WIN32
@@ -138,66 +151,68 @@ static void *raThreadMainRedirector( void *p ){
(void)sigaddset(&set, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &set, NULL);
-
#endif
- ret = ((rAthread*)p)->proc( ((rAthread*)p)->param ) ;
+ ret = self->proc(self->param);
#ifdef WIN32
- CloseHandle( ((rAthread*)p)->hThread );
+ CloseHandle(self->hThread);
#endif
- rat_thread_terminated( (rAthread*)p );
+ thread_terminated(self);
#ifdef WIN32
return (DWORD)ret;
#else
return ret;
#endif
-}//end: raThreadMainRedirector()
+}
+
+// API Level
-///
-/// API Level
-///
-rAthread *rathread_create(rAthreadProc entryPoint, void *param) {
- return rathread_createEx( entryPoint, param, (1<<23) /*8MB*/, RAT_PRIO_NORMAL );
-}//end: rathread_create()
+/// @copydoc thread_interface::create()
+struct thread_handle *thread_create(threadFunc entry_point, void *param)
+{
+ return thread->create_opt(entry_point, param, (1<<23) /*8MB*/, THREADPRIO_NORMAL);
+}
-rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio) {
+/// @copydoc thread_interface::create_opt()
+struct thread_handle *thread_create_opt(threadFunc entry_point, void *param, size_t stack_size, enum thread_priority prio)
+{
#ifndef WIN32
pthread_attr_t attr;
#endif
size_t tmp;
- unsigned int i;
- rAthread *handle = NULL;
+ int i;
+ struct thread_handle *handle = NULL;
// given stacksize aligned to systems pagesize?
- tmp = szStack % sysinfo->getpagesize();
- if(tmp != 0)
- szStack += tmp;
+ tmp = stack_size % sysinfo->getpagesize();
+ if (tmp != 0)
+ stack_size += tmp;
// Get a free Thread Slot.
- for(i = 0; i < RA_THREADS_MAX; i++){
+ for (i = 0; i < THREADS_MAX; i++) {
if(l_threads[i].proc == NULL){
handle = &l_threads[i];
break;
}
}
- if(handle == NULL){
- ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint);
+ if (handle == NULL) {
+ ShowError("thread_create_opt: cannot create new thread (entry_point: %p) - no free thread slot found!", entry_point);
return NULL;
}
- handle->proc = entryPoint;
+ handle->proc = entry_point;
handle->param = param;
#ifdef WIN32
- handle->hThread = CreateThread(NULL, szStack, raThreadMainRedirector, (void*)handle, 0, NULL);
+ handle->hThread = CreateThread(NULL, stack_size, thread_main_redirector, handle, 0, NULL);
#else
pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, szStack);
+ pthread_attr_setstacksize(&attr, stack_size);
- if(pthread_create(&handle->hThread, &attr, raThreadMainRedirector, (void*)handle) != 0){
+ if (pthread_create(&handle->hThread, &attr, thread_main_redirector, handle) != 0) {
handle->proc = NULL;
handle->param = NULL;
return NULL;
@@ -205,99 +220,122 @@ rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack
pthread_attr_destroy(&attr);
#endif
- rathread_prio_set( handle, prio );
+ thread->prio_set(handle, prio);
return handle;
-}//end: rathread_createEx
+}
-void rathread_destroy(rAthread *handle) {
+/// @copydoc thread_interface::destroy()
+void thread_destroy(struct thread_handle *handle)
+{
#ifdef WIN32
- if( TerminateThread(handle->hThread, 0) != FALSE){
+ if (TerminateThread(handle->hThread, 0) != FALSE) {
CloseHandle(handle->hThread);
- rat_thread_terminated(handle);
+ thread_terminated(handle);
}
#else
- if( pthread_cancel( handle->hThread ) == 0){
+ if (pthread_cancel(handle->hThread) == 0) {
// We have to join it, otherwise pthread wont re-cycle its internal resources assoc. with this thread.
- pthread_join( handle->hThread, NULL );
+ pthread_join(handle->hThread, NULL);
// Tell our manager to release resources ;)
- rat_thread_terminated(handle);
+ thread_terminated(handle);
}
#endif
-}//end: rathread_destroy()
+}
-rAthread *rathread_self(void) {
+struct thread_handle *thread_self(void)
+{
#ifdef HAS_TLS
- rAthread *handle = &l_threads[g_rathread_ID];
+ struct thread_handle *handle = &l_threads[g_rathread_ID];
- if(handle->proc != NULL) // entry point set, so its used!
+ if (handle->proc != NULL) // entry point set, so its used!
return handle;
#else
// .. so no tls means we have to search the thread by its api-handle ..
int i;
- #ifdef WIN32
- HANDLE hSelf;
- hSelf = GetCurrent = GetCurrentThread();
- #else
- pthread_t hSelf;
- hSelf = pthread_self();
- #endif
+#ifdef WIN32
+ HANDLE hSelf;
+ hSelf = GetCurrent = GetCurrentThread();
+#else
+ pthread_t hSelf;
+ hSelf = pthread_self();
+#endif
- for(i = 0; i < RA_THREADS_MAX; i++){
- if(l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
+ for (i = 0; i < THREADS_MAX; i++) {
+ if (l_threads[i].hThread == hSelf && l_threads[i].proc != NULL)
return &l_threads[i];
}
#endif
return NULL;
-}//end: rathread_self()
+}
-int rathread_get_tid(void) {
-
-#ifdef HAS_TLS
+/// @copydoc thread_interface::get_tid()
+int thread_get_tid(void)
+{
+#if defined(HAS_TLS)
return g_rathread_ID;
+#elif defined(WIN32)
+ return (int)GetCurrentThreadId();
#else
- // TODO
- #ifdef WIN32
- return (int)GetCurrentThreadId();
- #else
- return (int)pthread_self();
- #endif
+ return (int)pthread_self();
#endif
+}
-}//end: rathread_get_tid()
-
-bool rathread_wait(rAthread *handle, void **out_exitCode) {
+/// @copydoc thread_interface::wait()
+bool thread_wait(struct thread_handle *handle, void **out_exit_code)
+{
// Hint:
// no thread data cleanup routine call here!
// its managed by the callProxy itself..
- //
#ifdef WIN32
WaitForSingleObject(handle->hThread, INFINITE);
return true;
#else
- if(pthread_join(handle->hThread, out_exitCode) == 0)
+ if (pthread_join(handle->hThread, out_exit_code) == 0)
return true;
return false;
#endif
-}//end: rathread_wait()
+}
-void rathread_prio_set(rAthread *handle, RATHREAD_PRIO prio) {
- handle->prio = RAT_PRIO_NORMAL;
+/// @copydoc thread_interface::prio_set()
+void thread_prio_set(struct thread_handle *handle, enum thread_priority prio)
+{
+ handle->prio = THREADPRIO_NORMAL;
//@TODO
-}//end: rathread_prio_set()
+}
-RATHREAD_PRIO rathread_prio_get(rAthread *handle) {
+/// @copydoc thread_interface::prio_get()
+enum thread_priority thread_prio_get(struct thread_handle *handle)
+{
return handle->prio;
-}//end: rathread_prio_get()
+}
-void rathread_yield(void) {
+/// @copydoc thread_interface::yield()
+void thread_yield(void) {
#ifdef WIN32
SwitchToThread();
#else
sched_yield();
#endif
-}//end: rathread_yield()
+}
+
+/// Interface base initialization.
+void thread_defaults(void)
+{
+ thread = &thread_s;
+ thread->init = thread_init;
+ thread->final = thread_final;
+ thread->create = thread_create;
+ thread->create_opt = thread_create_opt;
+ thread->destroy = thread_destroy;
+ thread->self = thread_self;
+ thread->get_tid = thread_get_tid;
+ thread->wait = thread_wait;
+ thread->prio_set = thread_prio_set;
+ thread->prio_get = thread_prio_get;
+ thread->yield = thread_yield;
+}
diff --git a/src/common/thread.h b/src/common/thread.h
index 261735306..c668afbb4 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) rAthena Project (www.rathena.org)
*
* Hercules is free software: you can redistribute it and/or modify
@@ -21,114 +21,136 @@
#ifndef COMMON_THREAD_H
#define COMMON_THREAD_H
-#include "common/cbasetypes.h"
+#include "common/hercules.h"
-typedef struct rAthread rAthread;
-typedef void* (*rAthreadProc)(void*);
-
-typedef enum RATHREAD_PRIO {
- RAT_PRIO_LOW = 0,
- RAT_PRIO_NORMAL,
- RAT_PRIO_HIGH
-} RATHREAD_PRIO;
-
-
-#ifdef HERCULES_CORE
-/**
- * Creates a new Thread
- *
- * @param entyPoint - entryProc,
- * @param param - general purpose parameter, would be given as parameter to the thread's entry point.
- *
- * @return not NULL if success
+/** @file
+ * Basic Threading abstraction (for pthread / win32 based systems).
*/
-rAthread *rathread_create(rAthreadProc entryPoint, void *param);
+/* Opaque Types */
+struct thread_handle; ///< Thread handle.
+typedef void *(*threadFunc)(void *); ///< Thread entry point function.
+
+/* Enums */
+
+/// Thread priority
+enum thread_priority {
+ THREADPRIO_LOW = 0,
+ THREADPRIO_NORMAL,
+ THREADPRIO_HIGH
+};
+
+/// The thread interface
+struct thread_interface {
+ /// Interface initialization.
+ void (*init) (void);
+
+ /// Interface finalization.
+ void (*final) (void);
+
+ /**
+ * Creates a new Thread.
+ *
+ * @param enty_point Thread's entry point.
+ * @param param General purpose parameter, would be given as
+ * parameter to the thread's entry point.
+ *
+ * @return The created thread object.
+ * @retval NULL in vase of failure.
+ */
+ struct thread_handle *(*create) (threadFunc entry_point, void *param);
+
+ /**
+ * Creates a new Thread (with more creation options).
+ *
+ * @param enty_point Thread's entry point.
+ * @param param General purpose parameter, would be given as
+ * parameter to the thread's entry point.
+ * @param stack_size Stack Size in bytes.
+ * @param prio Priority of the Thread in the OS scheduler.
+ *
+ * @return The created thread object.
+ * @retval NULL in case of failure.
+ */
+ struct thread_handle *(*create_opt) (threadFunc entry_point, void *param, size_t stack_size, enum thread_priority prio);
+
+ /**
+ * Destroys the given Thread immediately.
+ *
+ * @remark
+ * The Handle gets invalid after call! don't use it afterwards.
+ *
+ * @param handle The thread to destroy.
+ */
+ void (*destroy) (struct thread_handle *handle);
+
+ /**
+ * Returns the thread handle of the thread calling this function.
+ *
+ * @remark
+ * This won't work in the program's main thread.
+ *
+ * @warning
+ * The underlying implementation might not perform very well, cache
+ * the value received!
+ *
+ * @return the thread handle.
+ * @retval NULL in case of failure.
+ */
+ struct thread_handle *(*self) (void);
+
+ /**
+ * Returns own thread id (TID).
+ *
+ * @remark
+ * This is an unique identifier for the calling thread, and depends
+ * on platform/ compiler, and may not be the systems Thread ID!
+ *
+ * @return the thread ID.
+ * @retval -1 in case of failure.
+ */
+ int (*get_tid) (void);
+
+ /**
+ * Waits for the given thread to terminate.
+ *
+ * @param[in] handle The thread to wait (join) for.
+ * @param[out] out_exit_code Pointer to return the exit code of the
+ * given thread after termination (optional).
+ *
+ * @retval true if the given thread has been terminated.
+ */
+ bool (*wait) (struct thread_handle *handle, void **out_exit_code);
+
+ /**
+ * Sets the given priority in the OS scheduler.
+ *
+ * @param handle The thread to set the priority for.
+ * @param prio The priority to set (@see enum thread_priority).
+ */
+ void (*prio_set) (struct thread_handle *handle, enum thread_priority prio);
+
+ /**
+ * Gets the current priority of the given thread.
+ *
+ * @param handle The thread to get the priority for.
+ */
+ enum thread_priority (*prio_get) (struct thread_handle *handle);
+
+ /**
+ * Tells the OS scheduler to yield the execution of the calling thread.
+ *
+ * @remark
+ * This will not "pause" the thread, it just allows the OS to spend
+ * the remaining time of the slice to another thread.
+ */
+ void (*yield) (void);
+};
-/**
- * Creates a new Thread (with more creation options)
- *
- * @param entyPoint - entryProc,
- * @param param - general purpose parameter, would be given as parameter to the thread's entry point
- * @param szStack - stack Size in bytes
- * @param prio - Priority of the Thread @ OS Scheduler..
- *
- * @return not NULL if success
- */
-rAthread *rathread_createEx(rAthreadProc entryPoint, void *param, size_t szStack, RATHREAD_PRIO prio);
-
-
-/**
- * Destroys the given Thread immediately
- *
- * @note The Handle gets invalid after call! don't use it afterwards.
- *
- * @param handle - thread to destroy.
- */
-void rathread_destroy(rAthread *handle);
-
-
-/**
- * Returns the thread handle of the thread calling this function
- *
- * @note this wont work @ programs main thread
- * @note the underlying implementation might not perform very well, cache the value received!
- *
- * @return not NULL if success
- */
-rAthread *rathread_self(void);
-
-
-/**
- * Returns own thread id (TID)
- *
- * @note this is an unique identifier for the calling thread, and
- * depends on platform/ compiler, and may not be the systems Thread ID!
- *
- * @return -1 when fails, otherwise >= 0
- */
-int rathread_get_tid(void);
-
-
-/**
- * Waits for the given thread to terminate
- *
- * @param handle - thread to wait (join) for
- * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated
- *
- * @return true - if the given thread has been terminated.
- */
-bool rathread_wait(rAthread *handle, void **out_exitCode);
-
-
-/**
- * Sets the given PRIORITY @ OS Task Scheduler
- *
- * @param handle - thread to set prio for
- * @param rio - the priority (RAT_PRIO_LOW ... )
- */
-void rathread_prio_set(rAthread *handle, RATHREAD_PRIO prio);
-
-
-/**
- * Gets the current Prio of the given thread
- *
- * @param handle - the thread to get the prio for.
- */
-RATHREAD_PRIO rathread_prio_get(rAthread *handle);
-
-
-/**
- * Tells the OS scheduler to yield the execution of the calling thread
- *
- * @note: this will not "pause" the thread,
- * it just allows the OS to spend the remaining time
- * of the slice to another thread.
- */
-void rathread_yield(void);
-
-void rathread_init(void);
-void rathread_final(void);
+#ifdef HERCULES_CORE
+void thread_defaults(void);
#endif // HERCULES_CORE
+HPShared struct thread_interface *thread; ///< Pointer to the thread interface.
+
#endif /* COMMON_THREAD_H */