Connect is now non-blocking. Fixed problem in resolver thread where socket was closed.
This commit is contained in:
+23
-5
@@ -101,14 +101,32 @@ private:
|
||||
ResolverThread *m_resolver;
|
||||
};
|
||||
|
||||
// State: Connecting to server.
|
||||
class ClientStateConnect : public ClientState
|
||||
// State: Initiate server connection.
|
||||
class ClientStateStartConnect : public ClientState
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ClientStateConnect &Instance();
|
||||
static ClientStateStartConnect &Instance();
|
||||
|
||||
virtual ~ClientStateConnect();
|
||||
virtual ~ClientStateStartConnect();
|
||||
|
||||
// Call connect.
|
||||
virtual int Process(ClientThread &client);
|
||||
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ClientStateStartConnect();
|
||||
};
|
||||
|
||||
// State: Connecting to server.
|
||||
class ClientStateConnecting : public ClientState
|
||||
{
|
||||
public:
|
||||
// Access the state singleton.
|
||||
static ClientStateConnecting &Instance();
|
||||
|
||||
virtual ~ClientStateConnecting();
|
||||
|
||||
// "Poll" for the completion of the TCP/IP connect call.
|
||||
virtual int Process(ClientThread &client);
|
||||
@@ -116,7 +134,7 @@ public:
|
||||
protected:
|
||||
|
||||
// Protected constructor - this is a singleton.
|
||||
ClientStateConnect();
|
||||
ClientStateConnecting();
|
||||
};
|
||||
|
||||
// State: Final (TODO).
|
||||
|
||||
@@ -61,7 +61,8 @@ private:
|
||||
friend class ClientStateInit;
|
||||
friend class ClientStateStartResolve;
|
||||
friend class ClientStateResolving;
|
||||
friend class ClientStateConnect;
|
||||
friend class ClientStateStartConnect;
|
||||
friend class ClientStateConnecting;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define CLIENT_WAIT_TIMEOUT_MSEC 100
|
||||
|
||||
|
||||
ClientState::~ClientState()
|
||||
{
|
||||
@@ -65,9 +67,9 @@ ClientStateInit::Process(ClientThread &client)
|
||||
if (!IS_VALID_SOCKET(data.sockfd))
|
||||
throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
||||
|
||||
// unsigned long mode = 1;
|
||||
// if (IOCTLSOCKET(data.sockfd, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
// throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
||||
unsigned long mode = 1;
|
||||
if (IOCTLSOCKET(data.sockfd, FIONBIO, &mode) == SOCKET_ERROR)
|
||||
throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
||||
|
||||
client.SetState(ClientStateStartResolve::Instance());
|
||||
|
||||
@@ -112,7 +114,7 @@ ClientStateStartResolve::Process(ClientThread &client)
|
||||
throw ClientException(ERR_SOCK_SET_PORT_FAILED, 0);
|
||||
|
||||
// No need to resolve - start connecting.
|
||||
client.SetState(ClientStateConnect::Instance());
|
||||
client.SetState(ClientStateStartConnect::Instance());
|
||||
retVal = MSG_SOCK_RESOLVE_DONE;
|
||||
}
|
||||
else
|
||||
@@ -167,7 +169,7 @@ ClientStateResolving::Process(ClientThread &client)
|
||||
if (!m_resolver)
|
||||
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
||||
|
||||
if (m_resolver->Join(100))
|
||||
if (m_resolver->Join(CLIENT_WAIT_TIMEOUT_MSEC))
|
||||
{
|
||||
ClientData &data = client.GetData();
|
||||
bool success = m_resolver->GetResult(data);
|
||||
@@ -176,7 +178,7 @@ ClientStateResolving::Process(ClientThread &client)
|
||||
if (!success)
|
||||
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
||||
|
||||
client.SetState(ClientStateConnect::Instance());
|
||||
client.SetState(ClientStateStartConnect::Instance());
|
||||
retVal = MSG_SOCK_RESOLVE_DONE;
|
||||
}
|
||||
else
|
||||
@@ -201,32 +203,100 @@ ClientStateResolving::Cleanup()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateConnect &
|
||||
ClientStateConnect::Instance()
|
||||
ClientStateStartConnect &
|
||||
ClientStateStartConnect::Instance()
|
||||
{
|
||||
static ClientStateConnect state;
|
||||
static ClientStateStartConnect state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ClientStateConnect::ClientStateConnect()
|
||||
ClientStateStartConnect::ClientStateStartConnect()
|
||||
{
|
||||
}
|
||||
|
||||
ClientStateConnect::~ClientStateConnect()
|
||||
ClientStateStartConnect::~ClientStateStartConnect()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateConnect::Process(ClientThread &client)
|
||||
ClientStateStartConnect::Process(ClientThread &client)
|
||||
{
|
||||
int retVal;
|
||||
ClientData &data = client.GetData();
|
||||
|
||||
if (!IS_VALID_CONNECT(connect(data.sockfd, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize())))
|
||||
throw ClientException(ERR_SOCK_CONNECT_FAILED, SOCKET_ERRNO());
|
||||
int connectResult = connect(data.sockfd, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize());
|
||||
|
||||
client.SetState(ClientStateFinal::Instance());
|
||||
if (IS_VALID_CONNECT(connectResult))
|
||||
{
|
||||
client.SetState(ClientStateFinal::Instance());
|
||||
retVal = MSG_SOCK_CONNECT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errCode = SOCKET_ERRNO();
|
||||
if (errCode == SOCKET_ERR_WOULDBLOCK)
|
||||
{
|
||||
client.SetState(ClientStateConnecting::Instance());
|
||||
retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
}
|
||||
else
|
||||
throw ClientException(ERR_SOCK_CONNECT_FAILED, SOCKET_ERRNO());
|
||||
}
|
||||
|
||||
return MSG_SOCK_CONNECT_DONE;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ClientStateConnecting &
|
||||
ClientStateConnecting::Instance()
|
||||
{
|
||||
static ClientStateConnecting state;
|
||||
return state;
|
||||
}
|
||||
|
||||
ClientStateConnecting::ClientStateConnecting()
|
||||
{
|
||||
}
|
||||
|
||||
ClientStateConnecting::~ClientStateConnecting()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
ClientStateConnecting::Process(ClientThread &client)
|
||||
{
|
||||
int retVal;
|
||||
ClientData &data = client.GetData();
|
||||
|
||||
struct fd_set writeSet;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&writeSet);
|
||||
FD_SET(data.sockfd, &writeSet);
|
||||
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = CLIENT_WAIT_TIMEOUT_MSEC * 1000;
|
||||
int selectResult = select(data.sockfd, NULL, &writeSet, NULL, &timeout);
|
||||
|
||||
if (selectResult > 0) // success
|
||||
{
|
||||
// Check whether the connect call succeeded.
|
||||
int connectResult = 0;
|
||||
int tmpSize = sizeof(connectResult);
|
||||
getsockopt(data.sockfd, SOL_SOCKET, SO_ERROR, (char *)&connectResult, &tmpSize);
|
||||
if (connectResult != 0)
|
||||
throw ClientException(ERR_SOCK_CONNECT_FAILED, connectResult);
|
||||
client.SetState(ClientStateFinal::Instance());
|
||||
retVal = MSG_SOCK_CONNECT_DONE;
|
||||
}
|
||||
else if (selectResult == 0) // timeout
|
||||
retVal = MSG_SOCK_INTERNAL_PENDING;
|
||||
else
|
||||
throw ClientException(ERR_SOCK_SELECT_FAILED, SOCKET_ERRNO());
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -43,7 +43,9 @@ ResolverThread::Init(const ClientData &data)
|
||||
if (IsRunning())
|
||||
return; // TODO: throw exception
|
||||
|
||||
*m_data = data;
|
||||
m_data->addrFamily = data.addrFamily;
|
||||
m_data->serverAddr = data.serverAddr;
|
||||
m_data->serverPort = data.serverPort;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define CLOSESOCKET closesocket
|
||||
#define IOCTLSOCKET ioctlsocket
|
||||
#define SOCKET_ERRNO() WSAGetLastError()
|
||||
#define SOCKET_ERR_WOULDBLOCK WSAEWOULDBLOCK
|
||||
#else
|
||||
#define SOCKET int
|
||||
#define SOCKET_ERROR -1
|
||||
@@ -38,6 +39,7 @@
|
||||
#define CLOSESOCKET close
|
||||
#define SOCKET_ERRNO() errno
|
||||
#define IOCTLSOCKET ioctl
|
||||
#define SOCKET_ERR_WOULDBLOCK EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
#define IS_VALID_SOCKET(_s) ((_s) != INVALID_SOCKET)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define ERR_SOCK_SET_PORT_FAILED 4
|
||||
#define ERR_SOCK_RESOLVE_FAILED 5
|
||||
#define ERR_SOCK_CONNECT_FAILED 6
|
||||
#define ERR_SOCK_SELECT_FAILED 7
|
||||
|
||||
// This is an internal message which is not reported.
|
||||
#define MSG_SOCK_INTERNAL_PENDING 0
|
||||
|
||||
Reference in New Issue
Block a user