diff --git a/src/gui/qt/mainwindow/mainwindowimpl.cpp b/src/gui/qt/mainwindow/mainwindowimpl.cpp index a62045bd..6205c9a2 100755 --- a/src/gui/qt/mainwindow/mainwindowimpl.cpp +++ b/src/gui/qt/mainwindow/mainwindowimpl.cpp @@ -2335,6 +2335,11 @@ void mainWindowImpl::networkError(int errorID, int osErrorID) { tr("Could not connect to the server."), QMessageBox::Close); } break; + case ERR_SOCK_CONNECT_TIMEOUT: + { QMessageBox::warning(this, tr("Network Error"), + tr("Connection timed out.\nPlease check the server address.\n\nIf the server is behind a NAT-Router, make sure port forwarding has been set up on server side."), + QMessageBox::Close); } + break; case ERR_SOCK_SELECT_FAILED: { QMessageBox::warning(this, tr("Network Error"), tr("Internal network error: \"select\" failed."), diff --git a/src/net/clientstate.h b/src/net/clientstate.h index 01050dd5..b3e4b18b 100644 --- a/src/net/clientstate.h +++ b/src/net/clientstate.h @@ -21,8 +21,10 @@ #ifndef _CLIENTSTATE_H_ #define _CLIENTSTATE_H_ +#include // needed for correct order of header files. #include #include +#include #define CLIENT_INITIAL_STATE ClientStateInit @@ -110,6 +112,8 @@ public: virtual ~ClientStateStartConnect(); + void SetTimer(boost::microsec_timer timer); + // Call connect. virtual int Process(ClientThread &client); @@ -128,6 +132,8 @@ public: virtual ~ClientStateConnecting(); + void SetTimer(const boost::microsec_timer &timer); + // "Poll" for the completion of the TCP/IP connect call. virtual int Process(ClientThread &client); @@ -135,6 +141,10 @@ protected: // Protected constructor - this is a singleton. ClientStateConnecting(); + +private: + + boost::microsec_timer m_connectTimer; }; // State: Session init. diff --git a/src/net/common/clientstate.cpp b/src/net/common/clientstate.cpp index 01c4d496..d6576620 100644 --- a/src/net/common/clientstate.cpp +++ b/src/net/common/clientstate.cpp @@ -34,6 +34,7 @@ using namespace std; #define CLIENT_WAIT_TIMEOUT_MSEC 50 +#define CLIENT_CONNECT_TIMEOUT_SEC 10 ClientState::~ClientState() @@ -240,6 +241,9 @@ ClientStateStartConnect::Process(ClientThread &client) int errCode = SOCKET_ERRNO(); if (errCode == SOCKET_ERR_WOULDBLOCK) { + boost::microsec_timer connectTimer; + connectTimer.start(); + ClientStateConnecting::Instance().SetTimer(connectTimer); client.SetState(ClientStateConnecting::Instance()); retVal = MSG_SOCK_INTERNAL_PENDING; } @@ -267,6 +271,12 @@ ClientStateConnecting::~ClientStateConnecting() { } +void +ClientStateConnecting::SetTimer(const boost::microsec_timer &timer) +{ + m_connectTimer = timer; +} + int ClientStateConnecting::Process(ClientThread &client) { @@ -295,7 +305,12 @@ ClientStateConnecting::Process(ClientThread &client) retVal = MSG_SOCK_CONNECT_DONE; } else if (selectResult == 0) // timeout - retVal = MSG_SOCK_INTERNAL_PENDING; + { + if (m_connectTimer.elapsed().seconds() >= CLIENT_CONNECT_TIMEOUT_SEC) + throw ClientException(ERR_SOCK_CONNECT_TIMEOUT, 0); + else + retVal = MSG_SOCK_INTERNAL_PENDING; + } else throw ClientException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO()); diff --git a/src/net/socket_msg.h b/src/net/socket_msg.h index 2a719028..13d57c52 100644 --- a/src/net/socket_msg.h +++ b/src/net/socket_msg.h @@ -32,13 +32,14 @@ #define ERR_SOCK_LISTEN_FAILED 9 #define ERR_SOCK_ACCEPT_FAILED 10 #define ERR_SOCK_CONNECT_FAILED 11 -#define ERR_SOCK_SELECT_FAILED 12 -#define ERR_SOCK_RECV_FAILED 13 -#define ERR_SOCK_SEND_FAILED 14 -#define ERR_SOCK_CONN_RESET 15 -#define ERR_SOCK_CONN_EXISTS 16 -#define ERR_SOCK_INVALID_PACKET 17 -#define ERR_SOCK_INVALID_STATE 18 +#define ERR_SOCK_CONNECT_TIMEOUT 12 +#define ERR_SOCK_SELECT_FAILED 13 +#define ERR_SOCK_RECV_FAILED 14 +#define ERR_SOCK_SEND_FAILED 15 +#define ERR_SOCK_CONN_RESET 16 +#define ERR_SOCK_CONN_EXISTS 17 +#define ERR_SOCK_INVALID_PACKET 18 +#define ERR_SOCK_INVALID_STATE 19 // The following errors are game errors. #define ERR_NET_VERSION_NOT_SUPPORTED 101 #define ERR_NET_SERVER_FULL 102