HttpSocket.cpp
上传用户:dengkfang
上传日期:2008-12-30
资源大小:5233k
文件大小:21k
源码类别:

CA认证

开发平台:

Visual C++

  1. /*
  2. Module : HttpSocket.cpp
  3. Purpose: Implementation for a simple MFC socket wrapper class
  4. Created: PJN / 22-04-1999
  5. History: None                    
  6. Copyright (c) 1999 - 2005 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)
  7. All rights reserved.
  8. Copyright / Usage Details:
  9. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
  10. when your product is released in binary form. You are allowed to modify the source code in any way you want 
  11. except you cannot modify the copyright details at the top of each module. If you want to distribute source 
  12. code with your application, then you are only allowed to distribute versions released by the author. This is 
  13. to maintain a single distribution point for the source code. 
  14. */
  15. //////////////// Includes ////////////////////////////////////////////
  16. #include "stdafx.h"
  17. #include "..resource.h"
  18. #include "HttpSocket.h"
  19. #include "HttpClient.h"
  20. #ifndef _WINSOCK2API_
  21. #include <winsock2.h>
  22. #pragma message("To avoid this message please put winsock2.h in your PCH (normally stdafx.h)")
  23. #endif
  24. //////////////// Macros //////////////////////////////////////////////
  25. #ifdef _DEBUG
  26. #define new DEBUG_NEW
  27. #undef THIS_FILE
  28. static char THIS_FILE[] = __FILE__;
  29. #endif
  30. //////////////// Implementation //////////////////////////////////////
  31. BOOL CHttpSocket::SplitRequestLine(const CString& sLine, CString& sField, CString& sValue)
  32. {
  33.   BOOL bSuccess = FALSE;
  34.   
  35.   //Find the first ":" in the line
  36.   int nColon = sLine.Find(_T(':'));
  37.   if (nColon != -1)
  38.   {
  39.     sField = sLine.Left(nColon);
  40.     sValue = sLine.Right(sLine.GetLength()-nColon-1);
  41.     //Trim any leading and trailing spaces
  42.     sField.TrimLeft();
  43.     sField.TrimRight();
  44.     sValue.TrimLeft();
  45.     sValue.TrimRight();
  46.   
  47.     bSuccess = TRUE;
  48.   }
  49.   return bSuccess;
  50. }
  51. BOOL CHttpSocket::SplitRequestLine(LPSTR pszLine, CString& sField, CString& sValue)
  52. {
  53.   return SplitRequestLine(CString(pszLine), sField, sValue);
  54. }
  55. BOOL CHttpSocket::ReadResponse(CHttpRequest& request, DWORD dwTimeout, int nGrowBy, CHttpClient& /*client*/, CWaitableTimer& timer, HANDLE hStopEvent, HANDLE hDataEvent)
  56. {
  57.   //must have been created first
  58.   ASSERT(m_hSocket != INVALID_SOCKET);
  59.   //The local variables which will receive the data
  60.   ASSERT(request.m_pRawRequest == NULL);
  61.   request.m_pRawRequest = new BYTE[nGrowBy];
  62.   LPSTR pszTerminator = "rnrn";
  63.   int nContentLength = -1;
  64.   int nBufSize = nGrowBy;
  65.   
  66.   //retrieve the reponse
  67. request.m_dwRawRequestSize = 0;
  68.   DWORD dwMaxDataToReceive = (DWORD)-1;
  69.   BOOL bJustFoundTerminator = FALSE;
  70.   BOOL bMoreDataToRead = TRUE;
  71. while (bMoreDataToRead)
  72. {
  73.     HANDLE hWaitHandles[3];
  74.     hWaitHandles[0] = hDataEvent;
  75.     hWaitHandles[1] = timer;
  76.     hWaitHandles[2] = hStopEvent;
  77.     //Wait for something interesting to happen
  78.     DWORD dwWait = WaitForMultipleObjects(3, hWaitHandles, FALSE, INFINITE);
  79.     int nSignaledHandle = dwWait - WAIT_OBJECT_0;
  80.     //Work out what the return value from WFMO means!
  81.     if (nSignaledHandle == 0)
  82.     {
  83.       //Reset the timer
  84.       timer.SetOnceOffRelative(dwTimeout);
  85.       //check to see if we have read all the data
  86.       if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  87.       {
  88.         bMoreDataToRead = FALSE;
  89.         break;
  90.       }
  91.   //receive the data from the socket
  92.       int nBufRemaining = nBufSize - request.m_dwRawRequestSize - 1; //Allows allow one space for the NULL terminator
  93.       if (nBufRemaining < 0)
  94.         nBufRemaining = 0;
  95.       int nData = 0;
  96.       try
  97.       {
  98.       nData = Receive(request.m_pRawRequest + request.m_dwRawRequestSize, nBufRemaining);
  99.       }
  100.       catch(CWSocketException* pEx)
  101.       {
  102.         request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  103.         TRACE(_T("CHttpSocket::ReadResponse, An error occurred reading data from the socket, Error:%dn"), pEx->m_nError);
  104.         pEx->Delete();
  105.         return FALSE;
  106.       }
  107.       //Increment the count of data received
  108.   request.m_dwRawRequestSize += nData;    
  109.       //NULL terminate the data received
  110.     request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  111.       if ((nBufRemaining-nData) == 0) //No space left in the current buffer
  112.       {
  113.         //Allocate the new receive buffer
  114.         nBufSize += nGrowBy; //Grow the buffer by the specified amount
  115.         LPBYTE pNewBuf = new BYTE[nBufSize];
  116.         //copy the old contents over to the new buffer and assign 
  117.         //the new buffer to the local variable used for retreiving 
  118.         //from the socket
  119.         CopyMemory(pNewBuf, request.m_pRawRequest, request.m_dwRawRequestSize);
  120.         delete [] request.m_pRawRequest;
  121.         request.m_pRawRequest = pNewBuf;
  122.       }
  123.       //Check to see if the terminator character(s) have been found
  124.       LPSTR pszTempTerminator = NULL;
  125.       if (!bJustFoundTerminator)
  126.       {
  127.         pszTempTerminator = strstr((LPSTR)request.m_pRawRequest, pszTerminator);
  128.         bJustFoundTerminator = (pszTempTerminator != NULL);
  129.       }
  130.       //Now that we have found the terminator we can get the Content-length if any
  131.       if (bJustFoundTerminator)
  132.       {
  133.         //To cause this code to only be executed once
  134.         bJustFoundTerminator = FALSE;
  135.         //Process each line looking for a content-length
  136.         LPSTR pszLine = (LPSTR) request.m_pRawRequest;
  137.         LPSTR pszNextLine = strstr(pszLine, "rn");
  138.         BOOL bMoreLines = TRUE;
  139.         while (bMoreLines) 
  140.         {
  141.           //Form the current line
  142.           int nCurSize = pszNextLine - pszLine + 1;
  143.           char* pszCurrentLine = new char[nCurSize];
  144.           strncpy(pszCurrentLine, pszLine, nCurSize-1);
  145.           pszCurrentLine[nCurSize-1] = ''; 
  146.           //Parse the current request line
  147.           CString sField;
  148.           CString sValue;
  149.           if (SplitRequestLine(pszCurrentLine, sField, sValue))
  150.           {
  151.             //Handle any other request headers  
  152.             if (sField.CompareNoCase(_T("Content-Length")) == 0)
  153.               nContentLength = _ttoi(sValue);
  154.           }
  155.           //Tidy up the temp heap memory we have used
  156.           delete [] pszCurrentLine;
  157.           //Move onto the next line
  158.           if (pszNextLine)
  159.           {
  160.             pszLine = pszNextLine+2;
  161.             pszNextLine = strstr(pszLine, "rn");
  162.             if (pszNextLine == NULL)
  163.               bMoreLines = FALSE;
  164.           }
  165.         }
  166.         //Found no content length in the header, in that case 
  167.         //we can assume there will be content entity-body and
  168.         //can stop looking for more data
  169.         if (nContentLength == -1)
  170.           bMoreDataToRead = FALSE;
  171.         else
  172.         {
  173.           ASSERT(pszTempTerminator);
  174.           dwMaxDataToReceive = (pszTempTerminator - (LPSTR)(request.m_pRawRequest)) + strlen(pszTerminator) + nContentLength;
  175.           if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  176.        {
  177.             bMoreDataToRead = FALSE;
  178.             break;
  179.        }
  180.         }
  181.       }
  182.     }
  183.     else if (nSignaledHandle == 1)
  184.     {
  185.      request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  186.       TRACE(_T("CHttpSocket::ReadResponse, Timed out waiting for response from socketn"));
  187. return FALSE;
  188.     }
  189.     else
  190.     {
  191.      request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  192.       TRACE(_T("CHttpSocket::ReadResponse, Thread being asked to exitn"));
  193. return FALSE;
  194.     }
  195. }
  196.   return TRUE;
  197. }
  198. BOOL CHttpSocket::ReadResponse(CHttpRequest& request, DWORD dwTimeout, int nGrowBy, CHttpClient& client)
  199. {
  200.   //must have been created first
  201.   ASSERT(m_hSocket != INVALID_SOCKET);
  202.   //The local variables which will receive the data
  203.   ASSERT(request.m_pRawRequest == NULL);
  204.   request.m_pRawRequest = new BYTE[nGrowBy];
  205.   LPSTR pszTerminator = "rnrn";
  206.   int nContentLength = -1;
  207.   int nBufSize = nGrowBy;
  208.   
  209.   //retrieve the reponse
  210. request.m_dwRawRequestSize = 0;
  211.   DWORD dwMaxDataToReceive = (DWORD)-1;
  212.   BOOL bJustFoundTerminator = FALSE;
  213.   BOOL bMoreDataToRead = TRUE;
  214. while (bMoreDataToRead)
  215. {
  216.     //Is the thread being asked to exit
  217.     if (client.m_bRequestToStop)
  218.     {
  219.      request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  220.       TRACE(_T("CHttpSocket::ReadResponse, Thread being asked to exitn"));
  221. return FALSE;
  222.     }
  223.     //check to see if we have read all the data
  224.     if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  225.     {
  226.       bMoreDataToRead = FALSE;
  227.       break;
  228.     }
  229.     //check the socket for readability
  230.     try
  231.     {
  232.       if (!IsReadible(dwTimeout))
  233.       {
  234.        request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  235.         TRACE(_T("CHttpSocket::ReadResponse, Timed out waiting for response from socketn"));
  236.         return FALSE;
  237.       }
  238.     }
  239.     catch(CWSocketException* pEx)
  240.     {
  241.       request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  242.       TRACE(_T("CHttpSocket::ReadResponse, An error occurred checking the readibility of the socket, Error:%dn"), pEx->m_nError);
  243.       pEx->Delete();
  244.       return FALSE;
  245.     }
  246. //receive the data from the socket
  247.     int nBufRemaining = nBufSize - request.m_dwRawRequestSize - 1; //Allows allow one space for the NULL terminator
  248.     if (nBufRemaining < 0)
  249.       nBufRemaining = 0;
  250.     int nData = 0;
  251.     try
  252.     {
  253.     nData = Receive(request.m_pRawRequest + request.m_dwRawRequestSize, nBufRemaining);
  254.     }
  255.     catch(CWSocketException* pEx)
  256.     {
  257.       request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  258.       TRACE(_T("CHttpSocket::ReadResponse, An error occurred reading data from the socket, Error:%dn"), pEx->m_nError);
  259.       pEx->Delete();
  260.       return FALSE;
  261.     }
  262.     //Increment the count of data received
  263. request.m_dwRawRequestSize += nData;    
  264.     //NULL terminate the data received
  265.   request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  266.     if ((nBufRemaining-nData) == 0) //No space left in the current buffer
  267.     {
  268.       //Allocate the new receive buffer
  269.       nBufSize += nGrowBy; //Grow the buffer by the specified amount
  270.       LPBYTE pNewBuf = new BYTE[nBufSize];
  271.       //copy the old contents over to the new buffer and assign 
  272.       //the new buffer to the local variable used for retreiving 
  273.       //from the socket
  274.       CopyMemory(pNewBuf, request.m_pRawRequest, request.m_dwRawRequestSize);
  275.       delete [] request.m_pRawRequest;
  276.       request.m_pRawRequest = pNewBuf;
  277.     }
  278.     //Check to see if the terminator character(s) have been found
  279.     LPSTR pszTempTerminator = NULL;
  280.     if (!bJustFoundTerminator)
  281.     {
  282.       pszTempTerminator = strstr((LPSTR)request.m_pRawRequest, pszTerminator);
  283.       bJustFoundTerminator = (pszTempTerminator != NULL);
  284.     }
  285.     //Now that we have found the terminator we can get the Content-length if any
  286.     if (bJustFoundTerminator)
  287.     {
  288.       //To cause this code to only be executed once
  289.       bJustFoundTerminator = FALSE;
  290.       //Process each line looking for a content-length
  291.       LPSTR pszLine = (LPSTR) request.m_pRawRequest;
  292.       LPSTR pszNextLine = strstr(pszLine, "rn");
  293.       BOOL bMoreLines = TRUE;
  294.       while (bMoreLines) 
  295.       {
  296.         //Form the current line
  297.         int nCurSize = pszNextLine - pszLine + 1;
  298.         char* pszCurrentLine = new char[nCurSize];
  299.         strncpy(pszCurrentLine, pszLine, nCurSize-1);
  300.         pszCurrentLine[nCurSize-1] = ''; 
  301.         //Parse the current request line
  302.         CString sField;
  303.         CString sValue;
  304.         if (SplitRequestLine(pszCurrentLine, sField, sValue))
  305.         {
  306.           //Handle any other request headers  
  307.           if (sField.CompareNoCase(_T("Content-Length")) == 0)
  308.             nContentLength = _ttoi(sValue);
  309.         }
  310.         //Tidy up the temp heap memory we have used
  311.         delete [] pszCurrentLine;
  312.         //Move onto the next line
  313.         if (pszNextLine)
  314.         {
  315.           pszLine = pszNextLine+2;
  316.           pszNextLine = strstr(pszLine, "rn");
  317.           if (pszNextLine == NULL)
  318.             bMoreLines = FALSE;
  319.         }
  320.       }
  321.       //Found no content length in the header, in that case 
  322.       //we can assume there will be content entity-body and
  323.       //can stop looking for more data
  324.       if (nContentLength == -1)
  325.         bMoreDataToRead = FALSE;
  326.       else
  327.       {
  328.         ASSERT(pszTempTerminator);
  329.         dwMaxDataToReceive = (pszTempTerminator - (LPSTR)(request.m_pRawRequest)) + strlen(pszTerminator) + nContentLength;
  330.         if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  331.      {
  332.           bMoreDataToRead = FALSE;
  333.           break;
  334.      }
  335.       }
  336.     }
  337. }
  338.   return TRUE;
  339. }
  340. #ifdef W3MFC_SSL_SUPPORT
  341. BOOL CHttpSocket::ReadResponse(CHttpRequest& request, DWORD dwTimeout, int nGrowBy, CSSL& ssl, CHttpClient& client)
  342. {
  343.   if (ssl.operator SSL *())
  344.   {
  345.     //must have been created first
  346.     ASSERT(m_hSocket != INVALID_SOCKET);
  347.     //The local variables which will receive the data
  348.     ASSERT(request.m_pRawRequest == NULL);
  349.     request.m_pRawRequest = new BYTE[nGrowBy];
  350.     LPSTR pszTerminator = "rnrn";
  351.     int nContentLength = -1;
  352.     int nBufSize = nGrowBy;
  353.   
  354.     //retrieve the reponse
  355.   request.m_dwRawRequestSize = 0;
  356.     DWORD dwMaxDataToReceive = (DWORD)-1;
  357.     BOOL bJustFoundTerminator = FALSE;
  358.     BOOL bMoreDataToRead = TRUE;
  359.   while (bMoreDataToRead)
  360.   {
  361.       //Is the thread being asked to exit
  362.       if (client.m_bRequestToStop)
  363.       {
  364.        request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  365.         TRACE(_T("CHttpSocket::ReadResponse, Thread being asked to exitn"));
  366.   return FALSE;
  367.       }
  368.       //check to see if we have read all the data
  369.       if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  370.       {
  371.         bMoreDataToRead = FALSE;
  372.         break;
  373.       }
  374.       //check the socket for readability
  375.       try
  376.       {
  377.         if (!SSL_pending(ssl)) //only check the socket for readibility if SSL_pending fails
  378.         {
  379.           if (!IsReadible(dwTimeout))
  380.           {
  381.            request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  382.             TRACE(_T("CHttpSocket::ReadResponse, Timed out waiting for response from socketn"));
  383.       return FALSE;
  384.           }
  385.         }
  386.       }
  387.       catch(CWSocketException* pEx)
  388.       {
  389.         request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  390.         TRACE(_T("CHttpSocket::ReadResponse, An error occurred checking the readibility of the socket, Error:%dn"), pEx->m_nError);
  391.         pEx->Delete();
  392.         return FALSE;
  393.       }
  394.   //receive the data from the socket
  395.       int nBufRemaining = nBufSize - request.m_dwRawRequestSize - 1; //Allows allow one space for the NULL terminator
  396.       if (nBufRemaining < 0)
  397.         nBufRemaining = 0;
  398.       //Read the data from the socket
  399.       int nData = SSL_read(ssl, request.m_pRawRequest + request.m_dwRawRequestSize, nBufRemaining);
  400.       if (nData <= 0)
  401.       {
  402.         int nSSLError = SSL_get_error(ssl, nData);
  403.         if (nSSLError != SSL_ERROR_WANT_READ)
  404.         {
  405.           request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  406.           TRACE(_T("CHttpSocket::ReadResponse, An error occurred reading data from the socket, SSL_read:%d, SSL_get_error:%dn"), nData, nSSLError);
  407.           return FALSE;
  408.         }
  409.       }
  410.       else if (nData)
  411.       {
  412.         //Increment the count of data received
  413.     request.m_dwRawRequestSize += nData;    
  414.         //NULL terminate the data received
  415.       request.m_pRawRequest[request.m_dwRawRequestSize] = '';
  416.         if ((nBufRemaining-nData) == 0) //No space left in the current buffer
  417.         {
  418.           //Allocate the new receive buffer
  419.           nBufSize += nGrowBy; //Grow the buffer by the specified amount
  420.           LPBYTE pNewBuf = new BYTE[nBufSize];
  421.           //copy the old contents over to the new buffer and assign 
  422.           //the new buffer to the local variable used for retreiving 
  423.           //from the socket
  424.           CopyMemory(pNewBuf, request.m_pRawRequest, request.m_dwRawRequestSize);
  425.           delete [] request.m_pRawRequest;
  426.           request.m_pRawRequest = pNewBuf;
  427.         }
  428.         //Check to see if the terminator character(s) have been found
  429.         LPSTR pszTempTerminator = NULL;
  430.         if (!bJustFoundTerminator)
  431.         {
  432.           pszTempTerminator = strstr((LPSTR)request.m_pRawRequest, pszTerminator);
  433.           bJustFoundTerminator = (pszTempTerminator != NULL);
  434.         }
  435.         //Now that we have found the terminator we can get the Content-length if any
  436.         if (bJustFoundTerminator)
  437.         {
  438.           //To cause this code to only be executed once
  439.           bJustFoundTerminator = FALSE;
  440.           //Process each line looking for a content-length
  441.           LPSTR pszLine = (LPSTR) request.m_pRawRequest;
  442.           LPSTR pszNextLine = strstr(pszLine, "rn");
  443.           BOOL bMoreLines = TRUE;
  444.           while (bMoreLines) 
  445.           {
  446.             //Form the current line
  447.             int nCurSize = pszNextLine - pszLine + 1;
  448.             char* pszCurrentLine = new char[nCurSize];
  449.             strncpy(pszCurrentLine, pszLine, nCurSize-1);
  450.             pszCurrentLine[nCurSize-1] = ''; 
  451.             //Parse the current request line
  452.             CString sField;
  453.             CString sValue;
  454.             if (SplitRequestLine(pszCurrentLine, sField, sValue))
  455.             {
  456.               //Handle any other request headers  
  457.               if (sField.CompareNoCase(_T("Content-Length")) == 0)
  458.                 nContentLength = _ttoi(sValue);
  459.             }
  460.             //Tidy up the temp heap memory we have used
  461.             delete [] pszCurrentLine;
  462.             //Move onto the next line
  463.             if (pszNextLine)
  464.             {
  465.               pszLine = pszNextLine+2;
  466.               pszNextLine = strstr(pszLine, "rn");
  467.               if (pszNextLine == NULL)
  468.                 bMoreLines = FALSE;
  469.             }
  470.           }
  471.           //Found no content length in the header, in that case 
  472.           //we can assume there will be content entity-body and
  473.           //can stop looking for more data
  474.           if (nContentLength == -1)
  475.             bMoreDataToRead = FALSE;
  476.           else
  477.           {
  478.             ASSERT(pszTempTerminator);
  479.             dwMaxDataToReceive = (pszTempTerminator - (LPSTR)(request.m_pRawRequest)) + strlen(pszTerminator) + nContentLength;
  480.             if ((dwMaxDataToReceive != (DWORD)-1) && (request.m_dwRawRequestSize >= dwMaxDataToReceive))
  481.          {
  482.               bMoreDataToRead = FALSE;
  483.               break;
  484.          }
  485.           }
  486.         }
  487.       }
  488.   }
  489.     return TRUE;
  490.   }
  491.   else
  492.     return ReadResponse(request, dwTimeout, nGrowBy, client); 
  493. }
  494. BOOL CHttpSocket::ReadResponse(CHttpRequest& request, DWORD dwTimeout, int nGrowBy, CSSL& ssl, CHttpClient& client, CWaitableTimer& timer, HANDLE hStopEvent, HANDLE hDataEvent)
  495. {
  496.   if (ssl.operator SSL *())
  497.   {
  498.     //We do not support using events for the OpenSSL code path
  499.     return ReadResponse(request, dwTimeout, nGrowBy, ssl, client);
  500.   }
  501.   else
  502.     return ReadResponse(request, dwTimeout, nGrowBy, client, timer, hStopEvent, hDataEvent); 
  503. }
  504. #endif
  505. void CHttpSocket::SendWithRetry(void* pBuffer, int nBuf, DWORD dwTimeout)
  506. {
  507.   BOOL bSent = FALSE;
  508.   do
  509.   {
  510.     try
  511.     {
  512.       //Let the socket do the send
  513.       CWSocket::Send(pBuffer, nBuf);
  514.       bSent = TRUE;
  515.     }
  516.     catch(CWSocketException* pEx)
  517.     {
  518.       //Pull out the exceptions details before we delete it
  519.       int nError = pEx->m_nError;
  520.       //Delete the exception before we go any further
  521.       pEx->Delete();
  522.       if (nError == WSAEWOULDBLOCK)
  523.       {
  524.         //If a WSAEWOULDBLOCK error occurred then wait until the socket becomes
  525.         //writtable or the timeout occurs
  526.         int nEvent = WSAEventSelect(*this, m_WSABlockEvent, FD_WRITE);
  527.         //Handle the error
  528.         if (nEvent != 0)
  529.           AfxThrowWSocketException();
  530.         //Wait for the socket to become writable
  531.         DWORD dwWait = WaitForSingleObject(m_WSABlockEvent, dwTimeout);
  532.         //Cancel the notification
  533.         WSAEventSelect(*this, m_WSABlockEvent, 0);
  534.         //If the socket does not become writable in the timeout period, 
  535.         //then rethrow the exception
  536.         if (dwWait != WAIT_OBJECT_0)
  537.           AfxThrowWSocketException(WSAEWOULDBLOCK);
  538.       }
  539.       else
  540.       {
  541.         //We caught an exception which we do not know how to handle.
  542.         //In this case just rethrow the exception
  543.         AfxThrowWSocketException(nError);
  544.       }
  545.     }
  546.   }
  547.   while (!bSent);
  548. }
  549. #ifdef W3MFC_SSL_SUPPORT
  550. void CHttpSocket::SendWithRetry(void* pBuffer, int nBuf, DWORD dwTimeout, CSSL& ssl)
  551. {
  552.   if (ssl.operator SSL *())
  553.   {
  554.     BOOL bSent = FALSE;
  555.     do
  556.     {
  557.       int nSSLWrite = SSL_write(ssl, pBuffer, nBuf);
  558.       if (nSSLWrite < 1)
  559.       {
  560.         if (SSL_get_error(ssl, nSSLWrite) == SSL_ERROR_WANT_WRITE)
  561.         {
  562.           if (!IsWritable(dwTimeout))
  563.             AfxThrowWSocketException(WSAEWOULDBLOCK);
  564.         }
  565.       }
  566.       else
  567.         bSent = TRUE;
  568.     }
  569.     while (!bSent);
  570.   }
  571.   else
  572.     SendWithRetry(pBuffer, nBuf, dwTimeout);
  573. }
  574. #endif