Connect is now non-blocking. Fixed problem in resolver thread where socket was closed.

This commit is contained in:
lotodore
2007-02-25 18:22:19 +00:00
parent d63588f54b
commit 82cf963f0a
6 changed files with 117 additions and 23 deletions
+23 -5
View File
@@ -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).
+2 -1
View File
@@ -61,7 +61,8 @@ private:
friend class ClientStateInit;
friend class ClientStateStartResolve;
friend class ClientStateResolving;
friend class ClientStateConnect;
friend class ClientStateStartConnect;
friend class ClientStateConnecting;
};
#endif
+86 -16
View File
@@ -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;
}
//-----------------------------------------------------------------------------
+3 -1
View File
@@ -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
+2
View File
@@ -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)
+1
View File
@@ -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