Microsoft KB Archive/154649

= FIX: CSocket Operation Hangs if a Timer is Active =

Article ID: 154649

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 4.2 Enterprise Edition

 Microsoft Visual C++ 4.2 Professional Edition 

-



This article was previously published under Q154649





SYMPTOMS
A call to CSocket Connect, Accept, Send, or Receive hangs if a timer is active.



CAUSE
CSocket operations are written using "pseudo-blocking." The WinSock API call is not a true blocking call, but if it doesn't return immediately then CSocket will call PumpMessages. PumpMessages looks for the FD_xxx notification and the CSocket function will not return until the FD_xxx notification arrives.

PumpMessages will not detect the socket notification if a timer is active because it looks for WM_TIMER messages first. When a WM_TIMER message arrives, the function doesn't look any further for other messages.

The PumpMessages function is looking for WM_TIMER messages because it sets up its own timer to cause the application to retry its socket calls and do periodic idle-time processing while waiting for the socket notification.

<div class="resolution_section">

RESOLUTION
There are two possible resolutions:

<ol> Disable all timers while making CSocket calls.</li>  Override the PumpMessages function so that it only looks for its own WM_TIMER messages and does not pick up other timer messages. This can be done by borrowing the CSocket::PumpMessages function from SOCKCORE.CPP and changing it as follows: #if _MFC_VER == 0x0420

#define _AFX_SOCK_THREAD_STATE AFX_MODULE_THREAD_STATE #define WM_SOCKET_NOTIFY   0x0373 #define WM_SOCKET_DEAD     0x0374

#define _afxSockThreadState AfxGetModuleThreadState

#endif

BOOL CMySocket::PumpMessages(UINT uStopFlag) {  #if _MFC_VER != 0x0420 return CSocket::PumpMessages(uStopFlag); #else

// 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, 0,                             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"); bPeek = TRUE; }      END_CATCH_ALL }



if (!bBlocking) {      WSASetLastError(WSAEINTR); return FALSE; }    m_pbBlocking = NULL;



return TRUE;

#endif // _MFC_VER }                       </li></ol>

<div class="status_section">

STATUS
Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This bug has been fixed with the Visual C++ 4.2b patch. For more information on this patch, please see the following articles in the Microsoft Knowledge Base:

156934 PATCH: Visual C++ 4.2b Patch

160491 Information on Files Modified by VC42b Patch: Part 1 of 4

160496 Information on Files Modified by VC42b Patch: Part 2 of 4

160505 Information on Files Modified by VC42b Patch: Part 3 of 4

160506 Information on Files Modified by VC42b Patch: Part 4 of 4

Additional query words: kbVC420bug kbDSupport CAsyncSocket CSocket hangs timer

Keywords: kbbug kbfix kbnetwork kbvc420fix kbwinsock KB154649

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.