Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

329 lines
8.9 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. asynccon.cxx
  5. Abstract:
  6. Author:
  7. --*/
  8. #define INCL_INETSRV_INCS
  9. #include "smtpinc.h"
  10. #include "remoteq.hxx"
  11. #include <asynccon.hxx>
  12. #include <dnsreci.h>
  13. #include "asyncmx.hxx"
  14. #include "smtpout.hxx"
  15. extern void DeleteDnsRec(PSMTPDNS_RECS pDnsRec);
  16. CPool CAsyncMx::Pool(ASYNCMX_SIGNATURE);
  17. CAsyncMx::CAsyncMx(PMXPARAMS Parameters)
  18. :CAsyncConnection(Parameters->PortNum, Parameters->TimeOut, Parameters->HostName, Parameters->CallBack)
  19. {
  20. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::CAsyncMx");
  21. m_Signature = ASYNCMX_SIGNATURE;
  22. NumMxRecords = Parameters->pDnsRec->NumRecords;
  23. m_DomainOptions = 0;
  24. m_NextMxRecord = Parameters->pDnsRec->StartRecord;
  25. m_CurrentMxRec = 0;
  26. m_fTriedOnFailHost = FALSE;
  27. m_fLoopback = FALSE;
  28. pSmtpConnection = Parameters->pISMTPConnection;
  29. pServiceInstance = Parameters->pInstance;
  30. m_pDnsRec = Parameters->pDnsRec;
  31. m_pNextIpAddress = NULL;
  32. m_pDNS_RESOLVER_RECORD = Parameters->pDNS_RESOLVER_RECORD;
  33. m_fInitCalled = FALSE;
  34. m_pszSSLVerificationName = NULL;
  35. pServiceInstance->InsertAsyncObject(this);
  36. DebugTrace((LPARAM) this, "Constructing MX object with %d records", NumMxRecords);
  37. DebugTrace((LPARAM) this, "Got DNS_RESOLVER_RECORD = 0x%08x", m_pDNS_RESOLVER_RECORD);
  38. TraceFunctLeaveEx((LPARAM) this);
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Description:
  42. // Initializes heap allocated members of CAsyncMx, ~CAsyncMx cleans up.
  43. // Arguments:
  44. // pszSSLVerificationName - For outbound session, name against which
  45. // server SSL certificate is matched (if config option to match the
  46. // name is set in SMTP).
  47. // Returns:
  48. // FALSE on failure (caller should then delete CAsyncMx), else TRUE
  49. //-----------------------------------------------------------------------------
  50. BOOL CAsyncMx::Init (LPSTR pszSSLVerificationName)
  51. {
  52. BOOL fRet = FALSE;
  53. TraceFunctEnterEx ((LPARAM) this, "CAsyncMx::Init");
  54. m_fInitCalled = TRUE;
  55. if (pszSSLVerificationName) {
  56. m_pszSSLVerificationName = new char [lstrlen (pszSSLVerificationName) + 1];
  57. if (!m_pszSSLVerificationName)
  58. goto Exit;
  59. lstrcpy (m_pszSSLVerificationName, pszSSLVerificationName);
  60. }
  61. fRet = TRUE;
  62. Exit:
  63. TraceFunctLeaveEx ((LPARAM) this);
  64. return fRet;
  65. }
  66. CAsyncMx::~CAsyncMx()
  67. {
  68. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::~CAsyncMx");
  69. _ASSERT (m_fInitCalled && "Init not called for CAsyncMx object");
  70. if(m_pDNS_RESOLVER_RECORD != NULL)
  71. {
  72. DebugTrace((LPARAM) this, "Deleting embedded DNS_RESOLVER_RECORD in async MX obj");
  73. delete m_pDNS_RESOLVER_RECORD;
  74. m_pDNS_RESOLVER_RECORD = NULL;
  75. }
  76. DBG_CODE(else DebugTrace((LPARAM)this, "No DNS_RESOLVER_RECORD object in async MX obj"));
  77. if(m_pDnsRec != NULL)
  78. {
  79. DeleteDnsRec (m_pDnsRec);
  80. m_pDnsRec = NULL;
  81. }
  82. if(m_pszSSLVerificationName != NULL)
  83. {
  84. delete [] m_pszSSLVerificationName;
  85. m_pszSSLVerificationName = NULL;
  86. }
  87. pServiceInstance->RemoveAsyncObject(this);
  88. m_Signature = ASYNCMX_SIGNATURE_FREE;
  89. TraceFunctLeaveEx((LPARAM) this);
  90. }
  91. BOOL CAsyncMx::CheckIpAddress(DWORD IpAddress, DWORD PortNum)
  92. {
  93. BOOL fRet = TRUE;
  94. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::CheckIpAddress");
  95. fRet = pServiceInstance->IsAddressMine (IpAddress, PortNum);
  96. m_fLoopback = fRet;
  97. return !fRet;
  98. TraceFunctLeaveEx((LPARAM) this);
  99. }
  100. BOOL CAsyncMx::IsMoreIpAddresses(void)
  101. {
  102. BOOL fMore = FALSE;
  103. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::IsMoreIpAddresses");
  104. if(m_pDnsRec && m_pNextIpAddress && m_pDnsRec->DnsArray[m_CurrentMxRec])
  105. {
  106. if(m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead)
  107. {
  108. fMore = TRUE;
  109. }
  110. else
  111. {
  112. m_pNextIpAddress = NULL;
  113. }
  114. }
  115. TraceFunctLeaveEx((LPARAM) this);
  116. return fMore;
  117. }
  118. void CAsyncMx::IncNextIpToTry (void)
  119. {
  120. if(m_pNextIpAddress)
  121. {
  122. m_pNextIpAddress = m_pNextIpAddress->Flink;
  123. }
  124. }
  125. DWORD CAsyncMx::GetNextIpAddress(void)
  126. {
  127. PMXIPLIST_ENTRY pContext = NULL;
  128. DWORD IpAddress = INADDR_NONE;
  129. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::GetNextIpAddress");
  130. if(m_pDnsRec && m_pNextIpAddress && m_pDnsRec->DnsArray[m_CurrentMxRec])
  131. {
  132. //m_pNextIpAddress = m_pNextIpAddress->Flink;
  133. //if m_pNextIpAddress == &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead
  134. //this means we have tried every IP address in the list, and there is no more.
  135. //else we get the next IP address and try to connect to it.
  136. if(m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead)
  137. {
  138. pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
  139. IpAddress = pContext->IpAddress;
  140. }
  141. else
  142. {
  143. m_pNextIpAddress = NULL;
  144. }
  145. }
  146. else
  147. {
  148. m_pNextIpAddress = NULL;
  149. }
  150. TraceFunctLeaveEx((LPARAM) this);
  151. return IpAddress;
  152. }
  153. BOOL CAsyncMx::ConnectToNextMxHost(void)
  154. {
  155. BOOL fReturn = FALSE;
  156. LIST_ENTRY * pEntry = NULL;
  157. PMXIPLIST_ENTRY pContext = NULL;
  158. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::ConnectToNextMxHost");
  159. SetLastError(NO_ERROR);
  160. DebugTrace((LPARAM)this, "m_NextMxRecord is %d", m_NextMxRecord);
  161. DebugTrace((LPARAM)this, "NumMxRecords is %d", NumMxRecords);
  162. //If there are more MX records to connect to, then try and connect
  163. //to the next one.
  164. if((m_NextMxRecord < NumMxRecords) && (m_pDnsRec->DnsArray[m_NextMxRecord] != NULL))
  165. {
  166. m_CurrentMxRec = m_NextMxRecord;
  167. SetNewHost(m_pDnsRec->DnsArray[m_NextMxRecord]->DnsName);
  168. DebugTrace((LPARAM)this, "m_NextMxRecord for %s is %d", GetHostName(), m_NextMxRecord);
  169. //if the first entry is non NULL, then see if this
  170. //entry has an Ip Address. If it has an ip address,
  171. //save the link to the next ip address incase this
  172. //one fails to connect. Also, bump the next MX record
  173. //to try counter.
  174. if(!IsListEmpty(&m_pDnsRec->DnsArray[m_NextMxRecord]->IpListHead))
  175. {
  176. m_pNextIpAddress = m_pDnsRec->DnsArray[m_NextMxRecord]->IpListHead.Flink;
  177. pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
  178. m_NextMxRecord++;
  179. SetErrorCode(NO_ERROR);
  180. #define BYTE_VAL(dw, ByteNo) ( ((dw) >> (8 * (ByteNo))) & 0xFF)
  181. DebugTrace((LPARAM) this, "ConnectToNextMxHost trying IP address %d.%d.%d.%d",
  182. BYTE_VAL(pContext->IpAddress, 0),
  183. BYTE_VAL(pContext->IpAddress, 1),
  184. BYTE_VAL(pContext->IpAddress, 2),
  185. BYTE_VAL(pContext->IpAddress, 3));
  186. fReturn = ConnectToHost(pContext->IpAddress);
  187. }
  188. else
  189. {
  190. //the list is empty.
  191. DebugTrace((LPARAM) this, "No more MX hosts in ConnectToNextMxHost");
  192. m_NextMxRecord++;
  193. m_pDnsRec->StartRecord++;
  194. SetErrorCode(WSAHOST_NOT_FOUND);
  195. }
  196. }
  197. else
  198. {
  199. SetLastError(ERROR_NO_MORE_ITEMS);
  200. }
  201. TraceFunctLeaveEx((LPARAM) this);
  202. return fReturn;
  203. }
  204. BOOL CAsyncMx::MakeFirstAsyncConnect(void)
  205. {
  206. BOOL fReturn = FALSE;
  207. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::MakeFirstAsyncConnect");
  208. fReturn = ConnectToNextMxHost();
  209. TraceFunctLeaveEx((LPARAM) this);
  210. return fReturn;
  211. }
  212. BOOL CAsyncMx::OnConnect(BOOL fConnected)
  213. {
  214. LIST_ENTRY * pEntryNext = NULL;
  215. PMXIPLIST_ENTRY pContext = NULL;
  216. BOOL fReturn = TRUE;
  217. TraceFunctEnterEx((LPARAM) this, "CAsyncMx::OnConnect");
  218. //remove this IP address from the list, so we do not connect
  219. //to it again if the connection drops when we perform all our
  220. //outbound processing
  221. if(m_pNextIpAddress &&
  222. (m_pNextIpAddress != &m_pDnsRec->DnsArray[m_CurrentMxRec]->IpListHead))
  223. {
  224. //save the next entry in the list
  225. pEntryNext = m_pNextIpAddress->Flink;
  226. //get the current entry, remove it, then delete it
  227. pContext = CONTAINING_RECORD( m_pNextIpAddress, MXIPLIST_ENTRY, ListEntry );
  228. RemoveEntryList( &(pContext->ListEntry));
  229. delete pContext;
  230. //set the current entry equal to the saved entry
  231. m_pNextIpAddress = pEntryNext;
  232. }
  233. else
  234. {
  235. fReturn = FALSE;
  236. }
  237. TraceFunctLeaveEx((LPARAM) this);
  238. return fReturn;
  239. }
  240. void CAsyncMx::AckMessage(void)
  241. {
  242. MessageAck MsgAck;
  243. if(m_pDnsRec != NULL)
  244. {
  245. if(m_pDnsRec->pMailMsgObj)
  246. {
  247. MsgAck.dwMsgStatus = MESSAGE_STATUS_RETRY_ALL;
  248. MsgAck.pvMsgContext = (DWORD *) m_pDnsRec->pAdvQContext;
  249. MsgAck.pIMailMsgProperties = (IMailMsgProperties *) m_pDnsRec->pMailMsgObj;
  250. pSmtpConnection->AckMessage(&MsgAck);
  251. MsgAck.pIMailMsgProperties->Release();
  252. m_pDnsRec->pMailMsgObj = NULL;
  253. }
  254. }
  255. }