Windows2003-3790/inetsrv/iis/svcs/smtp/server/asyncmx.cxx
2020-09-30 16:53:55 +02:00

330 lines
9.3 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;
}
}
}