diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/HPM.c | 10 | ||||
-rw-r--r-- | src/common/console.c | 12 | ||||
-rw-r--r-- | src/common/core.c | 10 | ||||
-rw-r--r-- | src/common/db.c | 1 | ||||
-rw-r--r-- | src/common/ers.c | 21 | ||||
-rw-r--r-- | src/common/ers.h | 6 | ||||
-rw-r--r-- | src/common/malloc.c | 146 | ||||
-rw-r--r-- | src/common/malloc.h | 16 | ||||
-rw-r--r-- | src/common/mmo.h | 16 | ||||
-rw-r--r-- | src/common/mutex.c | 2 | ||||
-rw-r--r-- | src/common/random.c | 2 | ||||
-rw-r--r-- | src/common/socket.c | 72 | ||||
-rw-r--r-- | src/common/socket.h | 14 | ||||
-rw-r--r-- | src/common/sql.c | 149 | ||||
-rw-r--r-- | src/common/sql.h | 192 | ||||
-rw-r--r-- | src/common/strlib.h | 10 | ||||
-rw-r--r-- | src/common/timer.c | 37 | ||||
-rw-r--r-- | src/common/timer.h | 41 |
18 files changed, 467 insertions, 290 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c index 28ea8f413..9283360dc 100644 --- a/src/common/HPM.c +++ b/src/common/HPM.c @@ -265,7 +265,7 @@ void hplugins_share_defaults(void) { HPM->share((void*)get_svn_revision,"get_svn_revision"); HPM->share((void*)get_git_hash,"get_git_hash"); HPM->share(DB, "DB"); - HPM->share(malloclib, "malloclib"); + HPM->share(iMalloc, "iMalloc"); /* socket */ HPM->share(RFIFOSKIP,"RFIFOSKIP"); HPM->share(WFIFOSET,"WFIFOSET"); @@ -281,12 +281,8 @@ void hplugins_share_defaults(void) { /* sql */ HPM->share(SQL,"SQL"); /* timer */ - HPM->share(gettick,"gettick"); - HPM->share(add_timer,"add_timer"); - HPM->share(add_timer_interval,"add_timer_interval"); - HPM->share(add_timer_func_list,"add_timer_func_list"); - HPM->share(delete_timer,"delete_timer"); - HPM->share(get_uptime,"get_uptime"); + HPM->share(iTimer,"iTimer"); + } CPCMD(plugins) { if( HPM->plugin_count == 0 ) { diff --git a/src/common/console.c b/src/common/console.c index ba93b8e09..08daec04e 100644 --- a/src/common/console.c +++ b/src/common/console.c @@ -85,6 +85,9 @@ CPCMD(exit) { CPCMD(ers_report) { ers_report(); } +CPCMD(mem_report) { + memmgr_report(line?atoi(line):0); +} CPCMD(help) { unsigned int i = 0; for ( i = 0; i < console->cmd_list_count; i++ ) { @@ -98,7 +101,7 @@ CPCMD(help) { } /* [Ind/Hercules] */ CPCMD(malloc_usage) { - unsigned int val = (unsigned int)malloclib->usage(); + unsigned int val = (unsigned int)iMalloc->usage(); ShowInfo("malloc_usage: %.2f MB\n",(double)(val)/1024); } #define CP_DEF_C(x) { #x , NULL , NULL, NULL } @@ -115,6 +118,7 @@ void console_load_defaults(void) { CP_DEF(help), CP_DEF_C(server), CP_DEF_S(ers_report,server), + CP_DEF_S(mem_report,server), CP_DEF_S(malloc_usage,server), CP_DEF_S(exit,server), }; @@ -227,8 +231,10 @@ void console_parse_sub(char *line) { char *tok; char sublist[CP_CMD_LENGTH * 5]; unsigned int i, len = 0; + memcpy(bline, line, 200); tok = strtok(line, " "); + for ( i = 0; i < console->cmd_list_count; i++ ) { if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 ) break; @@ -363,8 +369,8 @@ void console_parse_init(void) { exit(EXIT_FAILURE); } - add_timer_func_list(console->parse_timer, "console_parse_timer"); - add_timer_interval(gettick() + 1000, console->parse_timer, 0, 0, 500);/* start listening in 1s; re-try every 0.5s */ + iTimer->add_timer_func_list(console->parse_timer, "console_parse_timer"); + iTimer->add_timer_interval(iTimer->gettick() + 1000, console->parse_timer, 0, 0, 500);/* start listening in 1s; re-try every 0.5s */ } #endif /* CONSOLE_INPUT */ diff --git a/src/common/core.c b/src/common/core.c index 0959e6fc9..c53d2243b 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -307,7 +307,7 @@ int main (int argc, char **argv) { } core_defaults(); - malloclib->init();// needed for Show* in display_title() [FlavioJS] + iMalloc->init();// needed for Show* in display_title() [FlavioJS] console->display_title(); @@ -329,7 +329,7 @@ int main (int argc, char **argv) { cevents_init(); #endif - timer_init(); + iTimer->init(); console->init(); @@ -343,7 +343,7 @@ int main (int argc, char **argv) { {// Main runtime cycle int next; while (runflag != CORE_ST_STOP) { - next = do_timer(gettick_nocache()); + next = iTimer->do_timer(iTimer->gettick_nocache()); do_sockets(next); } } @@ -354,14 +354,14 @@ int main (int argc, char **argv) { #ifndef MINICORE HPM->final(); #endif - timer_final(); + iTimer->final(); socket_final(); DB->final(); mempool_final(); rathread_final(); #endif - malloclib->final(); + iMalloc->final(); return 0; } diff --git a/src/common/db.c b/src/common/db.c index 561371787..99c758a8d 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -2611,6 +2611,7 @@ void* db_data2ptr(DBData *data) void db_init(void) { db_iterator_ers = ers_new(sizeof(struct DBIterator_impl),"db.c::db_iterator_ers",ERS_OPT_NONE); db_alloc_ers = ers_new(sizeof(struct DBMap_impl),"db.c::db_alloc_ers",ERS_OPT_NONE); + ers_chunk_size(db_alloc_ers, 50); DB_COUNTSTAT(db_init); } diff --git a/src/common/ers.c b/src/common/ers.c index 69b7609d6..22269a51f 100644 --- a/src/common/ers.c +++ b/src/common/ers.c @@ -84,6 +84,9 @@ typedef struct ers_cache // Objects in-use count unsigned int UsedObjs; + // Default = ERS_BLOCK_ENTRIES, can be adjusted for performance for individual cache sizes. + unsigned int ChunkSize; + // Linked list struct ers_cache *Next, *Prev; } ers_cache_t; @@ -136,6 +139,7 @@ static ers_cache_t *ers_find_cache(unsigned int size) cache->Used = 0; cache->UsedObjs = 0; cache->Max = 0; + cache->ChunkSize = ERS_BLOCK_ENTRIES; if (CacheList == NULL) { @@ -200,10 +204,10 @@ static void *ers_obj_alloc_entry(ERS self) RECREATE(instance->Cache->Blocks, unsigned char *, instance->Cache->Max); } - CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * ERS_BLOCK_ENTRIES); + CREATE(instance->Cache->Blocks[instance->Cache->Used], unsigned char, instance->Cache->ObjectSize * instance->Cache->ChunkSize); instance->Cache->Used++; - instance->Cache->Free = ERS_BLOCK_ENTRIES -1; + instance->Cache->Free = instance->Cache->ChunkSize -1; ret = &instance->Cache->Blocks[instance->Cache->Used - 1][instance->Cache->Free * instance->Cache->ObjectSize + sizeof(struct ers_list)]; } @@ -286,6 +290,18 @@ static void ers_obj_destroy(ERS self) aFree(instance); } +void ers_cache_size(ERS self, unsigned int new_size) { + struct ers_instance_t *instance = (struct ers_instance_t *)self; + + if (instance == NULL) {//change as per piotrhalaczkiewicz comment + ShowError("ers_cache_size: NULL object, skipping...\n"); + return; + } + + instance->Cache->ChunkSize = new_size; +} + + ERS ers_new(uint32 size, char *name, enum ERSOptions options) { struct ers_instance_t *instance; @@ -299,6 +315,7 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options) instance->VTable.free = ers_obj_free_entry; instance->VTable.entry_size = ers_obj_entry_size; instance->VTable.destroy = ers_obj_destroy; + instance->VTable.chunk_size = ers_cache_size; instance->Name = ( options & ERS_OPT_FREE_NAME ) ? aStrdup(name) : name; instance->Options = options; diff --git a/src/common/ers.h b/src/common/ers.h index 4871d8d50..51701d778 100644 --- a/src/common/ers.h +++ b/src/common/ers.h @@ -119,6 +119,8 @@ typedef struct eri { */ void (*destroy)(struct eri *self); + /* */ + void (*chunk_size) (struct eri *self, unsigned int new_size); } *ERS; #ifdef DISABLE_ERS @@ -127,6 +129,7 @@ typedef struct eri { # define ers_free(obj,entry) aFree(entry) # define ers_entry_size(obj) (size_t)0 # define ers_destroy(obj) +# define ers_chunk_size(obj,size) // Disable the public functions # define ers_new(size,name,options) NULL # define ers_report() @@ -138,6 +141,7 @@ typedef struct eri { # define ers_free(obj,entry) (obj)->free((obj),(entry)) # define ers_entry_size(obj) (obj)->entry_size(obj) # define ers_destroy(obj) (obj)->destroy(obj) +# define ers_chunk_size(obj,size) (obj)->chunk_size(obj,size) /** * Get a new instance of the manager that handles the specified entry size. @@ -154,7 +158,7 @@ ERS ers_new(uint32 size, char *name, enum ERSOptions options); /** * Print a report about the current state of the Entry Reusage System. * Shows information about the global system and each entry manager. - * The number of entries are checked and a warning is shown if extra reusable + * The number of entries are checked and a warning is shown if extra reusable * entries are found. * The extra entries are included in the count of reusable entries. */ diff --git a/src/common/malloc.c b/src/common/malloc.c index 592027f56..d629aa63f 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -200,6 +200,8 @@ static struct unit_head_large *unit_head_large_first = NULL; static struct block* block_malloc(unsigned short hash); static void block_free(struct block* p); static size_t memmgr_usage_bytes; +static size_t memmgr_usage_bytes_t; + #define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ])) #define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0) @@ -245,6 +247,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) /* At that time, the distinction by assigning NULL to unit_head.block */ if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) { struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func); + memmgr_usage_bytes_t += size+sizeof(struct unit_head_large); if(p != NULL) { p->size = size; p->unit_head.block = NULL; @@ -332,7 +335,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func ) void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) { - void *p = malloclib->malloc(num * size,file,line,func); + void *p = iMalloc->malloc(num * size,file,line,func); memset(p,0,num * size); return p; } @@ -341,7 +344,7 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c { size_t old_size; if(memblock == NULL) { - return malloclib->malloc(size,file,line,func); + return iMalloc->malloc(size,file,line,func); } old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size; @@ -353,11 +356,11 @@ void* _mrealloc(void *memblock, size_t size, const char *file, int line, const c return memblock; } else { // Size Large - void *p = malloclib->malloc(size,file,line,func); + void *p = iMalloc->malloc(size,file,line,func); if(p != NULL) { memcpy(p,memblock,old_size); } - malloclib->free(memblock,file,line,func); + iMalloc->free(memblock,file,line,func); return p; } } @@ -368,7 +371,7 @@ char* _mstrdup(const char *p, const char *file, int line, const char *func ) return NULL; } else { size_t len = strlen(p); - char *string = (char *)malloclib->malloc(len + 1,file,line,func); + char *string = (char *)iMalloc->malloc(len + 1,file,line,func); memcpy(string,p,len+1); return string; } @@ -401,6 +404,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) head_large->next->prev = head_large->prev; } memmgr_usage_bytes -= head_large->size; + memmgr_usage_bytes_t -= head_large->size + sizeof(struct unit_head_large); #ifdef DEBUG_MEMMGR // set freed memory to 0xfd memset(ptr, 0xfd, head_large->size); @@ -457,6 +461,7 @@ static struct block* block_malloc(unsigned short hash) } else { /* Newly allocated space for the block */ p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); + memmgr_usage_bytes_t += sizeof(struct block) * (BLOCK_ALLOC); if(p == NULL) { ShowFatalError("Memory manager::block_alloc failed.\n"); exit(EXIT_FAILURE); @@ -621,7 +626,7 @@ static void memmgr_final (void) memmgr_log (buf); #endif /* LOG_MEMMGR */ // get block pointer and free it [celest] - malloclib->free(ptr, ALC_MARK); + iMalloc->free(ptr, ALC_MARK); } } } @@ -650,6 +655,86 @@ static void memmgr_final (void) } #endif /* LOG_MEMMGR */ } +/* [Ind/Hercules] */ +void memmgr_report (int extra) { + struct block *block = block_first; + struct unit_head_large *large = unit_head_large_first; + unsigned int count = 0, size = 0; + int j; + unsigned short msize = 1024; + struct { + const char *file; + unsigned short line; + unsigned int size; + unsigned int count; + } data[100]; + memset(&data, 0, sizeof(data)); + + if( extra != 0 ) + msize = extra; + + while (block) { + if (block->unit_used) { + int i; + for (i = 0; i < block->unit_maxused; i++) { + struct unit_head *head = block2unit(block, i); + if( head->block != NULL && head->size > msize ) { + for( j = 0; j < 100; j++ ) { + if( data[j].file == head->file && data[j].line == head->line ) { + data[j].size += head->size; + data[j].count += 1; + break; + } else if( data[j].size == 0 ) { + data[j].file = head->file; + data[j].line = head->line; + data[j].size = head->size; + data[j].count += 1; + break; + } + } + size += (unsigned int)head->size; + count++; + } + } + } + block = block->block_next; + } + + while(large) { + if( large->size > msize ) { + for( j = 0; j < 100; j++ ) { + if( data[j].file == large->unit_head.file && data[j].line == large->unit_head.line ) { + data[j].size += large->size; + data[j].count += 1; + break; + } else if( data[j].size == 0 ) { + data[j].file = large->unit_head.file; + data[j].line = large->unit_head.line; + data[j].size = large->size; + data[j].count += 1; + break; + } + } + size += (unsigned int)large->size; + count++; + } + large = large->next; + } + for( j = 0; j < 100; j++ ) { + if( data[j].size != 0 ) { + ShowMessage("[malloc] : "CL_WHITE"%s"CL_RESET":"CL_WHITE"%d"CL_RESET" %d instances => %.2f MB\n",data[j].file,data[j].line,data[j].count,(double)((data[j].size)/1024)/1024); + } + } + ShowMessage("[malloc] : reporting %u instances | %.2f MB\n",count,(double)((size)/1024)/1024); + ShowMessage("[malloc] : internal usage %.2f MB | %.2f MB\n",(double)((memmgr_usage_bytes_t-memmgr_usage_bytes)/1024)/1024,(double)((memmgr_usage_bytes_t)/1024)/1024); + + if( extra ) { + ShowMessage("[malloc] : unit_head_large: %d bytes\n",sizeof(struct unit_head_large)); + ShowMessage("[malloc] : unit_head: %d bytes\n",sizeof(struct unit_head)); + ShowMessage("[malloc] : block: %d bytes\n",sizeof(struct block)); + } + +} static void memmgr_init (void) { @@ -677,8 +762,7 @@ void malloc_memory_check(void) /// Returns true if a pointer is valid. /// The check is best-effort, false positives are possible. -bool malloc_verify_ptr(void* ptr) -{ +bool malloc_verify_ptr(void* ptr) { #ifdef USE_MEMMGR return memmgr_verify(ptr) && MEMORY_VERIFY(ptr); #else @@ -687,8 +771,7 @@ bool malloc_verify_ptr(void* ptr) } -size_t malloc_usage (void) -{ +size_t malloc_usage (void) { #ifdef USE_MEMMGR return memmgr_usage (); #else @@ -696,16 +779,16 @@ size_t malloc_usage (void) #endif } -void malloc_final (void) -{ +void malloc_final (void) { #ifdef USE_MEMMGR memmgr_final (); #endif MEMORY_CHECK(); } -void malloc_init (void) -{ +void malloc_init (void) { + memmgr_usage_bytes_t = 0; + memmgr_usage_bytes = 0; #if defined(DMALLOC) && defined(CYGWIN) // http://dmalloc.com/docs/latest/online/dmalloc_19.html dmalloc_debug_setup(getenv("DMALLOC_OPTIONS")); @@ -720,27 +803,26 @@ void malloc_init (void) #endif } -void malloc_defaults() -{ - malloclib = &malloclib_s; - malloclib->init = malloc_init; - malloclib->final = malloc_final; - malloclib->memory_check = malloc_memory_check; - malloclib->usage = malloc_usage; - malloclib->verify_ptr = malloc_verify_ptr; +void malloc_defaults(void) { + iMalloc = &iMalloc_s; + iMalloc->init = malloc_init; + iMalloc->final = malloc_final; + iMalloc->memory_check = malloc_memory_check; + iMalloc->usage = malloc_usage; + iMalloc->verify_ptr = malloc_verify_ptr; // Athena's built-in Memory Manager #ifdef USE_MEMMGR - malloclib->malloc = _mmalloc; - malloclib->calloc = _mcalloc; - malloclib->realloc = _mrealloc; - malloclib->astrdup = _mstrdup; - malloclib->free = _mfree; + iMalloc->malloc = _mmalloc; + iMalloc->calloc = _mcalloc; + iMalloc->realloc = _mrealloc; + iMalloc->astrdup = _mstrdup; + iMalloc->free = _mfree; #else - malloclib->malloc = aMalloc_; - malloclib->calloc = aCalloc_; - malloclib->realloc = aRealloc_; - malloclib->astrdup = aStrdup_; - malloclib->free = aFree_; + iMalloc->malloc = aMalloc_; + iMalloc->calloc = aCalloc_; + iMalloc->realloc = aRealloc_; + iMalloc->astrdup = aStrdup_; + iMalloc->free = aFree_; #endif } diff --git a/src/common/malloc.h b/src/common/malloc.h index 34a26b56e..834781905 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -30,11 +30,11 @@ #undef LOG_MEMMGR #endif -# define aMalloc(n) malloclib->malloc (n,ALC_MARK) -# define aCalloc(m,n) malloclib->calloc (m,n,ALC_MARK) -# define aRealloc(p,n) malloclib->realloc (p,n,ALC_MARK) -# define aStrdup(p) malloclib->astrdup (p,ALC_MARK) -# define aFree(p) malloclib->free (p,ALC_MARK) +# define aMalloc(n) iMalloc->malloc (n,ALC_MARK) +# define aCalloc(m,n) iMalloc->calloc (m,n,ALC_MARK) +# define aRealloc(p,n) iMalloc->realloc (p,n,ALC_MARK) +# define aStrdup(p) iMalloc->astrdup (p,ALC_MARK) +# define aFree(p) iMalloc->free (p,ALC_MARK) /////////////// Buffer Creation ///////////////// // Full credit for this goes to Shinomori [Ajarn] @@ -78,7 +78,9 @@ struct malloc_interface { size_t (*usage) (void); void (*init) (void); void (*final) (void); -} malloclib_s; +} iMalloc_s; -struct malloc_interface *malloclib; +void memmgr_report (int extra); + +struct malloc_interface *iMalloc; #endif /* _MALLOC_H_ */ diff --git a/src/common/mmo.h b/src/common/mmo.h index 172b27b15..8643d2b54 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -54,6 +54,13 @@ // Comment the following line if your client is NOT ragexeRE (required because of conflicting packets in ragexe vs ragexeRE). #define PACKETVER_RE +// Client support for experimental RagexeRE UI present in 2012-04-10 and 2012-04-18 +#ifdef PACKETVER_RE +#if (PACKETVER == 20120410) || (PACKETVER == 20120418) + #define PARTY_RECRUIT +#endif +#endif + // Comment the following line to disable sc_data saving. [Skotlex] #define ENABLE_SC_SAVING @@ -72,7 +79,6 @@ #define MAX_HOTKEYS 38 #endif -#define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps #define MAX_INVENTORY 100 //Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well. #define MAX_CHARS 9 @@ -84,7 +90,7 @@ #define MAX_ZENY 1000000000 #define MAX_FAME 1000000000 #define MAX_CART 100 -#define MAX_SKILL 1477 +#define MAX_SKILL 1478 #define MAX_SKILL_ID 10015 // [Ind/Hercules] max used skill ID #define GLOBAL_REG_NUM 256 // Max permanent character variables per char #define ACCOUNT_REG_NUM 64 // Max permanent local account variables per account @@ -104,7 +110,7 @@ #define MAX_GUILDSKILL 15 // Increased max guild skills because of new skills [Sara-chan] #define MAX_GUILDLEVEL 50 #define MAX_GUARDIANS 8 // Local max per castle. [Skotlex] -#define MAX_QUEST_DB 2400 // Max quests that the server will load +#define MAX_QUEST_DB 2410 // Max quests that the server will load #define MAX_QUEST_OBJECTIVES 3 // Max quest objectives for a quest #define MAX_START_ITEMS 32 // Max number of items allowed to be given to a char whenever it's created. [mkbu95] @@ -527,6 +533,10 @@ struct guild { /* TODO: still used for something?|: */ unsigned short save_flag; // for TXT saving + + unsigned short *instance; + unsigned short instances; + void *channel; }; diff --git a/src/common/mutex.c b/src/common/mutex.c index 6b4f55119..6bb1efdab 100644 --- a/src/common/mutex.c +++ b/src/common/mutex.c @@ -201,7 +201,7 @@ void racond_wait( racond c, ramutex m, sysint timeout_ticks){ pthread_cond_wait( &c->hCond, &m->hMutex ); }else{ struct timespec wtime; - int64 exact_timeout = gettick() + timeout_ticks; + int64 exact_timeout = iTimer->gettick() + timeout_ticks; wtime.tv_sec = exact_timeout/1000; wtime.tv_nsec = (exact_timeout%1000)*1000000; diff --git a/src/common/random.c b/src/common/random.c index 5c048c7eb..a7d432e34 100644 --- a/src/common/random.c +++ b/src/common/random.c @@ -17,7 +17,7 @@ /// Initializes the random number generator with an appropriate seed. void rnd_init(void) { - uint32 seed = gettick(); + uint32 seed = iTimer->gettick(); seed += (uint32)time(NULL); #if defined(WIN32) seed += GetCurrentProcessId(); diff --git a/src/common/socket.c b/src/common/socket.c index 5126d231b..15b20b16f 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -280,9 +280,10 @@ void set_nonblocking(int fd, unsigned long yes) ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg()); } -void setsocketopts(int fd) -{ +void setsocketopts(int fd, struct hSockOpt *opt) { int yes = 1; // reuse fix + struct linger lopt; + #if !defined(WIN32) // set SO_REAUSEADDR to true, unix only. on windows this option causes // the previous owner of the socket to give up, which is not desirable @@ -297,15 +298,22 @@ void setsocketopts(int fd) // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); + if( opt && opt->setTimeo ) { + struct timeval timeout; + + timeout.tv_sec = 5; + timeout.tv_usec = 0; + + sSetsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout)); + sSetsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout)); + } + // force the socket into no-wait, graceful-close mode (should be the default, but better make sure) //(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp) - { - struct linger opt; - opt.l_onoff = 0; // SO_DONTLINGER - opt.l_linger = 0; // Do not care - if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) ) + lopt.l_onoff = 0; // SO_DONTLINGER + lopt.l_linger = 0; // Do not care + if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&lopt, sizeof(lopt)) ) ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd); - } } /*====================================== @@ -404,8 +412,7 @@ void flush_fifos(void) /*====================================== * CORE : Connection functions *--------------------------------------*/ -int connect_client(int listen_fd) -{ +int connect_client(int listen_fd) { int fd; struct sockaddr_in client_address; socklen_t len; @@ -417,20 +424,18 @@ int connect_client(int listen_fd) ShowError("connect_client: accept failed (%s)!\n", error_msg()); return -1; } - if( fd == 0 ) - {// reserved + if( fd == 0 ) { // reserved ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n"); sClose(fd); return -1; } - if( fd >= FD_SETSIZE ) - {// socket number too big + if( fd >= FD_SETSIZE ) { // socket number too big ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); sClose(fd); return -1; } - setsocketopts(fd); + setsocketopts(fd,NULL); set_nonblocking(fd, 1); #ifndef MINICORE @@ -457,25 +462,22 @@ int make_listen_bind(uint32 ip, uint16 port) fd = sSocket(AF_INET, SOCK_STREAM, 0); - if( fd == -1 ) - { + if( fd == -1 ) { ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg()); exit(EXIT_FAILURE); } - if( fd == 0 ) - {// reserved + if( fd == 0 ) { // reserved ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n"); sClose(fd); return -1; } - if( fd >= FD_SETSIZE ) - {// socket number too big + if( fd >= FD_SETSIZE ) { // socket number too big ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); sClose(fd); return -1; } - setsocketopts(fd); + setsocketopts(fd,NULL); set_nonblocking(fd, 1); server_address.sin_family = AF_INET; @@ -503,7 +505,7 @@ int make_listen_bind(uint32 ip, uint16 port) return fd; } -int make_connection(uint32 ip, uint16 port, bool silent) { +int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) { struct sockaddr_in remote_address; int fd; int result; @@ -514,31 +516,29 @@ int make_connection(uint32 ip, uint16 port, bool silent) { ShowError("make_connection: socket creation failed (%s)!\n", error_msg()); return -1; } - if( fd == 0 ) - {// reserved + if( fd == 0 ) {// reserved ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n"); sClose(fd); return -1; } - if( fd >= FD_SETSIZE ) - {// socket number too big + if( fd >= FD_SETSIZE ) {// socket number too big ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE); sClose(fd); return -1; } - setsocketopts(fd); + setsocketopts(fd,opt); remote_address.sin_family = AF_INET; remote_address.sin_addr.s_addr = htonl(ip); remote_address.sin_port = htons(port); - if( !silent ) + if( !( opt && opt->silent ) ) ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port); result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in)); if( result == SOCKET_ERROR ) { - if( !silent ) + if( !( opt && opt->silent ) ) ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg()); do_close(fd); return -1; @@ -947,9 +947,9 @@ static int connect_check_(uint32 ip) if( hist->ddos ) {// flagged as DDoS return (connect_ok == 2 ? 1 : 0); - } else if( DIFF_TICK(gettick(),hist->tick) < ddos_interval ) + } else if( DIFF_TICK(iTimer->gettick(),hist->tick) < ddos_interval ) {// connection within ddos_interval - hist->tick = gettick(); + hist->tick = iTimer->gettick(); if( hist->count++ >= ddos_count ) {// DDoS attack detected hist->ddos = 1; @@ -959,7 +959,7 @@ static int connect_check_(uint32 ip) return connect_ok; } else {// not within ddos_interval, clear data - hist->tick = gettick(); + hist->tick = iTimer->gettick(); hist->count = 0; return connect_ok; } @@ -970,7 +970,7 @@ static int connect_check_(uint32 ip) CREATE(hist, ConnectHistory, 1); memset(hist, 0, sizeof(ConnectHistory)); hist->ip = ip; - hist->tick = gettick(); + hist->tick = iTimer->gettick(); hist->next = connect_history[ip&0xFFFF]; connect_history[ip&0xFFFF] = hist; return connect_ok; @@ -1331,8 +1331,8 @@ void socket_init(void) #ifndef MINICORE // Delete old connection history every 5 minutes memset(connect_history, 0, sizeof(connect_history)); - add_timer_func_list(connect_check_clear, "connect_check_clear"); - add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); + iTimer->add_timer_func_list(connect_check_clear, "connect_check_clear"); + iTimer->add_timer_interval(iTimer->gettick()+1000, connect_check_clear, 0, 0, 5*60*1000); #endif ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur); diff --git a/src/common/socket.h b/src/common/socket.h index 4879cb109..b58cbdccf 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -1,5 +1,6 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams #ifndef _SOCKET_H_ #define _SOCKET_H_ @@ -48,6 +49,9 @@ } \ } while(0) +/* [Ind/Hercules] */ +#define RFIFO2PTR(fd,len) (void*)(session[fd]->rdata + len) + // buffer I/O macros #define RBUFP(p,pos) (((uint8*)(p)) + (pos)) #define RBUFB(p,pos) (*(uint8*)RBUFP((p),(pos))) @@ -94,6 +98,10 @@ struct socket_data void* session_data; // stores application-specific data related to the session }; +struct hSockOpt { + unsigned int silent : 1; + unsigned int setTimeo : 1; +}; // Data prototype declaration @@ -113,7 +121,7 @@ extern bool session_isActive(int fd); // Function prototype declaration int make_listen_bind(uint32 ip, uint16 port); -int make_connection(uint32 ip, uint16 port, bool silent); +int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt); int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size); int realloc_writefifo(int fd, size_t addition); int WFIFOSET(int fd, size_t len); diff --git a/src/common/sql.c b/src/common/sql.c index 391211183..441b860da 100644 --- a/src/common/sql.c +++ b/src/common/sql.c @@ -116,9 +116,9 @@ int Sql_GetTimeout(Sql* self, uint32* out_timeout) size_t len; if( SQL_SUCCESS == SQL->NextRow(self) && SQL_SUCCESS == SQL->GetData(self, 1, &data, &len) ) { - *out_timeout = (uint32)strtoul(data, NULL, 10); - SQL->FreeResult(self); - return SQL_SUCCESS; + *out_timeout = (uint32)strtoul(data, NULL, 10); + SQL->FreeResult(self); + return SQL_SUCCESS; } SQL->FreeResult(self); } @@ -210,7 +210,7 @@ static int Sql_P_Keepalive(Sql* self) // establish keepalive ping_interval = timeout - 30; // 30-second reserve //add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer"); - return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); + return iTimer->add_timer_interval(iTimer->gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000); } @@ -404,7 +404,7 @@ void Sql_Free(Sql* self) { SQL->FreeResult(self); StrBuf->Destroy(&self->buf); - if( self->keepalive != INVALID_TIMER ) delete_timer(self->keepalive, Sql_P_KeepaliveTimer); + if( self->keepalive != INVALID_TIMER ) iTimer->delete_timer(self->keepalive, Sql_P_KeepaliveTimer); aFree(self); } } @@ -447,7 +447,7 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, case SQLDT_NULL: bind->buffer_type = MYSQL_TYPE_NULL; buffer_len = 0;// FIXME length = ? [FlavioJS] break; - // fixed size + // fixed size case SQLDT_UINT8: bind->is_unsigned = 1; case SQLDT_INT8: bind->buffer_type = MYSQL_TYPE_TINY; buffer_len = 1; @@ -464,7 +464,7 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, case SQLDT_INT64: bind->buffer_type = MYSQL_TYPE_LONGLONG; buffer_len = 8; break; - // platform dependent size + // platform dependent size case SQLDT_UCHAR: bind->is_unsigned = 1; case SQLDT_CHAR: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(char)); buffer_len = sizeof(char); @@ -485,14 +485,14 @@ static int Sql_P_BindSqlDataType(MYSQL_BIND* bind, enum SqlDataType buffer_type, case SQLDT_LONGLONG: bind->buffer_type = Sql_P_SizeToMysqlIntType(sizeof(int64)); buffer_len = sizeof(int64); break; - // floating point + // floating point case SQLDT_FLOAT: bind->buffer_type = MYSQL_TYPE_FLOAT; buffer_len = 4; break; case SQLDT_DOUBLE: bind->buffer_type = MYSQL_TYPE_DOUBLE; buffer_len = 8; break; - // other + // other case SQLDT_STRING: case SQLDT_ENUM: bind->buffer_type = MYSQL_TYPE_STRING; break; @@ -524,25 +524,25 @@ static void Sql_P_ShowDebugMysqlFieldInfo(const char* prefix, enum enum_field_ty ShowDebug("%stype=%s%u, length=%d\n", prefix, sign, type, length); return; #define SHOW_DEBUG_OF(x) case x: type_string = #x; break - SHOW_DEBUG_OF(MYSQL_TYPE_TINY); - SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); - SHOW_DEBUG_OF(MYSQL_TYPE_LONG); - SHOW_DEBUG_OF(MYSQL_TYPE_INT24); - SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); - SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); - SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); - SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); - SHOW_DEBUG_OF(MYSQL_TYPE_DATE); - SHOW_DEBUG_OF(MYSQL_TYPE_TIME); - SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); - SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); - SHOW_DEBUG_OF(MYSQL_TYPE_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); - SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); - SHOW_DEBUG_OF(MYSQL_TYPE_SET); - SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); - SHOW_DEBUG_OF(MYSQL_TYPE_NULL); + SHOW_DEBUG_OF(MYSQL_TYPE_TINY); + SHOW_DEBUG_OF(MYSQL_TYPE_SHORT); + SHOW_DEBUG_OF(MYSQL_TYPE_LONG); + SHOW_DEBUG_OF(MYSQL_TYPE_INT24); + SHOW_DEBUG_OF(MYSQL_TYPE_LONGLONG); + SHOW_DEBUG_OF(MYSQL_TYPE_DECIMAL); + SHOW_DEBUG_OF(MYSQL_TYPE_FLOAT); + SHOW_DEBUG_OF(MYSQL_TYPE_DOUBLE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIMESTAMP); + SHOW_DEBUG_OF(MYSQL_TYPE_DATE); + SHOW_DEBUG_OF(MYSQL_TYPE_TIME); + SHOW_DEBUG_OF(MYSQL_TYPE_DATETIME); + SHOW_DEBUG_OF(MYSQL_TYPE_YEAR); + SHOW_DEBUG_OF(MYSQL_TYPE_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_VAR_STRING); + SHOW_DEBUG_OF(MYSQL_TYPE_BLOB); + SHOW_DEBUG_OF(MYSQL_TYPE_SET); + SHOW_DEBUG_OF(MYSQL_TYPE_ENUM); + SHOW_DEBUG_OF(MYSQL_TYPE_NULL); #undef SHOW_DEBUG_TYPE_OF } ShowDebug("%stype=%s%s, length=%d%s\n", prefix, sign, type_string, length, length_postfix); @@ -610,7 +610,7 @@ int SqlStmt_Prepare(SqlStmt* self, const char* query, ...) va_list args; va_start(args, query); - res = SqlStmt_PrepareV(self, query, args); + res = SQL->StmtPrepareV(self, query, args); va_end(args); return res; @@ -624,7 +624,7 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args) if( self == NULL ) return SQL_ERROR; - SqlStmt_FreeResult(self); + SQL->StmtFreeResult(self); StrBuf->Clear(&self->buf); StrBuf->Vprintf(&self->buf, query, args); if( mysql_stmt_prepare(self->stmt, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) @@ -646,7 +646,7 @@ int SqlStmt_PrepareStr(SqlStmt* self, const char* query) if( self == NULL ) return SQL_ERROR; - SqlStmt_FreeResult(self); + SQL->StmtFreeResult(self); StrBuf->Clear(&self->buf); StrBuf->AppendStr(&self->buf, query); if( mysql_stmt_prepare(self->stmt, StrBuf->Value(&self->buf), (unsigned long)StrBuf->Length(&self->buf)) ) @@ -677,14 +677,14 @@ size_t SqlStmt_NumParams(SqlStmt* self) int SqlStmt_BindParam(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, void* buffer, size_t buffer_len) { if( self == NULL ) - return SQL_ERROR; + return SQL_ERROR; if( !self->bind_params ) {// initialize the bindings size_t i; size_t count; - count = SqlStmt_NumParams(self); + count = SQL->StmtNumParams(self); if( self->max_params < count ) { self->max_params = count; @@ -709,7 +709,7 @@ int SqlStmt_Execute(SqlStmt* self) if( self == NULL ) return SQL_ERROR; - SqlStmt_FreeResult(self); + SQL->StmtFreeResult(self); if( (self->bind_params && mysql_stmt_bind_param(self->stmt, self->params)) || mysql_stmt_execute(self->stmt) ) { @@ -772,7 +772,7 @@ int SqlStmt_BindColumn(SqlStmt* self, size_t idx, enum SqlDataType buffer_type, size_t i; size_t cols; - cols = SqlStmt_NumColumns(self); + cols = SQL->StmtNumColumns(self); if( self->max_columns < cols ) { self->max_columns = cols; @@ -843,7 +843,7 @@ int SqlStmt_NextRow(SqlStmt* self) } // find truncated column - cols = SqlStmt_NumColumns(self); + cols = SQL->StmtNumColumns(self); for( i = 0; i < cols; ++i ) { column = &self->columns[i]; @@ -868,7 +868,7 @@ int SqlStmt_NextRow(SqlStmt* self) } // propagate column lengths and clear unused parts of string/enum/blob buffers - cols = SqlStmt_NumColumns(self); + cols = SQL->StmtNumColumns(self); for( i = 0; i < cols; ++i ) { length = self->column_lengths[i].length; @@ -946,21 +946,21 @@ void SqlStmt_Free(SqlStmt* self) void hercules_mysql_error_handler(unsigned int ecode) { static unsigned int retry = 1; switch( ecode ) { - case 2003:/* Can't connect to MySQL (this error only happens here when failing to reconnect) */ - if( mysql_reconnect_type == 1 ) { - if( ++retry > mysql_reconnect_count ) { - ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry); - exit(EXIT_FAILURE); - } + case 2003:/* Can't connect to MySQL (this error only happens here when failing to reconnect) */ + if( mysql_reconnect_type == 1 ) { + if( ++retry > mysql_reconnect_count ) { + ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry); + exit(EXIT_FAILURE); } - break; + } + break; } } void Sql_inter_server_read(const char* cfgName, bool first) { int i; char line[1024], w1[1024], w2[1024]; FILE* fp; - + fp = fopen(cfgName, "r"); if(fp == NULL) { if( first ) { @@ -970,22 +970,22 @@ void Sql_inter_server_read(const char* cfgName, bool first) { ShowError("File not found: %s\n", cfgName); return; } - + while(fgets(line, sizeof(line), fp)) { i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); if(i != 2) continue; - + if(!strcmpi(w1,"mysql_reconnect_type")) { mysql_reconnect_type = atoi(w2); switch( mysql_reconnect_type ) { - case 1: - case 2: - break; - default: - ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type); - mysql_reconnect_type = 1; - break; + case 1: + case 2: + break; + default: + ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type); + mysql_reconnect_type = 1; + break; } } else if(!strcmpi(w1,"mysql_reconnect_count")) { mysql_reconnect_count = atoi(w2); @@ -995,7 +995,7 @@ void Sql_inter_server_read(const char* cfgName, bool first) { Sql_inter_server_read(w2,false); } fclose(fp); - + return; } @@ -1003,7 +1003,7 @@ void Sql_HerculesUpdateCheck(Sql* self) { char line[22];// "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1 FILE* ifp;/* index fp */ unsigned int performed = 0; - + if( !( ifp = fopen("sql-files/upgrades/index.txt", "r") ) ) { ShowError("SQL upgrade index was not found!\n"); return; @@ -1013,22 +1013,22 @@ void Sql_HerculesUpdateCheck(Sql* self) { char path[41];// "sql-files/upgrades/" (19) + "yyyy-mm-dd--hh-mm" (17) + ".sql" (4) + 1 char timestamp[11];// "1360186680" (10) + 1 FILE* ufp;/* upgrade fp */ - + if( line[0] == '\n' || ( line[0] == '/' && line[1] == '/' ) )/* skip \n and "//" comments */ continue; - + sprintf(path,"sql-files/upgrades/%s",line); - + if( !( ufp = fopen(path, "r") ) ) { ShowError("SQL upgrade file %s was not found!\n",path); continue; } - + if( fgetc(ufp) != '#' ) continue; - + fseek (ufp,1,SEEK_SET);/* woo. skip the # */ - + if( fgets(timestamp,sizeof(timestamp),ufp) ) { unsigned int timestampui = atol(timestamp); if( SQL_ERROR == SQL->Query(self, "SELECT 1 FROM `sql_updates` WHERE `timestamp` = '%u' LIMIT 1", timestampui) ) @@ -1038,12 +1038,12 @@ void Sql_HerculesUpdateCheck(Sql* self) { performed++; } } - + fclose(ufp); } - + fclose(ifp); - + if( performed ) { ShowSQL("If you did apply these updates or would like to be skip, insert a new entry in your sql_updates table with the timestamp of each file\n"); } @@ -1054,7 +1054,7 @@ void Sql_Init(void) { } void sql_defaults(void) { SQL = &sql_s; - + SQL->Connect = Sql_Connect; SQL->GetTimeout = Sql_GetTimeout; SQL->GetColumnNames = Sql_GetColumnNames; @@ -1074,4 +1074,21 @@ void sql_defaults(void) { SQL->ShowDebug_ = Sql_ShowDebug_; SQL->Free = Sql_Free; SQL->Malloc = Sql_Malloc; + + /* SqlStmt defaults [Susu] */ + SQL->StmtBindColumn = SqlStmt_BindColumn; + SQL->StmtBindParam = SqlStmt_BindParam; + SQL->StmtExecute = SqlStmt_Execute; + SQL->StmtFree = SqlStmt_Free; + SQL->StmtFreeResult = SqlStmt_FreeResult; + SQL->StmtLastInsertId = SqlStmt_LastInsertId; + SQL->StmtMalloc = SqlStmt_Malloc; + SQL->StmtNextRow = SqlStmt_NextRow; + SQL->StmtNumColumns = SqlStmt_NumColumns; + SQL->StmtNumParams = SqlStmt_NumParams; + SQL->StmtNumRows = SqlStmt_NumRows; + SQL->StmtPrepare = SqlStmt_Prepare; + SQL->StmtPrepareStr = SqlStmt_PrepareStr; + SQL->StmtPrepareV = SqlStmt_PrepareV; + SQL->StmtShowDebug_ = SqlStmt_ShowDebug_; } diff --git a/src/common/sql.h b/src/common/sql.h index d5a0eda2c..535990649 100644 --- a/src/common/sql.h +++ b/src/common/sql.h @@ -142,145 +142,157 @@ struct sql_interface { void (*Free) (Sql* self); /// Allocates and initializes a new Sql handle. struct Sql *(*Malloc) (void); -} sql_s; -struct sql_interface *SQL; -void sql_defaults(void); -#if defined(SQL_REMOVE_SHOWDEBUG) - #define Sql_ShowDebug(self) (void)0 -#else - #define Sql_ShowDebug(self) SQL->ShowDebug_(self, __FILE__, __LINE__) -#endif + /////////////////////////////////////////////////////////////////////////////// + // Prepared Statements + /////////////////////////////////////////////////////////////////////////////// + // Parameters are placed in the statement by embedding question mark ('?') + // characters into the query at the appropriate positions. + // The markers are legal only in places where they represent data. + // The markers cannot be inside quotes. Quotes will be added automatically + // when they are required. + // + // example queries with parameters: + // 1) SELECT col FROM table WHERE id=? + // 2) INSERT INTO table(col1,col2) VALUES(?,?) -/////////////////////////////////////////////////////////////////////////////// -// Prepared Statements -/////////////////////////////////////////////////////////////////////////////// -// Parameters are placed in the statement by embedding question mark ('?') -// characters into the query at the appropriate positions. -// The markers are legal only in places where they represent data. -// The markers cannot be inside quotes. Quotes will be added automatically -// when they are required. -// -// example queries with parameters: -// 1) SELECT col FROM table WHERE id=? -// 2) INSERT INTO table(col1,col2) VALUES(?,?) -/// Allocates and initializes a new SqlStmt handle. -/// It uses the connection of the parent Sql handle. -/// Queries in Sql and SqlStmt are independent and don't affect each other. -/// -/// @return SqlStmt handle or NULL if an error occured -struct SqlStmt* SqlStmt_Malloc(Sql* sql); + /*===================================== + SQL Statement interface [Susu] + *-------------------------------------*/ + /// Allocates and initializes a new SqlStmt handle. + /// It uses the connection of the parent Sql handle. + /// Queries in Sql and SqlStmt are independent and don't affect each other. + /// + /// @return SqlStmt handle or NULL if an error occured + struct SqlStmt* (*StmtMalloc)(Sql* sql); -/// Prepares the statement. -/// Any previous result is freed and all parameter bindings are removed. -/// The query is constructed as if it was sprintf. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Prepare(SqlStmt* self, const char* query, ...); -/// Prepares the statement. -/// Any previous result is freed and all parameter bindings are removed. -/// The query is constructed as if it was svprintf. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args); + /// Prepares the statement. + /// Any previous result is freed and all parameter bindings are removed. + /// The query is constructed as if it was sprintf. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtPrepare)(SqlStmt* self, const char* query, ...); + /// Prepares the statement. + /// Any previous result is freed and all parameter bindings are removed. + /// The query is constructed as if it was svprintf. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtPrepareV)(SqlStmt* self, const char* query, va_list args); -/// Prepares the statement. -/// Any previous result is freed and all parameter bindings are removed. -/// The query is used directly. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_PrepareStr(SqlStmt* self, const char* query); + /// Prepares the statement. + /// Any previous result is freed and all parameter bindings are removed. + /// The query is used directly. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtPrepareStr)(SqlStmt* self, const char* query); -/// Returns the number of parameters in the prepared statement. -/// -/// @return Number or paramenters -size_t SqlStmt_NumParams(SqlStmt* self); + /// Returns the number of parameters in the prepared statement. + /// + /// @return Number or paramenters + size_t (*StmtNumParams)(SqlStmt* self); -/// Binds a parameter to a buffer. -/// The buffer data will be used when the statement is executed. -/// All parameters should have bindings. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindParam(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len); + /// Binds a parameter to a buffer. + /// The buffer data will be used when the statement is executed. + /// All parameters should have bindings. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtBindParam)(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len); -/// Executes the prepared statement. -/// Any previous result is freed and all column bindings are removed. -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_Execute(SqlStmt* self); + /// Executes the prepared statement. + /// Any previous result is freed and all column bindings are removed. + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtExecute)(SqlStmt* self); -/// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. -/// -/// @return Value of the auto-increment column -uint64 SqlStmt_LastInsertId(SqlStmt* self); + /// Returns the number of the AUTO_INCREMENT column of the last INSERT/UPDATE statement. + /// + /// @return Value of the auto-increment column + uint64 (*StmtLastInsertId)(SqlStmt* self); -/// Returns the number of columns in each row of the result. -/// -/// @return Number of columns -size_t SqlStmt_NumColumns(SqlStmt* self); + /// Returns the number of columns in each row of the result. + /// + /// @return Number of columns + size_t (*StmtNumColumns)(SqlStmt* self); + + + + /// Binds the result of a column to a buffer. + /// The buffer will be filled with data when the next row is fetched. + /// For string/enum buffer types there has to be enough space for the data + /// and the nul-terminator (an extra byte). + /// + /// @return SQL_SUCCESS or SQL_ERROR + int (*StmtBindColumn)(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null); + + + + /// Returns the number of rows in the result. + /// + /// @return Number of rows + uint64 (*StmtNumRows)(SqlStmt* self); -/// Binds the result of a column to a buffer. -/// The buffer will be filled with data when the next row is fetched. -/// For string/enum buffer types there has to be enough space for the data -/// and the nul-terminator (an extra byte). -/// -/// @return SQL_SUCCESS or SQL_ERROR -int SqlStmt_BindColumn(SqlStmt* self, size_t idx, SqlDataType buffer_type, void* buffer, size_t buffer_len, uint32* out_length, int8* out_is_null); + /// Fetches the next row. + /// All column bindings will be filled with data. + /// + /// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA + int (*StmtNextRow)(SqlStmt* self); -/// Returns the number of rows in the result. -/// -/// @return Number of rows -uint64 SqlStmt_NumRows(SqlStmt* self); + /// Frees the result of the statement execution. + void (*StmtFreeResult)(SqlStmt* self); + /// Frees a SqlStmt returned by SqlStmt_Malloc. + void (*StmtFree)(SqlStmt* self); -/// Fetches the next row. -/// All column bindings will be filled with data. -/// -/// @return SQL_SUCCESS, SQL_ERROR or SQL_NO_DATA -int SqlStmt_NextRow(SqlStmt* self); + void (*StmtShowDebug_)(SqlStmt* self, const char* debug_file, const unsigned long debug_line); +} sql_s; + +struct sql_interface *SQL; +void sql_defaults(void); -/// Frees the result of the statement execution. -void SqlStmt_FreeResult(SqlStmt* self); +#if defined(SQL_REMOVE_SHOWDEBUG) +#define Sql_ShowDebug(self) (void)0 +#else +#define Sql_ShowDebug(self) SQL->ShowDebug_(self, __FILE__, __LINE__) +#endif void Sql_HerculesUpdateCheck(Sql* self); #if defined(SQL_REMOVE_SHOWDEBUG) - #define SqlStmt_ShowDebug(self) (void)0 +#define SqlStmt_ShowDebug(self) (void)0 #else - #define SqlStmt_ShowDebug(self) SqlStmt_ShowDebug_(self, __FILE__, __LINE__) +#define SqlStmt_ShowDebug(self) SQL->StmtShowDebug_(self, __FILE__, __LINE__) #endif /// Shows debug information (with statement). -void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned long debug_line); -/// Frees a SqlStmt returned by SqlStmt_Malloc. -void SqlStmt_Free(SqlStmt* self); + + void Sql_Init(void); diff --git a/src/common/strlib.h b/src/common/strlib.h index 4a073c3bc..9b1875d45 100644 --- a/src/common/strlib.h +++ b/src/common/strlib.h @@ -8,9 +8,13 @@ #include "../common/cbasetypes.h" #include <stdarg.h> -#define __USE_GNU // required to enable strnlen on some platforms -#include <string.h> -#undef __USE_GNU +#ifndef __USE_GNU + #define __USE_GNU // required to enable strnlen on some platforms + #include <string.h> + #undef __USE_GNU +#else + #include <string.h> +#endif #ifdef WIN32 #define HAVE_STRTOK_R diff --git a/src/common/timer.c b/src/common/timer.c index edb46bd71..955a971c8 100644 --- a/src/common/timer.c +++ b/src/common/timer.c @@ -257,7 +257,7 @@ int timer_add_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int tid; if( interval < 1 ) { - ShowError("timer_add_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, gettick())); + ShowError("timer_add_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, iTimer->gettick())); return INVALID_TIMER; } @@ -300,7 +300,7 @@ int timer_do_delete(int tid, TimerFunc func) { /// Adjusts a timer's expiration time. /// Returns the new tick value, or -1 if it fails. int timer_addtick(int tid, unsigned int tick) { - return settick_timer(tid, timer_data[tid].tick+tick); + return iTimer->settick_timer(tid, timer_data[tid].tick+tick); } /// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one). @@ -409,15 +409,26 @@ void timer_final(void) { BHEAP_CLEAR(timer_heap); if (free_timer_list) aFree(free_timer_list); } -void timer_defaults(void) { - gettick = timer_gettick; - gettick_nocache = timer_gettick_nocache; - add_timer = timer_add; - add_timer_interval = timer_add_interval; - add_timer_func_list = timer_add_func_list; - get_timer = timer_get; - delete_timer = timer_do_delete; - addtick_timer = timer_addtick; - settick_timer = timer_settick; - get_uptime = timer_get_uptime; +/*===================================== +* Default Functions : timer.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void timer_defaults(void) { + iTimer = &iTimer_s; + + /* funcs */ + iTimer->gettick = timer_gettick; + iTimer->gettick_nocache = timer_gettick_nocache; + iTimer->add_timer = timer_add; + iTimer->add_timer_interval = timer_add_interval; + iTimer->add_timer_func_list = timer_add_func_list; + iTimer->get_timer = timer_get; + iTimer->delete_timer = timer_do_delete; + iTimer->addtick_timer = timer_addtick; + iTimer->settick_timer = timer_settick; + iTimer->get_uptime = timer_get_uptime; + iTimer->do_timer = do_timer; + iTimer->init = timer_init; + iTimer->final = timer_final; } diff --git a/src/common/timer.h b/src/common/timer.h index 902679f51..50f1c354b 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -1,10 +1,8 @@ // Copyright (c) Hercules Dev Team, licensed under GNU GPL. // See the LICENSE file // Portions Copyright (c) Athena Dev Teams - #ifndef _TIMER_H_ #define _TIMER_H_ - #include "../common/cbasetypes.h" #define DIFF_TICK(a,b) ((int)((a)-(b))) @@ -34,27 +32,36 @@ struct TimerData { intptr_t data; }; -// Function prototype declaration -int do_timer(unsigned int tick); -void timer_init(void); -void timer_final(void); +/*===================================== +* Interface : timer.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct timer_interface { + + /* funcs */ + unsigned int (*gettick) (void); + unsigned int (*gettick_nocache) (void); + + int (*add_timer) (unsigned int tick, TimerFunc func, int id, intptr_t data); + int (*add_timer_interval) (unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); + const struct TimerData *(*get_timer) (int tid); + int (*delete_timer) (int tid, TimerFunc func); -/* Hercules Renewal Phase One */ -unsigned int (*gettick) (void); -unsigned int (*gettick_nocache) (void); + int (*addtick_timer) (int tid, unsigned int tick); + int (*settick_timer) (int tid, unsigned int tick); -int (*add_timer) (unsigned int tick, TimerFunc func, int id, intptr_t data); -int (*add_timer_interval) (unsigned int tick, TimerFunc func, int id, intptr_t data, int interval); -const struct TimerData *(*get_timer) (int tid); -int (*delete_timer) (int tid, TimerFunc func); + int (*add_timer_func_list) (TimerFunc func, char* name); -int (*addtick_timer) (int tid, unsigned int tick); -int (*settick_timer) (int tid, unsigned int tick); + unsigned long (*get_uptime) (void); -int (*add_timer_func_list) (TimerFunc func, char* name); + int (*do_timer) (unsigned int tick); + void (*init) (void); + void (*final) (void); +} iTimer_s; -unsigned long (*get_uptime) (void); +struct timer_interface *iTimer; void timer_defaults(void); |