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.
691 lines
25 KiB
691 lines
25 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// File: linkmsgq.h
|
|
//
|
|
// Description:
|
|
// This provides a description of one of the external interfaces provided
|
|
// by the CMT. CLinkMsgQueue provides Route factoring with an interface
|
|
// to get the next message for a given link.
|
|
//
|
|
// Owner: mikeswa
|
|
//
|
|
// Copyright (C) 1997 Microsoft Corporation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#ifndef _LINKMSGQ_H_
|
|
#define _LINKMSGQ_H_
|
|
|
|
#include "cmt.h"
|
|
#include <rwnew.h>
|
|
#include <baseobj.h>
|
|
#include <aqueue.h>
|
|
#include "domain.h"
|
|
#include "aqroute.h"
|
|
#include "smproute.h"
|
|
#include <listmacr.h>
|
|
#include "qwiklist.h"
|
|
#include "dcontext.h"
|
|
#include "aqstats.h"
|
|
#include "aqnotify.h"
|
|
#include "aqadmsvr.h"
|
|
|
|
class CAQSvrInst;
|
|
class CDestMsgQueue;
|
|
class CConnMgr;
|
|
class CSMTPConn;
|
|
class CInternalDomainInfo;
|
|
|
|
#define LINK_MSGQ_SIG ' QML'
|
|
|
|
//Define private link state flags
|
|
//NOTE - Be sure to add new private flags to AssertPrivateLinkStateFlags as well
|
|
#define LINK_STATE_PRIV_CONFIG_TURN_ETRN 0x80000000
|
|
#define LINK_STATE_PRIV_ETRN_ENABLED 0x40000000
|
|
#define LINK_STATE_PRIV_TURN_ENABLED 0x20000000
|
|
#define LINK_STATE_PRIV_NO_NOTIFY 0x10000000
|
|
#define LINK_STATE_PRIV_NO_CONNECTION 0x08000000
|
|
#define LINK_STATE_PRIV_GENERATING_DSNS 0x04000000
|
|
#define LINK_STATE_PRIV_IGNORE_DELETE_IF_EMPTY 0x02000000
|
|
#define LINK_STATE_PRIV_HAVE_SENT_NOTIFICATION 0x01000000
|
|
#define LINK_STATE_PRIV_HAVE_SENT_NO_LONGER_USED 0x00400000
|
|
|
|
#define EMPTY_LMQ_EXPIRE_TIME_MINUTES 2
|
|
|
|
//---[ enum LinkFlags ]--------------------------------------------------------
|
|
//
|
|
//
|
|
// Hungarian: lf, pfl
|
|
//
|
|
// Private link data flags
|
|
//-----------------------------------------------------------------------------
|
|
typedef enum _LinkFlags
|
|
{
|
|
eLinkFlagsClear = 0x00000000,
|
|
eLinkFlagsSentNewNotification = 0x00000001,
|
|
eLinkFlagsRouteChangePending = 0x00000002,
|
|
eLinkFlagsFileTimeSpinLock = 0x00000004,
|
|
eLinkFlagsDiagnosticSpinLock = 0x00000008,
|
|
eLinkFlagsConnectionVerifed = 0x00000010,
|
|
eLinkFlagsGetInfoFailed = 0x00000020,
|
|
eLinkFlagsAQSpecialLinkInfo = 0x00000040,
|
|
eLinkFlagsInternalSMTPLinkInfo = 0x00000080,
|
|
eLinkFlagsExternalSMTPLinkInfo = 0x00000100,
|
|
eLinkFlagsMarkedAsEmpty = 0x00000200,
|
|
eLinkFlagsInvalid = 0x80000000, //link has been tagged as invalid
|
|
} LinkFlags, *PLinkFlags;
|
|
|
|
//inline function to verify that private flags are only using reserved bits
|
|
inline void AssertPrivateLinkStateFlags()
|
|
{
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_CONFIG_TURN_ETRN));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_ETRN_ENABLED));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_TURN_ENABLED));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_NO_NOTIFY));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_NO_CONNECTION));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_GENERATING_DSNS));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_IGNORE_DELETE_IF_EMPTY));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_HAVE_SENT_NOTIFICATION));
|
|
_ASSERT(!(~LINK_STATE_RESERVED & LINK_STATE_PRIV_HAVE_SENT_NO_LONGER_USED));
|
|
}
|
|
|
|
// {34E2DCCB-C91A-11d2-A6B1-00C04FA3490A}
|
|
static const GUID g_sDefaultLinkGuid =
|
|
{ 0x34e2dccb, 0xc91a, 0x11d2, { 0xa6, 0xb1, 0x0, 0xc0, 0x4f, 0xa3, 0x49, 0xa } };
|
|
|
|
// Global count of failures : "failed to add queue to link because link was
|
|
// marked as no longer in use"
|
|
_declspec(selectany) DWORD g_cFailedToAddQueueToRemovedLink = 0;
|
|
|
|
//---[ CLinkMsgQueue ]---------------------------------------------------------
|
|
//
|
|
//
|
|
// Hungarian: linkq, plinkq
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
class CLinkMsgQueue :
|
|
public IQueueAdminAction,
|
|
public IQueueAdminLink,
|
|
public CBaseObject,
|
|
public IAQNotify,
|
|
public CQueueAdminRetryNotify
|
|
{
|
|
protected:
|
|
DWORD m_dwSignature;
|
|
DWORD m_dwLinkFlags; //private data
|
|
DWORD m_dwLinkStateFlags; //Link state flags (private + eLinkStateFlagsf)
|
|
CAQSvrInst *m_paqinst; //ptr to the virtual server intance object
|
|
DWORD m_cQueues; //Number of queues on Link
|
|
CQuickList m_qlstQueues;
|
|
CDomainEntry *m_pdentryLink; //Domain Entry for link
|
|
DWORD m_cConnections; //Number of current connections
|
|
DWORD m_dwRoundRobinIndex; //Used to round-robin through queues
|
|
CShareLockInst m_slConnections; //lock to access connections
|
|
CShareLockInst m_slInfo; //share lock for link info
|
|
CShareLockInst m_slQueues; //lock to access queues
|
|
DWORD m_cbSMTPDomain; //byte count of next hop domain name
|
|
LPSTR m_szSMTPDomain; //ptr to string of next hop
|
|
CInternalDomainInfo *m_pIntDomainInfo; //internal config info for domain
|
|
LONG m_lConnMgrCount; //Count used by connection manager
|
|
|
|
//
|
|
// We have 2 failure counts to keep track of the 2 types of failures.
|
|
// m_lConsecutiveConnectionFailureCount keeps track of the number consecutive
|
|
// failures to make a connection to a remote machine.
|
|
// m_lConsecutiveMessageFailureCount tracks the number of failures to actually
|
|
// send a message. They will be different if we can connect to a remote
|
|
// server but cannot (or have not) sent mail. m_lConsecutiveConnectionFailureCount
|
|
// is reported to routing, so that mail will be routed to this link, while
|
|
// m_lConsecutiveMessageFailureCount is used to determine the retry interval.
|
|
// By doing this, we can avoid resetting our retry times if we successfully
|
|
// connect, but cannot actually send a message.
|
|
//
|
|
LONG m_lConsecutiveConnectionFailureCount;
|
|
LONG m_lConsecutiveMessageFailureCount;
|
|
|
|
LPSTR m_szConnectorName;
|
|
IMessageRouterLinkStateNotification *m_pILinkStateNotify;
|
|
|
|
//Filetimes reported to queue admin
|
|
FILETIME m_ftNextRetry;
|
|
FILETIME m_ftNextScheduledCallback;
|
|
|
|
//
|
|
// Used by RemoveLinkIfEmpty to make sure that we cache links for
|
|
// a period of time after them become empty. This is only
|
|
// valid when the eLinkFlagsMarkedAsEmpty bit is set.
|
|
//
|
|
FILETIME m_ftEmptyExpireTime;
|
|
|
|
//Message statistics
|
|
CAQStats m_aqstats;
|
|
|
|
CAQScheduleID m_aqsched; //ScheduleID returned by routing
|
|
LIST_ENTRY m_liLinks; //linked list of links for this domain
|
|
LIST_ENTRY m_liConnections; //linked list of connections for this domain
|
|
|
|
//Diagnostic information returned by SMTPSVC
|
|
HRESULT m_hrDiagnosticError;
|
|
CHAR m_szDiagnosticVerb[20]; //failed protocol VERB
|
|
CHAR m_szDiagnosticResponse[100]; //response from remote server
|
|
|
|
|
|
//See comments near SetLinkType()/GetLinkType() and
|
|
//SetSupportedActions()/fActionIsSupported() functions.
|
|
DWORD m_dwSupportedActions;
|
|
DWORD m_dwLinkType;
|
|
|
|
//Gets & verifies internal domain info
|
|
HRESULT HrGetInternalInfo(OUT CInternalDomainInfo **ppIntDomainInfo);
|
|
static inline BOOL fFlagsAllowConnection(DWORD dwFlags);
|
|
HRESULT m_hrLastConnectionFailure;
|
|
|
|
void InternalUpdateFileTime(FILETIME *pftDest, FILETIME *pftSrc);
|
|
|
|
void InternalInit();
|
|
|
|
HRESULT CLinkMsgQueue::HrInternalPrepareDelivery(
|
|
IN CMsgRef *pmsgref,
|
|
IN BOOL fQueuesLocked,
|
|
IN BOOL fLocal,
|
|
IN BOOL fDelayDSN,
|
|
IN OUT CDeliveryContext *pdcntxt,
|
|
OUT DWORD *pcRecips,
|
|
OUT DWORD **prgdwRecips);
|
|
|
|
|
|
//Static callback used to restart DSN generation
|
|
static BOOL fRestartDSNGenerationIfNecessary(PVOID pvContext,
|
|
DWORD dwStatus);
|
|
|
|
public:
|
|
CLinkMsgQueue(GUID guid = g_sDefaultLinkGuid) : m_aqsched(guid, 0)
|
|
{InternalInit();};
|
|
|
|
CLinkMsgQueue(DWORD dwScheduleID,
|
|
IMessageRouter *pIMessageRouter,
|
|
IMessageRouterLinkStateNotification *pILinkStateNotify);
|
|
~CLinkMsgQueue();
|
|
|
|
void SetLinkType(DWORD dwLinkType) { m_dwLinkType = dwLinkType; }
|
|
DWORD GetLinkType() { return m_dwLinkType; }
|
|
|
|
//For some links, certain actions are not supported:
|
|
//but they use the same class (CLinkMsgQueue) as others for which
|
|
//the actions are supported. For example CurrentlyUnreachable does
|
|
//not support freeze/thaw. So we need to maintain for the currently
|
|
//unreachable object, a list of actions that are supported, so it
|
|
//does not set the flags corresponding to an unsupported action
|
|
//when that action is commanded.
|
|
|
|
void SetSupportedActions(DWORD dwSupported) { m_dwSupportedActions = dwSupported; }
|
|
DWORD fActionIsSupported(LINK_ACTION la) { return (m_dwSupportedActions & la); }
|
|
|
|
BOOL fCanSchedule() //Can this link be scheduled
|
|
{
|
|
HrGetInternalInfo(NULL); //make sure link state flags are up to date
|
|
DWORD dwFlags = m_dwLinkStateFlags;
|
|
return fFlagsAllowConnection(dwFlags);
|
|
}
|
|
|
|
BOOL fCanSendCmd() //Is this link scheduled to send command on next connection
|
|
{
|
|
//Logic :
|
|
// Every time we see this flag set, the connection that is created also will
|
|
// be used to send a command
|
|
//
|
|
DWORD dwFlags = m_dwLinkStateFlags;
|
|
return (dwFlags & LINK_STATE_CMD_ENABLED);
|
|
}
|
|
|
|
BOOL fShouldConnect(IN DWORD cMaxLinkConnections,
|
|
IN DWORD cMinMessagesPerConnection);
|
|
|
|
//returns S_OK if connection is needed, S_FALSE if not.
|
|
HRESULT HrCreateConnectionIfNeeded(IN DWORD cMaxLinkConnections,
|
|
IN DWORD cMinMessagesPerConnection,
|
|
IN DWORD cMaxMessagesPerConnection,
|
|
IN CConnMgr *pConnMgr,
|
|
OUT CSMTPConn **ppSMTPConn);
|
|
|
|
LONG IncrementConnMgrCount() {return InterlockedIncrement(&m_lConnMgrCount);}
|
|
LONG DecrementConnMgrCount() {return InterlockedDecrement(&m_lConnMgrCount);}
|
|
|
|
//
|
|
// Connection failure API. This is used by the connection manager. We
|
|
// will always return the message failure count, since this is what we
|
|
// want to pass to the retry sink. However, we will not allow the
|
|
// connection manager to reset this count since only we should during
|
|
// ack message.
|
|
//
|
|
LONG IncrementFailureCounts()
|
|
{
|
|
InterlockedIncrement(&m_lConsecutiveConnectionFailureCount);
|
|
return InterlockedIncrement(&m_lConsecutiveMessageFailureCount);
|
|
}
|
|
LONG cGetMessageFailureCount() {return m_lConsecutiveMessageFailureCount;}
|
|
void ResetConnectionFailureCount(){InterlockedExchange(&m_lConsecutiveConnectionFailureCount, 0);}
|
|
|
|
DWORD cGetConnections() {return m_cConnections;};
|
|
|
|
HRESULT HrInitialize(IN CAQSvrInst *paqinst,
|
|
IN CDomainEntry *pdentryLink,
|
|
IN DWORD cbSMTPDomain,
|
|
IN LPSTR szSMTPDomain,
|
|
IN LinkFlags lf,
|
|
IN LPSTR szConnectorName);
|
|
|
|
HRESULT HrDeinitialize();
|
|
|
|
void AddConnection(IN CSMTPConn *pSMTPConn); //Add Connection to link
|
|
void RemoveConnection(IN CSMTPConn *pSMTPConn,
|
|
IN BOOL fForceDSNGeneration);
|
|
|
|
HRESULT HrGetDomainInfo(OUT DWORD *pcbSMTPDomain,
|
|
OUT LPSTR *pszSMTPDomain,
|
|
OUT CInternalDomainInfo **ppIntDomainInfo);
|
|
|
|
HRESULT HrGetSMTPDomain(OUT DWORD *pcbSMTPDomain,
|
|
OUT LPSTR *pszSMTPDomain);
|
|
|
|
//Queue manipulation routines
|
|
HRESULT HrAddQueue(IN CDestMsgQueue *pdmqNew);
|
|
void RemoveQueue(IN CDestMsgQueue *pdmq, IN CAQStats *paqstats);
|
|
|
|
HRESULT HrGetQueueListSnapshot(CQuickList **ppql);
|
|
|
|
void RemoveLinkIfEmpty();
|
|
|
|
//Called by DMT to signal complete routing change
|
|
void RemoveAllQueues();
|
|
|
|
// Called by DMT when this link is orphaned
|
|
void RemovedFromDMT();
|
|
|
|
|
|
// This function dequeues the next available message.The message
|
|
// retrieved will be the top one approximatly ordered by quality/class
|
|
// and arrival time.
|
|
HRESULT HrGetNextMsg(
|
|
IN OUT CDeliveryContext *pdcntxt, //delivery context for connection
|
|
OUT IMailMsgProperties **ppIMailMsgProperties, //IMsg dequeued
|
|
OUT DWORD *pcIndexes, //size of array
|
|
OUT DWORD **prgdwRecipIndex); //Array of recipient indexes
|
|
|
|
//Acknowledge the message ref.
|
|
//There should be one Ack for every dequeue from a link.
|
|
HRESULT HrAckMsg(IN MessageAck *pMsgAck);
|
|
|
|
//Gets the next message ref without getting delivery context or
|
|
//preparing for delivery
|
|
HRESULT HrGetNextMsgRef(IN BOOL fRoutingLockHeld, OUT CMsgRef **ppmsgref);
|
|
|
|
//Calls CMsgRef prepare delivery for all the messages
|
|
HRESULT HrPrepareDelivery(
|
|
IN CMsgRef *pmsgref,
|
|
IN BOOL fLocal,
|
|
IN BOOL fDelayDSN,
|
|
IN OUT CDeliveryContext *pdcntxt,
|
|
OUT DWORD *pcRecips,
|
|
OUT DWORD **prgdwRecips)
|
|
{
|
|
return HrInternalPrepareDelivery(pmsgref, FALSE, fLocal, fDelayDSN,
|
|
pdcntxt, pcRecips, prgdwRecips);
|
|
}
|
|
|
|
//Recieve notifications from contained queues
|
|
HRESULT HrNotify(IN CAQStats *paqstats, BOOL fAdd);
|
|
HRESULT HrNotifyRetryStatChange(BOOL fAdd);
|
|
|
|
|
|
// Gather statistical information for link mangment
|
|
DWORD cGetTotalMsgCount() {return m_aqstats.m_cMsgs;};
|
|
DWORD cGetRetryMsgCount() {return m_aqstats.m_cRetryMsgs;};
|
|
|
|
//functions used to manipulate lists of queues
|
|
inline CAQScheduleID *paqschedGetScheduleID();
|
|
inline BOOL fIsSameScheduleID(CAQScheduleID *paqsched);
|
|
static inline CLinkMsgQueue *plmqIsSameScheduleID(
|
|
CAQScheduleID *paqsched,
|
|
PLIST_ENTRY pli);
|
|
|
|
static inline CLinkMsgQueue *plmqGetLinkMsgQueue(PLIST_ENTRY pli);
|
|
|
|
inline PLIST_ENTRY pliGetNextListEntry();
|
|
|
|
inline void InsertLinkInList(PLIST_ENTRY pliHead);
|
|
inline BOOL fRemoveLinkFromList();
|
|
|
|
DWORD dwModifyLinkState(IN DWORD dwLinkStateToSet,
|
|
IN DWORD dwLinkStateToUnset);
|
|
|
|
//Used to send notification to routing/scheduling sink
|
|
void SendLinkStateNotification();
|
|
|
|
void SendLinkStateNotificationIfNew() {
|
|
if (m_pILinkStateNotify &&
|
|
!(m_dwLinkStateFlags & LINK_STATE_PRIV_HAVE_SENT_NOTIFICATION))
|
|
SendLinkStateNotification();
|
|
}
|
|
|
|
DWORD dwGetLinkState() {return m_dwLinkStateFlags;};
|
|
|
|
void SetLastConnectionFailure(HRESULT hrLastConnectionFailure)
|
|
{m_hrLastConnectionFailure = hrLastConnectionFailure;};
|
|
|
|
inline BOOL fRPCCopyName(OUT LPWSTR *pwszLinkName);
|
|
|
|
DWORD cGetNumQueues() {return m_cQueues;};
|
|
|
|
virtual void SetNextRetry(FILETIME *pft)
|
|
{
|
|
_ASSERT(pft);
|
|
InternalUpdateFileTime(&m_ftNextRetry, pft);
|
|
};
|
|
|
|
void SetNextScheduledConnection(FILETIME *pft)
|
|
{
|
|
_ASSERT(pft);
|
|
InternalUpdateFileTime(&m_ftNextScheduledCallback, pft);
|
|
};
|
|
|
|
static void ScheduledCallback(PVOID pvContext);
|
|
|
|
void GenerateDSNsIfNecessary(BOOL fCheckIfEmpty, BOOL fMergeOnly);
|
|
|
|
void SetDiagnosticInfo(
|
|
IN HRESULT hrDiagnosticError,
|
|
IN LPCSTR szDiagnosticVerb,
|
|
IN LPCSTR szDiagnosticResponse);
|
|
void GetDiagnosticInfo(
|
|
IN LPSTR szDiagnosticVerb,
|
|
IN DWORD cDiagnosticVerb,
|
|
IN LPSTR szDiagnosticResponse,
|
|
IN DWORD cbDiagnosticResponse,
|
|
OUT HRESULT *phrDiagnosticError);
|
|
|
|
virtual BOOL fIsRemote() {return TRUE;};
|
|
|
|
//
|
|
// Returns the connector name. Used by CSMTPConn. Valid as long
|
|
// as the link is valid.
|
|
//
|
|
LPSTR szGetConnectorName() {return m_szConnectorName;};
|
|
|
|
public: //IUnknown
|
|
STDMETHOD(QueryInterface)(REFIID riid, LPVOID * ppvObj);
|
|
STDMETHOD_(ULONG, AddRef)(void) { return CBaseObject::AddRef(); };
|
|
STDMETHOD_(ULONG, Release)(void) { return CBaseObject::Release(); };
|
|
|
|
public: //IQueueAdminAction
|
|
STDMETHOD(HrApplyQueueAdminFunction)(
|
|
IQueueAdminMessageFilter *pIQueueAdminMessageFilter);
|
|
|
|
STDMETHOD(HrApplyActionToMessage)(
|
|
IUnknown *pIUnknownMsg,
|
|
MESSAGE_ACTION ma,
|
|
PVOID pvContext,
|
|
BOOL *pfShouldDelete);
|
|
|
|
STDMETHOD_(BOOL, fMatchesID)
|
|
(QUEUELINK_ID *QueueLinkID);
|
|
|
|
STDMETHOD(QuerySupportedActions)(DWORD *pdwSupportedActions,
|
|
DWORD *pdwSupportedFilterFlags)
|
|
{
|
|
return QueryDefaultSupportedActions(pdwSupportedActions,
|
|
pdwSupportedFilterFlags);
|
|
};
|
|
|
|
public: //IQueueAdminLink
|
|
STDMETHOD(HrGetLinkInfo)(
|
|
LINK_INFO *pliLinkInfo,
|
|
HRESULT *phrLinkDiagnostic);
|
|
|
|
STDMETHOD(HrApplyActionToLink)(
|
|
LINK_ACTION la);
|
|
|
|
STDMETHOD(HrGetLinkID)(
|
|
QUEUELINK_ID *pLinkID);
|
|
|
|
STDMETHOD(HrGetNumQueues)(
|
|
DWORD *pcQueues);
|
|
|
|
STDMETHOD(HrGetQueueIDs)(
|
|
DWORD *pcQueues,
|
|
QUEUELINK_ID *rgQueues);
|
|
};
|
|
|
|
//---[ CLinkMsgQueue::paqschedGetScheduleID ]----------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Returns the schedule ID for this link
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// ScheduleID for this link
|
|
// History:
|
|
// 6/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CAQScheduleID *CLinkMsgQueue::paqschedGetScheduleID()
|
|
{
|
|
return (&m_aqsched);
|
|
}
|
|
|
|
//---[ CLinkMsgQueue::fIsSameScheduleID ]--------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Checks if a given schedule ID is the same as ours
|
|
// Parameters:
|
|
// paqsched - ScheduleID to check against
|
|
// Returns:
|
|
// TRUE if same schedule ID
|
|
// History:
|
|
// 6/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CLinkMsgQueue::fIsSameScheduleID(CAQScheduleID *paqsched)
|
|
{
|
|
return (m_aqsched.fIsEqual(paqsched));
|
|
}
|
|
|
|
//---[ CLinkMsgQueue::plmqIsSameScheduleID ]-----------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Gets the link if it matches the given schedule ID
|
|
// Parameters:
|
|
// paqsched - ScheduleID to check
|
|
// pli - list entry to get link for
|
|
// Returns:
|
|
// pointer to link if scheduleID matches..
|
|
// NULL otherwise
|
|
// History:
|
|
// 6/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CLinkMsgQueue *CLinkMsgQueue::plmqIsSameScheduleID(
|
|
CAQScheduleID *paqsched,
|
|
PLIST_ENTRY pli)
|
|
{
|
|
CLinkMsgQueue *plmq = CONTAINING_RECORD(pli, CLinkMsgQueue, m_liLinks);
|
|
_ASSERT(LINK_MSGQ_SIG == plmq->m_dwSignature);
|
|
|
|
if (!plmq->fIsSameScheduleID(paqsched))
|
|
plmq = NULL;
|
|
|
|
return plmq;
|
|
}
|
|
|
|
//---[ CLinkMsgQueue::plmqGetLinkMsgQueue ]------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Returns the LinkMsgQueue associated with the given list entry
|
|
// Parameters:
|
|
// pli - List entry to get Link for
|
|
// Returns:
|
|
// pointer to link for list entry
|
|
// History:
|
|
// 6/8/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CLinkMsgQueue *CLinkMsgQueue::plmqGetLinkMsgQueue(PLIST_ENTRY pli)
|
|
{
|
|
_ASSERT(LINK_MSGQ_SIG == (CONTAINING_RECORD(pli, CLinkMsgQueue, m_liLinks))->m_dwSignature);
|
|
return (CONTAINING_RECORD(pli, CLinkMsgQueue, m_liLinks));
|
|
}
|
|
|
|
//---[ CLinkMsgQueue::InsertLinkInList ]---------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Inserts link in given linked list
|
|
// Parameters:
|
|
// pliHead - Head of list to insert in
|
|
// Returns:
|
|
// -
|
|
// History:
|
|
// 6/9/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void CLinkMsgQueue::InsertLinkInList(PLIST_ENTRY pliHead)
|
|
{
|
|
_ASSERT(NULL == m_liLinks.Flink);
|
|
_ASSERT(NULL == m_liLinks.Blink);
|
|
InsertHeadList(pliHead, &m_liLinks);
|
|
};
|
|
|
|
//---[ CLinkMsgQueue::fRemoveLinkFromList ]-------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Remove link from link list
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// -
|
|
// History:
|
|
// 6/9/98 - MikeSwa Created
|
|
// 6/11/99 - MikeSwa Modified to allow multiple calls
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CLinkMsgQueue::fRemoveLinkFromList()
|
|
{
|
|
if (m_liLinks.Flink && m_liLinks.Blink)
|
|
{
|
|
RemoveEntryList(&m_liLinks);
|
|
m_liLinks.Flink = NULL;
|
|
m_liLinks.Blink = NULL;
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
};
|
|
|
|
//---[ CLinkMsgQueue::pliGetNextListEntry ]----------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Gets the pointer to the next list entry for this queue.
|
|
// Parameters:
|
|
// -
|
|
// Returns:
|
|
// The Flink of the queues LIST_ENTRY
|
|
// History:
|
|
// 6/16/98 - Created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
PLIST_ENTRY CLinkMsgQueue::pliGetNextListEntry()
|
|
{
|
|
return m_liLinks.Flink;
|
|
};
|
|
|
|
|
|
//---[ CLinkMsgQueue::fFlagsAllowConnection ]---------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Static helper function that examines if a given set of flags will
|
|
// allow a connection. Used by fCanSchedule and the linkstate debugger
|
|
// extension.
|
|
// Parameters:
|
|
// IN dwFlags Flags to check
|
|
// Returns:
|
|
// TRUE if a connection can be made, FALSE otherwise
|
|
// History:
|
|
// 9/30/98 - MikeSwa Created (separated out from fCanSchedule)
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CLinkMsgQueue::fFlagsAllowConnection(DWORD dwFlags)
|
|
{
|
|
//Logic :
|
|
// We make a connection for a link, if the admin has not specified an override and
|
|
// one of the following conditions is met
|
|
// -the force a connection NOW flag has been set
|
|
// -the command enable flag has been set
|
|
// -the ETRN or TURN enable flag has been set
|
|
// -the retry enable as well as the schedule enable flag has been set
|
|
// (and domain is not TURN only).
|
|
//
|
|
|
|
BOOL fRet = FALSE;
|
|
if (dwFlags & LINK_STATE_ADMIN_HALT)
|
|
fRet = FALSE;
|
|
else if (dwFlags & LINK_STATE_PRIV_NO_CONNECTION)
|
|
fRet = FALSE;
|
|
else if (dwFlags & LINK_STATE_PRIV_GENERATING_DSNS)
|
|
fRet = FALSE;
|
|
else if (dwFlags & LINK_STATE_ADMIN_FORCE_CONN)
|
|
fRet = TRUE;
|
|
else if (dwFlags & LINK_STATE_PRIV_CONFIG_TURN_ETRN)
|
|
{
|
|
//Obey retry flag... even for ETRN domains
|
|
if ((dwFlags & LINK_STATE_PRIV_ETRN_ENABLED) &&
|
|
(dwFlags & LINK_STATE_RETRY_ENABLED))
|
|
fRet = TRUE;
|
|
else
|
|
fRet = FALSE;
|
|
}
|
|
else if ((dwFlags & LINK_STATE_RETRY_ENABLED) &&
|
|
(dwFlags & LINK_STATE_SCHED_ENABLED))
|
|
fRet = TRUE;
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//---[ CLinkMsgQueue::fRPCCopyName ]--------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Used by Queue admin functions to copy the name of this link
|
|
// Parameters:
|
|
// IN pszLinkName UNICODE copy of name
|
|
// Returns:
|
|
// TRUE on success
|
|
// FALSE on failure
|
|
// History:
|
|
// 12/5/98 - MikeSwa Created
|
|
// 6/7/99 - MikeSwa Changed to UNICODE
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CLinkMsgQueue::fRPCCopyName(OUT LPWSTR *pwszLinkName)
|
|
{
|
|
_ASSERT(pwszLinkName);
|
|
|
|
if (!m_cbSMTPDomain || !m_szSMTPDomain)
|
|
return FALSE;
|
|
|
|
*pwszLinkName = wszQueueAdminConvertToUnicode(m_szSMTPDomain,
|
|
m_cbSMTPDomain);
|
|
if (!pwszLinkName)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
#endif // _LINKMSGQ_H_
|