751 lines
25 KiB
C++
751 lines
25 KiB
C++
/*****************************************************************************\
|
|
* MODULE: anycon.cxx
|
|
*
|
|
* The module contains the base class for connections
|
|
*
|
|
* Copyright (C) 1997-1998 Microsoft Corporation
|
|
*
|
|
* History:
|
|
* 07/31/98 Weihaic Created
|
|
*
|
|
\*****************************************************************************/
|
|
|
|
|
|
#include "precomp.h"
|
|
#include "priv.h"
|
|
|
|
/******************************************************************************
|
|
* Class Data Static Members
|
|
*****************************************************************************/
|
|
const DWORD CAnyConnection::gm_dwConnectTimeout = 30000; // Thirty second timeout on connect
|
|
const DWORD CAnyConnection::gm_dwSendTimeout = 30000; // Thirty timeout on send timeout
|
|
const DWORD CAnyConnection::gm_dwReceiveTimeout = 60000; // Thirty seconds on receive timeout
|
|
const DWORD CAnyConnection::gm_dwSendSize = 0x10000; // We use a 16K sections when sending
|
|
// data through WININET
|
|
extern BOOL Ping (LPTSTR pszServerName);
|
|
|
|
CAnyConnection::CAnyConnection (
|
|
BOOL bSecure,
|
|
INTERNET_PORT nServerPort,
|
|
BOOL bIgnoreSecurityDlg,
|
|
DWORD dwAuthMethod):
|
|
|
|
m_lpszPassword (NULL),
|
|
m_lpszUserName (NULL),
|
|
m_hSession (NULL),
|
|
m_hConnect (NULL),
|
|
m_dwAccessFlag (INTERNET_OPEN_TYPE_PRECONFIG),
|
|
m_bSecure (bSecure),
|
|
m_bShowSecDlg (FALSE),
|
|
m_dwAuthMethod (dwAuthMethod),
|
|
m_bIgnoreSecurityDlg (bIgnoreSecurityDlg),
|
|
m_bValid (FALSE)
|
|
|
|
{
|
|
if (!nServerPort) {
|
|
if (bSecure) {
|
|
m_nServerPort = INTERNET_DEFAULT_HTTPS_PORT;
|
|
}
|
|
else {
|
|
m_nServerPort = INTERNET_DEFAULT_HTTP_PORT;
|
|
}
|
|
}
|
|
else
|
|
m_nServerPort = nServerPort;
|
|
|
|
|
|
m_bValid = TRUE;
|
|
}
|
|
|
|
CAnyConnection::~CAnyConnection ()
|
|
{
|
|
if (m_hConnect) {
|
|
(void) CAnyConnection::Disconnect ();
|
|
}
|
|
|
|
if (m_hSession) {
|
|
(void) CAnyConnection::CloseSession ();
|
|
}
|
|
LocalFree (m_lpszPassword);
|
|
m_lpszPassword = NULL;
|
|
LocalFree (m_lpszUserName);
|
|
m_lpszUserName = NULL;
|
|
}
|
|
|
|
HINTERNET
|
|
CAnyConnection::OpenSession ()
|
|
{
|
|
|
|
m_hSession = InetInternetOpen(g_szUserAgent,
|
|
m_dwAccessFlag,
|
|
NULL,
|
|
NULL,
|
|
#ifndef WINNT32
|
|
INTERNET_FLAG_ASYNC);
|
|
#else
|
|
0);
|
|
#endif
|
|
|
|
|
|
|
|
if (m_hSession) { // Set up the callback function if successful
|
|
|
|
|
|
#ifndef WINNT32
|
|
INTERNET_STATUS_CALLBACK dwISC;
|
|
|
|
dwISC = InternetSetStatusCallback( m_hSession, CAsyncContext::InternetCallback );
|
|
|
|
if (dwISC != NULL) {
|
|
// We do not support chaining down to a previous callback, there should not
|
|
// be one and if it fails it will also be non NULL, Set last error to invalid handle and
|
|
// Clean Up
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
// Also set an internet connection timeout for the session for when we try the
|
|
// connection, should we do this instead of a ping?
|
|
DWORD dwTimeout = gm_dwConnectTimeout;
|
|
|
|
if (!InetInternetSetOption( m_hSession,
|
|
INTERNET_OPTION_CONNECT_TIMEOUT,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(dwTimeout)
|
|
))
|
|
goto Cleanup;
|
|
|
|
// Now set the Send and Receive Timeout values
|
|
|
|
dwTimeout = gm_dwSendTimeout;
|
|
|
|
if (!InetInternetSetOption( m_hSession,
|
|
INTERNET_OPTION_SEND_TIMEOUT,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(dwTimeout)
|
|
))
|
|
goto Cleanup;
|
|
|
|
dwTimeout = gm_dwReceiveTimeout;
|
|
|
|
if (!InetInternetSetOption( m_hSession,
|
|
INTERNET_OPTION_RECEIVE_TIMEOUT,
|
|
(LPVOID)&dwTimeout,
|
|
sizeof(dwTimeout)
|
|
))
|
|
goto Cleanup;
|
|
}
|
|
|
|
return m_hSession;
|
|
|
|
Cleanup:
|
|
|
|
if (m_hSession) {
|
|
InetInternetCloseHandle (m_hSession);
|
|
m_hSession = NULL;
|
|
}
|
|
|
|
return m_hSession;
|
|
}
|
|
|
|
BOOL CAnyConnection::CloseSession ()
|
|
{
|
|
BOOL bRet = InetInternetCloseHandle (m_hSession);
|
|
|
|
m_hSession = NULL;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
HINTERNET
|
|
CAnyConnection::Connect(
|
|
LPTSTR lpszServerName)
|
|
{
|
|
|
|
if (m_hSession) {
|
|
// Ping the server if it is in the intranet to make sure that the server is online
|
|
|
|
if (lpszServerName &&
|
|
|
|
(_tcschr ( lpszServerName, TEXT ('.')) || Ping (lpszServerName) )) {
|
|
|
|
m_hConnect = InetInternetConnect(m_hSession,
|
|
lpszServerName,
|
|
m_nServerPort,
|
|
NULL,//m_lpszUserName,
|
|
NULL, //m_lpszPassword,
|
|
INTERNET_SERVICE_HTTP,
|
|
0,
|
|
0);
|
|
}
|
|
}
|
|
|
|
return m_hConnect;
|
|
}
|
|
|
|
BOOL
|
|
CAnyConnection::Disconnect ()
|
|
{
|
|
BOOL bRet = InetInternetCloseHandle (m_hConnect);
|
|
|
|
m_hConnect = NULL;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
HINTERNET
|
|
CAnyConnection::OpenRequest (
|
|
LPTSTR lpszUrl)
|
|
{
|
|
HINTERNET hReq = NULL;
|
|
DWORD dwFlags;
|
|
|
|
if (m_hConnect) {
|
|
// We need to create an Asynchronous Context for the Rest of the operations to use,
|
|
// passing this in of course makes this request also asynchronous
|
|
|
|
WIN9X_NEW_ASYNC( pacSync );
|
|
|
|
WIN9X_IF_ASYNC( pacSync )
|
|
WIN9X_IF_ASYNC( pacSync->bValid() ) {
|
|
hReq = InetHttpOpenRequest(m_hConnect,
|
|
g_szPOST,
|
|
lpszUrl,
|
|
g_szHttpVersion,
|
|
NULL,
|
|
NULL,
|
|
INETPP_REQ_FLAGS | (m_bSecure? INTERNET_FLAG_SECURE:0),
|
|
WIN9X_CONTEXT_ASYNC(pacSync));
|
|
|
|
} WIN9X_ELSE_ASYNC( delete pacSync );
|
|
|
|
}
|
|
return hReq;
|
|
}
|
|
|
|
BOOL
|
|
CAnyConnection::CloseRequest (HINTERNET hReq)
|
|
{ // BUG: We have to close the handle manually, since WININET seems not to be giving us
|
|
// an INTERNET_STATUS_HANDLE_CLOSING message
|
|
BOOL bSuccess;
|
|
|
|
WIN9X_GET_ASYNC( pacSync, hReq );
|
|
|
|
bSuccess = InetInternetCloseHandle (hReq); // When this handle is closed, the context will be closed
|
|
|
|
WIN9X_IF_ASYNC(pacSync) WIN9X_OP_ASYNC(delete pacSync;)
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
CAnyConnection::SendRequest(
|
|
HINTERNET hReq,
|
|
LPCTSTR lpszHdr,
|
|
DWORD cbData,
|
|
LPBYTE pidi)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
CMemStream *pStream;
|
|
|
|
pStream = new CMemStream (pidi, cbData);
|
|
|
|
if (pStream && pStream->bValid ()){
|
|
|
|
bRet = SendRequest (hReq, lpszHdr, pStream);
|
|
}
|
|
|
|
if (pStream) {
|
|
delete pStream;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CAnyConnection::SendRequest(
|
|
HINTERNET hReq,
|
|
LPCTSTR lpszHdr,
|
|
CStream *pStream)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DWORD dwStatus;
|
|
DWORD cbStatus = sizeof(dwStatus);
|
|
BOOL bRetry = FALSE;
|
|
DWORD dwRetryCount = 0;
|
|
BOOL bShowUI = FALSE;
|
|
|
|
DWORD cbData;
|
|
PBYTE pBuf = NULL;
|
|
DWORD cbRead;
|
|
|
|
|
|
if (!pStream->GetTotalSize (&cbData))
|
|
return FALSE;
|
|
|
|
pBuf = new BYTE[gm_dwSendSize];
|
|
if (!pBuf)
|
|
return FALSE;
|
|
|
|
#define MAX_RETRY 3
|
|
do {
|
|
BOOL bSuccess = FALSE;
|
|
BOOL bLeave;
|
|
|
|
WIN9X_GET_ASYNC( pacSync, hReq );
|
|
|
|
WIN9X_IF_ASYNC (!pacSync) WIN9X_BREAK_ASYNC(FALSE);
|
|
|
|
if (cbData < gm_dwSendSize) {
|
|
|
|
if (pStream->Reset() &&
|
|
pStream->Read (pBuf, cbData, &cbRead) && cbRead == cbData) {
|
|
|
|
// If what we want to send is small, we send it with HttpSendRequest and not
|
|
// HttpSendRequestEx, this is to wotk around a problem where we get timeouts on
|
|
// receive on very small data transactions
|
|
bSuccess = InetHttpSendRequest(hReq,
|
|
lpszHdr,
|
|
(lpszHdr ? (DWORD)-1 : 0),
|
|
pBuf,
|
|
cbData);
|
|
|
|
(void) WIN9X_TIMEOUT_ASYNC(pacSync, bSuccess);
|
|
}
|
|
|
|
} else {
|
|
do {
|
|
BOOL bSuccessSend;
|
|
// The timeout value for the packets applies for an entire session, so, instead of sending in
|
|
// one chuck, we have to send in smaller chunks
|
|
INTERNET_BUFFERS BufferIn;
|
|
|
|
bLeave = TRUE;
|
|
|
|
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
|
|
BufferIn.Next = NULL;
|
|
BufferIn.lpcszHeader = lpszHdr;
|
|
if (lpszHdr)
|
|
BufferIn.dwHeadersLength = sizeof(TCHAR)*lstrlen(lpszHdr);
|
|
else
|
|
BufferIn.dwHeadersLength = 0;
|
|
BufferIn.dwHeadersTotal = 1; // There is one header to send
|
|
BufferIn.lpvBuffer = NULL; // We defer this to the multiple write side
|
|
BufferIn.dwBufferLength = 0; // The total buffer length
|
|
BufferIn.dwBufferTotal = cbData; // This is the size of the data we are about to send
|
|
BufferIn.dwOffsetLow = 0; // No offset into the buffers
|
|
BufferIn.dwOffsetHigh = 0;
|
|
|
|
// Since we will only ever be sending one request per hReq handle, we can associate
|
|
// the context with all of these operations
|
|
|
|
bSuccess = InetHttpSendRequestEx (hReq,
|
|
&BufferIn,
|
|
NULL,
|
|
0,
|
|
WIN9X_CONTEXT_ASYNC(pacSync));
|
|
|
|
(void) WIN9X_TIMEOUT_ASYNC(pacSync, bSuccess );
|
|
|
|
if (bSuccess) {
|
|
bSuccess = pStream->Reset();
|
|
}
|
|
|
|
DWORD dwBufPos = 0; // This is our current point in the buffer
|
|
DWORD dwRemaining = cbData; // These are the number of bytes left to send
|
|
|
|
bSuccessSend = bSuccess;
|
|
|
|
while (bSuccess && dwRemaining) { // While we have data to send and the operations are
|
|
// successful
|
|
DWORD dwWrite = min( dwRemaining, gm_dwSendSize); // The amount to write
|
|
DWORD dwWritten; // The amount actually written
|
|
|
|
if (pStream->Read (pBuf, dwWrite, &cbRead) && cbRead == dwWrite) {
|
|
|
|
bSuccess = InetInternetWriteFile (hReq, pBuf, dwWrite, &dwWritten);
|
|
|
|
(void) WIN9X_TIMEOUT_ASYNC(pacSync, bSuccess ); // Wait for the operation to actually happen
|
|
|
|
if (bSuccess) {
|
|
bSuccess = dwWritten ? TRUE : FALSE;
|
|
|
|
dwRemaining -= dwWritten; // Remaining amount decreases by this
|
|
dwBufPos += dwWritten; // Advance through the buffer
|
|
|
|
if (dwWritten != dwWrite) {
|
|
// We need to adjust the pointer, since not all the bytes are
|
|
// successfully sent to the server
|
|
//
|
|
bSuccess = pStream->SetPtr (dwBufPos);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
bSuccess = FALSE;
|
|
}
|
|
|
|
BOOL bEndSuccess = FALSE;
|
|
|
|
if (bSuccessSend) { // We started the request successfully, so we can end it successfully
|
|
bEndSuccess = InetHttpEndRequest (hReq,
|
|
NULL,
|
|
0,
|
|
WIN9X_CONTEXT_ASYNC(pacSync));
|
|
|
|
(void) WIN9X_TIMEOUT_ASYNC(pacSync, bEndSuccess );
|
|
}
|
|
|
|
if (!bEndSuccess && GetLastError() == ERROR_INTERNET_FORCE_RETRY)
|
|
bLeave = FALSE;
|
|
|
|
|
|
bSuccess = bSuccess && bEndSuccess && bSuccessSend;
|
|
|
|
} while (!bLeave);
|
|
}
|
|
|
|
if (bSuccess) {
|
|
|
|
if ( InetHttpQueryInfo(hReq,
|
|
HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
|
|
&dwStatus,
|
|
&cbStatus,
|
|
NULL) ) {
|
|
switch (dwStatus) {
|
|
case HTTP_STATUS_DENIED:
|
|
case HTTP_STATUS_PROXY_AUTH_REQ:
|
|
SetLastError (ERROR_ACCESS_DENIED);
|
|
break;
|
|
case HTTP_STATUS_FORBIDDEN:
|
|
SetLastError (HTTP_STATUS_FORBIDDEN);
|
|
break;
|
|
case HTTP_STATUS_OK:
|
|
bRet = TRUE;
|
|
break;
|
|
case HTTP_STATUS_SERVER_ERROR:
|
|
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : HTTP_STATUS_SERVER_ERROR")));
|
|
|
|
SetLastError (ERROR_INVALID_PRINTER_NAME);
|
|
break;
|
|
default:
|
|
|
|
if ((dwStatus >= HTTP_STATUS_BAD_REQUEST) &&
|
|
(dwStatus < HTTP_STATUS_SERVER_ERROR)) {
|
|
|
|
SetLastError(ERROR_INVALID_PRINTER_NAME);
|
|
|
|
} else {
|
|
|
|
// We get some other errors, but don't know how to handle it
|
|
//
|
|
DBG_MSG(DBG_LEV_ERROR, (TEXT("CAnyConnection::SendRequest : Unknown Error (%d)"), dwStatus));
|
|
|
|
SetLastError (ERROR_INVALID_HANDLE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (m_bSecure) {
|
|
#if NEVER
|
|
//
|
|
// In the future, we need to change this part to call InternetQueryOption on
|
|
// INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT
|
|
// and pass it back to the client
|
|
//
|
|
LPTSTR szBuf[1024];
|
|
DWORD dwSize = 1024;
|
|
|
|
switch (GetLastError ()) {
|
|
case ERROR_INTERNET_INVALID_CA:
|
|
case ERROR_INTERNET_SEC_CERT_DATE_INVALID:
|
|
case ERROR_INTERNET_SEC_CERT_CN_INVALID:
|
|
|
|
|
|
if (InternetQueryOption(hReq,
|
|
INTERNET_OPTION_SECURITY_CERTIFICATE,
|
|
szBuf, &dwSize)) {
|
|
|
|
|
|
DBG_MSG(DBG_LEV_WARN, (TEXT("Cert: %ws\n"), szBuf));
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
DWORD dwFlags = 0;
|
|
DWORD dwRet;
|
|
|
|
if (m_bShowSecDlg) {
|
|
bShowUI = TRUE;
|
|
dwRet = InetInternetErrorDlg (GetTopWindow (NULL),
|
|
hReq,
|
|
GetLastError(),
|
|
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);
|
|
|
|
if (dwRet == ERROR_SUCCESS || dwRet == ERROR_INTERNET_FORCE_RETRY) {
|
|
bRetry = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
switch (GetLastError ()) {
|
|
case ERROR_INTERNET_INVALID_CA:
|
|
dwFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
|
|
break;
|
|
default:
|
|
// All other failure, try to ignore everything and retry
|
|
dwFlags = SECURITY_FLAG_IGNORE_REVOCATION |
|
|
SECURITY_FLAG_IGNORE_UNKNOWN_CA |
|
|
SECURITY_FLAG_IGNORE_WRONG_USAGE |
|
|
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
|
|
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID|
|
|
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTPS |
|
|
SECURITY_FLAG_IGNORE_REDIRECT_TO_HTTP ;
|
|
break;
|
|
}
|
|
|
|
if (InetInternetSetOption(hReq,
|
|
INTERNET_OPTION_SECURITY_FLAGS,
|
|
&dwFlags,
|
|
sizeof (DWORD))) {
|
|
bRetry = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (bRetry && ++dwRetryCount < MAX_RETRY);
|
|
|
|
if (!bRet && GetLastError () == ERROR_INTERNET_LOGIN_FAILURE)
|
|
{
|
|
SetLastError (ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
if (bShowUI) {
|
|
// We only show the dialog once.
|
|
m_bShowSecDlg = FALSE;
|
|
}
|
|
|
|
if (pBuf) {
|
|
delete [] pBuf;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CAnyConnection::ReadFile (
|
|
HINTERNET hReq,
|
|
LPVOID lpvBuffer,
|
|
DWORD cbBuffer,
|
|
LPDWORD lpcbRd)
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
bSuccess = InetInternetReadFile(hReq, lpvBuffer, cbBuffer, lpcbRd);
|
|
|
|
return WIN9X_WAIT_ASYNC( hReq, bSuccess );
|
|
}
|
|
|
|
|
|
BOOL CAnyConnection::SetPassword (
|
|
HINTERNET hReq,
|
|
LPTSTR lpszUserName,
|
|
LPTSTR lpszPassword)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
TCHAR szNULL[] = TEXT ("");
|
|
|
|
if (!lpszUserName) {
|
|
lpszUserName = szNULL;
|
|
}
|
|
|
|
if (!lpszPassword) {
|
|
lpszPassword = szNULL;
|
|
}
|
|
|
|
if ( InetInternetSetOption (hReq,
|
|
INTERNET_OPTION_USERNAME,
|
|
lpszUserName,
|
|
(DWORD) (lstrlen(lpszUserName) + 1)) &&
|
|
InetInternetSetOption (hReq,
|
|
INTERNET_OPTION_PASSWORD,
|
|
lpszPassword,
|
|
(DWORD) (lstrlen(lpszPassword) + 1)) ) {
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
BOOL CAnyConnection::GetAuthSchem (
|
|
HINTERNET hReq,
|
|
LPSTR lpszScheme,
|
|
DWORD dwSize)
|
|
{
|
|
DWORD dwIndex = 0;
|
|
|
|
return InetHttpQueryInfo(hReq, HTTP_QUERY_WWW_AUTHENTICATE, (LPVOID)lpszScheme, &dwSize, &dwIndex);
|
|
}
|
|
|
|
void CAnyConnection::SetShowSecurityDlg (
|
|
BOOL bShowSecDlg)
|
|
{
|
|
m_bShowSecDlg = bShowSecDlg;
|
|
}
|
|
|
|
|
|
#ifndef WINNT32 // We use asynchronous code in this case
|
|
/**********************************************************************************************
|
|
** Method - GetAsyncContext
|
|
** Description - Get the async context from the handle
|
|
**********************************************************************************************/
|
|
CAnyConnection::CAsyncContext *CAnyConnection::GetAsyncContext( IN HINTERNET hInternet ) {
|
|
CAsyncContext *pacContext; // This is the context we wish to retrieve
|
|
|
|
DWORD dwContextSize = sizeof(pacContext);
|
|
|
|
if (InternetQueryOption( hInternet,
|
|
INTERNET_OPTION_CONTEXT_VALUE,
|
|
(LPBYTE)&pacContext,
|
|
&dwContextSize ))
|
|
return pacContext;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/**********************************************************************************************
|
|
** Method - AsynchronousWait
|
|
** Description - This is really a wrapper for the object asynchronous wait, we simply first
|
|
** get the object out of the context before we continue doing anything
|
|
**********************************************************************************************/
|
|
BOOL CAnyConnection::AsynchronousWait( IN HINTERNET hInternet, IN OUT BOOL &bSuccess) {
|
|
// We get the context value from the internet handle
|
|
CAsyncContext *pacContext; // This is the context we wish to retrieve
|
|
|
|
if (bSuccess) return TRUE; // Saves having to get the context
|
|
|
|
DWORD dwContextSize = sizeof(pacContext);
|
|
|
|
if (InternetQueryOption( hInternet,
|
|
INTERNET_OPTION_CONTEXT_VALUE,
|
|
(LPBYTE)&pacContext,
|
|
&dwContextSize ))
|
|
return pacContext->TimeoutWait (bSuccess);
|
|
else
|
|
return bSuccess = FALSE;
|
|
}
|
|
|
|
#endif // #ifndef WINNT32
|
|
|
|
|
|
#ifndef WINNT32
|
|
/**********************************************************************************************
|
|
** Class Implementation - CAnyConnection::CAsyncContext
|
|
**********************************************************************************************/
|
|
|
|
/**********************************************************************************************
|
|
** Constructor - CAsyncContext
|
|
** Description - Create the Event Handle, set the point to the CAnyConnection and ensure
|
|
** that the two return values are correctly set
|
|
***********************************************************************************************/
|
|
CAnyConnection::CAsyncContext::CAsyncContext(void) :
|
|
m_dwRet (0),
|
|
m_dwError (ERROR_SUCCESS),
|
|
m_hEvent (NULL) {
|
|
|
|
// Create an event with no inheritable security, automatic reset semantics, a non-signalled
|
|
// initial state and no name
|
|
m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
|
|
|
|
}
|
|
|
|
/************************************************************************************************
|
|
** Destructor - CAsyncContext
|
|
** Description - Deallocate the event handle
|
|
************************************************************************************************/
|
|
CAnyConnection::CAsyncContext::~CAsyncContext() {
|
|
if (m_hEvent) CloseHandle(m_hEvent);
|
|
}
|
|
|
|
/************************************************************************************************
|
|
** Method - TimeoutWait
|
|
** Description - Wait on an event callback if the call was asynchronous, clear the event, the
|
|
** callback routine does the hard work, this one is for a bool
|
|
************************************************************************************************/
|
|
BOOL CAnyConnection::CAsyncContext::TimeoutWait(IN OUT BOOL &bSuccess) {
|
|
if (!bSuccess && GetLastError() == ERROR_IO_PENDING) { // The call was asynchronously deferred
|
|
DWORD dwRet;
|
|
|
|
dwRet = WaitForSingleObject( m_hEvent , INFINITE );
|
|
// This is not a real infinite wait since the timeout has been set in WININET
|
|
// The callback will signal us back when it is all done
|
|
|
|
// The object was signalled
|
|
// The m_dwRet value will have been set to indicate success or failure
|
|
// if the synchronisation was wrong it will be set to 0, so also a failure
|
|
bSuccess = (BOOL)m_dwRet;
|
|
|
|
if (!bSuccess) SetLastError (m_dwError);
|
|
else SetLastError(ERROR_SUCCESS);
|
|
|
|
} else ResetEvent(m_hEvent);
|
|
// Some events are synchronous, but still generate a callback, in this case the callback
|
|
// will be in the same thread and set event, leaving the event open for next time,
|
|
// In either case it is safe to do this, since if there is no callback, there will
|
|
// be no data to pass back and no set event.
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
/************************************************************************************************
|
|
** Callback - InternetCallback
|
|
** Description - This handles the callback from the Wininet API, it is responsible for asyncronous
|
|
** handle returns as well as other call returns, it also destructs the context
|
|
** when it is eventually deleted
|
|
************************************************************************************************/
|
|
void CALLBACK CAnyConnection::CAsyncContext::InternetCallback(
|
|
IN HINTERNET hInternet,
|
|
IN DWORD_PTR dwContext,
|
|
IN DWORD dwInternetStatus,
|
|
IN LPVOID lpvStatusInformation,
|
|
IN DWORD dwStatusInformationLength) {
|
|
|
|
CAsyncContext *pThis = (CAsyncContext *)dwContext;
|
|
|
|
// Regardless of whether we are in a critical failure state or not, we want to delete the
|
|
// context of this handle is closing
|
|
switch(dwInternetStatus) {
|
|
|
|
#if 0
|
|
// BUG: We do not get this notification from WININET, so we have to do this from outside
|
|
// When this is resolved, this code is much neater
|
|
|
|
case INTERNET_STATUS_HANDLE_CLOSING:
|
|
delete pThis;
|
|
break;
|
|
#endif // #if 0
|
|
case INTERNET_STATUS_REQUEST_COMPLETE: // The request we sent was successful (or timed
|
|
// out)
|
|
pThis->m_dwRet = ((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult;
|
|
pThis->m_dwError = ((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwError;
|
|
SetEvent (pThis->m_hEvent);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
#endif // #ifndef WINNT32
|
|
|
|
|
|
/************************************************************************************************
|
|
** End of File (anycon.cxx)
|
|
************************************************************************************************/
|