diff options
author | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-10-17 20:24:48 +0000 |
---|---|---|
committer | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-10-17 20:24:48 +0000 |
commit | 5f6a6a2557a90573a504b541a3234f0dc566bf6a (patch) | |
tree | 4e4522d1c1c7411a2c7672af9af7887333dcdc50 /src | |
parent | 724babffe10a6908d1510c941e5abfbe840fd271 (diff) | |
download | hercules-5f6a6a2557a90573a504b541a3234f0dc566bf6a.tar.gz hercules-5f6a6a2557a90573a504b541a3234f0dc566bf6a.tar.bz2 hercules-5f6a6a2557a90573a504b541a3234f0dc566bf6a.tar.xz hercules-5f6a6a2557a90573a504b541a3234f0dc566bf6a.zip |
* Merged do_sendrecv() and do_parse() into do_sockets()
* Fixed subnet check message displaying incorrect ip addresses
* client_addr will now be properly set to 0 for server connections
* Removed socket code that attempts to cope with code bugs at runtime
* Removed outdated copyright and version number from startup logo
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11503 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 4 | ||||
-rw-r--r-- | src/char_sql/char.c | 4 | ||||
-rw-r--r-- | src/common/core.c | 57 | ||||
-rw-r--r-- | src/common/socket.c | 193 | ||||
-rw-r--r-- | src/common/socket.h | 22 | ||||
-rw-r--r-- | src/ladmin/ladmin.c | 5 | ||||
-rw-r--r-- | src/login/login.c | 1 | ||||
-rw-r--r-- | src/login_sql/login.c | 1 | ||||
-rw-r--r-- | src/map/chrif.c | 1 |
9 files changed, 135 insertions, 153 deletions
diff --git a/src/char/char.c b/src/char/char.c index c99c1e3c4..da7300fbb 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3745,12 +3745,13 @@ int parse_char(int fd) WFIFOB(fd,2) = 0; WFIFOSET(fd,3); - session[fd]->func_parse = parse_frommap; server_fd[i] = fd; server[i].ip = ntohl(RFIFOL(fd,54)); server[i].port = ntohs(RFIFOW(fd,58)); server[i].users = 0; memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->client_addr = 0; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); char_mapif_init(fd); // send gm acccounts level to map-servers @@ -3951,6 +3952,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, int data) return 0; } session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->client_addr = 0; realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); WFIFOHEAD(login_fd,86); diff --git a/src/char_sql/char.c b/src/char_sql/char.c index f8729a39b..d233788c2 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -3075,12 +3075,13 @@ int parse_char(int fd) WFIFOB(fd,2) = 0; WFIFOSET(fd,3); - session[fd]->func_parse = parse_frommap; server_fd[i] = fd; server[i].ip = ntohl(RFIFOL(fd,54)); server[i].port = ntohs(RFIFOW(fd,58)); server[i].users = 0; memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->client_addr = 0; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); char_mapif_init(fd); // send gm acccounts level to map-servers @@ -3280,6 +3281,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, int data) return 0; } session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->client_addr = 0; realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); WFIFOHEAD(login_fd,86); diff --git a/src/common/core.c b/src/common/core.c index 49fbcec7d..301760759 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -1,28 +1,27 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include <stdio.h> -#include <stdlib.h> -#ifndef _WIN32 -#include <unistd.h> -#endif -#include <signal.h> -#include <string.h> - -#include "core.h" #include "../common/mmo.h" #include "../common/version.h" #include "../common/showmsg.h" #include "../common/malloc.h" +#include "core.h" #ifndef MINICORE #include "../common/db.h" #include "../common/socket.h" #include "../common/timer.h" #include "../common/plugins.h" #endif +#ifndef _WIN32 +#include "svnversion.h" +#endif +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> #ifndef _WIN32 - #include "svnversion.h" +#include <unistd.h> #endif int runflag = 1; @@ -32,7 +31,7 @@ char **arg_v = NULL; char *SERVER_NAME = NULL; char SERVER_TYPE = ATHENA_SERVER_NONE; #ifndef SVNVERSION - static char eA_svn_version[10]; + static char eA_svn_version[10] = ""; #endif #ifndef MINICORE // minimalist Core @@ -178,21 +177,21 @@ static void display_title(void) { //ClearScreen(); // clear screen and go up/left (0, 0 position in text) ShowMessage("\n"); - ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n"); // white writing (37) on blue background (44), \033[K clean until end of file - ShowMessage(""CL_XXBL" ("CL_BT_YELLOW" (c)2005 eAthena Development Team presents "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // yellow writing (33) - ShowMessage(""CL_XXBL" ("CL_BOLD" ______ __ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ _ \\/\\ \\__/\\ \\ v%2d.%02d.%02d "CL_XXBL")"CL_CLL""CL_NORMAL"\n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" __\\ \\ \\_\\ \\ \\ ,_\\ \\ \\___ __ ___ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" /'__`\\ \\ __ \\ \\ \\/\\ \\ _ `\\ /'__`\\/' _ `\\ /'__`\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ __/\\ \\ \\/\\ \\ \\ \\_\\ \\ \\ \\ \\/\\ __//\\ \\/\\ \\/\\ \\_\\.\\_ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" \\ \\____\\\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\____\\ \\_\\ \\_\\ \\__/.\\_\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" \\/____/ \\/_/\\/_/\\/__/ \\/_/\\/_/\\/____/\\/_/\\/_/\\/__/\\/_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" _ _ _ _ _ _ _ _ _ _ _ _ _ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" ( e | n | g | l | i | s | h ) ( A | t | h | e | n | a ) "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char - ShowMessage(""CL_XXBL" ("CL_BOLD" "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // yellow writing (33) - ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n\n"); // reset color + ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BT_YELLOW" eAthena Development Team presents "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" ______ __ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ _ \\/\\ \\__/\\ \\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" __\\ \\ \\_\\ \\ \\ ,_\\ \\ \\___ __ ___ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" /'__`\\ \\ __ \\ \\ \\/\\ \\ _ `\\ /'__`\\/' _ `\\ /'__`\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ __/\\ \\ \\/\\ \\ \\ \\_\\ \\ \\ \\ \\/\\ __//\\ \\/\\ \\/\\ \\_\\.\\_ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" \\ \\____\\\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\____\\ \\_\\ \\_\\ \\__/.\\_\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" \\/____/ \\/_/\\/_/\\/__/ \\/_/\\/_/\\/____/\\/_/\\/_/\\/__/\\/_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" _ _ _ _ _ _ _ _ _ _ _ _ _ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" ( e | n | g | l | i | s | h ) ( A | t | h | e | n | a ) "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_XXBL" ("CL_BOLD" "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); + ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n\n"); ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision()); } @@ -224,9 +223,6 @@ int main (int argc, char **argv) } arg_c = argc; arg_v = argv; - #ifndef SVNVERSION - *eA_svn_version = '\0'; - #endif } malloc_init();// needed for Show* in display_title() [FlavioJS] @@ -255,8 +251,7 @@ int main (int argc, char **argv) int next; while (runflag) { next = do_timer(gettick_nocache()); - do_sendrecv(next); - do_parsepacket(); + do_sockets(next); } } diff --git a/src/common/socket.c b/src/common/socket.c index 6b52dd402..d8f3365d3 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -41,6 +41,7 @@ #define s_errno WSAGetLastError() #define S_ENOTSOCK WSAENOTSOCK #define S_EWOULDBLOCK WSAEWOULDBLOCK + #define S_EINTR WSAEINTR #define S_ECONNABORTED WSAECONNABORTED #define SHUT_RD SD_RECEIVE @@ -55,6 +56,7 @@ #define s_errno errno #define S_ENOTSOCK EBADF #define S_EWOULDBLOCK EAGAIN + #define S_EINTR EINTR #define S_ECONNABORTED ECONNABORTED #endif @@ -66,13 +68,11 @@ time_t stall_time = 60; uint32 addr_[16]; // ip addresses of local host (host byte order) int naddr_ = 0; // # of ip addresses -#define MODE_NODELAY 1 // disables|enables packet buffering - -// values derived from freya -// a player that send more than 2k is probably a hacker without be parsed +// initial recv buffer size (this will also be the max. size) // biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes) -size_t rfifo_size = (16*1024); -size_t wfifo_size = (16*1024); +#define RFIFO_SIZE (2*1024) +// initial send buffer size (will be resized as needed) +#define WFIFO_SIZE (16*1024) struct socket_data* session[FD_SETSIZE]; @@ -82,7 +82,7 @@ int send_shortlist_count = 0;// how many fd's are in the shortlist fd_set send_shortlist_fd_set;// to know if specific fd's are already in the shortlist #endif -int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); +static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse); #ifndef MINICORE int ip_rules = 1; @@ -110,11 +110,6 @@ void set_defaultparse(ParseFunc defaultparse) *--------------------------------------*/ void set_nonblocking(int fd, unsigned long yes) { - // TCP_NODELAY BOOL Disables the Nagle algorithm for send coalescing. -#if defined(MODE_NODELAY) && MODE_NODELAY == 1 - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof yes); -#endif - // FIONBIO Use with a nonzero argp parameter to enable the nonblocking mode of socket s. // The argp parameter is zero if nonblocking is to be disabled. if (ioctlsocket(fd, FIONBIO, &yes) != 0) @@ -133,9 +128,10 @@ void setsocketopts(int fd) setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,(char *)&yes,sizeof(yes)); #endif #endif + + // Set the socket into no-delay mode; otherwise packets get delayed for up to 200ms, likely creating server-side lag. + // The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway. setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); -// setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *) &wfifo_size , sizeof(rfifo_size )); -// setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *) &rfifo_size , sizeof(rfifo_size )); // 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) @@ -172,19 +168,17 @@ int recv_to_fifo(int fd) len = recv(fd, (char *) session[fd]->rdata + session[fd]->rdata_size, (int)RFIFOSPACE(fd), 0); - if (len == SOCKET_ERROR) { - if (s_errno == S_ECONNABORTED) { - ShowWarning("recv_to_fifo: Software caused connection abort on session #%d\n", fd); - FD_CLR(fd, &readfds); //Remove the socket so the select() won't hang on it. - } - if (s_errno != S_EWOULDBLOCK) { - //ShowDebug("recv_to_fifo: error %d, ending connection #%d\n", s_errno, fd); + if( len == SOCKET_ERROR ) + {//An exception has occured + if( s_errno != S_EWOULDBLOCK ) { + ShowDebug("recv_to_fifo: code %d, closing connection #%d\n", s_errno, fd); set_eof(fd); } return 0; } - if (len == 0) { //Normal connection end. + if( len == 0 ) + {//Normal connection end. set_eof(fd); return 0; } @@ -201,27 +195,28 @@ int send_from_fifo(int fd) if( !session_isValid(fd) ) return -1; - if (session[fd]->wdata_size == 0) - return 0; + if( session[fd]->wdata_size == 0 ) + return 0; // nothing to send + + ShowInfo("Session #%d sending %d bytes.\n", fd, session[fd]->wdata_size); len = send(fd, (const char *) session[fd]->wdata, (int)session[fd]->wdata_size, 0); - if (len == SOCKET_ERROR) { - if (s_errno == S_ECONNABORTED) { - ShowWarning("send_from_fifo: Software caused connection abort on session #%d\n", fd); - FD_CLR(fd, &readfds); //Remove the socket so the select() won't hang on it. - } - if (s_errno != S_EWOULDBLOCK) { - //ShowDebug("send_from_fifo: error %d, ending connection #%d\n", s_errno, fd); + if( len == SOCKET_ERROR ) + { + if( s_errno != S_EWOULDBLOCK ) { + ShowDebug("send_from_fifo: error %d, ending connection #%d\n", s_errno, fd); session[fd]->wdata_size = 0; //Clear the send queue as we can't send anymore. [Skotlex] set_eof(fd); } return 0; } - //{ int i; ShowMessage("send %d : ",fd); for(i=0;i<len;i++){ ShowMessage("%02x ",session[fd]->wdata[i]); } ShowMessage("\n");} - if(len > 0) { - if((size_t)len < session[fd]->wdata_size) + // some data could not be transferred? + if( len > 0 ) + { + // shift unsent data to the beginning of the queue + if( (size_t)len < session[fd]->wdata_size ) memmove(session[fd]->wdata, session[fd]->wdata + len, session[fd]->wdata_size - len); session[fd]->wdata_size -= len; @@ -282,7 +277,6 @@ int connect_client(int listen_fd) create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); session[fd]->client_addr = ntohl(client_address.sin_addr.s_addr); - session[fd]->rdata_tick = last_tick; return fd; } @@ -333,6 +327,8 @@ int make_listen_bind(uint32 ip, uint16 port) FD_SET(fd, &readfds); create_session(fd, connect_client, null_send, null_parse); + session[fd]->rdata_tick = 0; // disable timeouts on this socket + session[fd]->client_addr = 0; return fd; } @@ -377,25 +373,26 @@ int make_connection(uint32 ip, uint16 port) FD_SET(fd,&readfds); create_session(fd, recv_to_fifo, send_from_fifo, default_func_parse); - session[fd]->rdata_tick = last_tick; + session[fd]->client_addr = 0; return fd; } -int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse) +static int create_session(int fd, RecvFunc func_recv, SendFunc func_send, ParseFunc func_parse) { CREATE(session[fd], struct socket_data, 1); - CREATE(session[fd]->rdata, unsigned char, rfifo_size); - CREATE(session[fd]->wdata, unsigned char, wfifo_size); - session[fd]->max_rdata = rfifo_size; - session[fd]->max_wdata = wfifo_size; + CREATE(session[fd]->rdata, unsigned char, RFIFO_SIZE); + CREATE(session[fd]->wdata, unsigned char, WFIFO_SIZE); + session[fd]->max_rdata = RFIFO_SIZE; + session[fd]->max_wdata = WFIFO_SIZE; session[fd]->func_recv = func_recv; session[fd]->func_send = func_send; session[fd]->func_parse = func_parse; + session[fd]->rdata_tick = last_tick; return 0; } -int delete_session(int fd) +static int delete_session(int fd) { if (fd <= 0 || fd >= FD_SETSIZE) return -1; @@ -435,29 +432,45 @@ int realloc_writefifo(int fd, size_t addition) return 0; if( session[fd]->wdata_size + addition > session[fd]->max_wdata ) - { // grow rule; grow in multiples of wfifo_size - newsize = wfifo_size; + { // grow rule; grow in multiples of WFIFO_SIZE + newsize = WFIFO_SIZE; while( session[fd]->wdata_size + addition > newsize ) newsize += newsize; } - else if( session[fd]->max_wdata >= FIFOSIZE_SERVERLINK) { + else + if( session[fd]->max_wdata >= FIFOSIZE_SERVERLINK) + { //Inter-server adjust. [Skotlex] if ((session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata) newsize = session[fd]->max_wdata / 2; else return 0; //No change - } else if( session[fd]->max_wdata > wfifo_size && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata ) + } + else + if( session[fd]->max_wdata > WFIFO_SIZE && (session[fd]->wdata_size+addition)*4 < session[fd]->max_wdata ) { // shrink rule, shrink by 2 when only a quater of the fifo is used, don't shrink below 4*addition newsize = session[fd]->max_wdata / 2; } else // no change return 0; + // crash prevention for bugs that cause the send queue to fill up in an infinite loop + if( newsize > 1*1024*1024 ) // 1 megabyte is way beyond reasonable + { + ShowError("realloc_writefifo: session #%d's send buffer was overloaded! Disconnecting...\n", fd); + // drop all data (but the space will still be available) + session[fd]->wdata_size = 0; + // request disconnect + set_eof(fd); + return 0; + } + RECREATE(session[fd]->wdata, unsigned char, newsize); session[fd]->max_wdata = newsize; return 0; } +/// advance the RFIFO cursor (marking 'len' bytes as processed) int RFIFOSKIP(int fd, size_t len) { struct socket_data *s; @@ -468,16 +481,15 @@ int RFIFOSKIP(int fd, size_t len) s = session[fd]; if ( s->rdata_size < s->rdata_pos + len ) { - //fprintf(stderr,"too many skip\n"); - //exit(EXIT_FAILURE); - //better than a COMPLETE program abort // TEST! :) - ShowError("too many skip (%d) now skipped: %d (FD: %d)\n", len, RFIFOREST(fd), fd); + ShowError("RFIFOSKIP: skipped past end of read buffer! Adjusting from %d to %d (session #%d)\n", len, RFIFOREST(fd), fd); len = RFIFOREST(fd); } + s->rdata_pos = s->rdata_pos + len; return 0; } +/// advance the WFIFO cursor (marking 'len' bytes for sending) int WFIFOSET(int fd, size_t len) { size_t newreserve; @@ -490,20 +502,18 @@ int WFIFOSET(int fd, size_t len) if(s->wdata_size+len > s->max_wdata) { // actually there was a buffer overflow already uint32 ip = s->client_addr; - ShowFatalError("socket: Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %d bytes on a %d/%d bytes buffer.\n", - fd, CONVIP(ip), len, s->wdata_size, s->max_wdata); + ShowFatalError("WFIFOSET: Write Buffer Overflow. Connection %d (%d.%d.%d.%d) has written %d bytes on a %d/%d bytes buffer.\n", fd, CONVIP(ip), len, s->wdata_size, s->max_wdata); ShowDebug("Likely command that caused it: 0x%x\n", (*(unsigned short*)(s->wdata + s->wdata_size))); // no other chance, make a better fifo model exit(EXIT_FAILURE); } s->wdata_size += len; - // always keep a wfifo_size reserve in the buffer + // always keep a WFIFO_SIZE reserve in the buffer // For inter-server connections, let the reserve be 1/4th of the link size. - newreserve = s->wdata_size + (s->max_wdata >= FIFOSIZE_SERVERLINK ? FIFOSIZE_SERVERLINK / 4 : wfifo_size); + newreserve = s->wdata_size + (s->max_wdata >= FIFOSIZE_SERVERLINK ? FIFOSIZE_SERVERLINK / 4 : WFIFO_SIZE); - // readfifo does not need to be realloced at all - // Even the inter-server buffer may need reallocating! [Skotlex] + // readjust the buffer to the newly chosen size realloc_writefifo(fd, newreserve); #ifdef SEND_SHORTLIST @@ -513,17 +523,16 @@ int WFIFOSET(int fd, size_t len) return 0; } -int do_sendrecv(int next) +int do_sockets(int next) { fd_set rfd; - struct sockaddr_in addr_check; struct timeval timeout; - int ret,i,size; + int ret,i; last_tick = time(0); - // PRESEND Timers are executed before do_sendrecv and can send packets - // and/or set sessions to eof. Send remaining data and handle eof sessions. + // PRESEND Timers are executed before do_sendrecv and can send packets and/or set sessions to eof. + // Send remaining data and process client-side disconnects here. #ifdef SEND_SHORTLIST send_shortlist_do_sends(); #else @@ -541,45 +550,17 @@ int do_sendrecv(int next) timeout.tv_sec = next/1000; timeout.tv_usec = next%1000*1000; - for(memcpy(&rfd, &readfds, sizeof(rfd)); - (ret = select(fd_max, &rfd, NULL, NULL, &timeout))<0; - memcpy(&rfd, &readfds, sizeof(rfd))) - { - if(s_errno != S_ENOTSOCK) - return 0; + memcpy(&rfd, &readfds, sizeof(rfd)); + ret = select(fd_max, &rfd, NULL, NULL, &timeout); - //Well then the error is due to a bad socket. Lets find and remove it - //and try again - for(i = 1; i < fd_max; i++) + if( ret < 0 ) + { + if( ret != S_EINTR ) { - if(!session[i]) - { - if (FD_ISSET(i, &readfds)) { - ShowError("Deleting non-cleared session %d\n", i); - FD_CLR(i, &readfds); - } - continue; - } - - //check the validity of the socket. Does what the last thing did - //just alot faster [Meruru] - size = sizeof(struct sockaddr); - if(getsockname(i,(struct sockaddr*)&addr_check,&size)<0) - if(s_errno == S_ENOTSOCK) - { - ShowError("Deleting invalid session %d\n", i); - //So the code can react accordingly - set_eof(i); - session[i]->func_parse(i); - delete_session(i); //free the bad session - continue; - } - - if (!FD_ISSET(i, &readfds)) - FD_SET(i,&readfds); - ret = i; + ShowFatalError("do_sockets: select() returned %d!\n", ret); + exit(EXIT_FAILURE); } - fd_max = ret; + return 0; } #ifdef WIN32 @@ -618,12 +599,7 @@ int do_sendrecv(int next) } #endif - return 0; -} - -int do_parsepacket(void) -{ - int i; + // parse input data on each socket for(i = 1; i < fd_max; i++) { if(!session[i]) @@ -639,13 +615,14 @@ int do_parsepacket(void) if(!session[i]) continue; - /* after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) */ - if (session[i]->rdata_size == rfifo_size && session[i]->max_rdata == rfifo_size) { + // after parse, check client's RFIFO size to know if there is an invalid packet (too big and not parsed) + if (session[i]->rdata_size == RFIFO_SIZE && session[i]->max_rdata == RFIFO_SIZE) { set_eof(i); continue; } RFIFOFLUSH(i); } + return 0; } @@ -1120,12 +1097,12 @@ void socket_init(void) } -int session_isValid(int fd) +bool session_isValid(int fd) { - return ( (fd > 0) && (fd < FD_SETSIZE) && (session[fd] != NULL) ); + return ( fd > 0 && fd < FD_SETSIZE && session[fd] != NULL ); } -int session_isActive(int fd) +bool session_isActive(int fd) { return ( session_isValid(fd) && !session[fd]->eof ); } diff --git a/src/common/socket.h b/src/common/socket.h index 4015fed97..cdbac8f00 100644 --- a/src/common/socket.h +++ b/src/common/socket.h @@ -68,18 +68,23 @@ typedef int (*RecvFunc)(int fd); typedef int (*SendFunc)(int fd); typedef int (*ParseFunc)(int fd); -struct socket_data { +struct socket_data +{ unsigned char eof; + unsigned char *rdata, *wdata; size_t max_rdata, max_wdata; size_t rdata_size, wdata_size; size_t rdata_pos; - time_t rdata_tick; // time of last receive (for detecting timeouts) - uint32 client_addr; // remote client address (zero for s2s connections) - void* session_data; + time_t rdata_tick; // time of last recv (for detecting timeouts); zero when timeout is disabled + + uint32 client_addr; // remote client address (0 for server connections) + RecvFunc func_recv; SendFunc func_send; ParseFunc func_parse; + + void* session_data; // stores application-specific data related to the session }; @@ -94,8 +99,8 @@ extern time_t stall_time; ////////////////////////////////// // some checking on sockets -extern int session_isValid(int fd); -extern int session_isActive(int fd); +extern bool session_isValid(int fd); +extern bool session_isActive(int fd); ////////////////////////////////// // Function prototype declaration @@ -107,8 +112,7 @@ int realloc_writefifo(int fd, size_t addition); int WFIFOSET(int fd, size_t len); int RFIFOSKIP(int fd, size_t len); -int do_sendrecv(int next); -int do_parsepacket(void); +int do_sockets(int next); void do_close(int fd); void socket_init(void); void socket_final(void); @@ -123,7 +127,7 @@ void set_defaultparse(ParseFunc defaultparse); uint32 host2ip(const char* hostname); const char* ip2str(uint32 ip, char ip_str[16]); uint32 str2ip(const char* ip_str); -#define CONVIP(ip) (ip>>24)&0xFF,(ip>>16)&0xFF,(ip>>8)&0xFF,(ip>>0)&0xFF +#define CONVIP(ip) ((ip)>>24)&0xFF,((ip)>>16)&0xFF,((ip)>>8)&0xFF,((ip)>>0)&0xFF uint16 ntows(uint16 netshort); int socket_getips(uint32* ips, int max); diff --git a/src/ladmin/ladmin.c b/src/ladmin/ladmin.c index 475bdcdeb..7a7cf3dda 100644 --- a/src/ladmin/ladmin.c +++ b/src/ladmin/ladmin.c @@ -3248,7 +3248,7 @@ int parse_fromlogin(int fd) ladmin_log("Impossible to have a connection with the login-server [%s:%d] !\n", loginserverip, loginserverport); } do_close(fd); - exit (0); + exit(EXIT_FAILURE); } // ShowMessage("parse_fromlogin : %d %d %d\n", fd, RFIFOREST(fd), RFIFOW(fd,0)); @@ -4384,8 +4384,7 @@ int do_init(int argc, char **argv) // so we have to do this ourselves while (runflag) { next = do_timer(gettick_nocache()); - do_sendrecv(next); - do_parsepacket(); + do_sockets(next); } return 0; diff --git a/src/login/login.c b/src/login/login.c index d087097d3..8acc10d73 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -3194,6 +3194,7 @@ int parse_login(int fd) WFIFOSET(fd,3); session[fd]->func_parse = parse_fromchar; + session[fd]->client_addr = 0; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); send_GM_accounts(fd); // send GM account to char-server diff --git a/src/login_sql/login.c b/src/login_sql/login.c index aa80f200a..d40cfcdf5 100644 --- a/src/login_sql/login.c +++ b/src/login_sql/login.c @@ -1538,6 +1538,7 @@ int parse_login(int fd) WFIFOSET(fd,3); session[fd]->func_parse = parse_fromchar; + session[fd]->client_addr = 0; realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); send_GM_accounts(fd); // send GM account to char-server diff --git a/src/map/chrif.c b/src/map/chrif.c index ccf92a6cf..a29987a6d 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1386,6 +1386,7 @@ int check_connect_char_server(int tid, unsigned int tick, int id, int data) } session[char_fd]->func_parse = chrif_parse; + session[char_fd]->client_addr = 0; realloc_fifo(char_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); chrif_connect(char_fd); |