home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
mfc
/
src
/
sockcore.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-16
|
28KB
|
1,174 lines
// 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 <stddef.h>
#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)
/////////////////////////////////////////////////////////////////////////////