/////////////////////////////////////////////////////////////////////////////// // // 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 ); }