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;
|
ResolverThread *m_resolver;
|
||||||
};
|
};
|
||||||
|
|
||||||
// State: Connecting to server.
|
// State: Initiate server connection.
|
||||||
class ClientStateConnect : public ClientState
|
class ClientStateStartConnect : public ClientState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Access the state singleton.
|
// 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.
|
// "Poll" for the completion of the TCP/IP connect call.
|
||||||
virtual int Process(ClientThread &client);
|
virtual int Process(ClientThread &client);
|
||||||
@@ -116,7 +134,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Protected constructor - this is a singleton.
|
// Protected constructor - this is a singleton.
|
||||||
ClientStateConnect();
|
ClientStateConnecting();
|
||||||
};
|
};
|
||||||
|
|
||||||
// State: Final (TODO).
|
// State: Final (TODO).
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ private:
|
|||||||
friend class ClientStateInit;
|
friend class ClientStateInit;
|
||||||
friend class ClientStateStartResolve;
|
friend class ClientStateStartResolve;
|
||||||
friend class ClientStateResolving;
|
friend class ClientStateResolving;
|
||||||
friend class ClientStateConnect;
|
friend class ClientStateStartConnect;
|
||||||
|
friend class ClientStateConnecting;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#define CLIENT_WAIT_TIMEOUT_MSEC 100
|
||||||
|
|
||||||
|
|
||||||
ClientState::~ClientState()
|
ClientState::~ClientState()
|
||||||
{
|
{
|
||||||
@@ -65,9 +67,9 @@ ClientStateInit::Process(ClientThread &client)
|
|||||||
if (!IS_VALID_SOCKET(data.sockfd))
|
if (!IS_VALID_SOCKET(data.sockfd))
|
||||||
throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
||||||
|
|
||||||
// unsigned long mode = 1;
|
unsigned long mode = 1;
|
||||||
// if (IOCTLSOCKET(data.sockfd, FIONBIO, &mode) == SOCKET_ERROR)
|
if (IOCTLSOCKET(data.sockfd, FIONBIO, &mode) == SOCKET_ERROR)
|
||||||
// throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
throw ClientException(ERR_SOCK_CREATION_FAILED, SOCKET_ERRNO());
|
||||||
|
|
||||||
client.SetState(ClientStateStartResolve::Instance());
|
client.SetState(ClientStateStartResolve::Instance());
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ ClientStateStartResolve::Process(ClientThread &client)
|
|||||||
throw ClientException(ERR_SOCK_SET_PORT_FAILED, 0);
|
throw ClientException(ERR_SOCK_SET_PORT_FAILED, 0);
|
||||||
|
|
||||||
// No need to resolve - start connecting.
|
// No need to resolve - start connecting.
|
||||||
client.SetState(ClientStateConnect::Instance());
|
client.SetState(ClientStateStartConnect::Instance());
|
||||||
retVal = MSG_SOCK_RESOLVE_DONE;
|
retVal = MSG_SOCK_RESOLVE_DONE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -167,7 +169,7 @@ ClientStateResolving::Process(ClientThread &client)
|
|||||||
if (!m_resolver)
|
if (!m_resolver)
|
||||||
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
||||||
|
|
||||||
if (m_resolver->Join(100))
|
if (m_resolver->Join(CLIENT_WAIT_TIMEOUT_MSEC))
|
||||||
{
|
{
|
||||||
ClientData &data = client.GetData();
|
ClientData &data = client.GetData();
|
||||||
bool success = m_resolver->GetResult(data);
|
bool success = m_resolver->GetResult(data);
|
||||||
@@ -176,7 +178,7 @@ ClientStateResolving::Process(ClientThread &client)
|
|||||||
if (!success)
|
if (!success)
|
||||||
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
throw ClientException(ERR_SOCK_RESOLVE_FAILED, 0);
|
||||||
|
|
||||||
client.SetState(ClientStateConnect::Instance());
|
client.SetState(ClientStateStartConnect::Instance());
|
||||||
retVal = MSG_SOCK_RESOLVE_DONE;
|
retVal = MSG_SOCK_RESOLVE_DONE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -201,32 +203,100 @@ ClientStateResolving::Cleanup()
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
ClientStateConnect &
|
ClientStateStartConnect &
|
||||||
ClientStateConnect::Instance()
|
ClientStateStartConnect::Instance()
|
||||||
{
|
{
|
||||||
static ClientStateConnect state;
|
static ClientStateStartConnect state;
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientStateConnect::ClientStateConnect()
|
ClientStateStartConnect::ClientStateStartConnect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientStateConnect::~ClientStateConnect()
|
ClientStateStartConnect::~ClientStateStartConnect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ClientStateConnect::Process(ClientThread &client)
|
ClientStateStartConnect::Process(ClientThread &client)
|
||||||
{
|
{
|
||||||
|
int retVal;
|
||||||
ClientData &data = client.GetData();
|
ClientData &data = client.GetData();
|
||||||
|
|
||||||
if (!IS_VALID_CONNECT(connect(data.sockfd, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize())))
|
int connectResult = connect(data.sockfd, (struct sockaddr *)&data.clientAddr, data.GetServerAddrSize());
|
||||||
throw ClientException(ERR_SOCK_CONNECT_FAILED, SOCKET_ERRNO());
|
|
||||||
|
|
||||||
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())
|
if (IsRunning())
|
||||||
return; // TODO: throw exception
|
return; // TODO: throw exception
|
||||||
|
|
||||||
*m_data = data;
|
m_data->addrFamily = data.addrFamily;
|
||||||
|
m_data->serverAddr = data.serverAddr;
|
||||||
|
m_data->serverPort = data.serverPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#define CLOSESOCKET closesocket
|
#define CLOSESOCKET closesocket
|
||||||
#define IOCTLSOCKET ioctlsocket
|
#define IOCTLSOCKET ioctlsocket
|
||||||
#define SOCKET_ERRNO() WSAGetLastError()
|
#define SOCKET_ERRNO() WSAGetLastError()
|
||||||
|
#define SOCKET_ERR_WOULDBLOCK WSAEWOULDBLOCK
|
||||||
#else
|
#else
|
||||||
#define SOCKET int
|
#define SOCKET int
|
||||||
#define SOCKET_ERROR -1
|
#define SOCKET_ERROR -1
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
#define CLOSESOCKET close
|
#define CLOSESOCKET close
|
||||||
#define SOCKET_ERRNO() errno
|
#define SOCKET_ERRNO() errno
|
||||||
#define IOCTLSOCKET ioctl
|
#define IOCTLSOCKET ioctl
|
||||||
|
#define SOCKET_ERR_WOULDBLOCK EWOULDBLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define IS_VALID_SOCKET(_s) ((_s) != INVALID_SOCKET)
|
#define IS_VALID_SOCKET(_s) ((_s) != INVALID_SOCKET)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#define ERR_SOCK_SET_PORT_FAILED 4
|
#define ERR_SOCK_SET_PORT_FAILED 4
|
||||||
#define ERR_SOCK_RESOLVE_FAILED 5
|
#define ERR_SOCK_RESOLVE_FAILED 5
|
||||||
#define ERR_SOCK_CONNECT_FAILED 6
|
#define ERR_SOCK_CONNECT_FAILED 6
|
||||||
|
#define ERR_SOCK_SELECT_FAILED 7
|
||||||
|
|
||||||
// This is an internal message which is not reported.
|
// This is an internal message which is not reported.
|
||||||
#define MSG_SOCK_INTERNAL_PENDING 0
|
#define MSG_SOCK_INTERNAL_PENDING 0
|
||||||
|
|||||||
Reference in New Issue
Block a user