Files
FutureChecker/ZXSocket.cpp
2013-07-21 00:33:24 +00:00

562 lines
14 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1997-1999 by Bitek System Inc.
// All rights reserved.
//
// ZXSocket.cpp : implementation of the CZXSocket class.
//
////////////////////////////////////////////////////////////////////////////////
//
// DESCRIPTION
//
// CZXSocket class
//
#include "stdafx.h"
#include "ZXSocket.h"
////////////////////////////////////////////////////////////////////////////////
//
// CZXSocket
//
////////////////////////////////////////
// Public Members :
//
//
// Constructor & Destructor
//
CZXSocket::CZXSocket(int nConnectTimeout /*= 10*/, int nReadTimeout /*= 10*/, int nWriteTimeout /*= 10*/)
{
m_nSocket = INVALID_SOCKET;
m_szConnectedServer[0] = '\0';
m_nConnectedPort = 0;
m_nConnectTimeout = nConnectTimeout;
m_nReadTimeout = nReadTimeout;
m_nWriteTimeout = nWriteTimeout;
m_bCancel = FALSE;
m_bConnected = FALSE;
}
CZXSocket::~CZXSocket()
{
Close();
}
void CZXSocket::SetConnectTimeout(int nConnectTimeout)
{
m_nConnectTimeout = nConnectTimeout;
}
void CZXSocket::SetReadTimeout(int nReadTimeout)
{
m_nReadTimeout = nReadTimeout;
}
void CZXSocket::SetWriteTimeout(int nWriteTimeout)
{
m_nWriteTimeout = nWriteTimeout;
}
int CZXSocket::Open(BOOL bServerMode)
{
long lAsyncIO = 1;
BOOL bReuse = TRUE;
if (m_nSocket != INVALID_SOCKET)
{
Close();
}
//
// socket is blocking at creation time.
//
if ((m_nSocket=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
goto _fail;
if (setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&bReuse, sizeof(bReuse)) == SOCKET_ERROR)
goto _fail;
//
// Set non-blocking IO
//
// ioctl(m_nSocket, FIONBIO, 1);
// ioctlsocket(m_nSocket, FIONBIO, (unsigned long *)&lAsyncIO);
//
if (ioctlsocket(m_nSocket, FIONBIO, (LPDWORD)&lAsyncIO) == SOCKET_ERROR)
goto _fail;
if( bServerMode )
{
if (Bind(NULL, 0) == ZXFAILURE)
goto _fail;
}
return ZXSUCCESS;
_fail:
Close();
return ZXFAILURE;
}
int CZXSocket::Close()
{
int nResult = ZXSUCCESS;
if (m_nSocket == INVALID_SOCKET)
return nResult;
if (WSAIsBlocking())
WSACancelBlockingCall();
shutdown(m_nSocket, SD_BOTH);
if (closesocket(m_nSocket) == SOCKET_ERROR)
nResult = ZXFAILURE;
m_nSocket = INVALID_SOCKET;
m_bConnected = FALSE;
return nResult;
}
int CZXSocket::Bind(LPCTSTR lpszServer, int nPort)
{
SOCKADDR_IN sockAddr;
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
//
// Check if address is IP address format of hostname format.
//
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = (lpszServer == NULL) ? htonl(INADDR_ANY) : inet_addr(lpszServer);
sockAddr.sin_port = htons((u_short)nPort);
//
// copy network address of destination to structure
//
if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
LPHOSTENT lpHost;
lpHost = gethostbyname(lpszServer);
if (lpHost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lpHost->h_addr)->s_addr;
else {
// WSASetLastError(WSAEINVAL);
return ZXFAILURE;
}
}
//
// Bind the socket to the port which will system choose.
//
if (bind(m_nSocket, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
return ZXFAILURE;
return ZXSUCCESS;
}
int CZXSocket::Listen(int nBackLog)
{
// Queue the this listening socket
if (listen(m_nSocket, nBackLog) == SOCKET_ERROR)
return ZXFAILURE;
return ZXSUCCESS;
}
int CZXSocket::Connect(LPCTSTR lpszServer, int nPort)
{
SOCKADDR_IN sockAddr;
int nState;
if (m_nSocket == INVALID_SOCKET) {
return ZXFAILURE;
}
if (lpszServer[0] == '['
&& lpszServer[strlen(lpszServer) -1] == ']') {
strcpy(m_szConnectedServer, lpszServer+1);
m_szConnectedServer[strlen(m_szConnectedServer) -1] = '\0';
}
else {
strcpy(m_szConnectedServer, lpszServer);
}
m_nConnectedPort = nPort;
//
// Check if address is IP address format of hostname format.
//
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = inet_addr(lpszServer);
sockAddr.sin_port = htons((u_short)nPort);
//
// copy network address of destination to structure
//
if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
LPHOSTENT lpHost;
lpHost = gethostbyname(lpszServer);
if (lpHost != NULL)
sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lpHost->h_addr)->s_addr;
else {
// WSASetLastError(WSAEINVAL);
return ZXFAILURE;
}
}
nState = connect(m_nSocket, (LPSOCKADDR)&sockAddr, sizeof(sockAddr));
if (m_bCancel == TRUE) {
return ZXFAILURE;
}
if (nState == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK) {
TIMEVAL tv = { 1, 0 /*TIMEVAL_USEC*/ };
FD_SET fds, exceptfds;
int nTimeoutRemain = 0;
while (1) {
FD_ZERO(&fds);
FD_ZERO(&exceptfds);
FD_SET(m_nSocket, &fds);
FD_SET(m_nSocket, &exceptfds);
nState = select(m_nSocket+1, NULL, &fds, &exceptfds, &tv);
if (m_bCancel == TRUE) {
return ZXFAILURE;
}
if (nState == 0) { // Timeout
if (++nTimeoutRemain == m_nConnectTimeout)
return ZXFAILURE;
continue;
}
else if (nState == SOCKET_ERROR) {
return ZXFAILURE;
}
if (FD_ISSET(m_nSocket, &exceptfds)) { // Failure
WSASetLastError(WSAECONNREFUSED);
return ZXFAILURE;
}
if (FD_ISSET(m_nSocket, &fds)) { // Success
break;
}
} // while
}
else {
return ZXFAILURE;
}
}
m_bConnected = TRUE;
return ZXSUCCESS;
}
int CZXSocket::Accept(CZXSocket* lpConnectedSocket)
{
SOCKADDR_IN sockAddr;
int nLength;
TIMEVAL tv = { 1, 0 /*TIMEVAL_USEC*/ };
FD_SET fds;
int nTimeoutRemain = 0;
int nState;
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
nLength = sizeof(sockAddr);
while (1) {
FD_ZERO(&fds);
FD_SET(m_nSocket, &fds);
nState = select(m_nSocket+1, &fds, NULL, NULL, &tv);
if (m_bCancel == TRUE) {
return ZXFAILURE;
}
if (nState == 0) { // Timeout
if (++nTimeoutRemain == m_nReadTimeout)
return ZXFAILURE;
continue;
}
else if (nState == SOCKET_ERROR) {
return ZXFAILURE;
}
if (!FD_ISSET(m_nSocket, &fds))
continue;
lpConnectedSocket->m_nSocket = accept(m_nSocket, (LPSOCKADDR)&sockAddr, &nLength);
if (lpConnectedSocket->m_nSocket == INVALID_SOCKET) {
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return ZXFAILURE;
}
else
break;
}
_tcscpy(lpConnectedSocket->m_szConnectedServer, m_szConnectedServer);
lpConnectedSocket->m_nConnectedPort = m_nConnectedPort;
lpConnectedSocket->m_nConnectTimeout = m_nConnectTimeout;
lpConnectedSocket->m_nReadTimeout = m_nReadTimeout;
lpConnectedSocket->m_nWriteTimeout = m_nWriteTimeout;
return ZXSUCCESS;
}
int CZXSocket::GetSockName(LPTSTR* lppszSocketAddress, int* lpnSocketPort)
{
SOCKADDR_IN sockAddr;
int nLength;
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
nLength = sizeof(sockAddr);
if (getsockname(m_nSocket, (LPSOCKADDR)&sockAddr, &nLength) == SOCKET_ERROR)
return ZXFAILURE;
if (lppszSocketAddress != NULL)
*lppszSocketAddress = inet_ntoa(sockAddr.sin_addr);
if (lpnSocketPort != NULL)
*lpnSocketPort = ntohs(sockAddr.sin_port);
return ZXSUCCESS;
}
/***
int CZXSocket::GetSockAddr(LPSOCKADDR lpSockAddr, int* lpnSockAddrLen)
{
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
if (getsockname(m_nSocket, (LPSOCKADDR)lpSockAddr, lpnSockAddrLen) == SOCKET_ERROR)
return ZXFAILURE;
return ZXSUCCESS;
}
***/
////////////////////////////////////////////////////////////////////////////////
int CZXSocket::ReadBytes(LPSTR lpszBuffer, int nLength)
{
TIMEVAL tv = { 1, 0 /*TIMEVAL_USEC*/ };
FD_SET fds;
int nTimeoutRemain = 0;
int nBufferOffset, nBufferRemain, nLen;
int nState;
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
nBufferRemain = nLength;
nBufferOffset = 0;
while (nBufferRemain > 0) {
FD_ZERO(&fds);
FD_SET(m_nSocket, &fds);
nState = select(m_nSocket+1, &fds, NULL, NULL, &tv);
if (m_bCancel == TRUE) {
return ZXFAILURE;
}
if (nState == 0) { // Timeout
if (++nTimeoutRemain == m_nReadTimeout)
return ZXFAILURE;
continue;
}
else if (nState == SOCKET_ERROR) {
return ZXFAILURE;
}
if (!FD_ISSET(m_nSocket, &fds))
continue;
nLen = recv(m_nSocket, lpszBuffer+nBufferOffset, nBufferRemain, 0);
if (nLen == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return ZXFAILURE;
}
else if (nLen == 0) {
break;
}
nBufferRemain -= nLen;
nBufferOffset += nLen;
}
return nBufferOffset;
}
int CZXSocket::WriteBytes(LPCSTR lpszBuffer, int nLength)
{
TIMEVAL tv = { 1, 0 /*TIMEVAL_USEC*/ };
FD_SET fds;
int nTimeoutRemain = 0;
int nBufferOffset, nBufferRemain, nLen;
int nState;
if (m_nSocket == INVALID_SOCKET)
return ZXFAILURE;
nBufferRemain = nLength;
nBufferOffset = 0;
while (nBufferRemain > 0) {
FD_ZERO(&fds);
FD_SET(m_nSocket, &fds);
nState = select(m_nSocket+1, NULL, &fds, NULL, &tv);
if (m_bCancel == TRUE) {
return ZXFAILURE;
}
if (nState == 0) { // Timeout
if (++nTimeoutRemain == m_nWriteTimeout)
return ZXFAILURE;
continue;
}
else if (nState == SOCKET_ERROR) {
return ZXFAILURE;
}
if (!FD_ISSET(m_nSocket, &fds))
continue;
nLen = send(m_nSocket, lpszBuffer+nBufferOffset, nBufferRemain, 0);
if (nLen == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEWOULDBLOCK)
continue;
return ZXFAILURE;
}
nBufferRemain -= nLen;
nBufferOffset += nLen;
}
return nBufferOffset;
}
////////////////////////////////////////////////////////////////////////////////
int CZXSocket::ReadLine(LPTSTR lpszLine, int nLength)
{
BOOL bFindReturn;
int nIndex;
bFindReturn = FALSE;
nIndex = 0;
while (1) {
if (nIndex >= nLength-1)
nIndex = 0;
if (ReadBytes(lpszLine+nIndex, 1) <= 0)
return ZXFAILURE;
if (!bFindReturn) {
if (lpszLine[nIndex++] == '\r')
bFindReturn = TRUE;
}
else {
if (lpszLine[nIndex++] == '\n')
break;
}
}
if (--nIndex <= 0)
return ZXFAILURE;
while (lpszLine[nIndex] == '\r' || lpszLine[nIndex] == '\n') nIndex--;
lpszLine[nIndex+1] = '\0';
return nIndex;
}
int CZXSocket::WriteLine(LPCTSTR lpszLine)
{
int nLength;
if ((nLength=_tcslen(lpszLine)) == 0)
return ZXFAILURE;
if (_tcscmp(&lpszLine[nLength-2], _T("\r\n"))) {
LPTSTR lpLine;
lpLine = new TCHAR[nLength+3];
if (lpLine == NULL)
return ZXFAILURE;
_stprintf(lpLine, _T("%s\r\n"), lpszLine);
return WriteBytes(lpLine, _tcslen(lpLine));
}
return WriteBytes((LPTSTR)lpszLine, _tcslen(lpszLine));
}
BOOL CZXSocket::HasConnectionDropped( void )
{
if (m_nSocket == INVALID_SOCKET)
return FALSE;
BOOL bConnDropped = FALSE;
INT iRet = 0;
BOOL bOK = TRUE;
struct timeval timeout = { 0, 0 };
fd_set readSocketSet;
FD_ZERO( &readSocketSet );
FD_SET( m_nSocket, &readSocketSet );
iRet = ::select( 0, &readSocketSet, NULL, NULL, &timeout );
bOK = ( iRet > 0 );
if( bOK )
{
bOK = FD_ISSET( m_nSocket, &readSocketSet );
}
if( bOK )
{
CHAR szBuffer[1] = "";
iRet = ::recv( m_nSocket, szBuffer, 1, MSG_PEEK );
bOK = ( iRet > 0 );
if( !bOK )
{
INT iError = ::WSAGetLastError();
bConnDropped = ( ( iError == WSAENETRESET ) ||
( iError == WSAECONNABORTED ) ||
( iError == WSAECONNRESET ) ||
( iError == WSAEINVAL ) ||
( iRet == 0 ) ); //Graceful disconnect from other side.
}
}
return( bConnDropped );
}