Browse Source

* 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://svn.code.sf.net/p/rathena/svn/trunk@11503 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage 17 years ago
parent
commit
0bbf505d59
10 changed files with 140 additions and 153 deletions
  1. 5 0
      Changelog-Trunk.txt
  2. 3 1
      src/char/char.c
  3. 3 1
      src/char_sql/char.c
  4. 26 31
      src/common/core.c
  5. 85 108
      src/common/socket.c
  6. 13 9
      src/common/socket.h
  7. 2 3
      src/ladmin/ladmin.c
  8. 1 0
      src/login/login.c
  9. 1 0
      src/login_sql/login.c
  10. 1 0
      src/map/chrif.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2007/10/17
+	* Removed outdated copyright and version number from startup logo
+	* Removed socket code that attempts to cope with code bugs at runtime
+	* client_addr will now be properly set to 0 for server connections
+	* Fixed subnet check message displaying incorrect ip addresses
+	* Merged do_sendrecv() and do_parse() into do_sockets() [ultramage]
 	* Reworked the parsing at npc.c.
 	- Fixes npc.c discarding the '}' at the end of file, when there is no 
 	  newline. (uncovered as a side-effect of r11487)

+ 3 - 1
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);

+ 3 - 1
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);

+ 26 - 31
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);
 		}
 	}
 

+ 85 - 108
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 );
 }

+ 13 - 9
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);

+ 2 - 3
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;

+ 1 - 0
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

+ 1 - 0
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

+ 1 - 0
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);