summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/console.c6
-rw-r--r--src/common/malloc.c102
-rw-r--r--src/common/malloc.h2
-rw-r--r--src/common/mmo.h5
-rw-r--r--src/common/socket.c60
-rw-r--r--src/common/socket.h14
6 files changed, 145 insertions, 44 deletions
diff --git a/src/common/console.c b/src/common/console.c
index ba93b8e09..33d485497 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++ ) {
@@ -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;
diff --git a/src/common/malloc.c b/src/common/malloc.c
index 4874aa0f4..e98ec770a 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;
@@ -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);
@@ -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,8 +803,7 @@ void malloc_init (void)
#endif
}
-void malloc_defaults()
-{
+void malloc_defaults(void) {
malloclib = &malloclib_s;
malloclib->init = malloc_init;
malloclib->final = malloc_final;
diff --git a/src/common/malloc.h b/src/common/malloc.h
index 34a26b56e..1b8e82bd9 100644
--- a/src/common/malloc.h
+++ b/src/common/malloc.h
@@ -80,5 +80,7 @@ struct malloc_interface {
void (*final) (void);
} malloclib_s;
+void memmgr_report (int extra);
+
struct malloc_interface *malloclib;
#endif /* _MALLOC_H_ */
diff --git a/src/common/mmo.h b/src/common/mmo.h
index d45dea212..a86aba723 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -71,7 +71,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
@@ -526,6 +525,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/socket.c b/src/common/socket.c
index 5126d231b..0459004cc 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;
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);