// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include #ifdef AFX_SOCK_SEG #pragma code_seg(AFX_SOCK_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW #define _afxSockThreadState AfxGetModuleThreadState() #define _AFX_SOCK_THREAD_STATE AFX_MODULE_THREAD_STATE #pragma comment(lib, "wsock32.lib") ///////////////////////////////////////////////////////////////////////////// // socket state cleanup _AFX_SOCK_STATE::~_AFX_SOCK_STATE() { if (m_pfnSockTerm != NULL) m_pfnSockTerm(); } ///////////////////////////////////////////////////////////////////////////// // sockets globals and implementation helpers void AFXAPI AfxSocketTerm() { _AFX_SOCK_STATE* pState = _afxSockState.GetData(); if (pState->m_hInstSOCK != NULL) { if (pState->m_pfnSockTerm != NULL) WSACleanup(); FreeLibrary(pState->m_hInstSOCK);// handle of WSOCK32.DLL pState->m_hInstSOCK = NULL; } } BOOL AFXAPI AfxSocketInit(WSADATA* lpwsaData) { _AFX_SOCK_STATE* pState = _afxSockState.GetData(); if (pState->m_pfnSockTerm == NULL) { // initialize Winsock library WSADATA wsaData; if (lpwsaData == NULL) lpwsaData = &wsaData; WORD wVersionRequested = MAKEWORD(1, 1); int nResult = WSAStartup(wVersionRequested, lpwsaData); if (nResult != 0) return FALSE; if (LOBYTE(lpwsaData->wVersion) != 1 || HIBYTE(lpwsaData->wVersion) != 1) { WSACleanup(); return FALSE; } // setup for termination of sockets pState->m_pfnSockTerm = &AfxSocketTerm; #ifndef _AFXDLL // setup maps and lists specific to socket state _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; if (pState->m_pmapSocketHandle == NULL) pState->m_pmapSocketHandle = new CMapPtrToPtr; if (pState->m_pmapDeadSockets == NULL) pState->m_pmapDeadSockets = new CMapPtrToPtr; if (pState->m_plistSocketNotifications == NULL) pState->m_plistSocketNotifications = new CPtrList; #endif } return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CAsyncSocket Construction CAsyncSocket::CAsyncSocket() { m_hSocket = INVALID_SOCKET; } BOOL CAsyncSocket::Create(UINT nSocketPort, int nSocketType, long lEvent, LPCTSTR lpszSocketAddress) { if (Socket(nSocketType, lEvent)) { if (Bind(nSocketPort,lpszSocketAddress)) return TRUE; int nResult = GetLastError(); Close(); WSASetLastError(nResult); } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // CAsyncSocket Attributes BOOL CAsyncSocket::Attach(SOCKET hSocket, long lEvent) { ASSERT(hSocket != INVALID_SOCKET); m_hSocket = hSocket; CAsyncSocket::AttachHandle(hSocket, this); return AsyncSelect(lEvent); } SOCKET CAsyncSocket::Detach() { SOCKET hSocket = m_hSocket; if (AsyncSelect(0)) { CAsyncSocket::KillSocket(hSocket, this); m_hSocket = INVALID_SOCKET; return hSocket; } return INVALID_SOCKET; } BOOL CAsyncSocket::GetPeerName(CString& rPeerAddress, UINT& rPeerPort) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) { rPeerPort = ntohs(sockAddr.sin_port); rPeerAddress = inet_ntoa(sockAddr.sin_addr); } return bResult; } BOOL CAsyncSocket::GetSockName(CString& rSocketAddress, UINT& rSocketPort) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); BOOL bResult = GetSockName((SOCKADDR*)&sockAddr, &nSockAddrLen); if (bResult) { rSocketPort = ntohs(sockAddr.sin_port); rSocketAddress = inet_ntoa(sockAddr.sin_addr); } return bResult; } ///////////////////////////////////////////////////////////////////////////// // CAscynSocket Operations BOOL CAsyncSocket::Accept(CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr, int* lpSockAddrLen) { ASSERT(rConnectedSocket.m_hSocket == INVALID_SOCKET); ASSERT(CAsyncSocket::FromHandle(INVALID_SOCKET) == NULL); CAsyncSocket::AttachHandle(INVALID_SOCKET, &rConnectedSocket); SOCKET hTemp = accept(m_hSocket, lpSockAddr, lpSockAddrLen); if (hTemp == INVALID_SOCKET) { DWORD dwProblem = GetLastError(); CAsyncSocket::DetachHandle(rConnectedSocket.m_hSocket, FALSE); rConnectedSocket.m_hSocket = INVALID_SOCKET; SetLastError(dwProblem); } else if (CAsyncSocket::FromHandle(INVALID_SOCKET) != NULL) { rConnectedSocket.m_hSocket = hTemp; CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE); CAsyncSocket::AttachHandle(hTemp, &rConnectedSocket); } return (hTemp != INVALID_SOCKET); } BOOL CAsyncSocket::Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress) { USES_CONVERSION; SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); LPSTR lpszAscii = T2A((LPTSTR)lpszSocketAddress); sockAddr.sin_family = AF_INET; if (lpszAscii == NULL) sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); else { DWORD lResult = inet_addr(lpszAscii); if (lResult == INADDR_NONE) { WSASetLastError(WSAEINVAL); return FALSE; } sockAddr.sin_addr.s_addr = lResult; } sockAddr.sin_port = htons((u_short)nSocketPort); return Bind((SOCKADDR*)&sockAddr, sizeof(sockAddr)); } void CAsyncSocket::Close() { if (m_hSocket != INVALID_SOCKET) { VERIFY(SOCKET_ERROR != closesocket(m_hSocket)); CAsyncSocket::KillSocket(m_hSocket, this); m_hSocket = INVALID_SOCKET; } } BOOL CAsyncSocket::Connect(LPCTSTR lpszHostAddress, UINT nHostPort) { USES_CONVERSION; ASSERT(lpszHostAddress != NULL); SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); LPSTR lpszAscii = T2A((LPTSTR)lpszHostAddress); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr(lpszAscii); if (sockAddr.sin_addr.s_addr == INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(lpszAscii); if (lphost != NULL) sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; else { WSASetLastError(WSAEINVAL); return FALSE; } } sockAddr.sin_port = htons((u_short)nHostPort); return Connect((SOCKADDR*)&sockAddr, sizeof(sockAddr)); } int CAsyncSocket::Receive(void* lpBuf, int nBufLen, int nFlags) { return recv(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags); } int CAsyncSocket::ReceiveFrom(void* lpBuf, int nBufLen, CString& rSocketAddress, UINT& rSocketPort, int nFlags) { SOCKADDR_IN sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); int nSockAddrLen = sizeof(sockAddr); int nResult = ReceiveFrom(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, &nSockAddrLen, nFlags); if(nResult != SOCKET_ERROR) { rSocketPort = ntohs(sockAddr.sin_port); rSocketAddress = inet_ntoa(sockAddr.sin_addr); } return nResult; } int CAsyncSocket::Send(const void* lpBuf, int nBufLen, int nFlags) { return send(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags); } int CAsyncSocket::SendTo(const void* lpBuf, int nBufLen, UINT nHostPort, LPCTSTR lpszHostAddress, int nFlags) { USES_CONVERSION; SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); LPSTR lpszAscii = T2A((LPTSTR)lpszHostAddress); sockAddr.sin_family = AF_INET; if (lpszAscii == NULL) sockAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); else { sockAddr.sin_addr.s_addr = inet_addr(lpszAscii); if (sockAddr.sin_addr.s_addr == INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(lpszAscii); if (lphost != NULL) sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; else { WSASetLastError(WSAEINVAL); return SOCKET_ERROR; } } } sockAddr.sin_port = htons((u_short)nHostPort); return SendTo(lpBuf, nBufLen, (SOCKADDR*)&sockAddr, sizeof(sockAddr), nFlags); } BOOL CAsyncSocket::AsyncSelect(long lEvent) { ASSERT(m_hSocket != INVALID_SOCKET); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; ASSERT(pState->m_hSocketWindow != NULL); return WSAAsyncSelect(m_hSocket, pState->m_hSocketWindow, WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR; } ///////////////////////////////////////////////////////////////////////////// // CAsyncSocket Overridable callbacks void CAsyncSocket::OnReceive(int /*nErrorCode*/) { } void CAsyncSocket::OnSend(int /*nErrorCode*/) { } void CAsyncSocket::OnOutOfBandData(int /*nErrorCode*/) { } void CAsyncSocket::OnAccept(int /*nErrorCode*/) { } void CAsyncSocket::OnConnect(int /*nErrorCode*/) { } void CAsyncSocket::OnClose(int /*nErrorCode*/) { } ///////////////////////////////////////////////////////////////////////////// // CAsyncSocket Implementation CAsyncSocket::~CAsyncSocket() { if (m_hSocket != INVALID_SOCKET) Close(); } CAsyncSocket* PASCAL CAsyncSocket::LookupHandle(SOCKET hSocket, BOOL bDead) { CAsyncSocket* pSocket; _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; if (!bDead) { pSocket = (CAsyncSocket*) pState->m_pmapSocketHandle->GetValueAt((void*)hSocket); if (pSocket != NULL) return pSocket; } else { pSocket = (CAsyncSocket*) pState->m_pmapDeadSockets->GetValueAt((void*)hSocket); if (pSocket != NULL) return pSocket; } return NULL; } void PASCAL CAsyncSocket::AttachHandle( SOCKET hSocket, CAsyncSocket* pSocket, BOOL bDead) { _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; BOOL bEnable = AfxEnableMemoryTracking(FALSE); if (!bDead) { ASSERT(CAsyncSocket::LookupHandle(hSocket, bDead) == NULL); if (pState->m_pmapSocketHandle->IsEmpty()) { ASSERT(pState->m_pmapDeadSockets->IsEmpty()); ASSERT(pState->m_hSocketWindow == NULL); CSocketWnd* pWnd = new CSocketWnd; pWnd->m_hWnd = NULL; if (!pWnd->CreateEx(0, AfxRegisterWndClass(0), _T("Socket Notification Sink"), WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL)) { TRACE0("Warning: unable to create socket notify window!\n"); AfxThrowResourceException(); } ASSERT(pWnd->m_hWnd != NULL); ASSERT(CWnd::FromHandlePermanent(pWnd->m_hWnd) == pWnd); pState->m_hSocketWindow = pWnd->m_hWnd; } pState->m_pmapSocketHandle->SetAt((void*)hSocket, pSocket); } else { int nCount; if (pState->m_pmapDeadSockets->Lookup((void*)hSocket, (void*&)nCount)) nCount++; else nCount = 1; pState->m_pmapDeadSockets->SetAt((void*)hSocket, (void*)nCount); } AfxEnableMemoryTracking(bEnable); } void PASCAL CAsyncSocket::DetachHandle(SOCKET hSocket, BOOL bDead) { ASSERT(CAsyncSocket::LookupHandle(hSocket, bDead) != NULL); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; if (!bDead) { pState->m_pmapSocketHandle->RemoveKey((void*)hSocket); if (pState->m_pmapSocketHandle->IsEmpty()) { ASSERT(pState->m_hSocketWindow != NULL); CWnd* pWnd = CWnd::FromHandlePermanent(pState->m_hSocketWindow); ASSERT_VALID(pWnd); pWnd->DestroyWindow(); delete pWnd; pState->m_hSocketWindow = NULL; pState->m_pmapDeadSockets->RemoveAll(); while (!pState->m_plistSocketNotifications->IsEmpty()) delete pState->m_plistSocketNotifications->RemoveHead(); } } else { int nCount; if (pState->m_pmapDeadSockets->Lookup((void*)hSocket, (void*&)nCount)) { nCount--; if (nCount == 0) pState->m_pmapDeadSockets->RemoveKey((void*)hSocket); else pState->m_pmapDeadSockets->SetAt((void*)hSocket, (void*)nCount); } } } void PASCAL CAsyncSocket::KillSocket(SOCKET hSocket, CAsyncSocket* pSocket) { ASSERT(CAsyncSocket::LookupHandle(hSocket, FALSE) != NULL); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; CAsyncSocket::DetachHandle(hSocket, FALSE); if (pState->m_hSocketWindow != NULL) { ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_DEAD, (WPARAM)hSocket, 0L); CAsyncSocket::AttachHandle(hSocket, pSocket, TRUE); } } void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam) { if (wParam == 0 && lParam == 0) return; // Has the socket be closed? CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE); // If yes ignore message if (pSocket != NULL) return; pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE); if (pSocket == NULL) { // Must be in the middle of an Accept call pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE); ASSERT(pSocket != NULL); pSocket->m_hSocket = (SOCKET)wParam; CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE); CAsyncSocket::AttachHandle(pSocket->m_hSocket, pSocket, FALSE); } int nErrorCode = WSAGETSELECTERROR(lParam); switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: { DWORD nBytes; if (!pSocket->IOCtl(FIONREAD, &nBytes)) nErrorCode = WSAGetLastError(); if (nBytes != 0 || nErrorCode != 0) pSocket->OnReceive(nErrorCode); } break; case FD_WRITE: pSocket->OnSend(nErrorCode); break; case FD_OOB: pSocket->OnOutOfBandData(nErrorCode); break; case FD_ACCEPT: pSocket->OnAccept(nErrorCode); break; case FD_CONNECT: pSocket->OnConnect(nErrorCode); break; case FD_CLOSE: pSocket->OnClose(nErrorCode); break; } } BOOL CAsyncSocket::Socket(int nSocketType, long lEvent, int nProtocolType, int nAddressFormat) { ASSERT(m_hSocket == INVALID_SOCKET); m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType); if (m_hSocket != INVALID_SOCKET) { CAsyncSocket::AttachHandle(m_hSocket, this, FALSE); return AsyncSelect(lEvent); } return FALSE; } #ifdef _DEBUG void CAsyncSocket::AssertValid() const { CObject::AssertValid(); ASSERT(m_hSocket == INVALID_SOCKET || CAsyncSocket::FromHandle(m_hSocket) != NULL); } void CAsyncSocket::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "m_hSocket = "; if (m_hSocket == INVALID_SOCKET) dc << "INVALID_SOCKET\n"; else dc << m_hSocket << "\n"; } #endif //_DEBUG int CAsyncSocket::ReceiveFromHelper(void* lpBuf, int nBufLen, SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags) { return recvfrom(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags, lpSockAddr, lpSockAddrLen); } int CAsyncSocket::SendToHelper(const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags) { return sendto(m_hSocket, (LPSTR)lpBuf, nBufLen, nFlags, lpSockAddr, nSockAddrLen); } BOOL CAsyncSocket::ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen) { return connect(m_hSocket, lpSockAddr, nSockAddrLen) != SOCKET_ERROR; } ///////////////////////////////////////////////////////////////////////////// // CSocket Construction CSocket::CSocket() { m_pbBlocking = NULL; m_nConnectError = -1; m_nTimeOut = 2000; } ///////////////////////////////////////////////////////////////////////////// // CSocket Operations void CSocket::CancelBlockingCall() { if (m_pbBlocking != NULL) { *m_pbBlocking = FALSE; m_pbBlocking = NULL; } } ///////////////////////////////////////////////////////////////////////////// // CSocket Overridable callbacks BOOL CSocket::OnMessagePending() { MSG msg; if (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) { ::DispatchMessage(&msg); return FALSE; // usually return TRUE, but OnIdle usually causes WM_PAINTs } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // CSocket Implementation CSocket::~CSocket() { if (m_hSocket != INVALID_SOCKET) Close(); } BOOL CSocket::Accept(CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr, int* lpSockAddrLen) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } while (!CAsyncSocket::Accept(rConnectedSocket, lpSockAddr, lpSockAddrLen)) { if (GetLastError() == WSAEWOULDBLOCK) { if (!PumpMessages(FD_ACCEPT)) return FALSE; } else return FALSE; } return TRUE; } void CSocket::Close() { if (m_hSocket != INVALID_SOCKET) { CancelBlockingCall(); VERIFY(AsyncSelect(0)); CAsyncSocket::Close(); m_hSocket = INVALID_SOCKET; } } int CSocket::Receive(void* lpBuf, int nBufLen, int nFlags) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } int nResult; while ((nResult = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR) { if (GetLastError() == WSAEWOULDBLOCK) { if (!PumpMessages(FD_READ)) return SOCKET_ERROR; } else return SOCKET_ERROR; } return nResult; } int CSocket::Send(const void* lpBuf, int nBufLen, int nFlags) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } int nLeft, nWritten; PBYTE pBuf = (PBYTE)lpBuf; nLeft = nBufLen; while (nLeft > 0) { nWritten = SendChunk(pBuf, nLeft, nFlags); if (nWritten == SOCKET_ERROR) return nWritten; nLeft -= nWritten; pBuf += nWritten; } return nBufLen - nLeft; } int CSocket::SendChunk(const void* lpBuf, int nBufLen, int nFlags) { int nResult; while ((nResult = CAsyncSocket::Send(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR) { if (GetLastError() == WSAEWOULDBLOCK) { if (!PumpMessages(FD_WRITE)) return SOCKET_ERROR; } else return SOCKET_ERROR; } return nResult; } BOOL CSocket::ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } m_nConnectError = -1; if (!CAsyncSocket::ConnectHelper(lpSockAddr, nSockAddrLen)) { if (GetLastError() == WSAEWOULDBLOCK) { while (PumpMessages(FD_CONNECT)) { if (m_nConnectError != -1) { WSASetLastError(m_nConnectError); return (m_nConnectError == 0); } } } return FALSE; } return TRUE; } int CSocket::ReceiveFromHelper(void* lpBuf, int nBufLen, SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return FALSE; } int nResult; while ((nResult = CAsyncSocket::ReceiveFromHelper(lpBuf, nBufLen, lpSockAddr, lpSockAddrLen, nFlags)) == SOCKET_ERROR) { if (GetLastError() == WSAEWOULDBLOCK) { if (!PumpMessages(FD_READ)) return SOCKET_ERROR; } else return SOCKET_ERROR; } return nResult; } int CSocket::SendToHelper(const void* lpBuf, int nBufLen, const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags) { if (m_pbBlocking != NULL) { WSASetLastError(WSAEINPROGRESS); return SOCKET_ERROR; } int nResult; while ((nResult = CAsyncSocket::SendToHelper(lpBuf, nBufLen, lpSockAddr, nSockAddrLen, nFlags)) == SOCKET_ERROR) { if (GetLastError() == WSAEWOULDBLOCK) { if (!PumpMessages(FD_WRITE)) return SOCKET_ERROR; } else return SOCKET_ERROR; } return nResult; } int PASCAL CSocket::ProcessAuxQueue() { _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; if (pState->m_plistSocketNotifications->IsEmpty()) return 0; int nCount = 0; while(!pState->m_plistSocketNotifications->IsEmpty()) { nCount++; MSG* pMsg = (MSG*)pState->m_plistSocketNotifications->RemoveHead(); ASSERT(pMsg != NULL); if (pMsg->message == WM_SOCKET_NOTIFY) { CAsyncSocket::DoCallBack(pMsg->wParam, pMsg->lParam); } else { ASSERT(CAsyncSocket::LookupHandle((SOCKET)pMsg->wParam, TRUE) != NULL); CAsyncSocket::DetachHandle((SOCKET)pMsg->wParam, TRUE); } delete pMsg; } return nCount; } void PASCAL CSocket::AuxQueueAdd(UINT message, WPARAM wParam, LPARAM lParam) { _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; MSG* pMsg = new MSG; pMsg->message = message; pMsg->wParam = wParam; pMsg->lParam = lParam; pState->m_plistSocketNotifications->AddTail(pMsg); } BOOL CSocket::PumpMessages(UINT uStopFlag) { // The same socket better not be blocking in more than one place. ASSERT(m_pbBlocking == NULL); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; ASSERT(pState->m_hSocketWindow != NULL); BOOL bBlocking = TRUE; m_pbBlocking = &bBlocking; CWinThread* pThread = AfxGetThread(); // This is not a timeout in the WinSock sense, but more // like a WM_KICKIDLE to keep message pumping alive UINT nTimerID = ::SetTimer(pState->m_hSocketWindow, 1, m_nTimeOut, NULL); if (nTimerID == 0) AfxThrowResourceException(); BOOL bPeek = TRUE; while (bBlocking) { TRY { MSG msg; if (::PeekMessage(&msg, pState->m_hSocketWindow, WM_SOCKET_NOTIFY, WM_SOCKET_DEAD, PM_REMOVE)) { if (msg.message == WM_SOCKET_NOTIFY && (SOCKET)msg.wParam == m_hSocket) { if (WSAGETSELECTEVENT(msg.lParam) == FD_CLOSE) { break; } if (WSAGETSELECTEVENT(msg.lParam) == uStopFlag) { if (uStopFlag == FD_CONNECT) m_nConnectError = WSAGETSELECTERROR(msg.lParam); break; } } if (msg.wParam != 0 || msg.lParam != 0) CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam); bPeek = TRUE; } else if (::PeekMessage(&msg, pState->m_hSocketWindow, WM_TIMER, WM_TIMER, PM_REMOVE)) { break; } if (bPeek && ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (OnMessagePending()) { // allow user-interface updates pThread->OnIdle(-1); } else { bPeek = FALSE; } } else { // no work to do -- allow CPU to sleep WaitMessage(); bPeek = TRUE; } } CATCH_ALL(e) { TRACE0("Error: caught exception in PumpMessage - continuing.\n"); DELETE_EXCEPTION(e); bPeek = TRUE; } END_CATCH_ALL } ::KillTimer(pState->m_hSocketWindow, nTimerID); if (!bBlocking) { WSASetLastError(WSAEINTR); return FALSE; } m_pbBlocking = NULL; ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_NOTIFY, 0, 0); return TRUE; } #ifdef _DEBUG void CSocket::AssertValid() const { CAsyncSocket::AssertValid(); } void CSocket::Dump(CDumpContext& dc) const { CAsyncSocket::Dump(dc); dc << "m_pbBlocking = " << m_pbBlocking <<"\n"; dc << "m_nConnectError = " << m_nConnectError <<"\n"; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CSocketFile Construction CSocketFile::CSocketFile(CSocket* pSocket, BOOL bArchiveCompatible) { m_pSocket = pSocket; m_bArchiveCompatible = bArchiveCompatible; #ifdef _DEBUG ASSERT(m_pSocket != NULL); ASSERT(m_pSocket->m_hSocket != INVALID_SOCKET); int nType = 0; int nTypeLen = sizeof(int); ASSERT(m_pSocket->GetSockOpt(SO_TYPE,&nType,&nTypeLen)); ASSERT(nType == SOCK_STREAM); #endif // _DEBUG } ///////////////////////////////////////////////////////////////////////////// // CSocketFile Implementation CSocketFile::~CSocketFile() { } UINT CSocketFile::Read(void* lpBuf, UINT nCount) { ASSERT(m_pSocket != NULL); int nRead; if (!m_bArchiveCompatible) { int nLeft = nCount; PBYTE pBuf = (PBYTE)lpBuf; while(nLeft > 0) { nRead = m_pSocket->Receive(pBuf, nLeft); if (nRead == SOCKET_ERROR) { int nError = m_pSocket->GetLastError(); AfxThrowFileException(CFileException::generic, nError); ASSERT(FALSE); } else if (nRead == 0) { return nCount - nLeft; } nLeft -= nRead; pBuf += nRead; } return nCount - nLeft; } nRead = m_pSocket->Receive(lpBuf, nCount, 0); if (nRead == SOCKET_ERROR) { int nError = m_pSocket->GetLastError(); AfxThrowFileException(CFileException::generic, nError); ASSERT(FALSE); } return nRead; } void CSocketFile::Write(const void* lpBuf, UINT nCount) { ASSERT (m_pSocket!=NULL); int nWritten = m_pSocket->Send(lpBuf, nCount); if (nWritten == SOCKET_ERROR) { int nError = m_pSocket->GetLastError(); AfxThrowFileException(CFileException::generic, nError); } } void CSocketFile::Close() { m_pSocket = NULL; } BOOL CSocketFile::Open( LPCTSTR /*lpszFileName*/, UINT /*nOpenFlags*/, CFileException* /*pError*/) { AfxThrowNotSupportedException(); return FALSE; } CFile* CSocketFile::Duplicate() const { AfxThrowNotSupportedException(); return NULL; } DWORD CSocketFile::GetPosition() const { AfxThrowNotSupportedException(); return 0; } LONG CSocketFile::Seek(LONG lOff, UINT nFrom) { if (lOff != 0L || nFrom != current) TRACE0("Warning - Attempt made to seek on a CSocketFile\n"); return 0; } void CSocketFile::SetLength(DWORD /*dwNewLen*/) { AfxThrowNotSupportedException(); } DWORD CSocketFile::GetLength() const { AfxThrowNotSupportedException(); return 0; } void CSocketFile::LockRange(DWORD /*dwPos*/, DWORD /*dwCount*/) { AfxThrowNotSupportedException(); } void CSocketFile::UnlockRange(DWORD /*dwPos*/, DWORD /*dwCount*/) { AfxThrowNotSupportedException(); } void CSocketFile::Flush() { } void CSocketFile::Abort() { AfxThrowNotSupportedException(); } #ifdef _DEBUG void CSocketFile::AssertValid() const { CFile::AssertValid(); if (m_pSocket != NULL) ASSERT_VALID(m_pSocket); } void CSocketFile::Dump(CDumpContext& dc) const { CFile::Dump(dc); if (dc.GetDepth() > 0) { if (m_pSocket != NULL) dc << "with no socket\n"; else dc << "with socket: " << m_pSocket; } } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CSocketWnd implementation CSocketWnd::CSocketWnd() { } LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam) { CSocket::AuxQueueAdd(WM_SOCKET_NOTIFY, wParam, lParam); CSocket::ProcessAuxQueue(); return 0L; } LRESULT CSocketWnd::OnSocketDead(WPARAM wParam, LPARAM lParam) { CSocket::AuxQueueAdd(WM_SOCKET_DEAD, wParam, lParam); CSocket::ProcessAuxQueue(); return 0L; } ///////////////////////////////////////////////////////////////////////////// // Message table implementation BEGIN_MESSAGE_MAP(CSocketWnd, CWnd) //{{AFX_MSG_MAP(CWnd) ON_MESSAGE(WM_SOCKET_NOTIFY, OnSocketNotify) ON_MESSAGE(WM_SOCKET_DEAD, OnSocketDead) //}}AFX_MSG_MAP END_MESSAGE_MAP() ////////////////////////////////////////////////////////////////////////////// // Inline function declarations expanded out-of-line #ifndef _AFX_ENABLE_INLINES static char _szAfxSockInl[] = "afxsock.inl"; #undef THIS_FILE #define THIS_FILE _szAfxSockInl #define _AFXSOCK_INLINE #include "afxsock.inl" #undef _AFXSOCK_INLINE #endif #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CAsyncSocket, CObject) IMPLEMENT_DYNAMIC(CSocket, CAsyncSocket) IMPLEMENT_DYNAMIC(CSocketFile, CFile) #pragma warning(disable: 4074) #pragma init_seg(lib) PROCESS_LOCAL(_AFX_SOCK_STATE, _afxSockState) /////////////////////////////////////////////////////////////////////////////