summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-10-17 20:24:48 +0000
committerultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec>2007-10-17 20:24:48 +0000
commit5f6a6a2557a90573a504b541a3234f0dc566bf6a (patch)
tree4e4522d1c1c7411a2c7672af9af7887333dcdc50
parent724babffe10a6908d1510c941e5abfbe840fd271 (diff)
downloadhercules-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
-rw-r--r--Changelog-Trunk.txt5
-rw-r--r--src/char/char.c4
-rw-r--r--src/char_sql/char.c4
-rw-r--r--src/common/core.c57
-rw-r--r--src/common/socket.c193
-rw-r--r--src/common/socket.h22
-rw-r--r--src/ladmin/ladmin.c5
-rw-r--r--src/login/login.c1
-rw-r--r--src/login_sql/login.c1
-rw-r--r--src/map/chrif.c1
10 files changed, 140 insertions, 153 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 5ccc9516a..2c4930c1e 100644
--- a/Changelog-Trunk.txt
+++ b/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)
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);