From 41974ae5265fbc23a06f276f9e008d5dad020e0b Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 30 Aug 2012 16:16:25 -0700 Subject: Rename files for C++ conversion. Does not compile. After updating, you can remove these files, as shown in 'git status': Untracked files: (use "git add ..." to include in what will be committed) src/map/magic-interpreter-lexer.c src/map/magic-interpreter-parser.c src/map/magic-interpreter-parser.h --- src/common/core.c | 97 --------- src/common/core.cpp | 97 +++++++++ src/common/core.h | 19 -- src/common/core.hpp | 19 ++ src/common/db.c | 546 ------------------------------------------------- src/common/db.cpp | 546 +++++++++++++++++++++++++++++++++++++++++++++++++ src/common/db.h | 87 -------- src/common/db.hpp | 87 ++++++++ src/common/grfio.c | 212 ------------------- src/common/grfio.cpp | 212 +++++++++++++++++++ src/common/grfio.h | 17 -- src/common/grfio.hpp | 17 ++ src/common/lock.c | 36 ---- src/common/lock.cpp | 36 ++++ src/common/lock.h | 8 - src/common/lock.hpp | 8 + src/common/md5calc.c | 339 ------------------------------ src/common/md5calc.cpp | 339 ++++++++++++++++++++++++++++++ src/common/md5calc.h | 64 ------ src/common/md5calc.hpp | 64 ++++++ src/common/mmo.h | 283 ------------------------- src/common/mmo.hpp | 283 +++++++++++++++++++++++++ src/common/mt_rand.c | 116 ----------- src/common/mt_rand.cpp | 116 +++++++++++ src/common/mt_rand.h | 24 --- src/common/mt_rand.hpp | 24 +++ src/common/nullpo.c | 66 ------ src/common/nullpo.cpp | 66 ++++++ src/common/nullpo.h | 61 ------ src/common/nullpo.hpp | 61 ++++++ src/common/sanity.h | 36 ---- src/common/sanity.hpp | 31 +++ src/common/socket.c | 405 ------------------------------------ src/common/socket.cpp | 405 ++++++++++++++++++++++++++++++++++++ src/common/socket.h | 135 ------------ src/common/socket.hpp | 135 ++++++++++++ src/common/timer.c | 257 ----------------------- src/common/timer.cpp | 257 +++++++++++++++++++++++ src/common/timer.h | 61 ------ src/common/timer.hpp | 61 ++++++ src/common/utils.h | 18 -- src/common/utils.hpp | 18 ++ src/common/version.h | 24 --- src/common/version.hpp | 24 +++ 44 files changed, 2906 insertions(+), 2911 deletions(-) delete mode 100644 src/common/core.c create mode 100644 src/common/core.cpp delete mode 100644 src/common/core.h create mode 100644 src/common/core.hpp delete mode 100644 src/common/db.c create mode 100644 src/common/db.cpp delete mode 100644 src/common/db.h create mode 100644 src/common/db.hpp delete mode 100644 src/common/grfio.c create mode 100644 src/common/grfio.cpp delete mode 100644 src/common/grfio.h create mode 100644 src/common/grfio.hpp delete mode 100644 src/common/lock.c create mode 100644 src/common/lock.cpp delete mode 100644 src/common/lock.h create mode 100644 src/common/lock.hpp delete mode 100644 src/common/md5calc.c create mode 100644 src/common/md5calc.cpp delete mode 100644 src/common/md5calc.h create mode 100644 src/common/md5calc.hpp delete mode 100644 src/common/mmo.h create mode 100644 src/common/mmo.hpp delete mode 100644 src/common/mt_rand.c create mode 100644 src/common/mt_rand.cpp delete mode 100644 src/common/mt_rand.h create mode 100644 src/common/mt_rand.hpp delete mode 100644 src/common/nullpo.c create mode 100644 src/common/nullpo.cpp delete mode 100644 src/common/nullpo.h create mode 100644 src/common/nullpo.hpp delete mode 100644 src/common/sanity.h create mode 100644 src/common/sanity.hpp delete mode 100644 src/common/socket.c create mode 100644 src/common/socket.cpp delete mode 100644 src/common/socket.h create mode 100644 src/common/socket.hpp delete mode 100644 src/common/timer.c create mode 100644 src/common/timer.cpp delete mode 100644 src/common/timer.h create mode 100644 src/common/timer.hpp delete mode 100644 src/common/utils.h create mode 100644 src/common/utils.hpp delete mode 100644 src/common/version.h create mode 100644 src/common/version.hpp (limited to 'src/common') diff --git a/src/common/core.c b/src/common/core.c deleted file mode 100644 index b08276c..0000000 --- a/src/common/core.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -#include -#include - -#include "core.h" -#include "socket.h" -#include "timer.h" -#include "version.h" -#include "mt_rand.h" -#include "nullpo.h" - -/// Defined by each server -extern int do_init (int, char **); -extern void term_func (void); - -// Added by Gabuzomeu -// -// This is an implementation of signal() using sigaction() for portability. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -typedef void (*sigfunc)(int); -sigfunc compat_signal (int signo, sigfunc func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigfillset (&sact.sa_mask); - sigdelset(&sact.sa_mask, SIGSEGV); - sigdelset(&sact.sa_mask, SIGBUS); - sigdelset(&sact.sa_mask, SIGTRAP); - sigdelset(&sact.sa_mask, SIGILL); - sigdelset(&sact.sa_mask, SIGFPE); - sact.sa_flags = 0; - - if (sigaction (signo, &sact, &oact) < 0) - return SIG_ERR; - - return oact.sa_handler; -} - -static void chld_proc (int UNUSED) -{ - wait(NULL); -} -static void sig_proc (int UNUSED) -{ - for (int i = 1; i < 31; ++i) - compat_signal(i, SIG_IGN); - term_func (); - _exit (0); -} - -bool runflag = true; - -/* - Note about fatal signals: - - Under certain circumstances, - the following signals MUST not be ignored: - SIGFPE, SIGSEGV, SIGILL - Unless you use SA_SIGINFO and *carefully* check the origin, - that means they must be SIG_DFL. - */ -int main (int argc, char **argv) -{ - /// Note that getpid() and getppid() may be very close - mt_seed (time (NULL) ^ (getpid () << 16) ^ (getppid () << 8)); - - do_socket (); - - do_init (argc, argv); - // set up exit handlers *after* the initialization has happened. - // This is because term_func is likely to depend on successful init. - - compat_signal (SIGPIPE, SIG_IGN); - compat_signal (SIGTERM, sig_proc); - compat_signal (SIGINT, sig_proc); - compat_signal (SIGCHLD, chld_proc); - - // Signal to create coredumps by system when necessary (crash) - compat_signal (SIGSEGV, SIG_DFL); - compat_signal (SIGBUS, SIG_DFL); - compat_signal (SIGTRAP, SIG_DFL); - compat_signal (SIGILL, SIG_DFL); - compat_signal (SIGFPE, SIG_DFL); - - atexit (term_func); - - while (runflag) - { - do_sendrecv (do_timer (gettick_nocache ())); - do_parsepacket (); - } -} diff --git a/src/common/core.cpp b/src/common/core.cpp new file mode 100644 index 0000000..38b2260 --- /dev/null +++ b/src/common/core.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include + +#include "core.hpp" +#include "socket.hpp" +#include "timer.hpp" +#include "version.hpp" +#include "mt_rand.hpp" +#include "nullpo.hpp" + +/// Defined by each server +extern int do_init (int, char **); +extern void term_func (void); + +// Added by Gabuzomeu +// +// This is an implementation of signal() using sigaction() for portability. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +typedef void (*sigfunc)(int); +sigfunc compat_signal (int signo, sigfunc func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigfillset (&sact.sa_mask); + sigdelset(&sact.sa_mask, SIGSEGV); + sigdelset(&sact.sa_mask, SIGBUS); + sigdelset(&sact.sa_mask, SIGTRAP); + sigdelset(&sact.sa_mask, SIGILL); + sigdelset(&sact.sa_mask, SIGFPE); + sact.sa_flags = 0; + + if (sigaction (signo, &sact, &oact) < 0) + return SIG_ERR; + + return oact.sa_handler; +} + +static void chld_proc (int UNUSED) +{ + wait(NULL); +} +static void sig_proc (int UNUSED) +{ + for (int i = 1; i < 31; ++i) + compat_signal(i, SIG_IGN); + term_func (); + _exit (0); +} + +bool runflag = true; + +/* + Note about fatal signals: + + Under certain circumstances, + the following signals MUST not be ignored: + SIGFPE, SIGSEGV, SIGILL + Unless you use SA_SIGINFO and *carefully* check the origin, + that means they must be SIG_DFL. + */ +int main (int argc, char **argv) +{ + /// Note that getpid() and getppid() may be very close + mt_seed (time (NULL) ^ (getpid () << 16) ^ (getppid () << 8)); + + do_socket (); + + do_init (argc, argv); + // set up exit handlers *after* the initialization has happened. + // This is because term_func is likely to depend on successful init. + + compat_signal (SIGPIPE, SIG_IGN); + compat_signal (SIGTERM, sig_proc); + compat_signal (SIGINT, sig_proc); + compat_signal (SIGCHLD, chld_proc); + + // Signal to create coredumps by system when necessary (crash) + compat_signal (SIGSEGV, SIG_DFL); + compat_signal (SIGBUS, SIG_DFL); + compat_signal (SIGTRAP, SIG_DFL); + compat_signal (SIGILL, SIG_DFL); + compat_signal (SIGFPE, SIG_DFL); + + atexit (term_func); + + while (runflag) + { + do_sendrecv (do_timer (gettick_nocache ())); + do_parsepacket (); + } +} diff --git a/src/common/core.h b/src/common/core.h deleted file mode 100644 index 44473e9..0000000 --- a/src/common/core.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CORE_H -#define CORE_H -#include -/// core.c contains a server-independent main() function -/// and then runs a do_sendrecv loop - -/// When this is cleared, the server exits gracefully -/// only used by map server's GM command: @mapexit -extern bool runflag; - -/// This is an external function defined by each server -/// This function must register stuff for the parse loop -extern int do_init (int, char **); - -/// Cleanup function called whenever a signal kills us -/// or when if we manage to exit() gracefully. -extern void term_func (void); - -#endif // CORE_H diff --git a/src/common/core.hpp b/src/common/core.hpp new file mode 100644 index 0000000..8a52c55 --- /dev/null +++ b/src/common/core.hpp @@ -0,0 +1,19 @@ +#ifndef CORE_HPP +#define CORE_HPP +#include +/// core.c contains a server-independent main() function +/// and then runs a do_sendrecv loop + +/// When this is cleared, the server exits gracefully +/// only used by map server's GM command: @mapexit +extern bool runflag; + +/// This is an external function defined by each server +/// This function must register stuff for the parse loop +extern int do_init (int, char **); + +/// Cleanup function called whenever a signal kills us +/// or when if we manage to exit() gracefully. +extern void term_func (void); + +#endif // CORE_HPP diff --git a/src/common/db.c b/src/common/db.c deleted file mode 100644 index f56a511..0000000 --- a/src/common/db.c +++ /dev/null @@ -1,546 +0,0 @@ -#include "db.h" - -#include -#include -#include - -#include "utils.h" - -#define ROOT_SIZE 4096 - -static int strdb_cmp (struct dbt *table, const char *a, const char* b) -{ - if (table->maxlen) - return strncmp (a, b, table->maxlen); - return strcmp (a, b); -} - -static hash_t strdb_hash (struct dbt *table, const char *a) -{ - size_t i = table->maxlen; - if (i == 0) - i = (size_t)-1; - hash_t h = 0; - const unsigned char *p = (const unsigned char*)a; - while (*p && i--) - { - h = (h * 33 + *p++) ^ (h >> 24); - } - return h; -} - -struct dbt *strdb_init (size_t maxlen) -{ - struct dbt *table; - CREATE (table, struct dbt, 1); - table->type = DB_STRING; - table->maxlen = maxlen; - return table; -} - -static int numdb_cmp (numdb_key_t a, numdb_key_t b) -{ - if (a == b) - return 0; - if (a < b) - return -1; - return 1; -} - -static hash_t numdb_hash (numdb_key_t a) -{ - return (hash_t) a; -} - -struct dbt *numdb_init (void) -{ - struct dbt *table; - CREATE (table, struct dbt, 1); - table->type = DB_NUMBER; - return table; -} - -static int table_cmp (struct dbt *table, db_key_t a, db_key_t b) -{ - switch(table->type) - { - case DB_NUMBER: return numdb_cmp (a.i, b.i); - case DB_STRING: return strdb_cmp (table, a.s, b.s); - } - abort(); -} - -static hash_t table_hash (struct dbt *table, db_key_t key) -{ - switch(table->type) - { - case DB_NUMBER: return numdb_hash (key.i); - case DB_STRING: return strdb_hash (table, key.s); - } - abort(); -} - -/// Search for a node with the given key -db_val_t db_search (struct dbt *table, db_key_t key) -{ - struct dbn *p = table->ht[table_hash (table, key) % HASH_SIZE]; - - while (p) - { - int c = table_cmp (table, key, p->key); - if (c == 0) - return p->data; - if (c < 0) - p = p->left; - else - p = p->right; - } - return NULL; -} - -// Tree maintainance methods -static void db_rotate_left (struct dbn *p, struct dbn **root) -{ - struct dbn *y = p->right; - p->right = y->left; - if (y->left) - y->left->parent = p; - y->parent = p->parent; - - if (p == *root) - *root = y; - else if (p == p->parent->left) - p->parent->left = y; - else - p->parent->right = y; - y->left = p; - p->parent = y; -} - -static void db_rotate_right (struct dbn *p, struct dbn **root) -{ - struct dbn *y = p->left; - p->left = y->right; - if (y->right) - y->right->parent = p; - y->parent = p->parent; - - if (p == *root) - *root = y; - else if (p == p->parent->right) - p->parent->right = y; - else - p->parent->left = y; - y->right = p; - p->parent = y; -} - -static void db_rebalance (struct dbn *p, struct dbn **root) -{ - p->color = RED; - while (p != *root && p->parent->color == RED) - { - if (p->parent == p->parent->parent->left) - { - struct dbn *y = p->parent->parent->right; - if (y && y->color == RED) - { - p->parent->color = BLACK; - y->color = BLACK; - p->parent->parent->color = RED; - p = p->parent->parent; - } - else - { - if (p == p->parent->right) - { - p = p->parent; - db_rotate_left (p, root); - } - p->parent->color = BLACK; - p->parent->parent->color = RED; - db_rotate_right (p->parent->parent, root); - } - } - else - { - struct dbn *y = p->parent->parent->left; - if (y && y->color == RED) - { - p->parent->color = BLACK; - y->color = BLACK; - p->parent->parent->color = RED; - p = p->parent->parent; - } - else - { - if (p == p->parent->left) - { - p = p->parent; - db_rotate_right (p, root); - } - p->parent->color = BLACK; - p->parent->parent->color = RED; - db_rotate_left (p->parent->parent, root); - } - } - } - (*root)->color = BLACK; -} - -// param z = node to remove -static void db_rebalance_erase (struct dbn *z, struct dbn **root) -{ - struct dbn *y = z; - struct dbn *x = NULL; - - if (!y->left) - x = y->right; - else if (!y->right) - x = y->left; - else - { - y = y->right; - while (y->left) - y = y->left; - x = y->right; - } - struct dbn *x_parent = NULL; - if (y != z) - { - z->left->parent = y; - y->left = z->left; - if (y != z->right) - { - x_parent = y->parent; - if (x) - x->parent = y->parent; - y->parent->left = x; - y->right = z->right; - z->right->parent = y; - } - else - x_parent = y; - if (*root == z) - *root = y; - else if (z->parent->left == z) - z->parent->left = y; - else - z->parent->right = y; - y->parent = z->parent; - { - dbn_color tmp = y->color; - y->color = z->color; - z->color = tmp; - } - y = z; - } - else - { - x_parent = y->parent; - if (x) - x->parent = y->parent; - if (*root == z) - *root = x; - else if (z->parent->left == z) - z->parent->left = x; - else - z->parent->right = x; - } - if (y->color != RED) - { - while (x != *root && (!x || x->color == BLACK)) - if (x == x_parent->left) - { - struct dbn *w = x_parent->right; - if (w->color == RED) - { - w->color = BLACK; - x_parent->color = RED; - db_rotate_left (x_parent, root); - w = x_parent->right; - } - if ((!w->left || w->left->color == BLACK) && - (!w->right || w->right->color == BLACK)) - { - w->color = RED; - x = x_parent; - x_parent = x->parent; - } - else - { - if (!w->right|| w->right->color == BLACK) - { - if (w->left) - w->left->color = BLACK; - w->color = RED; - db_rotate_right (w, root); - w = x_parent->right; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->right) - w->right->color = BLACK; - db_rotate_left (x_parent, root); - break; - } - } - else - { - // same as above, with right <-> left. - struct dbn *w = x_parent->left; - if (w->color == RED) - { - w->color = BLACK; - x_parent->color = RED; - db_rotate_right (x_parent, root); - w = x_parent->left; - } - if ((!w->right || w->right->color == BLACK) && - (!w->left || w->left->color == BLACK)) - { - w->color = RED; - x = x_parent; - x_parent = x_parent->parent; - } - else - { - if (!w->left || w->left->color == BLACK) - { - if (w->right) - w->right->color = BLACK; - w->color = RED; - db_rotate_left (w, root); - w = x_parent->left; - } - w->color = x_parent->color; - x_parent->color = BLACK; - if (w->left) - w->left->color = BLACK; - db_rotate_right (x_parent, root); - break; - } - } - if (x) - x->color = BLACK; - } -} - -struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data) -{ - hash_t hash = table_hash (table, key) % HASH_SIZE; - int c = 0; - struct dbn *prev = NULL; - struct dbn *p = table->ht[hash]; - while (p) - { - c = table_cmp (table, key, p->key); - if (c == 0) - { - // key found in table, replace - // Tell the user of the table to free the key and value - if (table->release) - table->release (p->key, p->data); - p->data = data; - p->key = key; - return p; - } - // prev is always p->parent? - prev = p; - if (c < 0) - p = p->left; - else - p = p->right; - } - CREATE (p, struct dbn, 1); - p->key = key; - p->data = data; - p->color = RED; - if (c == 0) - { // hash entry is empty - table->ht[hash] = p; - p->color = BLACK; - return p; - } - p->parent = prev; - if (c < 0) - prev->left = p; - else - prev->right = p; - if (prev->color == RED) - { - // must rebalance - db_rebalance (p, &table->ht[hash]); - } - return p; -} - -db_val_t db_erase (struct dbt *table, db_key_t key) -{ - hash_t hash = table_hash (table, key) % HASH_SIZE; - struct dbn *p = table->ht[hash]; - while (p) - { - int c = table_cmp (table, key, p->key); - if (c == 0) - break; - if (c < 0) - p = p->left; - else - p = p->right; - } - if (!p) - return NULL; - db_val_t data = p->data; - db_rebalance_erase (p, &table->ht[hash]); - free (p); - return data; -} -#ifdef SMART_WALK_TREE -static inline void db_walk_tree (bool dealloc, struct dbn* p, db_func_t func, va_list ap) -{ - if (!p) - return; - if (!dealloc && !func) - { - fprintf(stderr, "DEBUG: Must walk tree to either free or invoke a function.\n"); - abort(); - } - if (p->parent) - { - fprintf(stderr, "DEBUG: Root nodes must not have parents\n"); - abort(); - } - while (true) - { - // apply_func loop - if (func) - func (p->key, p->data, ap); - if (p->left) - { - // continue descending - p = p->left; - continue; //goto apply_func; - } - if (p->right) - { - // descending the other side - p = p->right; - continue; //goto apply_func; - } - while (true) - { - // backtrack loop - if (!p->parent) - { - if (dealloc) - free (p); - // if we have already done both children, there is no more to do - return; - } - if (p->parent->left == p && p->parent->right) - { - // finished the left tree, now walk the right tree - p = p->parent->right; - if (dealloc) - free (p->parent->left); - break; //goto apply_func; - } - // p->parent->right == p - // or p->parent->left == p but p->parent->right == NULL - // keep backtracking - p = p->parent; - if (dealloc) - free (p->right?:p->left); - } //backtrack loop - } // apply_func loop -} -#endif // SMART_WALK_TREE - -void db_foreach (struct dbt *table, db_func_t func, ...) -{ - va_list ap; - va_start (ap, func); - - for (int i = 0; i < HASH_SIZE; i++) - { -#ifdef SMART_WALK_TREE - db_walk_tree (false, table->ht[i], func, ap); -#else - struct dbn *p = table->ht[i]; - if (!p) - continue; - struct dbn *stack[64]; - int sp = 0; - while (1) - { - func (p->key, p->data, ap); - struct dbn *pn = p->left; - if (pn) - { - if (p->right) - stack[sp++] = p->right; - p = pn; - } - else // pn == NULL, time to do the right branch - { - if (p->right) - p = p->right; - else - { - if (sp == 0) - break; - p = stack[--sp]; - } - } // if pn else if !pn - } // while true -#endif // else ! SMART_WALK_TREE - } // for i - va_end (ap); -} - -// This function is suspiciously similar to the previous -void db_final (struct dbt *table, db_func_t func, ...) -{ - va_list ap; - va_start (ap, func); - - for (int i = 0; i < HASH_SIZE; i++) - { -#ifdef SMART_WALK_TREE - db_walk_tree (true, table->ht[i], func, ap); -#else - struct dbn *p = table->ht[i]; - if (!p) - continue; - struct dbn *stack[64]; - int sp = 0; - while (1) - { - if (func) - func (p->key, p->data, ap); - struct dbn *pn = p->left; - if (pn) - { - if (p->right) - stack[sp++] = p->right; - } - else // pn == NULL, check the right - { - if (p->right) - pn = p->right; - else - { - if (sp == 0) - break; - pn = stack[--sp]; - } - } // if pn else if !pn - free (p); - p = pn; - } // while true -#endif // else ! SMART_WALK_TREE - } // for i - free (table); - va_end (ap); -} diff --git a/src/common/db.cpp b/src/common/db.cpp new file mode 100644 index 0000000..21a3597 --- /dev/null +++ b/src/common/db.cpp @@ -0,0 +1,546 @@ +#include "db.hpp" + +#include +#include +#include + +#include "utils.hpp" + +#define ROOT_SIZE 4096 + +static int strdb_cmp (struct dbt *table, const char *a, const char* b) +{ + if (table->maxlen) + return strncmp (a, b, table->maxlen); + return strcmp (a, b); +} + +static hash_t strdb_hash (struct dbt *table, const char *a) +{ + size_t i = table->maxlen; + if (i == 0) + i = (size_t)-1; + hash_t h = 0; + const unsigned char *p = (const unsigned char*)a; + while (*p && i--) + { + h = (h * 33 + *p++) ^ (h >> 24); + } + return h; +} + +struct dbt *strdb_init (size_t maxlen) +{ + struct dbt *table; + CREATE (table, struct dbt, 1); + table->type = DB_STRING; + table->maxlen = maxlen; + return table; +} + +static int numdb_cmp (numdb_key_t a, numdb_key_t b) +{ + if (a == b) + return 0; + if (a < b) + return -1; + return 1; +} + +static hash_t numdb_hash (numdb_key_t a) +{ + return (hash_t) a; +} + +struct dbt *numdb_init (void) +{ + struct dbt *table; + CREATE (table, struct dbt, 1); + table->type = DB_NUMBER; + return table; +} + +static int table_cmp (struct dbt *table, db_key_t a, db_key_t b) +{ + switch(table->type) + { + case DB_NUMBER: return numdb_cmp (a.i, b.i); + case DB_STRING: return strdb_cmp (table, a.s, b.s); + } + abort(); +} + +static hash_t table_hash (struct dbt *table, db_key_t key) +{ + switch(table->type) + { + case DB_NUMBER: return numdb_hash (key.i); + case DB_STRING: return strdb_hash (table, key.s); + } + abort(); +} + +/// Search for a node with the given key +db_val_t db_search (struct dbt *table, db_key_t key) +{ + struct dbn *p = table->ht[table_hash (table, key) % HASH_SIZE]; + + while (p) + { + int c = table_cmp (table, key, p->key); + if (c == 0) + return p->data; + if (c < 0) + p = p->left; + else + p = p->right; + } + return NULL; +} + +// Tree maintainance methods +static void db_rotate_left (struct dbn *p, struct dbn **root) +{ + struct dbn *y = p->right; + p->right = y->left; + if (y->left) + y->left->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->left) + p->parent->left = y; + else + p->parent->right = y; + y->left = p; + p->parent = y; +} + +static void db_rotate_right (struct dbn *p, struct dbn **root) +{ + struct dbn *y = p->left; + p->left = y->right; + if (y->right) + y->right->parent = p; + y->parent = p->parent; + + if (p == *root) + *root = y; + else if (p == p->parent->right) + p->parent->right = y; + else + p->parent->left = y; + y->right = p; + p->parent = y; +} + +static void db_rebalance (struct dbn *p, struct dbn **root) +{ + p->color = RED; + while (p != *root && p->parent->color == RED) + { + if (p->parent == p->parent->parent->left) + { + struct dbn *y = p->parent->parent->right; + if (y && y->color == RED) + { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } + else + { + if (p == p->parent->right) + { + p = p->parent; + db_rotate_left (p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_right (p->parent->parent, root); + } + } + else + { + struct dbn *y = p->parent->parent->left; + if (y && y->color == RED) + { + p->parent->color = BLACK; + y->color = BLACK; + p->parent->parent->color = RED; + p = p->parent->parent; + } + else + { + if (p == p->parent->left) + { + p = p->parent; + db_rotate_right (p, root); + } + p->parent->color = BLACK; + p->parent->parent->color = RED; + db_rotate_left (p->parent->parent, root); + } + } + } + (*root)->color = BLACK; +} + +// param z = node to remove +static void db_rebalance_erase (struct dbn *z, struct dbn **root) +{ + struct dbn *y = z; + struct dbn *x = NULL; + + if (!y->left) + x = y->right; + else if (!y->right) + x = y->left; + else + { + y = y->right; + while (y->left) + y = y->left; + x = y->right; + } + struct dbn *x_parent = NULL; + if (y != z) + { + z->left->parent = y; + y->left = z->left; + if (y != z->right) + { + x_parent = y->parent; + if (x) + x->parent = y->parent; + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } + else + x_parent = y; + if (*root == z) + *root = y; + else if (z->parent->left == z) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + { + dbn_color tmp = y->color; + y->color = z->color; + z->color = tmp; + } + y = z; + } + else + { + x_parent = y->parent; + if (x) + x->parent = y->parent; + if (*root == z) + *root = x; + else if (z->parent->left == z) + z->parent->left = x; + else + z->parent->right = x; + } + if (y->color != RED) + { + while (x != *root && (!x || x->color == BLACK)) + if (x == x_parent->left) + { + struct dbn *w = x_parent->right; + if (w->color == RED) + { + w->color = BLACK; + x_parent->color = RED; + db_rotate_left (x_parent, root); + w = x_parent->right; + } + if ((!w->left || w->left->color == BLACK) && + (!w->right || w->right->color == BLACK)) + { + w->color = RED; + x = x_parent; + x_parent = x->parent; + } + else + { + if (!w->right|| w->right->color == BLACK) + { + if (w->left) + w->left->color = BLACK; + w->color = RED; + db_rotate_right (w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->right) + w->right->color = BLACK; + db_rotate_left (x_parent, root); + break; + } + } + else + { + // same as above, with right <-> left. + struct dbn *w = x_parent->left; + if (w->color == RED) + { + w->color = BLACK; + x_parent->color = RED; + db_rotate_right (x_parent, root); + w = x_parent->left; + } + if ((!w->right || w->right->color == BLACK) && + (!w->left || w->left->color == BLACK)) + { + w->color = RED; + x = x_parent; + x_parent = x_parent->parent; + } + else + { + if (!w->left || w->left->color == BLACK) + { + if (w->right) + w->right->color = BLACK; + w->color = RED; + db_rotate_left (w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = BLACK; + if (w->left) + w->left->color = BLACK; + db_rotate_right (x_parent, root); + break; + } + } + if (x) + x->color = BLACK; + } +} + +struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data) +{ + hash_t hash = table_hash (table, key) % HASH_SIZE; + int c = 0; + struct dbn *prev = NULL; + struct dbn *p = table->ht[hash]; + while (p) + { + c = table_cmp (table, key, p->key); + if (c == 0) + { + // key found in table, replace + // Tell the user of the table to free the key and value + if (table->release) + table->release (p->key, p->data); + p->data = data; + p->key = key; + return p; + } + // prev is always p->parent? + prev = p; + if (c < 0) + p = p->left; + else + p = p->right; + } + CREATE (p, struct dbn, 1); + p->key = key; + p->data = data; + p->color = RED; + if (c == 0) + { // hash entry is empty + table->ht[hash] = p; + p->color = BLACK; + return p; + } + p->parent = prev; + if (c < 0) + prev->left = p; + else + prev->right = p; + if (prev->color == RED) + { + // must rebalance + db_rebalance (p, &table->ht[hash]); + } + return p; +} + +db_val_t db_erase (struct dbt *table, db_key_t key) +{ + hash_t hash = table_hash (table, key) % HASH_SIZE; + struct dbn *p = table->ht[hash]; + while (p) + { + int c = table_cmp (table, key, p->key); + if (c == 0) + break; + if (c < 0) + p = p->left; + else + p = p->right; + } + if (!p) + return NULL; + db_val_t data = p->data; + db_rebalance_erase (p, &table->ht[hash]); + free (p); + return data; +} +#ifdef SMART_WALK_TREE +static inline void db_walk_tree (bool dealloc, struct dbn* p, db_func_t func, va_list ap) +{ + if (!p) + return; + if (!dealloc && !func) + { + fprintf(stderr, "DEBUG: Must walk tree to either free or invoke a function.\n"); + abort(); + } + if (p->parent) + { + fprintf(stderr, "DEBUG: Root nodes must not have parents\n"); + abort(); + } + while (true) + { + // apply_func loop + if (func) + func (p->key, p->data, ap); + if (p->left) + { + // continue descending + p = p->left; + continue; //goto apply_func; + } + if (p->right) + { + // descending the other side + p = p->right; + continue; //goto apply_func; + } + while (true) + { + // backtrack loop + if (!p->parent) + { + if (dealloc) + free (p); + // if we have already done both children, there is no more to do + return; + } + if (p->parent->left == p && p->parent->right) + { + // finished the left tree, now walk the right tree + p = p->parent->right; + if (dealloc) + free (p->parent->left); + break; //goto apply_func; + } + // p->parent->right == p + // or p->parent->left == p but p->parent->right == NULL + // keep backtracking + p = p->parent; + if (dealloc) + free (p->right?:p->left); + } //backtrack loop + } // apply_func loop +} +#endif // SMART_WALK_TREE + +void db_foreach (struct dbt *table, db_func_t func, ...) +{ + va_list ap; + va_start (ap, func); + + for (int i = 0; i < HASH_SIZE; i++) + { +#ifdef SMART_WALK_TREE + db_walk_tree (false, table->ht[i], func, ap); +#else + struct dbn *p = table->ht[i]; + if (!p) + continue; + struct dbn *stack[64]; + int sp = 0; + while (1) + { + func (p->key, p->data, ap); + struct dbn *pn = p->left; + if (pn) + { + if (p->right) + stack[sp++] = p->right; + p = pn; + } + else // pn == NULL, time to do the right branch + { + if (p->right) + p = p->right; + else + { + if (sp == 0) + break; + p = stack[--sp]; + } + } // if pn else if !pn + } // while true +#endif // else ! SMART_WALK_TREE + } // for i + va_end (ap); +} + +// This function is suspiciously similar to the previous +void db_final (struct dbt *table, db_func_t func, ...) +{ + va_list ap; + va_start (ap, func); + + for (int i = 0; i < HASH_SIZE; i++) + { +#ifdef SMART_WALK_TREE + db_walk_tree (true, table->ht[i], func, ap); +#else + struct dbn *p = table->ht[i]; + if (!p) + continue; + struct dbn *stack[64]; + int sp = 0; + while (1) + { + if (func) + func (p->key, p->data, ap); + struct dbn *pn = p->left; + if (pn) + { + if (p->right) + stack[sp++] = p->right; + } + else // pn == NULL, check the right + { + if (p->right) + pn = p->right; + else + { + if (sp == 0) + break; + pn = stack[--sp]; + } + } // if pn else if !pn + free (p); + p = pn; + } // while true +#endif // else ! SMART_WALK_TREE + } // for i + free (table); + va_end (ap); +} diff --git a/src/common/db.h b/src/common/db.h deleted file mode 100644 index 7152854..0000000 --- a/src/common/db.h +++ /dev/null @@ -1,87 +0,0 @@ -// WARNING: there is a system header by this name -#ifndef DB_H -#define DB_H -# include "sanity.h" - -# include - -/// Number of tree roots -// Somewhat arbitrary - larger wastes more space but is faster for large trees -// num % HASH_SIZE minimize collisions even for similar num -# define HASH_SIZE (256+27) - -typedef enum dbn_color -{ - RED, - BLACK -} dbn_color; - -typedef intptr_t numdb_key_t; -typedef union db_key_t -{ - char *ms __attribute__((deprecated)); - const char* s; - numdb_key_t i; -} db_key_t; -typedef void* db_val_t; -typedef uint32_t hash_t; -typedef void (*db_func_t)(db_key_t, db_val_t, va_list); - -/// DataBase Node -struct dbn -{ - struct dbn *parent, *left, *right; - dbn_color color; - db_key_t key; - db_val_t data; -}; - -typedef enum dbt_type -{ - DB_NUMBER, - DB_STRING, -} dbt_type; - -/// DataBase Table -struct dbt -{ - dbt_type type; - /// Note, before replacement, key/values to be replaced - // TODO refactor to decrease/eliminate the uses of this? - void (*release) (db_key_t, db_val_t) __attribute__((deprecated)); - /// Maximum length of a string key - TODO refactor to ensure all strings are NUL-terminated - size_t maxlen __attribute__((deprecated)); - /// The root trees - struct dbn *ht[HASH_SIZE]; -}; - -# define strdb_search(t,k) db_search((t),(db_key_t)(k)) -# define strdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) -# define strdb_erase(t,k) db_erase ((t),(db_key_t)(k)) -# define strdb_foreach db_foreach -# define strdb_final db_final -# define numdb_search(t,k) db_search((t),(db_key_t)(k)) -# define numdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) -# define numdb_erase(t,k) db_erase ((t),(db_key_t)(k)) -# define numdb_foreach db_foreach -# define numdb_final db_final - -/// Create a map from char* to void*, with strings possibly not null-terminated -struct dbt *strdb_init (size_t maxlen); -/// Create a map from int to void* -struct dbt *numdb_init (void); -/// Return the value corresponding to the key, or NULL if not found -db_val_t db_search (struct dbt *table, db_key_t key); -/// Add or replace table[key] = data -// if it was already there, call release -struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data); -/// Remove a key from the table, returning the data -db_val_t db_erase (struct dbt *table, db_key_t key); - -/// Execute a function for every element, in unspecified order -void db_foreach (struct dbt *, db_func_t, ...); -// opposite of init? Calls release for every element and frees memory -// This probably isn't really needed: we don't have to free memory while exiting -void db_final (struct dbt *, db_func_t, ...) __attribute__((deprecated)); - -#endif diff --git a/src/common/db.hpp b/src/common/db.hpp new file mode 100644 index 0000000..145ba13 --- /dev/null +++ b/src/common/db.hpp @@ -0,0 +1,87 @@ +// WARNING: there is a system header by this name +#ifndef DB_HPP +#define DB_HPP +# include "sanity.hpp" + +# include + +/// Number of tree roots +// Somewhat arbitrary - larger wastes more space but is faster for large trees +// num % HASH_SIZE minimize collisions even for similar num +# define HASH_SIZE (256+27) + +typedef enum dbn_color +{ + RED, + BLACK +} dbn_color; + +typedef intptr_t numdb_key_t; +typedef union db_key_t +{ + char *ms __attribute__((deprecated)); + const char* s; + numdb_key_t i; +} db_key_t; +typedef void* db_val_t; +typedef uint32_t hash_t; +typedef void (*db_func_t)(db_key_t, db_val_t, va_list); + +/// DataBase Node +struct dbn +{ + struct dbn *parent, *left, *right; + dbn_color color; + db_key_t key; + db_val_t data; +}; + +typedef enum dbt_type +{ + DB_NUMBER, + DB_STRING, +} dbt_type; + +/// DataBase Table +struct dbt +{ + dbt_type type; + /// Note, before replacement, key/values to be replaced + // TODO refactor to decrease/eliminate the uses of this? + void (*release) (db_key_t, db_val_t) __attribute__((deprecated)); + /// Maximum length of a string key - TODO refactor to ensure all strings are NUL-terminated + size_t maxlen __attribute__((deprecated)); + /// The root trees + struct dbn *ht[HASH_SIZE]; +}; + +# define strdb_search(t,k) db_search((t),(db_key_t)(k)) +# define strdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) +# define strdb_erase(t,k) db_erase ((t),(db_key_t)(k)) +# define strdb_foreach db_foreach +# define strdb_final db_final +# define numdb_search(t,k) db_search((t),(db_key_t)(k)) +# define numdb_insert(t,k,d) db_insert((t),(db_key_t)(k),(db_val_t)(d)) +# define numdb_erase(t,k) db_erase ((t),(db_key_t)(k)) +# define numdb_foreach db_foreach +# define numdb_final db_final + +/// Create a map from char* to void*, with strings possibly not null-terminated +struct dbt *strdb_init (size_t maxlen); +/// Create a map from int to void* +struct dbt *numdb_init (void); +/// Return the value corresponding to the key, or NULL if not found +db_val_t db_search (struct dbt *table, db_key_t key); +/// Add or replace table[key] = data +// if it was already there, call release +struct dbn *db_insert (struct dbt *table, db_key_t key, db_val_t data); +/// Remove a key from the table, returning the data +db_val_t db_erase (struct dbt *table, db_key_t key); + +/// Execute a function for every element, in unspecified order +void db_foreach (struct dbt *, db_func_t, ...); +// opposite of init? Calls release for every element and frees memory +// This probably isn't really needed: we don't have to free memory while exiting +void db_final (struct dbt *, db_func_t, ...) __attribute__((deprecated)); + +#endif diff --git a/src/common/grfio.c b/src/common/grfio.c deleted file mode 100644 index d640263..0000000 --- a/src/common/grfio.c +++ /dev/null @@ -1,212 +0,0 @@ -// Reads .gat files by name-mapping .wlk files -#include -#include -#include -#include - -#include "utils.h" -#include "grfio.h" -#include "mmo.h" -#include "socket.h" - -//---------------------------- -// file entry table struct -//---------------------------- -typedef struct -{ - size_t declen; - int16_t next; // next index into the filelist[] array, or -1 - char fn[128 - 4 - 2]; // file name -} FILELIST; - -#define FILELIST_LIMIT 32768 // limit to number of filelists - if you increase this, change all shorts to int -#define FILELIST_ADDS 1024 // amount to increment when reallocing - -static FILELIST *filelist = NULL; -/// Number of entries used -static uint16_t filelist_entrys = 0; -/// Number of FILELIST entries actually allocated -static uint16_t filelist_maxentry = 0; - -/// First index of the given hash, into the filelist[] array -static int16_t filelist_hash[256] = {[0 ... 255] = -1}; - -/// Hash a filename -static uint8_t filehash (const char *fname) -{ - // Larger than the return type - upper bits are used in the process - uint32_t hash = 0; - while (*fname) - { - hash = (hash << 1) + (hash >> 7) * 9 + (unsigned char)*fname; - fname++; - } - return hash; -} - -/// Find the filelist entry for the given filename, or NULL if it is not -FILELIST *filelist_find (const char *fname) -{ - int16_t index = filelist_hash[filehash (fname)]; - while (index >= 0) - { - if (strcmp (filelist[index].fn, fname) == 0) - return &filelist[index]; - index = filelist[index].next; - } - return NULL; -} - -/// Copy a temporary entry into the hash map -static FILELIST *filelist_add (FILELIST * entry) -{ - if (filelist_entrys >= FILELIST_LIMIT) - { - fprintf (stderr, "filelist limit : filelist_add\n"); - exit (1); - } - - if (filelist_entrys >= filelist_maxentry) - { - RECREATE(filelist, FILELIST, filelist_maxentry + FILELIST_ADDS); - memset (filelist + filelist_maxentry, '\0', - FILELIST_ADDS * sizeof (FILELIST)); - filelist_maxentry += FILELIST_ADDS; - } - - uint16_t new_index = filelist_entrys++; - uint8_t hash = filehash (entry->fn); - entry->next = filelist_hash[hash]; - filelist_hash[hash] = new_index; - - filelist[new_index] = *entry; - - return &filelist[new_index]; -} - -static FILELIST *filelist_modify (FILELIST * entry) -{ - FILELIST *fentry = filelist_find (entry->fn); - if (fentry) - { - entry->next = fentry->next; - *fentry = *entry; - return fentry; - } - return filelist_add (entry); -} - -/// Change fname data/*.gat to lfname data/*.wlk -// TODO even if the file exists, don't keep reopening it every time one loads -void grfio_resnametable (const char *fname, char *lfname) -{ - char restable[] = "data/resnametable.txt"; - - FILE *fp = fopen_ (restable, "rb"); - if (fp == NULL) - { - fprintf(stderr, "No resnametable, can't look for %s\n", fname); - strcpy(lfname, fname); - char* ext = lfname + strlen(lfname) - 4; - if (!strcmp(ext, ".gat")) - strcpy(ext, ".wlk"); - return; - } - - char line[512]; - while (fgets (line, sizeof (line), fp)) - { - char w1[256], w2[256]; - if ( - // line is of the form foo.gat#foo.wlk# - (sscanf (line, "%[^#]#%[^#]#", w1, w2) == 2) - // strip data/ from foo.gat before comparing - && (!strcmp (w1, fname + 5))) - { - strcpy (lfname, "data/"); - strcpy (lfname + 5, w2); - fclose_ (fp); - return; - } - } - fprintf(stderr, "Unable to find resource: %s\n", fname); - fclose_ (fp); - - strcpy(lfname, fname); - char* ext = lfname + strlen(lfname) - 4; - if (!strcmp(ext, ".gat")) - strcpy(ext, ".wlk"); - return; -} - -/// Size of resource -size_t grfio_size (const char *fname) -{ - FILELIST *entry = filelist_find (fname); - if (entry) - return entry->declen; - - char lfname[256]; - FILELIST lentry; - struct stat st; - - grfio_resnametable (fname, lfname); - - for (char *p = lfname; *p; p++) - if (*p == '\\') - *p = '/'; - - if (stat (lfname, &st) == 0) - { - strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); - lentry.declen = st.st_size; - entry = filelist_modify (&lentry); - } - else - { - printf ("%s not found\n", fname); - return 0; - } - return entry->declen; -} - -void *grfio_reads (const char *fname, size_t *size) -{ - char lfname[256]; - grfio_resnametable (fname, lfname); - - for (char *p = &lfname[0]; *p != 0; p++) - if (*p == '\\') - *p = '/'; // * At the time of Unix - - FILE *in = fopen_ (lfname, "rb"); - if (!in) - { - fprintf (stderr, "%s not found\n", fname); - return NULL; - } - FILELIST lentry; - FILELIST *entry = filelist_find (fname); - if (entry) - { - lentry.declen = entry->declen; - } - else - { - fseek (in, 0, SEEK_END); - lentry.declen = ftell (in); - fseek (in, 0, SEEK_SET); - strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); - entry = filelist_modify (&lentry); - } - uint8_t *buf2; - CREATE (buf2, uint8_t, lentry.declen + 1024); - if (fread (buf2, 1, lentry.declen, in) != lentry.declen) - exit(1); - fclose_ (in); - in = NULL; - - if (size) - *size = entry->declen; - return buf2; -} diff --git a/src/common/grfio.cpp b/src/common/grfio.cpp new file mode 100644 index 0000000..1b89b18 --- /dev/null +++ b/src/common/grfio.cpp @@ -0,0 +1,212 @@ +// Reads .gat files by name-mapping .wlk files +#include +#include +#include +#include + +#include "utils.hpp" +#include "grfio.hpp" +#include "mmo.hpp" +#include "socket.hpp" + +//---------------------------- +// file entry table struct +//---------------------------- +typedef struct +{ + size_t declen; + int16_t next; // next index into the filelist[] array, or -1 + char fn[128 - 4 - 2]; // file name +} FILELIST; + +#define FILELIST_LIMIT 32768 // limit to number of filelists - if you increase this, change all shorts to int +#define FILELIST_ADDS 1024 // amount to increment when reallocing + +static FILELIST *filelist = NULL; +/// Number of entries used +static uint16_t filelist_entrys = 0; +/// Number of FILELIST entries actually allocated +static uint16_t filelist_maxentry = 0; + +/// First index of the given hash, into the filelist[] array +static int16_t filelist_hash[256] = {[0 ... 255] = -1}; + +/// Hash a filename +static uint8_t filehash (const char *fname) +{ + // Larger than the return type - upper bits are used in the process + uint32_t hash = 0; + while (*fname) + { + hash = (hash << 1) + (hash >> 7) * 9 + (unsigned char)*fname; + fname++; + } + return hash; +} + +/// Find the filelist entry for the given filename, or NULL if it is not +FILELIST *filelist_find (const char *fname) +{ + int16_t index = filelist_hash[filehash (fname)]; + while (index >= 0) + { + if (strcmp (filelist[index].fn, fname) == 0) + return &filelist[index]; + index = filelist[index].next; + } + return NULL; +} + +/// Copy a temporary entry into the hash map +static FILELIST *filelist_add (FILELIST * entry) +{ + if (filelist_entrys >= FILELIST_LIMIT) + { + fprintf (stderr, "filelist limit : filelist_add\n"); + exit (1); + } + + if (filelist_entrys >= filelist_maxentry) + { + RECREATE(filelist, FILELIST, filelist_maxentry + FILELIST_ADDS); + memset (filelist + filelist_maxentry, '\0', + FILELIST_ADDS * sizeof (FILELIST)); + filelist_maxentry += FILELIST_ADDS; + } + + uint16_t new_index = filelist_entrys++; + uint8_t hash = filehash (entry->fn); + entry->next = filelist_hash[hash]; + filelist_hash[hash] = new_index; + + filelist[new_index] = *entry; + + return &filelist[new_index]; +} + +static FILELIST *filelist_modify (FILELIST * entry) +{ + FILELIST *fentry = filelist_find (entry->fn); + if (fentry) + { + entry->next = fentry->next; + *fentry = *entry; + return fentry; + } + return filelist_add (entry); +} + +/// Change fname data/*.gat to lfname data/*.wlk +// TODO even if the file exists, don't keep reopening it every time one loads +void grfio_resnametable (const char *fname, char *lfname) +{ + char restable[] = "data/resnametable.txt"; + + FILE *fp = fopen_ (restable, "rb"); + if (fp == NULL) + { + fprintf(stderr, "No resnametable, can't look for %s\n", fname); + strcpy(lfname, fname); + char* ext = lfname + strlen(lfname) - 4; + if (!strcmp(ext, ".gat")) + strcpy(ext, ".wlk"); + return; + } + + char line[512]; + while (fgets (line, sizeof (line), fp)) + { + char w1[256], w2[256]; + if ( + // line is of the form foo.gat#foo.wlk# + (sscanf (line, "%[^#]#%[^#]#", w1, w2) == 2) + // strip data/ from foo.gat before comparing + && (!strcmp (w1, fname + 5))) + { + strcpy (lfname, "data/"); + strcpy (lfname + 5, w2); + fclose_ (fp); + return; + } + } + fprintf(stderr, "Unable to find resource: %s\n", fname); + fclose_ (fp); + + strcpy(lfname, fname); + char* ext = lfname + strlen(lfname) - 4; + if (!strcmp(ext, ".gat")) + strcpy(ext, ".wlk"); + return; +} + +/// Size of resource +size_t grfio_size (const char *fname) +{ + FILELIST *entry = filelist_find (fname); + if (entry) + return entry->declen; + + char lfname[256]; + FILELIST lentry; + struct stat st; + + grfio_resnametable (fname, lfname); + + for (char *p = lfname; *p; p++) + if (*p == '\\') + *p = '/'; + + if (stat (lfname, &st) == 0) + { + strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); + lentry.declen = st.st_size; + entry = filelist_modify (&lentry); + } + else + { + printf ("%s not found\n", fname); + return 0; + } + return entry->declen; +} + +void *grfio_reads (const char *fname, size_t *size) +{ + char lfname[256]; + grfio_resnametable (fname, lfname); + + for (char *p = &lfname[0]; *p != 0; p++) + if (*p == '\\') + *p = '/'; // * At the time of Unix + + FILE *in = fopen_ (lfname, "rb"); + if (!in) + { + fprintf (stderr, "%s not found\n", fname); + return NULL; + } + FILELIST lentry; + FILELIST *entry = filelist_find (fname); + if (entry) + { + lentry.declen = entry->declen; + } + else + { + fseek (in, 0, SEEK_END); + lentry.declen = ftell (in); + fseek (in, 0, SEEK_SET); + strncpy (lentry.fn, fname, sizeof (lentry.fn) - 1); + entry = filelist_modify (&lentry); + } + uint8_t *buf2; + CREATE (buf2, uint8_t, lentry.declen + 1024); + if (fread (buf2, 1, lentry.declen, in) != lentry.declen) + exit(1); + fclose_ (in); + in = NULL; + + if (size) + *size = entry->declen; + return buf2; +} diff --git a/src/common/grfio.h b/src/common/grfio.h deleted file mode 100644 index 4919a7b..0000000 --- a/src/common/grfio.h +++ /dev/null @@ -1,17 +0,0 @@ -/// Accessor to the .gat map virtual files -// Note .gat files are mapped to .wlk files by data/resnametable.txt -// Note that there currently is a 1-1 correlation between them, -// but it is possible for a single .wlk to have multiple .gats reference it -#ifndef GRFIO_H -#define GRFIO_H - -/// Load file into memory -# define grfio_read(resourcename) grfio_reads (resourcename, NULL) -/// Load file into memory and possibly record length -// For some reason, this allocates an extra 1024 bytes at the end -void *grfio_reads (const char *resourcename, size_t *size); -/// Get size of file -// This is only called once, and that is to check the existence of a file. -size_t grfio_size (const char *resourcename) __attribute__((deprecated)); - -#endif // GRFIO_H diff --git a/src/common/grfio.hpp b/src/common/grfio.hpp new file mode 100644 index 0000000..3485904 --- /dev/null +++ b/src/common/grfio.hpp @@ -0,0 +1,17 @@ +/// Accessor to the .gat map virtual files +// Note .gat files are mapped to .wlk files by data/resnametable.txt +// Note that there currently is a 1-1 correlation between them, +// but it is possible for a single .wlk to have multiple .gats reference it +#ifndef GRFIO_HPP +#define GRFIO_HPP + +/// Load file into memory +# define grfio_read(resourcename) grfio_reads (resourcename, NULL) +/// Load file into memory and possibly record length +// For some reason, this allocates an extra 1024 bytes at the end +void *grfio_reads (const char *resourcename, size_t *size); +/// Get size of file +// This is only called once, and that is to check the existence of a file. +size_t grfio_size (const char *resourcename) __attribute__((deprecated)); + +#endif // GRFIO_HPP diff --git a/src/common/lock.c b/src/common/lock.c deleted file mode 100644 index dd42ef2..0000000 --- a/src/common/lock.c +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "lock.h" -#include "socket.h" - -/// Protected file writing -/// (Until the file is closed, it keeps the old file) - -// Start writing a tmpfile -FILE *lock_fopen (const char *filename, int *info) -{ - char newfile[512]; - FILE *fp; - int no = getpid (); - - // Get a filename that doesn't already exist - do - { - sprintf (newfile, "%s_%d.tmp", filename, no++); - } - while ((fp = fopen_ (newfile, "r")) && (fclose_ (fp), 1)); - *info = --no; - return fopen_ (newfile, "w"); -} - -// Delete the old file and rename the new file -void lock_fclose (FILE * fp, const char *filename, int *info) -{ - char newfile[512]; - if (fp) - { - fclose_ (fp); - sprintf (newfile, "%s_%d.tmp", filename, *info); - rename (newfile, filename); - } -} diff --git a/src/common/lock.cpp b/src/common/lock.cpp new file mode 100644 index 0000000..2ba9a0a --- /dev/null +++ b/src/common/lock.cpp @@ -0,0 +1,36 @@ +#include +#include +#include "lock.hpp" +#include "socket.hpp" + +/// Protected file writing +/// (Until the file is closed, it keeps the old file) + +// Start writing a tmpfile +FILE *lock_fopen (const char *filename, int *info) +{ + char newfile[512]; + FILE *fp; + int no = getpid (); + + // Get a filename that doesn't already exist + do + { + sprintf (newfile, "%s_%d.tmp", filename, no++); + } + while ((fp = fopen_ (newfile, "r")) && (fclose_ (fp), 1)); + *info = --no; + return fopen_ (newfile, "w"); +} + +// Delete the old file and rename the new file +void lock_fclose (FILE * fp, const char *filename, int *info) +{ + char newfile[512]; + if (fp) + { + fclose_ (fp); + sprintf (newfile, "%s_%d.tmp", filename, *info); + rename (newfile, filename); + } +} diff --git a/src/common/lock.h b/src/common/lock.h deleted file mode 100644 index 2f087fd..0000000 --- a/src/common/lock.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LOCK_H -#define LOCK_H -/// Locked FILE I/O -// Changes are made in a separate file until lock_fclose -FILE *lock_fopen (const char *filename, int *info); -void lock_fclose (FILE * fp, const char *filename, int *info); - -#endif // LOCK_H diff --git a/src/common/lock.hpp b/src/common/lock.hpp new file mode 100644 index 0000000..19c1302 --- /dev/null +++ b/src/common/lock.hpp @@ -0,0 +1,8 @@ +#ifndef LOCK_HPP +#define LOCK_HPP +/// Locked FILE I/O +// Changes are made in a separate file until lock_fclose +FILE *lock_fopen (const char *filename, int *info); +void lock_fclose (FILE * fp, const char *filename, int *info); + +#endif // LOCK_HPP diff --git a/src/common/md5calc.c b/src/common/md5calc.c deleted file mode 100644 index ba8f6af..0000000 --- a/src/common/md5calc.c +++ /dev/null @@ -1,339 +0,0 @@ -#include "md5calc.h" -#include -#include "mt_rand.h" - -// auxilary data -/* -sin() constant table -# Reformatted output of: -echo 'scale=40; obase=16; for (i=1;i<=64;i++) print 2^32 * sin(i), "\n"' | -bc | sed 's/^-//;s/^/0x/;s/\..*$/,/' -*/ -static const uint32_t T[64] = -{ - // used by round 1 - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 - // used by round 2 - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 - 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //20 - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 - // used by round 3 - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, //40 - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 - // used by round 4 - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, //60 -}; - -// auxilary functions -// note - the RFC defines these by non-CS conventions: or=v, and=(empty) -static inline uint32_t rotate_left(uint32_t val, unsigned shift) -{ - return val << shift | val >> (32-shift); -} - -static inline uint32_t F(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Y) | (~X & Z); -} -static inline uint32_t G(uint32_t X, uint32_t Y, uint32_t Z) -{ - return (X & Z) | (Y & ~Z); -} -static inline uint32_t H(uint32_t X, uint32_t Y, uint32_t Z) -{ - return X ^ Y ^ Z; -} -static inline uint32_t I(uint32_t X, uint32_t Y, uint32_t Z) -{ - return Y ^ (X | ~Z); -} - -static const struct -{ - uint8_t k : 4; - uint8_t : 0; - uint8_t s : 5; -// uint8_t i : 6; just increments constantly, from 1 .. 64 over all rounds -} -MD5_round1[16] = -{ - { 0, 7}, { 1, 12}, { 2, 17}, { 3, 22}, - { 4, 7}, { 5, 12}, { 6, 17}, { 7, 22}, - { 8, 7}, { 9, 12}, {10, 17}, {11, 22}, - {12, 7}, {13, 12}, {14, 17}, {15, 22}, -}, -MD5_round2[16] = -{ - { 1, 5}, { 6, 9}, {11, 14}, { 0, 20}, - { 5, 5}, {10, 9}, {15, 14}, { 4, 20}, - { 9, 5}, {14, 9}, { 3, 14}, { 8, 20}, - {13, 5}, { 2, 9}, { 7, 14}, {12, 20}, -}, -MD5_round3[16] = -{ - { 5, 4}, { 8, 11}, {11, 16}, {14, 23}, - { 1, 4}, { 4, 11}, { 7, 16}, {10, 23}, - {13, 4}, { 0, 11}, { 3, 16}, { 6, 23}, - { 9, 4}, {12, 11}, {15, 16}, { 2, 23}, -}, -MD5_round4[16] = -{ - { 0, 6}, { 7, 10}, {14, 15}, { 5, 21}, - {12, 6}, { 3, 10}, {10, 15}, { 1, 21}, - { 8, 6}, {15, 10}, { 6, 15}, {13, 21}, - { 4, 6}, {11, 10}, { 2, 15}, { 9, 21}, -}; - - -void MD5_init(MD5_state* state) -{ - // in the RFC, these are specified as bytes, interpreted as little-endian - state->val[0] = 0x67452301; - state->val[1] = 0xEFCDAB89; - state->val[2] = 0x98BADCFE; - state->val[3] = 0x10325476; -} - -void MD5_do_block(MD5_state* state, MD5_block block) -{ -#define X block.data -#define a state->val[(16-i)%4] -#define b state->val[(17-i)%4] -#define c state->val[(18-i)%4] -#define d state->val[(19-i)%4] - // save the values - const MD5_state saved = *state; - // round 1 - for (int i=0; i<16; i++) - { -#define k MD5_round1[i].k -#define s MD5_round1[i].s - a = b + rotate_left(a + F(b,c,d) + X[k] + T[i+0x0], s); -#undef k -#undef s - } - // round 2 - for (int i=0; i<16; i++) - { -#define k MD5_round2[i].k -#define s MD5_round2[i].s - a = b + rotate_left(a + G(b,c,d) + X[k] + T[i+0x10], s); -#undef k -#undef s - } - // round 3 - for (int i=0; i<16; i++) - { -#define k MD5_round3[i].k -#define s MD5_round3[i].s - a = b + rotate_left(a + H(b,c,d) + X[k] + T[i+0x20], s); -#undef k -#undef s - } - // round 4 - for (int i=0; i<16; i++) - { -#define k MD5_round4[i].k -#define s MD5_round4[i].s - a = b + rotate_left(a + I(b,c,d) + X[k] + T[i+0x30], s); -#undef k -#undef s - } - // adjust state based on original - state->val[0] += saved.val[0]; - state->val[1] += saved.val[1]; - state->val[2] += saved.val[2]; - state->val[3] += saved.val[3]; -#undef a -#undef b -#undef c -#undef d -} - -void MD5_to_bin(MD5_state state, uint8_t out[0x10]) -{ - for (int i=0; i<0x10; i++) - out[i] = state.val[i/4] >> 8*(i%4); -} - -static const char hex[] = "0123456789abcdef"; - -void MD5_to_str(MD5_state state, char out[0x21]) -{ - uint8_t bin[16]; - MD5_to_bin(state, bin); - for (int i=0; i<0x10; i++) - out[2*i] = hex[bin[i] >> 4], - out[2*i+1] = hex[bin[i] & 0xf]; - out[0x20] = '\0'; -} - -MD5_state MD5_from_string(const char* msg, const size_t msglen) -{ - MD5_state state; - MD5_init(&state); - MD5_block block; - size_t rem = msglen; - while (rem >= 64) - { - for (int i=0; i<0x10; i++) - X[i] = msg[4*i+0] | msg[4*i+1]<<8 | msg[4*i+2]<<16 | msg[4*i+3]<<24; - MD5_do_block(&state, block); - msg += 64; - rem -= 64; - } - // now pad 1-512 bits + the 64-bit length - may be two blocks - uint8_t buf[0x40] = {}; - memcpy (buf, msg, rem); - buf[rem] = 0x80; // a single one bit - if (64 - rem > 8) - { - for (int i=0; i<8; i++) - buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); - } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - if (64 - rem <= 8) - { - memset(buf,'\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - } - return state; -} - -// This could be reimplemented without the strlen() -MD5_state MD5_from_cstring(const char* msg) -{ - return MD5_from_string(msg, strlen(msg)); -} - -MD5_state MD5_from_FILE(FILE* in) { - uint64_t total_len = 0; - - uint8_t buf[0x40]; - uint8_t block_len = 0; - - MD5_state state; - MD5_init(&state); - - MD5_block block; - - while (true) - { - size_t rv = fread(buf + block_len, 1, 0x40 - block_len, in); - if (!rv) - break; - total_len += 8*rv; // in bits - block_len += rv; - if (block_len != 0x40) - continue; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - block_len = 0; - } - // no more input, just pad and append the length - buf[block_len] = 0x80; - memset(buf + block_len + 1, '\0', 0x40 - block_len - 1); - if (block_len < 0x38) - { - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; - } - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - if (0x38 <= block_len) - { - memset(buf, '\0', 0x38); - for (int i=0; i<8; i++) - buf[0x38+i] = total_len >> i*8; - for (int i=0; i<0x10; i++) - X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; - MD5_do_block(&state, block); - } - return state; -} - - -// Hash a password with a salt. -// Whoever wrote this FAILS programming -const char *MD5_saltcrypt(const char *key, const char *salt) -{ - char buf[65]; - - // hash the key then the salt - // buf ends up as a 64-char NUL-terminated string - MD5_to_str(MD5_from_cstring(key), buf); - MD5_to_str(MD5_from_cstring(salt), buf+32); - - // Hash the buffer back into sbuf - this is stupid - // (luckily, putting the result into itself is safe) - MD5_to_str(MD5_from_cstring(buf), buf+32); - - static char obuf[33]; - // This truncates the string, but we have to keep it like that for compatibility - snprintf(obuf, 32, "!%s$%s", salt, buf+32); - return obuf; -} - -const char *make_salt(void) { - static char salt[6]; - for (int i=0; i<5; i++) - salt[i] = MPRAND(48, 78); - return salt; -} - -bool pass_ok(const char *password, const char *crypted) { - char buf[40]; - strncpy(buf, crypted, 40); - char *salt = buf + 1; - *strchr(salt, '$') = '\0'; - - return !strcmp(crypted, MD5_saltcrypt(password, salt)); -} - -// [M|h]ashes up an IP address and a secret key -// to return a hopefully unique masked IP. -in_addr_t MD5_ip(char *secret, in_addr_t ip) -{ - char ipbuf[32]; - uint8_t obuf[16]; - union { - struct bytes { - uint8_t b1; - uint8_t b2; - uint8_t b3; - uint8_t b4; - } bytes; - in_addr_t ip; - } conv; - - // MD5sum a secret + the IP address - memset(&ipbuf, 0, sizeof(ipbuf)); - snprintf(ipbuf, sizeof(ipbuf), "%lu%s", (unsigned long)ip, secret); - /// TODO stop it from being a cstring - MD5_to_bin(MD5_from_cstring(ipbuf), obuf); - - // Fold the md5sum to 32 bits, pack the bytes to an in_addr_t - conv.bytes.b1 = obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]; - conv.bytes.b2 = obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]; - conv.bytes.b3 = obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]; - conv.bytes.b4 = obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]; - - return conv.ip; -} diff --git a/src/common/md5calc.cpp b/src/common/md5calc.cpp new file mode 100644 index 0000000..f00861d --- /dev/null +++ b/src/common/md5calc.cpp @@ -0,0 +1,339 @@ +#include "md5calc.hpp" +#include +#include "mt_rand.hpp" + +// auxilary data +/* +sin() constant table +# Reformatted output of: +echo 'scale=40; obase=16; for (i=1;i<=64;i++) print 2^32 * sin(i), "\n"' | +bc | sed 's/^-//;s/^/0x/;s/\..*$/,/' +*/ +static const uint32_t T[64] = +{ + // used by round 1 + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, //0 + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, //4 + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, //8 + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, //12 + // used by round 2 + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, //16 + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, //20 + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, //24 + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, //28 + // used by round 3 + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, //32 + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, //36 + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, //40 + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, //44 + // used by round 4 + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, //48 + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, //52 + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, //56 + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, //60 +}; + +// auxilary functions +// note - the RFC defines these by non-CS conventions: or=v, and=(empty) +static inline uint32_t rotate_left(uint32_t val, unsigned shift) +{ + return val << shift | val >> (32-shift); +} + +static inline uint32_t F(uint32_t X, uint32_t Y, uint32_t Z) +{ + return (X & Y) | (~X & Z); +} +static inline uint32_t G(uint32_t X, uint32_t Y, uint32_t Z) +{ + return (X & Z) | (Y & ~Z); +} +static inline uint32_t H(uint32_t X, uint32_t Y, uint32_t Z) +{ + return X ^ Y ^ Z; +} +static inline uint32_t I(uint32_t X, uint32_t Y, uint32_t Z) +{ + return Y ^ (X | ~Z); +} + +static const struct +{ + uint8_t k : 4; + uint8_t : 0; + uint8_t s : 5; +// uint8_t i : 6; just increments constantly, from 1 .. 64 over all rounds +} +MD5_round1[16] = +{ + { 0, 7}, { 1, 12}, { 2, 17}, { 3, 22}, + { 4, 7}, { 5, 12}, { 6, 17}, { 7, 22}, + { 8, 7}, { 9, 12}, {10, 17}, {11, 22}, + {12, 7}, {13, 12}, {14, 17}, {15, 22}, +}, +MD5_round2[16] = +{ + { 1, 5}, { 6, 9}, {11, 14}, { 0, 20}, + { 5, 5}, {10, 9}, {15, 14}, { 4, 20}, + { 9, 5}, {14, 9}, { 3, 14}, { 8, 20}, + {13, 5}, { 2, 9}, { 7, 14}, {12, 20}, +}, +MD5_round3[16] = +{ + { 5, 4}, { 8, 11}, {11, 16}, {14, 23}, + { 1, 4}, { 4, 11}, { 7, 16}, {10, 23}, + {13, 4}, { 0, 11}, { 3, 16}, { 6, 23}, + { 9, 4}, {12, 11}, {15, 16}, { 2, 23}, +}, +MD5_round4[16] = +{ + { 0, 6}, { 7, 10}, {14, 15}, { 5, 21}, + {12, 6}, { 3, 10}, {10, 15}, { 1, 21}, + { 8, 6}, {15, 10}, { 6, 15}, {13, 21}, + { 4, 6}, {11, 10}, { 2, 15}, { 9, 21}, +}; + + +void MD5_init(MD5_state* state) +{ + // in the RFC, these are specified as bytes, interpreted as little-endian + state->val[0] = 0x67452301; + state->val[1] = 0xEFCDAB89; + state->val[2] = 0x98BADCFE; + state->val[3] = 0x10325476; +} + +void MD5_do_block(MD5_state* state, MD5_block block) +{ +#define X block.data +#define a state->val[(16-i)%4] +#define b state->val[(17-i)%4] +#define c state->val[(18-i)%4] +#define d state->val[(19-i)%4] + // save the values + const MD5_state saved = *state; + // round 1 + for (int i=0; i<16; i++) + { +#define k MD5_round1[i].k +#define s MD5_round1[i].s + a = b + rotate_left(a + F(b,c,d) + X[k] + T[i+0x0], s); +#undef k +#undef s + } + // round 2 + for (int i=0; i<16; i++) + { +#define k MD5_round2[i].k +#define s MD5_round2[i].s + a = b + rotate_left(a + G(b,c,d) + X[k] + T[i+0x10], s); +#undef k +#undef s + } + // round 3 + for (int i=0; i<16; i++) + { +#define k MD5_round3[i].k +#define s MD5_round3[i].s + a = b + rotate_left(a + H(b,c,d) + X[k] + T[i+0x20], s); +#undef k +#undef s + } + // round 4 + for (int i=0; i<16; i++) + { +#define k MD5_round4[i].k +#define s MD5_round4[i].s + a = b + rotate_left(a + I(b,c,d) + X[k] + T[i+0x30], s); +#undef k +#undef s + } + // adjust state based on original + state->val[0] += saved.val[0]; + state->val[1] += saved.val[1]; + state->val[2] += saved.val[2]; + state->val[3] += saved.val[3]; +#undef a +#undef b +#undef c +#undef d +} + +void MD5_to_bin(MD5_state state, uint8_t out[0x10]) +{ + for (int i=0; i<0x10; i++) + out[i] = state.val[i/4] >> 8*(i%4); +} + +static const char hex[] = "0123456789abcdef"; + +void MD5_to_str(MD5_state state, char out[0x21]) +{ + uint8_t bin[16]; + MD5_to_bin(state, bin); + for (int i=0; i<0x10; i++) + out[2*i] = hex[bin[i] >> 4], + out[2*i+1] = hex[bin[i] & 0xf]; + out[0x20] = '\0'; +} + +MD5_state MD5_from_string(const char* msg, const size_t msglen) +{ + MD5_state state; + MD5_init(&state); + MD5_block block; + size_t rem = msglen; + while (rem >= 64) + { + for (int i=0; i<0x10; i++) + X[i] = msg[4*i+0] | msg[4*i+1]<<8 | msg[4*i+2]<<16 | msg[4*i+3]<<24; + MD5_do_block(&state, block); + msg += 64; + rem -= 64; + } + // now pad 1-512 bits + the 64-bit length - may be two blocks + uint8_t buf[0x40] = {}; + memcpy (buf, msg, rem); + buf[rem] = 0x80; // a single one bit + if (64 - rem > 8) + { + for (int i=0; i<8; i++) + buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); + } + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + if (64 - rem <= 8) + { + memset(buf,'\0', 0x38); + for (int i=0; i<8; i++) + buf[0x38+i] = ((uint64_t)msglen*8) >> (i*8); + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + } + return state; +} + +// This could be reimplemented without the strlen() +MD5_state MD5_from_cstring(const char* msg) +{ + return MD5_from_string(msg, strlen(msg)); +} + +MD5_state MD5_from_FILE(FILE* in) { + uint64_t total_len = 0; + + uint8_t buf[0x40]; + uint8_t block_len = 0; + + MD5_state state; + MD5_init(&state); + + MD5_block block; + + while (true) + { + size_t rv = fread(buf + block_len, 1, 0x40 - block_len, in); + if (!rv) + break; + total_len += 8*rv; // in bits + block_len += rv; + if (block_len != 0x40) + continue; + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + block_len = 0; + } + // no more input, just pad and append the length + buf[block_len] = 0x80; + memset(buf + block_len + 1, '\0', 0x40 - block_len - 1); + if (block_len < 0x38) + { + for (int i=0; i<8; i++) + buf[0x38+i] = total_len >> i*8; + } + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + if (0x38 <= block_len) + { + memset(buf, '\0', 0x38); + for (int i=0; i<8; i++) + buf[0x38+i] = total_len >> i*8; + for (int i=0; i<0x10; i++) + X[i] = buf[4*i+0] | buf[4*i+1]<<8 | buf[4*i+2]<<16 | buf[4*i+3]<<24; + MD5_do_block(&state, block); + } + return state; +} + + +// Hash a password with a salt. +// Whoever wrote this FAILS programming +const char *MD5_saltcrypt(const char *key, const char *salt) +{ + char buf[65]; + + // hash the key then the salt + // buf ends up as a 64-char NUL-terminated string + MD5_to_str(MD5_from_cstring(key), buf); + MD5_to_str(MD5_from_cstring(salt), buf+32); + + // Hash the buffer back into sbuf - this is stupid + // (luckily, putting the result into itself is safe) + MD5_to_str(MD5_from_cstring(buf), buf+32); + + static char obuf[33]; + // This truncates the string, but we have to keep it like that for compatibility + snprintf(obuf, 32, "!%s$%s", salt, buf+32); + return obuf; +} + +const char *make_salt(void) { + static char salt[6]; + for (int i=0; i<5; i++) + salt[i] = MPRAND(48, 78); + return salt; +} + +bool pass_ok(const char *password, const char *crypted) { + char buf[40]; + strncpy(buf, crypted, 40); + char *salt = buf + 1; + *strchr(salt, '$') = '\0'; + + return !strcmp(crypted, MD5_saltcrypt(password, salt)); +} + +// [M|h]ashes up an IP address and a secret key +// to return a hopefully unique masked IP. +in_addr_t MD5_ip(char *secret, in_addr_t ip) +{ + char ipbuf[32]; + uint8_t obuf[16]; + union { + struct bytes { + uint8_t b1; + uint8_t b2; + uint8_t b3; + uint8_t b4; + } bytes; + in_addr_t ip; + } conv; + + // MD5sum a secret + the IP address + memset(&ipbuf, 0, sizeof(ipbuf)); + snprintf(ipbuf, sizeof(ipbuf), "%lu%s", (unsigned long)ip, secret); + /// TODO stop it from being a cstring + MD5_to_bin(MD5_from_cstring(ipbuf), obuf); + + // Fold the md5sum to 32 bits, pack the bytes to an in_addr_t + conv.bytes.b1 = obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]; + conv.bytes.b2 = obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]; + conv.bytes.b3 = obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]; + conv.bytes.b4 = obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]; + + return conv.ip; +} diff --git a/src/common/md5calc.h b/src/common/md5calc.h deleted file mode 100644 index b864791..0000000 --- a/src/common/md5calc.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef MD5CALC_H -#define MD5CALC_H - -#include "sanity.h" - -#include - -#include // uint32_t, uint8_t -#include // size_t -#include // FILE* - -/// The digest state - becomes the output -typedef struct -{ - // classically named {A,B,C,D} - // but use an so we can index - uint32_t val[4]; -} MD5_state; -typedef struct -{ - uint32_t data[16]; -} MD5_block; - -// Implementation -void MD5_init(MD5_state* state); -void MD5_do_block(MD5_state* state, MD5_block block); - -// Output formatting -void MD5_to_bin(MD5_state state, uint8_t out[0x10]); -void MD5_to_str(MD5_state state, char out[0x21]); - -// Convenience -MD5_state MD5_from_string(const char* msg, const size_t msglen); -MD5_state MD5_from_cstring(const char* msg); -MD5_state MD5_from_FILE(FILE* in); - - -/// Output in ASCII - with lowercase hex digits, null-terminated -// these may overlap safely -static void MD5_String (const char *string, char output[33]) __attribute__((deprecated)); -static inline void MD5_String (const char *string, char output[33]) { - MD5_to_str(MD5_from_cstring(string), output); -} -/// Output in binary -static void MD5_String2binary (const char *string, uint8_t output[16]) __attribute__((deprecated)); -static inline void MD5_String2binary (const char *string, uint8_t output[16]) { - MD5_to_bin(MD5_from_cstring(string), output); -} - -// statically-allocated output -// whoever wrote this fails basic understanding of -const char *MD5_saltcrypt(const char *key, const char *salt); - -/// return some random characters (statically allocated) -// Currently, returns a 5-char string -const char *make_salt(void); - -/// check plaintext password against saved saltcrypt -bool pass_ok(const char *password, const char *crypted); - -/// This returns an in_addr_t because it is configurable whether it gets called at all -in_addr_t MD5_ip(char *secret, in_addr_t ip); - -#endif diff --git a/src/common/md5calc.hpp b/src/common/md5calc.hpp new file mode 100644 index 0000000..1dde2ed --- /dev/null +++ b/src/common/md5calc.hpp @@ -0,0 +1,64 @@ +#ifndef MD5CALC_HPP +#define MD5CALC_HPP + +#include "sanity.hpp" + +#include + +#include // uint32_t, uint8_t +#include // size_t +#include // FILE* + +/// The digest state - becomes the output +typedef struct +{ + // classically named {A,B,C,D} + // but use an so we can index + uint32_t val[4]; +} MD5_state; +typedef struct +{ + uint32_t data[16]; +} MD5_block; + +// Implementation +void MD5_init(MD5_state* state); +void MD5_do_block(MD5_state* state, MD5_block block); + +// Output formatting +void MD5_to_bin(MD5_state state, uint8_t out[0x10]); +void MD5_to_str(MD5_state state, char out[0x21]); + +// Convenience +MD5_state MD5_from_string(const char* msg, const size_t msglen); +MD5_state MD5_from_cstring(const char* msg); +MD5_state MD5_from_FILE(FILE* in); + + +/// Output in ASCII - with lowercase hex digits, null-terminated +// these may overlap safely +static void MD5_String (const char *string, char output[33]) __attribute__((deprecated)); +static inline void MD5_String (const char *string, char output[33]) { + MD5_to_str(MD5_from_cstring(string), output); +} +/// Output in binary +static void MD5_String2binary (const char *string, uint8_t output[16]) __attribute__((deprecated)); +static inline void MD5_String2binary (const char *string, uint8_t output[16]) { + MD5_to_bin(MD5_from_cstring(string), output); +} + +// statically-allocated output +// whoever wrote this fails basic understanding of +const char *MD5_saltcrypt(const char *key, const char *salt); + +/// return some random characters (statically allocated) +// Currently, returns a 5-char string +const char *make_salt(void); + +/// check plaintext password against saved saltcrypt +bool pass_ok(const char *password, const char *crypted); + +/// This returns an in_addr_t because it is configurable whether it gets called at all +in_addr_t MD5_ip(char *secret, in_addr_t ip); + +#endif diff --git a/src/common/mmo.h b/src/common/mmo.h deleted file mode 100644 index 64e0523..0000000 --- a/src/common/mmo.h +++ /dev/null @@ -1,283 +0,0 @@ -/// Global structures and defines -#ifndef MMO_H -#define MMO_H - -# include -# include "utils.h" // LCCWIN32 - -# define FIFOSIZE_SERVERLINK 256*1024 - -// set to 0 to not check IP of player between each server. -// set to another value if you want to check (1) -# define CMP_AUTHFIFO_IP 1 - -# define CMP_AUTHFIFO_LOGIN2 1 - -# define MAX_MAP_PER_SERVER 512 -# define MAX_INVENTORY 100 -# define MAX_AMOUNT 30000 -# define MAX_ZENY 1000000000 // 1G zeny -# define MAX_CART 100 -# define MAX_SKILL 450 -# define GLOBAL_REG_NUM 96 -# define ACCOUNT_REG_NUM 16 -# define ACCOUNT_REG2_NUM 16 -# define DEFAULT_WALK_SPEED 150 -# define MIN_WALK_SPEED 0 -# define MAX_WALK_SPEED 1000 -# define MAX_STORAGE 300 -# define MAX_GUILD_STORAGE 1000 -# define MAX_PARTY 12 -# define MAX_GUILD 120 // increased max guild members to accomodate for +2 increase for extension levels [Valaris] (removed) [PoW] -# define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] -# define MAX_GUILDEXPLUSION 32 -# define MAX_GUILDALLIANCE 16 -# define MAX_GUILDSKILL 8 -# define MAX_GUILDCASTLE 24 // increased to include novice castles [Valaris] -# define MAX_GUILDLEVEL 50 - -# define MIN_HAIR_STYLE battle_config.min_hair_style -# define MAX_HAIR_STYLE battle_config.max_hair_style -# define MIN_HAIR_COLOR battle_config.min_hair_color -# define MAX_HAIR_COLOR battle_config.max_hair_color -# define MIN_CLOTH_COLOR battle_config.min_cloth_color -# define MAX_CLOTH_COLOR battle_config.max_cloth_color - -// for produce -# define MIN_ATTRIBUTE 0 -# define MAX_ATTRIBUTE 4 -# define ATTRIBUTE_NORMAL 0 -# define MIN_STAR 0 -# define MAX_STAR 3 - -# define MIN_PORTAL_MEMO 0 -# define MAX_PORTAL_MEMO 2 - -# define MAX_STATUS_TYPE 5 - -# define CHAR_CONF_NAME "conf/char_athena.conf" - -struct item -{ - int id; - short nameid; - short amount; - unsigned short equip; - char identify; - char refine; - char attribute; - short card[4]; - short broken; -}; - -struct point -{ - char map[24]; - short x, y; -}; - -struct skill -{ - unsigned short id, lv, flags; -}; - -struct global_reg -{ - char str[32]; - int value; -}; - -struct mmo_charstatus -{ - int char_id; - int account_id; - int partner_id; - - int base_exp, job_exp, zeny; - - short pc_class; - short status_point, skill_point; - int hp, max_hp, sp, max_sp; - short option, karma, manner; - short hair, hair_color, clothes_color; - int party_id, guild_id; - - short weapon, shield; - short head_top, head_mid, head_bottom; - - char name[24]; - unsigned char base_level, job_level; - short str, agi, vit, int_, dex, luk; - unsigned char char_num, sex; - - unsigned long mapip; - unsigned int mapport; - - struct point last_point, save_point, memo_point[10]; - struct item inventory[MAX_INVENTORY], cart[MAX_CART]; - struct skill skill[MAX_SKILL]; - int global_reg_num; - struct global_reg global_reg[GLOBAL_REG_NUM]; - int account_reg_num; - struct global_reg account_reg[ACCOUNT_REG_NUM]; - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; -}; - -struct storage -{ - int dirty; - int account_id; - short storage_status; - short storage_amount; - struct item storage_[MAX_STORAGE]; -}; - -struct guild_storage -{ - int dirty; - int guild_id; - short storage_status; - short storage_amount; - struct item storage_[MAX_GUILD_STORAGE]; -}; - -struct map_session_data; - -struct gm_account -{ - int account_id; - int level; -}; - -struct party_member -{ - int account_id; - char name[24], map[24]; - int leader, online, lv; - struct map_session_data *sd; -}; - -struct party -{ - int party_id; - char name[24]; - int exp; - int item; - struct party_member member[MAX_PARTY]; -}; - -struct guild_member -{ - int account_id, char_id; - short hair, hair_color, gender, pc_class, lv; - int exp, exp_payper; - short online, position; - int rsv1, rsv2; - char name[24]; - struct map_session_data *sd; -}; - -struct guild_position -{ - char name[24]; - int mode; - int exp_mode; -}; - -struct guild_alliance -{ - int opposition; - int guild_id; - char name[24]; -}; - -struct guild_explusion -{ - char name[24]; - char mes[40]; - char acc[40]; - int account_id; - int rsv1, rsv2, rsv3; -}; - -struct guild_skill -{ - int id, lv; -}; - -struct guild -{ - int guild_id; - short guild_lv, connect_member, max_member, average_lv; - int exp, next_exp, skill_point, castle_id; - char name[24], master[24]; - struct guild_member member[MAX_GUILD]; - struct guild_position position[MAX_GUILDPOSITION]; - char mes1[60], mes2[120]; - int emblem_len, emblem_id; - char emblem_data[2048]; - struct guild_alliance alliance[MAX_GUILDALLIANCE]; - struct guild_explusion explusion[MAX_GUILDEXPLUSION]; - struct guild_skill skill[MAX_GUILDSKILL]; -}; - -struct guild_castle -{ - int castle_id; - char map_name[24]; - char castle_name[24]; - char castle_event[24]; - int guild_id; - int economy; - int defense; - int triggerE; - int triggerD; - int nextTime; - int payTime; - int createTime; - int visibleC; - int visibleG0; - int visibleG1; - int visibleG2; - int visibleG3; - int visibleG4; - int visibleG5; - int visibleG6; - int visibleG7; - int Ghp0; // added Guardian HP [Valaris] - int Ghp1; - int Ghp2; - int Ghp3; - int Ghp4; - int Ghp5; - int Ghp6; - int Ghp7; - int GID0; - int GID1; - int GID2; - int GID3; - int GID4; - int GID5; - int GID6; - int GID7; // end addition [Valaris] -}; -struct square -{ - int val1[5]; - int val2[5]; -}; - -enum -{ - GBI_EXP = 1, // ギルドのEXP - GBI_GUILDLV = 2, // ギルドのLv - GBI_SKILLPOINT = 3, // ギルドのスキルポイント - GBI_SKILLLV = 4, // ギルドスキルLv - - GMI_POSITION = 0, // メンバーの役職変更 - GMI_EXP = 1, // メンバーのEXP - -}; - -#endif // MMO_H diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp new file mode 100644 index 0000000..2ca93b0 --- /dev/null +++ b/src/common/mmo.hpp @@ -0,0 +1,283 @@ +/// Global structures and defines +#ifndef MMO_HPP +#define MMO_HPP + +# include +# include "utils.hpp" // LCCWIN32 + +# define FIFOSIZE_SERVERLINK 256*1024 + +// set to 0 to not check IP of player between each server. +// set to another value if you want to check (1) +# define CMP_AUTHFIFO_IP 1 + +# define CMP_AUTHFIFO_LOGIN2 1 + +# define MAX_MAP_PER_SERVER 512 +# define MAX_INVENTORY 100 +# define MAX_AMOUNT 30000 +# define MAX_ZENY 1000000000 // 1G zeny +# define MAX_CART 100 +# define MAX_SKILL 450 +# define GLOBAL_REG_NUM 96 +# define ACCOUNT_REG_NUM 16 +# define ACCOUNT_REG2_NUM 16 +# define DEFAULT_WALK_SPEED 150 +# define MIN_WALK_SPEED 0 +# define MAX_WALK_SPEED 1000 +# define MAX_STORAGE 300 +# define MAX_GUILD_STORAGE 1000 +# define MAX_PARTY 12 +# define MAX_GUILD 120 // increased max guild members to accomodate for +2 increase for extension levels [Valaris] (removed) [PoW] +# define MAX_GUILDPOSITION 20 // increased max guild positions to accomodate for all members [Valaris] (removed) [PoW] +# define MAX_GUILDEXPLUSION 32 +# define MAX_GUILDALLIANCE 16 +# define MAX_GUILDSKILL 8 +# define MAX_GUILDCASTLE 24 // increased to include novice castles [Valaris] +# define MAX_GUILDLEVEL 50 + +# define MIN_HAIR_STYLE battle_config.min_hair_style +# define MAX_HAIR_STYLE battle_config.max_hair_style +# define MIN_HAIR_COLOR battle_config.min_hair_color +# define MAX_HAIR_COLOR battle_config.max_hair_color +# define MIN_CLOTH_COLOR battle_config.min_cloth_color +# define MAX_CLOTH_COLOR battle_config.max_cloth_color + +// for produce +# define MIN_ATTRIBUTE 0 +# define MAX_ATTRIBUTE 4 +# define ATTRIBUTE_NORMAL 0 +# define MIN_STAR 0 +# define MAX_STAR 3 + +# define MIN_PORTAL_MEMO 0 +# define MAX_PORTAL_MEMO 2 + +# define MAX_STATUS_TYPE 5 + +# define CHAR_CONF_NAME "conf/char_athena.conf" + +struct item +{ + int id; + short nameid; + short amount; + unsigned short equip; + char identify; + char refine; + char attribute; + short card[4]; + short broken; +}; + +struct point +{ + char map[24]; + short x, y; +}; + +struct skill +{ + unsigned short id, lv, flags; +}; + +struct global_reg +{ + char str[32]; + int value; +}; + +struct mmo_charstatus +{ + int char_id; + int account_id; + int partner_id; + + int base_exp, job_exp, zeny; + + short pc_class; + short status_point, skill_point; + int hp, max_hp, sp, max_sp; + short option, karma, manner; + short hair, hair_color, clothes_color; + int party_id, guild_id; + + short weapon, shield; + short head_top, head_mid, head_bottom; + + char name[24]; + unsigned char base_level, job_level; + short str, agi, vit, int_, dex, luk; + unsigned char char_num, sex; + + unsigned long mapip; + unsigned int mapport; + + struct point last_point, save_point, memo_point[10]; + struct item inventory[MAX_INVENTORY], cart[MAX_CART]; + struct skill skill[MAX_SKILL]; + int global_reg_num; + struct global_reg global_reg[GLOBAL_REG_NUM]; + int account_reg_num; + struct global_reg account_reg[ACCOUNT_REG_NUM]; + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; +}; + +struct storage +{ + int dirty; + int account_id; + short storage_status; + short storage_amount; + struct item storage_[MAX_STORAGE]; +}; + +struct guild_storage +{ + int dirty; + int guild_id; + short storage_status; + short storage_amount; + struct item storage_[MAX_GUILD_STORAGE]; +}; + +struct map_session_data; + +struct gm_account +{ + int account_id; + int level; +}; + +struct party_member +{ + int account_id; + char name[24], map[24]; + int leader, online, lv; + struct map_session_data *sd; +}; + +struct party +{ + int party_id; + char name[24]; + int exp; + int item; + struct party_member member[MAX_PARTY]; +}; + +struct guild_member +{ + int account_id, char_id; + short hair, hair_color, gender, pc_class, lv; + int exp, exp_payper; + short online, position; + int rsv1, rsv2; + char name[24]; + struct map_session_data *sd; +}; + +struct guild_position +{ + char name[24]; + int mode; + int exp_mode; +}; + +struct guild_alliance +{ + int opposition; + int guild_id; + char name[24]; +}; + +struct guild_explusion +{ + char name[24]; + char mes[40]; + char acc[40]; + int account_id; + int rsv1, rsv2, rsv3; +}; + +struct guild_skill +{ + int id, lv; +}; + +struct guild +{ + int guild_id; + short guild_lv, connect_member, max_member, average_lv; + int exp, next_exp, skill_point, castle_id; + char name[24], master[24]; + struct guild_member member[MAX_GUILD]; + struct guild_position position[MAX_GUILDPOSITION]; + char mes1[60], mes2[120]; + int emblem_len, emblem_id; + char emblem_data[2048]; + struct guild_alliance alliance[MAX_GUILDALLIANCE]; + struct guild_explusion explusion[MAX_GUILDEXPLUSION]; + struct guild_skill skill[MAX_GUILDSKILL]; +}; + +struct guild_castle +{ + int castle_id; + char map_name[24]; + char castle_name[24]; + char castle_event[24]; + int guild_id; + int economy; + int defense; + int triggerE; + int triggerD; + int nextTime; + int payTime; + int createTime; + int visibleC; + int visibleG0; + int visibleG1; + int visibleG2; + int visibleG3; + int visibleG4; + int visibleG5; + int visibleG6; + int visibleG7; + int Ghp0; // added Guardian HP [Valaris] + int Ghp1; + int Ghp2; + int Ghp3; + int Ghp4; + int Ghp5; + int Ghp6; + int Ghp7; + int GID0; + int GID1; + int GID2; + int GID3; + int GID4; + int GID5; + int GID6; + int GID7; // end addition [Valaris] +}; +struct square +{ + int val1[5]; + int val2[5]; +}; + +enum +{ + GBI_EXP = 1, // ギルドのEXP + GBI_GUILDLV = 2, // ギルドのLv + GBI_SKILLPOINT = 3, // ギルドのスキルポイント + GBI_SKILLLV = 4, // ギルドスキルLv + + GMI_POSITION = 0, // メンバーの役職変更 + GMI_EXP = 1, // メンバーのEXP + +}; + +#endif // MMO_HPP diff --git a/src/common/mt_rand.c b/src/common/mt_rand.c deleted file mode 100644 index e4e8d12..0000000 --- a/src/common/mt_rand.c +++ /dev/null @@ -1,116 +0,0 @@ -/* -// This is the ``Mersenne Twister'' random number generator MT19937, which -// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) -// starting from any odd seed in 0..(2^32 - 1). This version is a recode -// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by -// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in -// July-August 1997). -// -// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha -// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to -// generate 300 million random numbers; after recoding: 24.0 sec. for the same -// (i.e., 46.5% of original time), so speed is now about 12.5 million random -// number generations per second on this machine. -// -// According to the URL -// (and paraphrasing a bit in places), the Mersenne Twister is ``designed -// with consideration of the flaws of various existing generators,'' has -// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally -// equidistributed, and ``has passed many stringent tests, including the -// die-hard test of G. Marsaglia and the load test of P. Hellekalek and -// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 -// to 5012 bytes of static data, depending on data type sizes, and the code -// is quite short as well). It generates random numbers in batches of 624 -// at a time, so the caching and pipelining of modern systems is exploited. -// It is also divide- and mod-free. -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Library General Public License as published by -// the Free Software Foundation (either version 2 of the License or, at your -// option, any later version). This library is distributed in the hope that -// it will be useful, but WITHOUT ANY WARRANTY, without even the implied -// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -// the GNU Library General Public License for more details. You should have -// received a copy of the GNU Library General Public License along with this -// library; if not, write to the Free Software Foundation, Inc., 59 Temple -// Place, Suite 330, Boston, MA 02111-1307, USA. -// -// The code as Shawn received it included the following notice: -// -// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When -// you use this, send an e-mail to with -// an appropriate reference to your work. -// -// It would be nice to CC: when you write. -// -*/ - -#include -#include "mt_rand.h" - -#define N 624 // length of state vector -#define M 397 // a period parameter -#define K 0x9908B0DFU // a magic constant - -#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u -#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u -#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u -#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v - -static uint32_t state[N+1]; // state vector the +1 is needed due to the coding -static uint32_t *next; // next random value is computed from here -static int left = -1; // can *next++ this many times before reloading - -void mt_seed (uint32_t seed) -{ - uint32_t x = seed | 1U; - uint32_t *s = state; - left = 0; - - for (int j = N; *s++ = x, --j; x *= 69069U); -} - -void mt_reload (void) -{ - // if mt_seed has never been called - if (left < -1) - mt_seed (time (NULL)); - - // conceptually, these are indices into the state that wrap - uint32_t *p0 = state; - uint32_t *p2 = state + 2; - uint32_t *pM = state + M; - - uint32_t s0 = state[0]; - uint32_t s1 = state[1]; - - // regenerate the lower N-M elements of the state - for (int j = N-M+1; --j != 0; s0 = s1, s1 = *p2++) - *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - pM = state; - // regenerate the next M-1 elements of the state - // note that s1 is set to state[N] at the end, but discarded - for (int j = M; --j != 0; s0 = s1, s1 = *p2++) - *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - // regenerate the last 1 element of the state - s1 = state[0]; - *p0 = *pM ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); - - // ready for the normal mt_random algorithm - left = N; - next = state; -} - -uint32_t mt_random (void) -{ - if (--left < 0) - mt_reload (); - - uint32_t y = *next++; - y ^= (y >> 11); - y ^= (y << 7) & 0x9D2C5680U; - y ^= (y << 15) & 0xEFC60000U; - return y ^ (y >> 18); -} diff --git a/src/common/mt_rand.cpp b/src/common/mt_rand.cpp new file mode 100644 index 0000000..89872ad --- /dev/null +++ b/src/common/mt_rand.cpp @@ -0,0 +1,116 @@ +/* +// This is the ``Mersenne Twister'' random number generator MT19937, which +// generates pseudorandom integers uniformly distributed in 0..(2^32 - 1) +// starting from any odd seed in 0..(2^32 - 1). This version is a recode +// by Shawn Cokus (Cokus@math.washington.edu) on March 8, 1998 of a version by +// Takuji Nishimura (who had suggestions from Topher Cooper and Marc Rieffel in +// July-August 1997). +// +// Effectiveness of the recoding (on Goedel2.math.washington.edu, a DEC Alpha +// running OSF/1) using GCC -O3 as a compiler: before recoding: 51.6 sec. to +// generate 300 million random numbers; after recoding: 24.0 sec. for the same +// (i.e., 46.5% of original time), so speed is now about 12.5 million random +// number generations per second on this machine. +// +// According to the URL +// (and paraphrasing a bit in places), the Mersenne Twister is ``designed +// with consideration of the flaws of various existing generators,'' has +// a period of 2^19937 - 1, gives a sequence that is 623-dimensionally +// equidistributed, and ``has passed many stringent tests, including the +// die-hard test of G. Marsaglia and the load test of P. Hellekalek and +// S. Wegenkittl.'' It is efficient in memory usage (typically using 2506 +// to 5012 bytes of static data, depending on data type sizes, and the code +// is quite short as well). It generates random numbers in batches of 624 +// at a time, so the caching and pipelining of modern systems is exploited. +// It is also divide- and mod-free. +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Library General Public License as published by +// the Free Software Foundation (either version 2 of the License or, at your +// option, any later version). This library is distributed in the hope that +// it will be useful, but WITHOUT ANY WARRANTY, without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See +// the GNU Library General Public License for more details. You should have +// received a copy of the GNU Library General Public License along with this +// library; if not, write to the Free Software Foundation, Inc., 59 Temple +// Place, Suite 330, Boston, MA 02111-1307, USA. +// +// The code as Shawn received it included the following notice: +// +// Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When +// you use this, send an e-mail to with +// an appropriate reference to your work. +// +// It would be nice to CC: when you write. +// +*/ + +#include +#include "mt_rand.hpp" + +#define N 624 // length of state vector +#define M 397 // a period parameter +#define K 0x9908B0DFU // a magic constant + +#define hiBit(u) ((u) & 0x80000000U) // mask all but highest bit of u +#define loBit(u) ((u) & 0x00000001U) // mask all but lowest bit of u +#define loBits(u) ((u) & 0x7FFFFFFFU) // mask the highest bit of u +#define mixBits(u, v) (hiBit(u)|loBits(v)) // move hi bit of u to hi bit of v + +static uint32_t state[N+1]; // state vector the +1 is needed due to the coding +static uint32_t *next; // next random value is computed from here +static int left = -1; // can *next++ this many times before reloading + +void mt_seed (uint32_t seed) +{ + uint32_t x = seed | 1U; + uint32_t *s = state; + left = 0; + + for (int j = N; *s++ = x, --j; x *= 69069U); +} + +void mt_reload (void) +{ + // if mt_seed has never been called + if (left < -1) + mt_seed (time (NULL)); + + // conceptually, these are indices into the state that wrap + uint32_t *p0 = state; + uint32_t *p2 = state + 2; + uint32_t *pM = state + M; + + uint32_t s0 = state[0]; + uint32_t s1 = state[1]; + + // regenerate the lower N-M elements of the state + for (int j = N-M+1; --j != 0; s0 = s1, s1 = *p2++) + *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + pM = state; + // regenerate the next M-1 elements of the state + // note that s1 is set to state[N] at the end, but discarded + for (int j = M; --j != 0; s0 = s1, s1 = *p2++) + *p0++ = *pM++ ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + // regenerate the last 1 element of the state + s1 = state[0]; + *p0 = *pM ^ (mixBits (s0, s1) >> 1) ^ (loBit (s1) ? K : 0U); + + // ready for the normal mt_random algorithm + left = N; + next = state; +} + +uint32_t mt_random (void) +{ + if (--left < 0) + mt_reload (); + + uint32_t y = *next++; + y ^= (y >> 11); + y ^= (y << 7) & 0x9D2C5680U; + y ^= (y << 15) & 0xEFC60000U; + return y ^ (y >> 18); +} diff --git a/src/common/mt_rand.h b/src/common/mt_rand.h deleted file mode 100644 index 84d32e5..0000000 --- a/src/common/mt_rand.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MT_RAND_H -#define MT_RAND_H - -# include "sanity.h" - -/// Initialize the generator (called automatically with time() if you don't) -void mt_seed (uint32_t seed); -/// Get a random number -uint32_t mt_random (void); - -/** - * ModuloRand and ModuloPlusRand - * These macros are used to replace the vast number of calls to rand()%mod - * TODO eliminate the rest of the calls to rand() - * MRAND(10) returns 0..9 - * MPRAND(5,10) returns 5..14 - */ -// The cast is essential because the result is sometimes -// compared with a possibly negative number. -// Because it's using modulus, high numbers shouldn't happen anyway. -# define MRAND(mod) ((int)(mt_random() % (mod))) -# define MPRAND(add, mod) ((add) + MRAND(mod)) - -#endif // MT_RAND_H diff --git a/src/common/mt_rand.hpp b/src/common/mt_rand.hpp new file mode 100644 index 0000000..c7bae4e --- /dev/null +++ b/src/common/mt_rand.hpp @@ -0,0 +1,24 @@ +#ifndef MT_RAND_HPP +#define MT_RAND_HPP + +# include "sanity.hpp" + +/// Initialize the generator (called automatically with time() if you don't) +void mt_seed (uint32_t seed); +/// Get a random number +uint32_t mt_random (void); + +/** + * ModuloRand and ModuloPlusRand + * These macros are used to replace the vast number of calls to rand()%mod + * TODO eliminate the rest of the calls to rand() + * MRAND(10) returns 0..9 + * MPRAND(5,10) returns 5..14 + */ +// The cast is essential because the result is sometimes +// compared with a possibly negative number. +// Because it's using modulus, high numbers shouldn't happen anyway. +# define MRAND(mod) ((int)(mt_random() % (mod))) +# define MPRAND(add, mod) ((add) + MRAND(mod)) + +#endif // MT_RAND_HPP diff --git a/src/common/nullpo.c b/src/common/nullpo.c deleted file mode 100644 index 8c7c405..0000000 --- a/src/common/nullpo.c +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include "nullpo.h" - -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap); - -/// Null check and print format -bool nullpo_chk_f (const char *file, int line, const char *func, - const void *target, const char *fmt, ...) -{ - va_list ap; - - if (target) - return 0; - - va_start (ap, fmt); - nullpo_info_core (file, line, func, fmt, ap); - va_end (ap); - return 1; -} -bool nullpo_chk (const char *file, int line, const char *func, - const void *target) -{ - if (target) - return 0; - - nullpo_info_core (file, line, func, NULL, NULL); - return 1; -} - -/// External functions -void nullpo_info_f (const char *file, int line, const char *func, - const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - nullpo_info_core (file, line, func, fmt, ap); - va_end (ap); -} -void nullpo_info (const char *file, int line, const char *func) -{ - nullpo_info_core (file, line, func, NULL, NULL); -} - -/// Actual output function -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap) __attribute__((format(printf, 4, 0))); -static void nullpo_info_core (const char *file, int line, const char *func, - const char *fmt, va_list ap) -{ - if (!file) - file = "??"; - if (!func || !*func) - func = "unknown"; - - fprintf (stderr, "%s:%d: in func `%s': NULL pointer\n", file, line, func); - if (fmt && *fmt) - { - vfprintf (stderr, fmt, ap); - if (fmt[strlen (fmt) - 1] != '\n') - fputc('\n', stderr); - } -} diff --git a/src/common/nullpo.cpp b/src/common/nullpo.cpp new file mode 100644 index 0000000..6dd2736 --- /dev/null +++ b/src/common/nullpo.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include "nullpo.hpp" + +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap); + +/// Null check and print format +bool nullpo_chk_f (const char *file, int line, const char *func, + const void *target, const char *fmt, ...) +{ + va_list ap; + + if (target) + return 0; + + va_start (ap, fmt); + nullpo_info_core (file, line, func, fmt, ap); + va_end (ap); + return 1; +} +bool nullpo_chk (const char *file, int line, const char *func, + const void *target) +{ + if (target) + return 0; + + nullpo_info_core (file, line, func, NULL, NULL); + return 1; +} + +/// External functions +void nullpo_info_f (const char *file, int line, const char *func, + const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + nullpo_info_core (file, line, func, fmt, ap); + va_end (ap); +} +void nullpo_info (const char *file, int line, const char *func) +{ + nullpo_info_core (file, line, func, NULL, NULL); +} + +/// Actual output function +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap) __attribute__((format(printf, 4, 0))); +static void nullpo_info_core (const char *file, int line, const char *func, + const char *fmt, va_list ap) +{ + if (!file) + file = "??"; + if (!func || !*func) + func = "unknown"; + + fprintf (stderr, "%s:%d: in func `%s': NULL pointer\n", file, line, func); + if (fmt && *fmt) + { + vfprintf (stderr, fmt, ap); + if (fmt[strlen (fmt) - 1] != '\n') + fputc('\n', stderr); + } +} diff --git a/src/common/nullpo.h b/src/common/nullpo.h deleted file mode 100644 index 9b33b4b..0000000 --- a/src/common/nullpo.h +++ /dev/null @@ -1,61 +0,0 @@ -/// return wrappers for unexpected NULL pointers -#ifndef NULLPO_H -#define NULLPO_H -/// Comment this out to live dangerously -# define NULLPO_CHECK - -/// All functions print to standard error (was: standard output) -/// nullpo_ret(cond) - return 0 if given pointer is NULL -/// nullpo_retv(cond) - just return (function returns void) -/// nullpo_retr(rv, cond) - return given value instead -/// the _f variants take a printf-format string and arguments - -# ifdef NULLPO_CHECK -# define NLP_MARK __FILE__, __LINE__, __func__ -# define nullpo_ret(t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return 0; -# define nullpo_retv(t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return; -# define nullpo_retr(ret, t) \ - if (nullpo_chk(NLP_MARK, t)) \ - return ret; -# define nullpo_ret_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return 0; -# define nullpo_retv_f(t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return; -# define nullpo_retr_f(ret, t, fmt, ...) \ - if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ - return ret; -# else // NULLPO_CHECK -# define nullpo_ret(t) t; -# define nullpo_retv(t) t; -# define nullpo_retr(ret, t) t; -# define nullpo_ret_f(t, fmt, ...) t; -# define nullpo_retv_f(t, fmt, ...) t; -# define nullpo_retr_f(ret, t, fmt, ...) t; -# endif // NULLPO_CHECK - -# include "sanity.h" - -/// Used by macros in this header -bool nullpo_chk (const char *file, int line, const char *func, - const void *target); - -/// Used by macros in this header -bool nullpo_chk_f (const char *file, int line, const char *func, - const void *target, const char *fmt, ...) - __attribute__ ((format (printf, 5, 6))); - -/// Used only by map/battle.c -void nullpo_info (const char *file, int line, const char *func); - -/// Not used -void nullpo_info_f (const char *file, int line, const char *func, - const char *fmt, ...) - __attribute__ ((format (printf, 4, 5))); - -#endif // NULLPO_H diff --git a/src/common/nullpo.hpp b/src/common/nullpo.hpp new file mode 100644 index 0000000..7aff691 --- /dev/null +++ b/src/common/nullpo.hpp @@ -0,0 +1,61 @@ +/// return wrappers for unexpected NULL pointers +#ifndef NULLPO_HPP +#define NULLPO_HPP +/// Comment this out to live dangerously +# define NULLPO_CHECK + +/// All functions print to standard error (was: standard output) +/// nullpo_ret(cond) - return 0 if given pointer is NULL +/// nullpo_retv(cond) - just return (function returns void) +/// nullpo_retr(rv, cond) - return given value instead +/// the _f variants take a printf-format string and arguments + +# ifdef NULLPO_CHECK +# define NLP_MARK __FILE__, __LINE__, __func__ +# define nullpo_ret(t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return 0; +# define nullpo_retv(t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return; +# define nullpo_retr(ret, t) \ + if (nullpo_chk(NLP_MARK, t)) \ + return ret; +# define nullpo_ret_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return 0; +# define nullpo_retv_f(t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return; +# define nullpo_retr_f(ret, t, fmt, ...) \ + if (nullpo_chk_f(NLP_MARK, t, fmt, ##__VA_ARGS__)) \ + return ret; +# else // NULLPO_CHECK +# define nullpo_ret(t) t; +# define nullpo_retv(t) t; +# define nullpo_retr(ret, t) t; +# define nullpo_ret_f(t, fmt, ...) t; +# define nullpo_retv_f(t, fmt, ...) t; +# define nullpo_retr_f(ret, t, fmt, ...) t; +# endif // NULLPO_CHECK + +# include "sanity.hpp" + +/// Used by macros in this header +bool nullpo_chk (const char *file, int line, const char *func, + const void *target); + +/// Used by macros in this header +bool nullpo_chk_f (const char *file, int line, const char *func, + const void *target, const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + +/// Used only by map/battle.c +void nullpo_info (const char *file, int line, const char *func); + +/// Not used +void nullpo_info_f (const char *file, int line, const char *func, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +#endif // NULLPO_HPP diff --git a/src/common/sanity.h b/src/common/sanity.h deleted file mode 100644 index 168671f..0000000 --- a/src/common/sanity.h +++ /dev/null @@ -1,36 +0,0 @@ -/// return wrappers for unexpected NULL pointers -#ifndef SANITY_H -#define SANITY_H -# if __STDC_VERSION__ < 199901L -# error "Please compile in C99 mode" -# endif -# if __GNUC__ < 3 -// I don't specifically know what version this requires, -// but GCC 3 was the beginning of modern GCC -# error "Please upgrade your compiler to at least GCC 3" -# endif -# ifndef __i386__ -// Known platform dependencies: -// endianness for the [RW]FIFO.* macros -// possibly, some signal-handling -# error "Unsupported platform" -# endif -# ifdef __x86_64__ -// I'm working on it - I know there are some pointer-size assumptions. -# error "Sorry, this code is believed not to be 64-bit safe" -# error "please compile with -m32" -# endif - -/// A name for unused function arguments - can be repeated -# define UNUSED UNUSED_IMPL(__COUNTER__) -// Don't you just love the hoops the preprocessor makes you go through? -# define UNUSED_IMPL(arg) UNUSED_IMPL2(arg) -# define UNUSED_IMPL2(suffix) unused_ ## suffix __attribute__((unused)) -/// Convert conditions to use the bool type -# include -/// Convert type assumptions to use the standard types here -# include -/// size_t, NULL -# include - -#endif // SANITY_H diff --git a/src/common/sanity.hpp b/src/common/sanity.hpp new file mode 100644 index 0000000..7ffd077 --- /dev/null +++ b/src/common/sanity.hpp @@ -0,0 +1,31 @@ +/// return wrappers for unexpected NULL pointers +#ifndef SANITY_HPP +#define SANITY_HPP +# ifndef __cplusplus +# error "Please compile in C++ mode" +# endif +# if __GNUC__ < 3 +// I don't specifically know what version this requires, +// but GCC 3 was the beginning of modern GCC +# error "Please upgrade your compiler to at least GCC 3" +# endif +# ifndef __i386__ +// Known platform dependencies: +// endianness for the [RW]FIFO.* macros +// possibly, some signal-handling +# error "Unsupported platform" +# endif +# ifdef __x86_64__ +// I'm working on it - I know there are some pointer-size assumptions. +# error "Sorry, this code is believed not to be 64-bit safe" +# error "please compile with -m32" +# endif + +/// A name for unused function arguments - can be repeated +# define UNUSED /* empty works for C++ */ +/// Convert type assumptions to use the standard types here +# include +/// size_t, NULL +# include + +#endif // SANITY_HPP diff --git a/src/common/socket.c b/src/common/socket.c deleted file mode 100644 index 67a5102..0000000 --- a/src/common/socket.c +++ /dev/null @@ -1,405 +0,0 @@ -// $Id: socket.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ -// original : core.c 2003/02/26 18:03:12 Rev 1.7 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "mmo.h" // [Valaris] thanks to fov -#include "socket.h" -#include "utils.h" - -fd_set readfds; -int fd_max; -int currentuse; - -const uint32_t RFIFO_SIZE = 65536; -const uint32_t WFIFO_SIZE = 65536; - -struct socket_data *session[FD_SETSIZE]; - -/// Discard all input -static void null_parse (int fd); -/// Default parser for new connections -static void (*default_func_parse) (int) = null_parse; - -void set_defaultparse (void (*defaultparse) (int)) -{ - default_func_parse = defaultparse; -} - -/// Read from socket to the queue -static void recv_to_fifo (int fd) -{ - if (session[fd]->eof) - return; - - ssize_t len = read (fd, session[fd]->rdata + session[fd]->rdata_size, - RFIFOSPACE (fd)); - - if (len > 0) - { - session[fd]->rdata_size += len; - session[fd]->connected = 1; - } - else - { - session[fd]->eof = 1; - } -} - -static void send_from_fifo (int fd) -{ - if (session[fd]->eof) - return; - - ssize_t len = write (fd, session[fd]->wdata, session[fd]->wdata_size); - - if (len > 0) - { - session[fd]->wdata_size -= len; - if (len < (ssize_t)session[fd]->wdata_size) - { - memmove (session[fd]->wdata, session[fd]->wdata + len, - session[fd]->wdata_size); - } - session[fd]->connected = 1; - } - else - { - session[fd]->eof = 1; - } -} - -static void null_parse (int fd) -{ - printf ("null_parse : %d\n", fd); - RFIFOSKIP (fd, RFIFOREST (fd)); -} - - -static void connect_client (int listen_fd) -{ - struct sockaddr_in client_address; - socklen_t len = sizeof (client_address); - - int fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); - if (fd == -1) - { - perror ("accept"); - return; - } - if (fd_max <= fd) - { - fd_max = fd + 1; - } - if (!free_fds ()) - { - fprintf (stderr, "softlimit reached, disconnecting : %d\n", fd); - delete_session (fd); - return; - } - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - FD_SET (fd, &readfds); - - fcntl (fd, F_SETFL, O_NONBLOCK); - - CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); - CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); - - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = recv_to_fifo; - session[fd]->func_send = send_from_fifo; - session[fd]->func_parse = default_func_parse; - session[fd]->client_addr = client_address; - session[fd]->created = time (NULL); - session[fd]->connected = 0; - - currentuse++; -} - -int make_listen_port (uint16_t port) -{ - struct sockaddr_in server_address; - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - perror ("socket"); - return -1; - } - if (fd_max <= fd) - fd_max = fd + 1; - - fcntl (fd, F_SETFL, O_NONBLOCK); - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl (INADDR_ANY); - server_address.sin_port = htons (port); - - if (bind (fd, (struct sockaddr *) &server_address, - sizeof (server_address)) == -1) - { - perror ("bind"); - exit (1); - } - if (listen (fd, 5) == -1) - { /* error */ - perror ("listen"); - exit (1); - } - - FD_SET (fd, &readfds); - - CREATE (session[fd], struct socket_data, 1); - - session[fd]->func_recv = connect_client; - session[fd]->created = time (NULL); - session[fd]->connected = 1; - - currentuse++; - return fd; -} - -int make_connection (uint32_t ip, uint16_t port) -{ - struct sockaddr_in server_address; - int fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd == -1) - { - perror ("socket"); - return -1; - } - if (fd_max <= fd) - fd_max = fd + 1; - - const int yes = 1; - /// Allow to bind() again after the server restarts. - // Since the socket is still in the TIME_WAIT, there's a possibility - // that formerly lost packets might be delivered and confuse the server. - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); - /// Send packets as soon as possible - /// even if the kernel thinks there is too little for it to be worth it! - // I'm not convinced this is a good idea; although in minimizes the - // latency for an individual write, it increases traffic in general. - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); - - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = ip; - server_address.sin_port = htons (port); - - fcntl (fd, F_SETFL, O_NONBLOCK); - - /// Errors not caught - we must not block - /// Let the main select() loop detect when we know the state - connect (fd, (struct sockaddr *) &server_address, - sizeof (struct sockaddr_in)); - - FD_SET (fd, &readfds); - - CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); - CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); - - session[fd]->max_rdata = RFIFO_SIZE; - session[fd]->max_wdata = WFIFO_SIZE; - session[fd]->func_recv = recv_to_fifo; - session[fd]->func_send = send_from_fifo; - session[fd]->func_parse = default_func_parse; - session[fd]->created = time (NULL); - session[fd]->connected = 1; - - currentuse++; - return fd; -} - -void delete_session (int fd) -{ - if (fd < 0 || fd >= FD_SETSIZE) - return; - // If this was the highest fd, decrease it - // We could add a loop to decrement fd_max further for every null session, - // but this is cheap and good enough for the typical case - if (fd == fd_max - 1) - fd_max--; - FD_CLR (fd, &readfds); - if (session[fd]) - { - free (session[fd]->rdata); - free (session[fd]->wdata); - free (session[fd]->session_data); - free (session[fd]); - } - session[fd] = NULL; - - // just close() would try to keep sending buffers - shutdown (fd, SHUT_RDWR); - close (fd); - currentuse--; - if (currentuse < 0) - { - fprintf (stderr, "delete_session: current sessions negative!\n"); - currentuse = 0; - } - return; -} - -void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size) -{ - struct socket_data *s = session[fd]; - if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) - { - RECREATE (s->rdata, uint8_t, rfifo_size); - s->max_rdata = rfifo_size; - } - if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) - { - RECREATE (s->wdata, uint8_t, wfifo_size); - s->max_wdata = wfifo_size; - } -} - -void WFIFOSET (int fd, size_t len) -{ - struct socket_data *s = session[fd]; - if (s->wdata_size + len + 16384 > s->max_wdata) - { - realloc_fifo (fd, s->max_rdata, s->max_wdata << 1); - printf ("socket: %d wdata expanded to %d bytes.\n", fd, s->max_wdata); - } - if (s->wdata_size + len + 2048 < s->max_wdata) - s->wdata_size += len; - else - fprintf (stderr, "socket: %d wdata lost !!\n", fd), abort (); -} - -void do_sendrecv (uint32_t next) -{ - fd_set rfd = readfds, wfd; - FD_ZERO (&wfd); - for (int i = 0; i < fd_max; i++) - { - if (session[i] && session[i]->wdata_size) - FD_SET (i, &wfd); - } - struct timeval timeout; - timeout.tv_sec = next / 1000; - timeout.tv_usec = next % 1000 * 1000; - if (select (fd_max, &rfd, &wfd, NULL, &timeout) <= 0) - return; - for (int i = 0; i < fd_max; i++) - { - if (!session[i]) - continue; - if (FD_ISSET (i, &wfd)) - { - if (session[i]->func_send) - //send_from_fifo(i); - session[i]->func_send (i); - } - if (FD_ISSET (i, &rfd)) - { - if (session[i]->func_recv) - //recv_to_fifo(i); - //or connect_client(i); - session[i]->func_recv (i); - } - } -} - -void do_parsepacket (void) -{ - for (int i = 0; i < fd_max; i++) - { - if (!session[i]) - continue; - if (!session[i]->connected - && time (NULL) - session[i]->created > CONNECT_TIMEOUT) - { - printf ("Session #%d timed out\n", i); - session[i]->eof = 1; - } - if (!session[i]->rdata_size && !session[i]->eof) - continue; - if (session[i]->func_parse) - { - session[i]->func_parse (i); - /// some func_parse may call delete_session - if (!session[i]) - continue; - } - /// Reclaim buffer space for what was read - RFIFOFLUSH (i); - } -} - -void do_socket (void) -{ - FD_ZERO (&readfds); - currentuse = 3; -} - -void RFIFOSKIP (int fd, size_t len) -{ - struct socket_data *s = session[fd]; - s->rdata_pos += len; - - if (s->rdata_size < s->rdata_pos) - { - fprintf (stderr, "too many skip\n"); - abort (); - } -} - -void fclose_ (FILE * fp) -{ - if (fclose (fp)) - perror ("fclose"), abort (); - currentuse--; -} - -FILE *fopen_ (const char *path, const char *mode) -{ - FILE *f = fopen (path, mode); - if (f) - currentuse++; - return f; -} - -bool free_fds (void) -{ - return currentuse < SOFT_LIMIT; -} diff --git a/src/common/socket.cpp b/src/common/socket.cpp new file mode 100644 index 0000000..cc6e4b3 --- /dev/null +++ b/src/common/socket.cpp @@ -0,0 +1,405 @@ +// $Id: socket.c,v 1.1.1.1 2004/09/10 17:44:49 MagicalTux Exp $ +// original : core.c 2003/02/26 18:03:12 Rev 1.7 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "mmo.hpp" // [Valaris] thanks to fov +#include "socket.hpp" +#include "utils.hpp" + +fd_set readfds; +int fd_max; +int currentuse; + +const uint32_t RFIFO_SIZE = 65536; +const uint32_t WFIFO_SIZE = 65536; + +struct socket_data *session[FD_SETSIZE]; + +/// Discard all input +static void null_parse (int fd); +/// Default parser for new connections +static void (*default_func_parse) (int) = null_parse; + +void set_defaultparse (void (*defaultparse) (int)) +{ + default_func_parse = defaultparse; +} + +/// Read from socket to the queue +static void recv_to_fifo (int fd) +{ + if (session[fd]->eof) + return; + + ssize_t len = read (fd, session[fd]->rdata + session[fd]->rdata_size, + RFIFOSPACE (fd)); + + if (len > 0) + { + session[fd]->rdata_size += len; + session[fd]->connected = 1; + } + else + { + session[fd]->eof = 1; + } +} + +static void send_from_fifo (int fd) +{ + if (session[fd]->eof) + return; + + ssize_t len = write (fd, session[fd]->wdata, session[fd]->wdata_size); + + if (len > 0) + { + session[fd]->wdata_size -= len; + if (len < (ssize_t)session[fd]->wdata_size) + { + memmove (session[fd]->wdata, session[fd]->wdata + len, + session[fd]->wdata_size); + } + session[fd]->connected = 1; + } + else + { + session[fd]->eof = 1; + } +} + +static void null_parse (int fd) +{ + printf ("null_parse : %d\n", fd); + RFIFOSKIP (fd, RFIFOREST (fd)); +} + + +static void connect_client (int listen_fd) +{ + struct sockaddr_in client_address; + socklen_t len = sizeof (client_address); + + int fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); + if (fd == -1) + { + perror ("accept"); + return; + } + if (fd_max <= fd) + { + fd_max = fd + 1; + } + if (!free_fds ()) + { + fprintf (stderr, "softlimit reached, disconnecting : %d\n", fd); + delete_session (fd); + return; + } + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + FD_SET (fd, &readfds); + + fcntl (fd, F_SETFL, O_NONBLOCK); + + CREATE (session[fd], struct socket_data, 1); + CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); + CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); + + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + session[fd]->client_addr = client_address; + session[fd]->created = time (NULL); + session[fd]->connected = 0; + + currentuse++; +} + +int make_listen_port (uint16_t port) +{ + struct sockaddr_in server_address; + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror ("socket"); + return -1; + } + if (fd_max <= fd) + fd_max = fd + 1; + + fcntl (fd, F_SETFL, O_NONBLOCK); + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl (INADDR_ANY); + server_address.sin_port = htons (port); + + if (bind (fd, (struct sockaddr *) &server_address, + sizeof (server_address)) == -1) + { + perror ("bind"); + exit (1); + } + if (listen (fd, 5) == -1) + { /* error */ + perror ("listen"); + exit (1); + } + + FD_SET (fd, &readfds); + + CREATE (session[fd], struct socket_data, 1); + + session[fd]->func_recv = connect_client; + session[fd]->created = time (NULL); + session[fd]->connected = 1; + + currentuse++; + return fd; +} + +int make_connection (uint32_t ip, uint16_t port) +{ + struct sockaddr_in server_address; + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror ("socket"); + return -1; + } + if (fd_max <= fd) + fd_max = fd + 1; + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = ip; + server_address.sin_port = htons (port); + + fcntl (fd, F_SETFL, O_NONBLOCK); + + /// Errors not caught - we must not block + /// Let the main select() loop detect when we know the state + connect (fd, (struct sockaddr *) &server_address, + sizeof (struct sockaddr_in)); + + FD_SET (fd, &readfds); + + CREATE (session[fd], struct socket_data, 1); + CREATE (session[fd]->rdata, uint8_t, RFIFO_SIZE); + CREATE (session[fd]->wdata, uint8_t, WFIFO_SIZE); + + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; + session[fd]->func_recv = recv_to_fifo; + session[fd]->func_send = send_from_fifo; + session[fd]->func_parse = default_func_parse; + session[fd]->created = time (NULL); + session[fd]->connected = 1; + + currentuse++; + return fd; +} + +void delete_session (int fd) +{ + if (fd < 0 || fd >= FD_SETSIZE) + return; + // If this was the highest fd, decrease it + // We could add a loop to decrement fd_max further for every null session, + // but this is cheap and good enough for the typical case + if (fd == fd_max - 1) + fd_max--; + FD_CLR (fd, &readfds); + if (session[fd]) + { + free (session[fd]->rdata); + free (session[fd]->wdata); + free (session[fd]->session_data); + free (session[fd]); + } + session[fd] = NULL; + + // just close() would try to keep sending buffers + shutdown (fd, SHUT_RDWR); + close (fd); + currentuse--; + if (currentuse < 0) + { + fprintf (stderr, "delete_session: current sessions negative!\n"); + currentuse = 0; + } + return; +} + +void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size) +{ + struct socket_data *s = session[fd]; + if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) + { + RECREATE (s->rdata, uint8_t, rfifo_size); + s->max_rdata = rfifo_size; + } + if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) + { + RECREATE (s->wdata, uint8_t, wfifo_size); + s->max_wdata = wfifo_size; + } +} + +void WFIFOSET (int fd, size_t len) +{ + struct socket_data *s = session[fd]; + if (s->wdata_size + len + 16384 > s->max_wdata) + { + realloc_fifo (fd, s->max_rdata, s->max_wdata << 1); + printf ("socket: %d wdata expanded to %d bytes.\n", fd, s->max_wdata); + } + if (s->wdata_size + len + 2048 < s->max_wdata) + s->wdata_size += len; + else + fprintf (stderr, "socket: %d wdata lost !!\n", fd), abort (); +} + +void do_sendrecv (uint32_t next) +{ + fd_set rfd = readfds, wfd; + FD_ZERO (&wfd); + for (int i = 0; i < fd_max; i++) + { + if (session[i] && session[i]->wdata_size) + FD_SET (i, &wfd); + } + struct timeval timeout; + timeout.tv_sec = next / 1000; + timeout.tv_usec = next % 1000 * 1000; + if (select (fd_max, &rfd, &wfd, NULL, &timeout) <= 0) + return; + for (int i = 0; i < fd_max; i++) + { + if (!session[i]) + continue; + if (FD_ISSET (i, &wfd)) + { + if (session[i]->func_send) + //send_from_fifo(i); + session[i]->func_send (i); + } + if (FD_ISSET (i, &rfd)) + { + if (session[i]->func_recv) + //recv_to_fifo(i); + //or connect_client(i); + session[i]->func_recv (i); + } + } +} + +void do_parsepacket (void) +{ + for (int i = 0; i < fd_max; i++) + { + if (!session[i]) + continue; + if (!session[i]->connected + && time (NULL) - session[i]->created > CONNECT_TIMEOUT) + { + printf ("Session #%d timed out\n", i); + session[i]->eof = 1; + } + if (!session[i]->rdata_size && !session[i]->eof) + continue; + if (session[i]->func_parse) + { + session[i]->func_parse (i); + /// some func_parse may call delete_session + if (!session[i]) + continue; + } + /// Reclaim buffer space for what was read + RFIFOFLUSH (i); + } +} + +void do_socket (void) +{ + FD_ZERO (&readfds); + currentuse = 3; +} + +void RFIFOSKIP (int fd, size_t len) +{ + struct socket_data *s = session[fd]; + s->rdata_pos += len; + + if (s->rdata_size < s->rdata_pos) + { + fprintf (stderr, "too many skip\n"); + abort (); + } +} + +void fclose_ (FILE * fp) +{ + if (fclose (fp)) + perror ("fclose"), abort (); + currentuse--; +} + +FILE *fopen_ (const char *path, const char *mode) +{ + FILE *f = fopen (path, mode); + if (f) + currentuse++; + return f; +} + +bool free_fds (void) +{ + return currentuse < SOFT_LIMIT; +} diff --git a/src/common/socket.h b/src/common/socket.h deleted file mode 100644 index b886df0..0000000 --- a/src/common/socket.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef SOCKET_H -#define SOCKET_H - -# include "sanity.h" - -# include - -# include -# include -# include - -# include - -/// Check how much can be read -# define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos) -/// Read from the queue -# define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos)) -# define RFIFOB(fd,pos) (*(uint8_t*)(RFIFOP(fd, pos))) -# define RFIFOW(fd,pos) (*(uint16_t*)(RFIFOP(fd, pos))) -# define RFIFOL(fd,pos) (*(uint32_t*)(RFIFOP(fd, pos))) -/// Done reading -void RFIFOSKIP (int fd, size_t len); -/// Internal - clean up by discarding handled bytes -// Atm this is also called in char/char.c, but that is unnecessary -# define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),\ -session[fd]->rdata_size=RFIFOREST(fd),\ -session[fd]->rdata_pos=0) - -/// Used internally - how much room there is to read more data -# define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size) - -/// Read from an arbitrary buffer -# define RBUFP(p,pos) (((uint8_t*)(p))+(pos)) -# define RBUFB(p,pos) (*(uint8_t*)RBUFP((p),(pos))) -# define RBUFW(p,pos) (*(uint16_t*)RBUFP((p),(pos))) -# define RBUFL(p,pos) (*(uint32_t*)RBUFP((p),(pos))) - - - -/// Unused - check how much data can be written -# define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size) -/// Write to the queue -# define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos)) -# define WFIFOB(fd,pos) (*(uint8_t*)(WFIFOP(fd,pos))) -# define WFIFOW(fd,pos) (*(uint16_t*)(WFIFOP(fd,pos))) -# define WFIFOL(fd,pos) (*(uint32_t*)(WFIFOP(fd,pos))) -/// Finish writing -void WFIFOSET (int fd, size_t len); - -/// Write to an arbitrary buffer -#define WBUFP(p,pos) (((uint8_t*)(p))+(pos)) -#define WBUFB(p,pos) (*(uint8_t*)WBUFP((p),(pos))) -#define WBUFW(p,pos) (*(uint16_t*)WBUFP((p),(pos))) -#define WBUFL(p,pos) (*(uint32_t*)WBUFP((p),(pos))) - -// Struct declaration - -struct socket_data -{ - /// Checks whether a newly-connected socket actually does anything - time_t created; - bool connected; - - /// Flag needed since structure must be freed in a server-dependent manner - bool eof; - - /// Since this is a single-threaded application, it can't block - /// These are the read/write queues - uint8_t *rdata, *wdata; - size_t max_rdata, max_wdata; - /// How much is actually in the queue - size_t rdata_size, wdata_size; - /// How much has already been read from the queue - /// Note that there is no need for a wdata_pos - size_t rdata_pos; - - struct sockaddr_in client_addr; - - /// Send or recieve - /// Only called when select() indicates the socket is ready - /// If, after that, nothing is read, it sets eof - // These could probably be hard-coded with a little work - void (*func_recv) (int); - void (*func_send) (int); - /// This is the important one - /// Set to different functions depending on whether the connection - /// is a player or a server/ladmin - /// Can be set explicitly or via set_defaultparse - void (*func_parse) (int); - /// Server-specific data type - void *session_data; -}; - -// save file descriptors for important stuff -# define SOFT_LIMIT (FD_SETSIZE - 50) - -// socket timeout to establish a full connection in seconds -# define CONNECT_TIMEOUT 15 - -/// Everyone who has connected -// note: call delete_session(i) to null out an element -extern struct socket_data *session[FD_SETSIZE]; - -/// Maximum used FD, +1 -extern int fd_max; - -/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, -/// but exit if bind() or listen() fails -int make_listen_port (uint16_t port); -/// Connect to an address, return a connected socket or -1 -// FIXME - this is IPv4 only! -int make_connection (uint32_t ip, uint16_t port); -/// free() the structure and close() the fd -void delete_session (int); -/// Make a the internal queues bigger -void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size); -/// Update all sockets that can be read/written from the queues -void do_sendrecv (uint32_t next); -/// Call the parser function for every socket that has read data -void do_parsepacket (void); - -/// An init function -void do_socket (void); - -/// Change the default parser for newly connected clients -// typically called once per server, but individual clients may identify -// themselves as servers -void set_defaultparse (void (*defaultparse) (int)); - -/// Wrappers to track number of free FDs -void fclose_ (FILE * fp); -FILE *fopen_ (const char *path, const char *mode); -bool free_fds (void); - -#endif // SOCKET_H diff --git a/src/common/socket.hpp b/src/common/socket.hpp new file mode 100644 index 0000000..00f2df0 --- /dev/null +++ b/src/common/socket.hpp @@ -0,0 +1,135 @@ +#ifndef SOCKET_HPP +#define SOCKET_HPP + +# include "sanity.hpp" + +# include + +# include +# include +# include + +# include + +/// Check how much can be read +# define RFIFOREST(fd) (session[fd]->rdata_size-session[fd]->rdata_pos) +/// Read from the queue +# define RFIFOP(fd,pos) (session[fd]->rdata+session[fd]->rdata_pos+(pos)) +# define RFIFOB(fd,pos) (*(uint8_t*)(RFIFOP(fd, pos))) +# define RFIFOW(fd,pos) (*(uint16_t*)(RFIFOP(fd, pos))) +# define RFIFOL(fd,pos) (*(uint32_t*)(RFIFOP(fd, pos))) +/// Done reading +void RFIFOSKIP (int fd, size_t len); +/// Internal - clean up by discarding handled bytes +// Atm this is also called in char/char.c, but that is unnecessary +# define RFIFOFLUSH(fd) (memmove(session[fd]->rdata,RFIFOP(fd,0),RFIFOREST(fd)),\ +session[fd]->rdata_size=RFIFOREST(fd),\ +session[fd]->rdata_pos=0) + +/// Used internally - how much room there is to read more data +# define RFIFOSPACE(fd) (session[fd]->max_rdata-session[fd]->rdata_size) + +/// Read from an arbitrary buffer +# define RBUFP(p,pos) (((uint8_t*)(p))+(pos)) +# define RBUFB(p,pos) (*(uint8_t*)RBUFP((p),(pos))) +# define RBUFW(p,pos) (*(uint16_t*)RBUFP((p),(pos))) +# define RBUFL(p,pos) (*(uint32_t*)RBUFP((p),(pos))) + + + +/// Unused - check how much data can be written +# define WFIFOSPACE(fd) (session[fd]->max_wdata-session[fd]->wdata_size) +/// Write to the queue +# define WFIFOP(fd,pos) (session[fd]->wdata+session[fd]->wdata_size+(pos)) +# define WFIFOB(fd,pos) (*(uint8_t*)(WFIFOP(fd,pos))) +# define WFIFOW(fd,pos) (*(uint16_t*)(WFIFOP(fd,pos))) +# define WFIFOL(fd,pos) (*(uint32_t*)(WFIFOP(fd,pos))) +/// Finish writing +void WFIFOSET (int fd, size_t len); + +/// Write to an arbitrary buffer +#define WBUFP(p,pos) (((uint8_t*)(p))+(pos)) +#define WBUFB(p,pos) (*(uint8_t*)WBUFP((p),(pos))) +#define WBUFW(p,pos) (*(uint16_t*)WBUFP((p),(pos))) +#define WBUFL(p,pos) (*(uint32_t*)WBUFP((p),(pos))) + +// Struct declaration + +struct socket_data +{ + /// Checks whether a newly-connected socket actually does anything + time_t created; + bool connected; + + /// Flag needed since structure must be freed in a server-dependent manner + bool eof; + + /// Since this is a single-threaded application, it can't block + /// These are the read/write queues + uint8_t *rdata, *wdata; + size_t max_rdata, max_wdata; + /// How much is actually in the queue + size_t rdata_size, wdata_size; + /// How much has already been read from the queue + /// Note that there is no need for a wdata_pos + size_t rdata_pos; + + struct sockaddr_in client_addr; + + /// Send or recieve + /// Only called when select() indicates the socket is ready + /// If, after that, nothing is read, it sets eof + // These could probably be hard-coded with a little work + void (*func_recv) (int); + void (*func_send) (int); + /// This is the important one + /// Set to different functions depending on whether the connection + /// is a player or a server/ladmin + /// Can be set explicitly or via set_defaultparse + void (*func_parse) (int); + /// Server-specific data type + void *session_data; +}; + +// save file descriptors for important stuff +# define SOFT_LIMIT (FD_SETSIZE - 50) + +// socket timeout to establish a full connection in seconds +# define CONNECT_TIMEOUT 15 + +/// Everyone who has connected +// note: call delete_session(i) to null out an element +extern struct socket_data *session[FD_SETSIZE]; + +/// Maximum used FD, +1 +extern int fd_max; + +/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, +/// but exit if bind() or listen() fails +int make_listen_port (uint16_t port); +/// Connect to an address, return a connected socket or -1 +// FIXME - this is IPv4 only! +int make_connection (uint32_t ip, uint16_t port); +/// free() the structure and close() the fd +void delete_session (int); +/// Make a the internal queues bigger +void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size); +/// Update all sockets that can be read/written from the queues +void do_sendrecv (uint32_t next); +/// Call the parser function for every socket that has read data +void do_parsepacket (void); + +/// An init function +void do_socket (void); + +/// Change the default parser for newly connected clients +// typically called once per server, but individual clients may identify +// themselves as servers +void set_defaultparse (void (*defaultparse) (int)); + +/// Wrappers to track number of free FDs +void fclose_ (FILE * fp); +FILE *fopen_ (const char *path, const char *mode); +bool free_fds (void); + +#endif // SOCKET_HPP diff --git a/src/common/timer.c b/src/common/timer.c deleted file mode 100644 index 6795824..0000000 --- a/src/common/timer.c +++ /dev/null @@ -1,257 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "timer.h" -#include "utils.h" - -static struct TimerData *timer_data; -static uint32_t timer_data_max, timer_data_num; -static timer_id *free_timer_list; -static uint32_t free_timer_list_max, free_timer_list_pos; - -/// Okay, I think I understand this structure now: -/// the timer heap is a magic queue that allows inserting timers and then popping them in order -/// designed to copy only log2(N) entries instead of N -// timer_heap[0] is the size (greatest index into the heap) -// timer_heap[1] is the first actual element -// timer_heap_max increases 256 at a time and never decreases -static uint32_t timer_heap_max = 0; -/// FIXME: refactor the code to put the size in a separate variable -//nontrivial because indices get multiplied -static timer_id *timer_heap = NULL; - - -static uint32_t gettick_cache; -static uint8_t gettick_count = 0; - -uint32_t gettick_nocache (void) -{ - struct timeval tval; - // BUG: This will cause strange behavior if the system clock is changed! - // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) - gettimeofday (&tval, NULL); - gettick_count = 255; - return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; -} - -uint32_t gettick (void) -{ - if (gettick_count--) - return gettick_cache; - return gettick_nocache (); -} - -static void push_timer_heap (timer_id index) -{ - if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) - { - timer_heap_max += 256; - RECREATE (timer_heap, timer_id, timer_heap_max); - memset (timer_heap + (timer_heap_max - 256), 0, sizeof (timer_id) * 256); - } -// timer_heap[0] is the greatest index into the heap, which increases - timer_heap[0]++; - - timer_id h = timer_heap[0]-1, i = (h - 1) / 2; - while (h) - { - // avoid wraparound problems, it really means this: - // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick - if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0) - break; - timer_heap[h + 1] = timer_heap[i + 1]; - h = i; - i = (h - 1) / 2; - } - timer_heap[h + 1] = index; -} - -static timer_id top_timer_heap (void) -{ - if (!timer_heap || !timer_heap[0]) - return -1; - return timer_heap[1]; -} - -static timer_id pop_timer_heap (void) -{ - if (!timer_heap || !timer_heap[0]) - return -1; - timer_id ret = timer_heap[1]; - timer_id last = timer_heap[timer_heap[0]]; - timer_heap[0]--; - - uint32_t h, k; - for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2) - { - if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0) - k--; - timer_heap[h + 1] = timer_heap[k + 1], h = k; - } - if (k == timer_heap[0]) - timer_heap[h + 1] = timer_heap[k], h = k - 1; - - uint32_t i = (h - 1) / 2; - while (h) - { - if (DIFF_TICK (timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) - break; - timer_heap[h + 1] = timer_heap[i + 1]; - h = i; - i = (h - 1) / 2; - } - timer_heap[h + 1] = last; - - return ret; -} - -timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data) -{ - timer_id i; - - if (free_timer_list_pos) - { - // Retrieve a freed timer id instead of a new one - // I think it should be possible to avoid the loop somehow - do - { - i = free_timer_list[--free_timer_list_pos]; - } - while (i >= timer_data_num && free_timer_list_pos > 0); - } - else - i = timer_data_num; - - // I have no idea what this is doing - if (i >= timer_data_num) - for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++) - ; - if (i >= timer_data_num && i >= timer_data_max) - { - if (timer_data_max == 0) - { - timer_data_max = 256; - CREATE (timer_data, struct TimerData, timer_data_max); - } - else - { - timer_data_max += 256; - RECREATE (timer_data, struct TimerData, timer_data_max); - memset (timer_data + (timer_data_max - 256), 0, - sizeof (struct TimerData) * 256); - } - } - timer_data[i].tick = tick; - timer_data[i].func = func; - timer_data[i].id = id; - timer_data[i].data = data; - timer_data[i].type = TIMER_ONCE_AUTODEL; - timer_data[i].interval = 1000; - push_timer_heap (i); - if (i >= timer_data_num) - timer_data_num = i + 1; - return i; -} - -timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, - custom_data_t data, interval_t interval) -{ - timer_id tid = add_timer (tick, func, id, data); - timer_data[tid].type = TIMER_INTERVAL; - timer_data[tid].interval = interval; - return tid; -} - -void delete_timer (timer_id id, timer_func func) -{ - if (id == 0 || id >= timer_data_num) - { - fprintf (stderr, "delete_timer error : no such timer %d\n", id); - abort (); - } - if (timer_data[id].func != func) - { - fprintf (stderr, "Timer mismatch\n"); - abort (); - } - // "to let them disappear" - is this just in case? - timer_data[id].func = NULL; - timer_data[id].type = TIMER_ONCE_AUTODEL; - timer_data[id].tick -= 60 * 60 * 1000; -} - -tick_t addtick_timer (timer_id tid, interval_t tick) -{ - return timer_data[tid].tick += tick; -} - -struct TimerData *get_timer (timer_id tid) -{ - return &timer_data[tid]; -} - -interval_t do_timer (tick_t tick) -{ - timer_id i; - /// Number of milliseconds until it calls this again - // this says to wait 1 sec if all timers get popped - interval_t nextmin = 1000; - - while ((i = top_timer_heap ()) != (timer_id)-1) - { - // while the heap is not empty and - if (DIFF_TICK (timer_data[i].tick, tick) > 0) - { - /// Return the time until the next timer needs to goes off - nextmin = DIFF_TICK (timer_data[i].tick, tick); - break; - } - pop_timer_heap (); - if (timer_data[i].func) - { - if (DIFF_TICK (timer_data[i].tick, tick) < -1000) - { - // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems - timer_data[i].func (i, tick, timer_data[i].id, timer_data[i].data); - } - else - { - timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); - } - } - switch (timer_data[i].type) - { - case TIMER_ONCE_AUTODEL: - timer_data[i].type = TIMER_NONE; - if (free_timer_list_pos >= free_timer_list_max) - { - free_timer_list_max += 256; - RECREATE (free_timer_list, uint32_t, free_timer_list_max); - memset (free_timer_list + (free_timer_list_max - 256), - 0, 256 * sizeof (uint32_t)); - } - free_timer_list[free_timer_list_pos++] = i; - break; - case TIMER_INTERVAL: - if (DIFF_TICK (timer_data[i].tick, tick) < -1000) - { - timer_data[i].tick = tick + timer_data[i].interval; - } - else - { - timer_data[i].tick += timer_data[i].interval; - } - push_timer_heap (i); - break; - } - } - - if (nextmin < 10) - nextmin = 10; - return nextmin; -} diff --git a/src/common/timer.cpp b/src/common/timer.cpp new file mode 100644 index 0000000..66aaa9b --- /dev/null +++ b/src/common/timer.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include + +#include +#include + +#include "timer.hpp" +#include "utils.hpp" + +static struct TimerData *timer_data; +static uint32_t timer_data_max, timer_data_num; +static timer_id *free_timer_list; +static uint32_t free_timer_list_max, free_timer_list_pos; + +/// Okay, I think I understand this structure now: +/// the timer heap is a magic queue that allows inserting timers and then popping them in order +/// designed to copy only log2(N) entries instead of N +// timer_heap[0] is the size (greatest index into the heap) +// timer_heap[1] is the first actual element +// timer_heap_max increases 256 at a time and never decreases +static uint32_t timer_heap_max = 0; +/// FIXME: refactor the code to put the size in a separate variable +//nontrivial because indices get multiplied +static timer_id *timer_heap = NULL; + + +static uint32_t gettick_cache; +static uint8_t gettick_count = 0; + +uint32_t gettick_nocache (void) +{ + struct timeval tval; + // BUG: This will cause strange behavior if the system clock is changed! + // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, ) + gettimeofday (&tval, NULL); + gettick_count = 255; + return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000; +} + +uint32_t gettick (void) +{ + if (gettick_count--) + return gettick_cache; + return gettick_nocache (); +} + +static void push_timer_heap (timer_id index) +{ + if (timer_heap == NULL || timer_heap[0] + 1 >= timer_heap_max) + { + timer_heap_max += 256; + RECREATE (timer_heap, timer_id, timer_heap_max); + memset (timer_heap + (timer_heap_max - 256), 0, sizeof (timer_id) * 256); + } +// timer_heap[0] is the greatest index into the heap, which increases + timer_heap[0]++; + + timer_id h = timer_heap[0]-1, i = (h - 1) / 2; + while (h) + { + // avoid wraparound problems, it really means this: + // timer_data[index].tick >= timer_data[timer_heap[i+1]].tick + if ( DIFF_TICK(timer_data[index].tick, timer_data[timer_heap[i+1]].tick) >= 0) + break; + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + i = (h - 1) / 2; + } + timer_heap[h + 1] = index; +} + +static timer_id top_timer_heap (void) +{ + if (!timer_heap || !timer_heap[0]) + return -1; + return timer_heap[1]; +} + +static timer_id pop_timer_heap (void) +{ + if (!timer_heap || !timer_heap[0]) + return -1; + timer_id ret = timer_heap[1]; + timer_id last = timer_heap[timer_heap[0]]; + timer_heap[0]--; + + uint32_t h, k; + for (h = 0, k = 2; k < timer_heap[0]; k = k * 2 + 2) + { + if (DIFF_TICK(timer_data[timer_heap[k + 1]].tick, timer_data[timer_heap[k]].tick) > 0) + k--; + timer_heap[h + 1] = timer_heap[k + 1], h = k; + } + if (k == timer_heap[0]) + timer_heap[h + 1] = timer_heap[k], h = k - 1; + + uint32_t i = (h - 1) / 2; + while (h) + { + if (DIFF_TICK (timer_data[timer_heap[i + 1]].tick, timer_data[last].tick) <= 0) + break; + timer_heap[h + 1] = timer_heap[i + 1]; + h = i; + i = (h - 1) / 2; + } + timer_heap[h + 1] = last; + + return ret; +} + +timer_id add_timer (tick_t tick, timer_func func, custom_id_t id, custom_data_t data) +{ + timer_id i; + + if (free_timer_list_pos) + { + // Retrieve a freed timer id instead of a new one + // I think it should be possible to avoid the loop somehow + do + { + i = free_timer_list[--free_timer_list_pos]; + } + while (i >= timer_data_num && free_timer_list_pos > 0); + } + else + i = timer_data_num; + + // I have no idea what this is doing + if (i >= timer_data_num) + for (i = timer_data_num; i < timer_data_max && timer_data[i].type; i++) + ; + if (i >= timer_data_num && i >= timer_data_max) + { + if (timer_data_max == 0) + { + timer_data_max = 256; + CREATE (timer_data, struct TimerData, timer_data_max); + } + else + { + timer_data_max += 256; + RECREATE (timer_data, struct TimerData, timer_data_max); + memset (timer_data + (timer_data_max - 256), 0, + sizeof (struct TimerData) * 256); + } + } + timer_data[i].tick = tick; + timer_data[i].func = func; + timer_data[i].id = id; + timer_data[i].data = data; + timer_data[i].type = TIMER_ONCE_AUTODEL; + timer_data[i].interval = 1000; + push_timer_heap (i); + if (i >= timer_data_num) + timer_data_num = i + 1; + return i; +} + +timer_id add_timer_interval (tick_t tick, timer_func func, custom_id_t id, + custom_data_t data, interval_t interval) +{ + timer_id tid = add_timer (tick, func, id, data); + timer_data[tid].type = TIMER_INTERVAL; + timer_data[tid].interval = interval; + return tid; +} + +void delete_timer (timer_id id, timer_func func) +{ + if (id == 0 || id >= timer_data_num) + { + fprintf (stderr, "delete_timer error : no such timer %d\n", id); + abort (); + } + if (timer_data[id].func != func) + { + fprintf (stderr, "Timer mismatch\n"); + abort (); + } + // "to let them disappear" - is this just in case? + timer_data[id].func = NULL; + timer_data[id].type = TIMER_ONCE_AUTODEL; + timer_data[id].tick -= 60 * 60 * 1000; +} + +tick_t addtick_timer (timer_id tid, interval_t tick) +{ + return timer_data[tid].tick += tick; +} + +struct TimerData *get_timer (timer_id tid) +{ + return &timer_data[tid]; +} + +interval_t do_timer (tick_t tick) +{ + timer_id i; + /// Number of milliseconds until it calls this again + // this says to wait 1 sec if all timers get popped + interval_t nextmin = 1000; + + while ((i = top_timer_heap ()) != (timer_id)-1) + { + // while the heap is not empty and + if (DIFF_TICK (timer_data[i].tick, tick) > 0) + { + /// Return the time until the next timer needs to goes off + nextmin = DIFF_TICK (timer_data[i].tick, tick); + break; + } + pop_timer_heap (); + if (timer_data[i].func) + { + if (DIFF_TICK (timer_data[i].tick, tick) < -1000) + { + // If we are too far past the requested tick, call with the current tick instead to fix reregistering problems + timer_data[i].func (i, tick, timer_data[i].id, timer_data[i].data); + } + else + { + timer_data[i].func (i, timer_data[i].tick, timer_data[i].id, timer_data[i].data); + } + } + switch (timer_data[i].type) + { + case TIMER_ONCE_AUTODEL: + timer_data[i].type = TIMER_NONE; + if (free_timer_list_pos >= free_timer_list_max) + { + free_timer_list_max += 256; + RECREATE (free_timer_list, uint32_t, free_timer_list_max); + memset (free_timer_list + (free_timer_list_max - 256), + 0, 256 * sizeof (uint32_t)); + } + free_timer_list[free_timer_list_pos++] = i; + break; + case TIMER_INTERVAL: + if (DIFF_TICK (timer_data[i].tick, tick) < -1000) + { + timer_data[i].tick = tick + timer_data[i].interval; + } + else + { + timer_data[i].tick += timer_data[i].interval; + } + push_timer_heap (i); + break; + } + } + + if (nextmin < 10) + nextmin = 10; + return nextmin; +} diff --git a/src/common/timer.h b/src/common/timer.h deleted file mode 100644 index e6a292c..0000000 --- a/src/common/timer.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef TIMER_H -#define TIMER_H - -# include "sanity.h" - -enum TIMER_TYPE -{ - TIMER_NONE, - TIMER_ONCE_AUTODEL, - TIMER_INTERVAL, -}; -/// This is needed to produce a signed result when 2 ticks are subtracted -# define DIFF_TICK(a,b) ((int32_t)((a)-(b))) - -// TODO replace with signed 64-bit to make code more clear and protect from the future -typedef uint32_t tick_t; -typedef uint32_t interval_t; -typedef uint32_t timer_id; -// BUG: pointers are stored in here -typedef int32_t custom_id_t; -typedef int32_t custom_data_t; -typedef void (*timer_func) (timer_id, tick_t, custom_id_t, custom_data_t); - -struct TimerData -{ - /// When it will be triggered - tick_t tick; - /// What will be done - timer_func func; - /// Arbitrary data. WARNING, callers are stupid and put pointers in here - // Should we change to void* or intptr_t ? - custom_id_t id; - custom_data_t data; - /// Type of timer - 0 initially - enum TIMER_TYPE type; - /// Repeat rate - interval_t interval; -}; - -/// Server time, in milliseconds, since the epoch, -/// but use of 32-bit integers means it wraps every 49 days. -// The only external caller of this function is the core.c main loop, but that makes sense -// in fact, it might make more sense if gettick() ALWAYS returned that cached value -tick_t gettick_nocache (void); -/// This function is called enough that it's worth caching the result for -/// the next 255 times -tick_t gettick (void); - -timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); -timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interval_t); -void delete_timer (timer_id, timer_func); - -tick_t addtick_timer (timer_id, interval_t); -struct TimerData *get_timer (timer_id tid); - -/// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens -interval_t do_timer (tick_t tick); - - - -#endif // TIMER_H diff --git a/src/common/timer.hpp b/src/common/timer.hpp new file mode 100644 index 0000000..fdda344 --- /dev/null +++ b/src/common/timer.hpp @@ -0,0 +1,61 @@ +#ifndef TIMER_HPP +#define TIMER_HPP + +# include "sanity.hpp" + +enum TIMER_TYPE +{ + TIMER_NONE, + TIMER_ONCE_AUTODEL, + TIMER_INTERVAL, +}; +/// This is needed to produce a signed result when 2 ticks are subtracted +# define DIFF_TICK(a,b) ((int32_t)((a)-(b))) + +// TODO replace with signed 64-bit to make code more clear and protect from the future +typedef uint32_t tick_t; +typedef uint32_t interval_t; +typedef uint32_t timer_id; +// BUG: pointers are stored in here +typedef int32_t custom_id_t; +typedef int32_t custom_data_t; +typedef void (*timer_func) (timer_id, tick_t, custom_id_t, custom_data_t); + +struct TimerData +{ + /// When it will be triggered + tick_t tick; + /// What will be done + timer_func func; + /// Arbitrary data. WARNING, callers are stupid and put pointers in here + // Should we change to void* or intptr_t ? + custom_id_t id; + custom_data_t data; + /// Type of timer - 0 initially + enum TIMER_TYPE type; + /// Repeat rate + interval_t interval; +}; + +/// Server time, in milliseconds, since the epoch, +/// but use of 32-bit integers means it wraps every 49 days. +// The only external caller of this function is the core.c main loop, but that makes sense +// in fact, it might make more sense if gettick() ALWAYS returned that cached value +tick_t gettick_nocache (void); +/// This function is called enough that it's worth caching the result for +/// the next 255 times +tick_t gettick (void); + +timer_id add_timer (tick_t, timer_func, custom_id_t, custom_data_t); +timer_id add_timer_interval (tick_t, timer_func, custom_id_t, custom_data_t, interval_t); +void delete_timer (timer_id, timer_func); + +tick_t addtick_timer (timer_id, interval_t); +struct TimerData *get_timer (timer_id tid); + +/// Do all timers scheduled before tick, and return the number of milliseconds until the next timer happens +interval_t do_timer (tick_t tick); + + + +#endif // TIMER_HPP diff --git a/src/common/utils.h b/src/common/utils.h deleted file mode 100644 index 961d960..0000000 --- a/src/common/utils.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H -/* -Notes about memory allocation in tmwAthena: -There used to be 3 sources of allocation: these macros, -a{C,M,Re}alloc in common/malloc.{h,c}, and direct calls. -I deleted malloc.{h,c} because it was redundant; -future calls should either use this or depend on the coming segfault. -*/ -# define CREATE(result, type, number) \ - if (!((result) = (type *) calloc ((number), sizeof(type)))) \ - { perror("SYSERR: malloc failure"); abort(); } else (void)0 - -# define RECREATE(result,type,number) \ - if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\ - { perror("SYSERR: realloc failure"); abort(); } else (void)0 - -#endif //UTILS_H diff --git a/src/common/utils.hpp b/src/common/utils.hpp new file mode 100644 index 0000000..7c7da16 --- /dev/null +++ b/src/common/utils.hpp @@ -0,0 +1,18 @@ +#ifndef UTILS_HPP +#define UTILS_HPP +/* +Notes about memory allocation in tmwAthena: +There used to be 3 sources of allocation: these macros, +a{C,M,Re}alloc in common/malloc.{h,c}, and direct calls. +I deleted malloc.{h,c} because it was redundant; +future calls should either use this or depend on the coming segfault. +*/ +# define CREATE(result, type, number) \ + if (!((result) = (type *) calloc ((number), sizeof(type)))) \ + { perror("SYSERR: malloc failure"); abort(); } else (void)0 + +# define RECREATE(result,type,number) \ + if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\ + { perror("SYSERR: realloc failure"); abort(); } else (void)0 + +#endif //UTILS_HPP diff --git a/src/common/version.h b/src/common/version.h deleted file mode 100644 index 46165aa..0000000 --- a/src/common/version.h +++ /dev/null @@ -1,24 +0,0 @@ -/// Some constants to identify the version of (e)Athena -/// The values are different if the client connects (-1,'T','M','W',flags32) -// These numbers have never been changed while TMW -#ifndef VERSION_H -#define VERSION_H -//When a server receives a 0x7530 packet from an admin connection, -//it sends an 0x7531 packet with the following bytes -# define ATHENA_MAJOR_VERSION 1 // Major Version -# define ATHENA_MINOR_VERSION 0 // Minor Version -# define ATHENA_REVISION 0 // Revision - -# define ATHENA_RELEASE_FLAG 1 // 1=Develop,0=Stable -# define ATHENA_OFFICIAL_FLAG 1 // 1=Mod,0=Official - -// and a bitmask of these (the char server sends char and inter) -# define ATHENA_SERVER_LOGIN 1 // login server -# define ATHENA_SERVER_CHAR 2 // char server -# define ATHENA_SERVER_INTER 4 // inter server -# define ATHENA_SERVER_MAP 8 // map server - -// and this as two bytes -# define ATHENA_MOD_VERSION 1052 // mod version (patch No.) - -#endif // VERSION_H diff --git a/src/common/version.hpp b/src/common/version.hpp new file mode 100644 index 0000000..d72f41e --- /dev/null +++ b/src/common/version.hpp @@ -0,0 +1,24 @@ +/// Some constants to identify the version of (e)Athena +/// The values are different if the client connects (-1,'T','M','W',flags32) +// These numbers have never been changed while TMW +#ifndef VERSION_HPP +#define VERSION_HPP +//When a server receives a 0x7530 packet from an admin connection, +//it sends an 0x7531 packet with the following bytes +# define ATHENA_MAJOR_VERSION 1 // Major Version +# define ATHENA_MINOR_VERSION 0 // Minor Version +# define ATHENA_REVISION 0 // Revision + +# define ATHENA_RELEASE_FLAG 1 // 1=Develop,0=Stable +# define ATHENA_OFFICIAL_FLAG 1 // 1=Mod,0=Official + +// and a bitmask of these (the char server sends char and inter) +# define ATHENA_SERVER_LOGIN 1 // login server +# define ATHENA_SERVER_CHAR 2 // char server +# define ATHENA_SERVER_INTER 4 // inter server +# define ATHENA_SERVER_MAP 8 // map server + +// and this as two bytes +# define ATHENA_MOD_VERSION 1052 // mod version (patch No.) + +#endif // VERSION_HPP -- cgit v1.2.3-60-g2f50