330 lines
8.9 KiB
C++
330 lines
8.9 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
asynccon.cxx
|
|
|
|
Abstract:
|
|
|
|
|
|
Author:
|
|
|
|
--*/
|
|
|
|
#define INCL_INETSRV_INCS
|
|
#include "smtpinc.h"
|
|
#include "remoteq.hxx"
|
|
#include <asynccon.hxx>
|
|
#include <dnsreci.h>
|
|
#include "asyncmx.hxx"
|
|
|
|
#include "smtpout.hxx"
|
|
|
|
extern void DeleteDnsRec(PSMTPDNS_RECS pDnsRec);
|
|
|
|
CPool CAsyncMx::Pool(ASYNCMX_SIGNATURE);
|
|
|
|
CAsyncMx::CAsyncMx(PMXPARAMS Parameters)
|
|
:CAsyncConnection(Parameters->PortNum, Parameters->TimeOut, Parameters->HostName, Parameters->CallBack)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::CAsyncMx");
|
|
|
|
m_Signature = ASYNCMX_SIGNATURE;
|
|
NumMxRecords = Parameters->pDnsRec->NumRecords;
|
|
m_DomainOptions = 0;
|
|
m_NextMxRecord = Parameters->pDnsRec->StartRecord;
|
|
m_CurrentMxRec = 0;
|
|
m_fTriedOnFailHost = FALSE;
|
|
m_fLoopback = FALSE;
|
|
pSmtpConnection = Parameters->pISMTPConnection;
|
|
pServiceInstance = Parameters->pInstance;
|
|
m_pDnsRec = Parameters->pDnsRec;
|
|
m_pNextIpAddress = NULL;
|
|
m_pDNS_RESOLVER_RECORD = Parameters->pDNS_RESOLVER_RECORD;
|
|
m_fInitCalled = FALSE;
|
|
m_pszSSLVerificationName = NULL;
|
|
|
|
pServiceInstance->InsertAsyncObject(this);
|
|
|
|
DebugTrace((LPARAM) this, "Constructing MX object with %d records", NumMxRecords);
|
|
DebugTrace((LPARAM) this, "Got DNS_RESOLVER_RECORD = 0x%08x", m_pDNS_RESOLVER_RECORD);
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Description:
|
|
// Initializes heap allocated members of CAsyncMx, ~CAsyncMx cleans up.
|
|
// Arguments:
|
|
// pszSSLVerificationName - For outbound session, name against which
|
|
// server SSL certificate is matched (if config option to match the
|
|
// name is set in SMTP).
|
|
// Returns:
|
|
// FALSE on failure (caller should then delete CAsyncMx), else TRUE
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CAsyncMx::Init (LPSTR pszSSLVerificationName)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
TraceFunctEnterEx ((LPARAM) this, "CAsyncMx::Init");
|
|
|
|
m_fInitCalled = TRUE;
|
|
if (pszSSLVerificationName) {
|
|
m_pszSSLVerificationName = new char [lstrlen (pszSSLVerificationName) + 1];
|
|
if (!m_pszSSLVerificationName)
|
|
goto Exit;
|
|
|
|
lstrcpy (m_pszSSLVerificationName, pszSSLVerificationName);
|
|
}
|
|
|
|
fRet = TRUE;
|
|
Exit:
|
|
TraceFunctLeaveEx ((LPARAM) this);
|
|
return fRet;
|
|
}
|
|
|
|
CAsyncMx::~CAsyncMx()
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::~CAsyncMx");
|
|
|
|
_ASSERT (m_fInitCalled && "Init not called for CAsyncMx object");
|
|
|
|
if(m_pDNS_RESOLVER_RECORD != NULL)
|
|
{
|
|
DebugTrace((LPARAM) this, "Deleting embedded DNS_RESOLVER_RECORD in async MX obj");
|
|
delete m_pDNS_RESOLVER_RECORD;
|
|
m_pDNS_RESOLVER_RECORD = NULL;
|
|
}
|
|
DBG_CODE(else DebugTrace((LPARAM)this, "No DNS_RESOLVER_RECORD object in async MX obj"));
|
|
|
|
if(m_pDnsRec != NULL)
|
|
{
|
|
DeleteDnsRec (m_pDnsRec);
|
|
m_pDnsRec = NULL;
|
|
}
|
|
|
|
if(m_pszSSLVerificationName != NULL)
|
|
{
|
|
delete [] m_pszSSLVerificationName;
|
|
m_pszSSLVerificationName = NULL;
|
|
}
|
|
|
|
pServiceInstance->RemoveAsyncObject(this);
|
|
|
|
m_Signature = ASYNCMX_SIGNATURE_FREE;
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
|
|
BOOL CAsyncMx::CheckIpAddress(DWORD IpAddress, DWORD PortNum)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::CheckIpAddress");
|
|
|
|
fRet = pServiceInstance->IsAddressMine (IpAddress, PortNum);
|
|
|
|
m_fLoopback = fRet;
|
|
|
|
return !fRet;
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
}
|
|
|
|
BOOL CAsyncMx::IsMoreIpAddresses(void)
|
|
{
|
|
BOOL fMore = FALSE;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::IsMoreIpAddresses");
|
|
|
|
if(m_pDnsRec && m_pNextIpAddress && m_pDnsRec->DnsArray[m_CurrentMxRec])
|
|
{
|
|
if(m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead)
|
|
{
|
|
fMore = TRUE;
|
|
}
|
|
else
|
|
{
|
|
m_pNextIpAddress = NULL;
|
|
}
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return fMore;
|
|
}
|
|
|
|
void CAsyncMx::IncNextIpToTry (void)
|
|
{
|
|
if(m_pNextIpAddress)
|
|
{
|
|
m_pNextIpAddress = m_pNextIpAddress->Flink;
|
|
}
|
|
}
|
|
|
|
DWORD CAsyncMx::GetNextIpAddress(void)
|
|
{
|
|
PMXIPLIST_ENTRY pContext = NULL;
|
|
DWORD IpAddress = INADDR_NONE;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::GetNextIpAddress");
|
|
|
|
if(m_pDnsRec && m_pNextIpAddress && m_pDnsRec->DnsArray[m_CurrentMxRec])
|
|
{
|
|
//m_pNextIpAddress = m_pNextIpAddress->Flink;
|
|
|
|
//if m_pNextIpAddress == &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead
|
|
//this means we have tried every IP address in the list, and there is no more.
|
|
//else we get the next IP address and try to connect to it.
|
|
if(m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead)
|
|
{
|
|
pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
|
|
IpAddress = pContext->IpAddress;
|
|
}
|
|
else
|
|
{
|
|
m_pNextIpAddress = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_pNextIpAddress = NULL;
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return IpAddress;
|
|
}
|
|
|
|
BOOL CAsyncMx::ConnectToNextMxHost(void)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
LIST_ENTRY * pEntry = NULL;
|
|
PMXIPLIST_ENTRY pContext = NULL;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::ConnectToNextMxHost");
|
|
|
|
SetLastError(NO_ERROR);
|
|
|
|
DebugTrace((LPARAM)this, "m_NextMxRecord is %d", m_NextMxRecord);
|
|
DebugTrace((LPARAM)this, "NumMxRecords is %d", NumMxRecords);
|
|
|
|
//If there are more MX records to connect to, then try and connect
|
|
//to the next one.
|
|
|
|
if((m_NextMxRecord < NumMxRecords) && (m_pDnsRec->DnsArray[m_NextMxRecord] != NULL))
|
|
{
|
|
m_CurrentMxRec = m_NextMxRecord;
|
|
|
|
SetNewHost(m_pDnsRec->DnsArray[m_NextMxRecord]->DnsName);
|
|
|
|
DebugTrace((LPARAM)this, "m_NextMxRecord for %s is %d", GetHostName(), m_NextMxRecord);
|
|
|
|
//if the first entry is non NULL, then see if this
|
|
//entry has an Ip Address. If it has an ip address,
|
|
//save the link to the next ip address incase this
|
|
//one fails to connect. Also, bump the next MX record
|
|
//to try counter.
|
|
if(!IsListEmpty(&m_pDnsRec->DnsArray[m_NextMxRecord]->IpListHead))
|
|
{
|
|
m_pNextIpAddress = m_pDnsRec->DnsArray[m_NextMxRecord]->IpListHead.Flink;
|
|
pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
|
|
|
|
m_NextMxRecord++;
|
|
SetErrorCode(NO_ERROR);
|
|
|
|
#define BYTE_VAL(dw, ByteNo) ( ((dw) >> (8 * (ByteNo))) & 0xFF)
|
|
|
|
DebugTrace((LPARAM) this, "ConnectToNextMxHost trying IP address %d.%d.%d.%d",
|
|
BYTE_VAL(pContext->IpAddress, 0),
|
|
BYTE_VAL(pContext->IpAddress, 1),
|
|
BYTE_VAL(pContext->IpAddress, 2),
|
|
BYTE_VAL(pContext->IpAddress, 3));
|
|
|
|
fReturn = ConnectToHost(pContext->IpAddress);
|
|
}
|
|
else
|
|
{
|
|
//the list is empty.
|
|
DebugTrace((LPARAM) this, "No more MX hosts in ConnectToNextMxHost");
|
|
|
|
m_NextMxRecord++;
|
|
m_pDnsRec->StartRecord++;
|
|
SetErrorCode(WSAHOST_NOT_FOUND);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLastError(ERROR_NO_MORE_ITEMS);
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return fReturn;
|
|
}
|
|
|
|
BOOL CAsyncMx::MakeFirstAsyncConnect(void)
|
|
{
|
|
BOOL fReturn = FALSE;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::MakeFirstAsyncConnect");
|
|
|
|
fReturn = ConnectToNextMxHost();
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return fReturn;
|
|
}
|
|
|
|
|
|
BOOL CAsyncMx::OnConnect(BOOL fConnected)
|
|
{
|
|
LIST_ENTRY * pEntryNext = NULL;
|
|
PMXIPLIST_ENTRY pContext = NULL;
|
|
BOOL fReturn = TRUE;
|
|
|
|
TraceFunctEnterEx((LPARAM) this, "CAsyncMx::OnConnect");
|
|
|
|
//remove this IP address from the list, so we do not connect
|
|
//to it again if the connection drops when we perform all our
|
|
//outbound processing
|
|
if(m_pNextIpAddress &&
|
|
(m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead))
|
|
{
|
|
//save the next entry in the list
|
|
pEntryNext = m_pNextIpAddress->Flink;
|
|
|
|
//get the current entry, remove it, then delete it
|
|
pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
|
|
RemoveEntryList( &(pContext->ListEntry));
|
|
delete pContext;
|
|
|
|
//set the current entry equal to the saved entry
|
|
m_pNextIpAddress = pEntryNext;
|
|
}
|
|
else
|
|
{
|
|
fReturn = FALSE;
|
|
}
|
|
|
|
TraceFunctLeaveEx((LPARAM) this);
|
|
return fReturn;
|
|
}
|
|
|
|
void CAsyncMx::AckMessage(void)
|
|
{
|
|
MessageAck MsgAck;
|
|
|
|
if(m_pDnsRec != NULL)
|
|
{
|
|
if(m_pDnsRec->pMailMsgObj)
|
|
{
|
|
MsgAck.dwMsgStatus = MESSAGE_STATUS_RETRY_ALL;
|
|
MsgAck.pvMsgContext = (DWORD *) m_pDnsRec->pAdvQContext;
|
|
MsgAck.pIMailMsgProperties = (IMailMsgProperties *) m_pDnsRec->pMailMsgObj;
|
|
pSmtpConnection->AckMessage(&MsgAck);
|
|
MsgAck.pIMailMsgProperties->Release();
|
|
m_pDnsRec->pMailMsgObj = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|