mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-12 23:46:52 +00:00
new network code to make the server not hung in receives
This commit is contained in:
parent
bb1118204d
commit
a345c4ab7c
@ -21,6 +21,7 @@
|
|||||||
#include "wassert.hpp"
|
#include "wassert.hpp"
|
||||||
//#include "wesconfig.h"
|
//#include "wesconfig.h"
|
||||||
#include "serialization/binary_wml.hpp"
|
#include "serialization/binary_wml.hpp"
|
||||||
|
#include "serialization/binary_or_text.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
@ -128,7 +129,59 @@ threading::condition* cond = NULL;
|
|||||||
std::map<Uint32,threading::thread*> threads;
|
std::map<Uint32,threading::thread*> threads;
|
||||||
std::vector<Uint32> to_clear;
|
std::vector<Uint32> to_clear;
|
||||||
|
|
||||||
|
int receive_bytes(TCPsocket s, char* buf, size_t nbytes)
|
||||||
|
{
|
||||||
|
#ifdef NETWORK_USE_RAW_SOCKETS
|
||||||
|
const _TCPsocket* sock = reinterpret_cast<const _TCPsocket*>(s);
|
||||||
|
return recv(sock->channel, buf, nbytes, MSG_DONTWAIT|MSG_ERRQUEUE);
|
||||||
|
#else
|
||||||
|
return SDLNet_TCP_Recv(s, buf, nbytes);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool receive_with_timeout(TCPsocket s, char* buf, size_t nbytes, bool update_stats=false, int timeout_ms=60000)
|
||||||
|
{
|
||||||
|
int nsleeps = 0;
|
||||||
|
while(nbytes > 0) {
|
||||||
|
const int bytes_read = receive_bytes(s, buf, nbytes);
|
||||||
|
if(bytes_read == 0) {
|
||||||
|
return false;
|
||||||
|
} else if(bytes_read < 0) {
|
||||||
|
#if defined(EAGAIN) && !defined(__BEOS__) && !defined(_WIN32)
|
||||||
|
if(errno == EAGAIN)
|
||||||
|
#elif defined(EWOULDBLOCK)
|
||||||
|
if(errno == EWOULDBLOCK)
|
||||||
|
#else
|
||||||
|
if(false)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
//TODO: consider replacing this with a select call
|
||||||
|
if(++nsleeps == timeout_ms) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
usleep(1000);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(bytes_read > static_cast<int>(nbytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nbytes -= bytes_read;
|
||||||
|
buf += bytes_read;
|
||||||
|
if(update_stats) {
|
||||||
|
const threading::lock lock(*global_mutex);
|
||||||
|
transfer_stats[s].second.transfer(static_cast<size_t>(bytes_read));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static SOCKET_STATE send_buf(TCPsocket sock, config& config_in) {
|
static SOCKET_STATE send_buf(TCPsocket sock, config& config_in) {
|
||||||
|
write_possibly_compressed(std::cerr, config_in, false);
|
||||||
#ifdef __BEOS__
|
#ifdef __BEOS__
|
||||||
int timeout = 15000;
|
int timeout = 15000;
|
||||||
#endif
|
#endif
|
||||||
@ -223,13 +276,13 @@ static SOCKET_STATE send_buf(TCPsocket sock, config& config_in) {
|
|||||||
static SOCKET_STATE receive_buf(TCPsocket sock, std::vector<char>& buf)
|
static SOCKET_STATE receive_buf(TCPsocket sock, std::vector<char>& buf)
|
||||||
{
|
{
|
||||||
char num_buf[4];
|
char num_buf[4];
|
||||||
int len = SDLNet_TCP_Recv(sock,num_buf,4);
|
bool res = receive_with_timeout(sock,num_buf,4,false);
|
||||||
|
|
||||||
if(len != 4) {
|
if(!res) {
|
||||||
return SOCKET_ERRORED;
|
return SOCKET_ERRORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = SDLNet_Read32(num_buf);
|
const int len = SDLNet_Read32(num_buf);
|
||||||
|
|
||||||
if(len < 1 || len > 100000000) {
|
if(len < 1 || len > 100000000) {
|
||||||
return SOCKET_ERRORED;
|
return SOCKET_ERRORED;
|
||||||
@ -244,61 +297,11 @@ static SOCKET_STATE receive_buf(TCPsocket sock, std::vector<char>& buf)
|
|||||||
transfer_stats[sock].second.fresh_current(len);
|
transfer_stats[sock].second.fresh_current(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(beg != end) {
|
res = receive_with_timeout(sock, beg, end - beg, true);
|
||||||
{
|
if(!res) {
|
||||||
// if we are receiving the socket is in sockets_locked
|
return SOCKET_ERRORED;
|
||||||
// check if it is still locked
|
|
||||||
const threading::lock lock(*global_mutex);
|
|
||||||
if(sockets_locked[sock] != SOCKET_LOCKED) {
|
|
||||||
return SOCKET_ERRORED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const int res = SDLNet_TCP_Recv(sock, beg, end - beg);
|
|
||||||
if(res <= 0) {
|
|
||||||
#if defined(EAGAIN) && !defined(__BEOS__) && !defined(_WIN32)
|
|
||||||
if(errno == EAGAIN)
|
|
||||||
#elif defined(EWOULDBLOCK)
|
|
||||||
if(errno == EWOULDBLOCK)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
|
|
||||||
#ifdef USE_POLL
|
|
||||||
struct pollfd fd = { ((_TCPsocket*)sock)->channel, POLLIN, 0 };
|
|
||||||
int poll_res;
|
|
||||||
do {
|
|
||||||
poll_res = poll(&fd, 1, 15000);
|
|
||||||
} while(poll_res == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if(poll_res > 0)
|
|
||||||
continue;
|
|
||||||
#elif defined(USE_SELECT)
|
|
||||||
fd_set readfds;
|
|
||||||
FD_ZERO(&readfds);
|
|
||||||
FD_SET(((_TCPsocket*)sock)->channel, &readfds);
|
|
||||||
int retval;
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = 15;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
retval = select(((_TCPsocket*)sock)->channel + 1, &readfds, NULL, NULL, &tv);
|
|
||||||
} while(retval == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if(retval > 0)
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
return SOCKET_ERRORED;
|
|
||||||
}
|
|
||||||
|
|
||||||
beg += res;
|
|
||||||
{
|
|
||||||
const threading::lock lock(*global_mutex);
|
|
||||||
transfer_stats[sock].second.transfer(static_cast<size_t>(res));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SOCKET_READY;
|
return SOCKET_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user