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.
737 lines
17 KiB
737 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
servinfo.hxx
|
|
|
|
Abstract:
|
|
|
|
Contains the CServerInfo class declaration
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 02-Oct-1996
|
|
|
|
Notes:
|
|
|
|
In this implementation, we maintain a single host name per server
|
|
|
|
Revision History:
|
|
|
|
02-Oct-1996 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
//
|
|
// manifests
|
|
//
|
|
|
|
#define SERVER_INFO_SIGNATURE 'fIvS'
|
|
|
|
//
|
|
// values for PurgeKeepAlives dwForce parameter, method & function
|
|
//
|
|
|
|
#define PKA_NO_FORCE 0
|
|
#define PKA_NOW 1
|
|
#define PKA_AUTH_FAILED 2
|
|
|
|
//
|
|
// data (forward references)
|
|
//
|
|
|
|
extern const DWORD GlobalServerInfoTimeout;
|
|
|
|
//
|
|
// forward references
|
|
//
|
|
|
|
class CFsm_GetConnection;
|
|
class HTTP_REQUEST_HANDLE_OBJECT;
|
|
|
|
//
|
|
// classes
|
|
//
|
|
|
|
//
|
|
// CServerInfo - we maintain an aged list of CServerInfo's. These are used as a
|
|
// database of all useful information about a server
|
|
//
|
|
|
|
class CServerInfo {
|
|
|
|
private:
|
|
|
|
//
|
|
// m_ServerInfoList, m_List - CServerInfo's are kept in a list
|
|
//
|
|
|
|
LIST_ENTRY m_List;
|
|
|
|
SERIALIZED_LIST * m_ServerInfoList;
|
|
|
|
//
|
|
// m_Expires - system tick count at which this entry will expire
|
|
//
|
|
|
|
LONG m_Expires;
|
|
LONG m_Wrap;
|
|
|
|
//
|
|
// m_ReferenceCount - number of other structures referencing this
|
|
//
|
|
|
|
LONG m_ReferenceCount;
|
|
|
|
//
|
|
// m_HostName - primary host name of the server. Stored as LOWER CASE so
|
|
// that we don't have to perform case insensitive string comparisons each
|
|
// time
|
|
//
|
|
|
|
ICSTRING m_HostName;
|
|
|
|
//
|
|
// m_Hash - hash value of m_HostName. Check this value first
|
|
//
|
|
|
|
DWORD m_Hash;
|
|
|
|
//
|
|
// m_ProxyLink - if this is an origin server, we link to the proxy
|
|
// that may carry
|
|
//
|
|
|
|
CServerInfo * m_ProxyLink;
|
|
|
|
//
|
|
// m_dwProxyVersion - a copy of the Global Proxy Version Count,
|
|
// the proxy link goes bad if version count changes
|
|
//
|
|
|
|
DWORD m_dwProxyVersion;
|
|
|
|
//
|
|
// m_HostScheme - Not used for direct connections,
|
|
// only used for matching proxy info with cached information
|
|
//
|
|
|
|
INTERNET_SCHEME m_HostScheme;
|
|
|
|
//
|
|
// m_HostPort - can also be, proxy port for cached proxy server
|
|
//
|
|
|
|
INTERNET_PORT m_HostPort;
|
|
|
|
|
|
INTERNET_HANDLE_OBJECT * m_pInternet;
|
|
|
|
private:
|
|
|
|
//
|
|
// m_Services - bitmap of services supported by the server
|
|
//
|
|
|
|
union {
|
|
struct {
|
|
unsigned HTTP : 1; // HTTP server running at host
|
|
unsigned FTP : 1; // FTP " " " "
|
|
unsigned Gopher : 1; // gopher " " " "
|
|
unsigned GopherPlus : 1; // gopher+ " " " "
|
|
unsigned NNTP : 1; // news " " " " (future)
|
|
unsigned SMTP : 1; // mail " " " " (future)
|
|
unsigned CERN_Proxy : 1; // server is running CERN proxy
|
|
unsigned FTP_Proxy : 1; // server is running (TIS) FTP proxy/gateway
|
|
unsigned Socks_Proxy: 1; // server is a Socks Gateway
|
|
} Bits;
|
|
unsigned Word;
|
|
} m_Services;
|
|
|
|
//
|
|
// m_HttpSupport - bitmap of HTTP properties supported by the server, such
|
|
// as HTTP version, keep-alive, SSL/PCT, etc.
|
|
//
|
|
|
|
union {
|
|
struct {
|
|
unsigned KeepAlive : 1; // HTTP server supports keep-alive
|
|
unsigned Http1_0 : 1; // " " IS HTTP/1.0
|
|
unsigned Http1_1 : 1; // " " " HTTP/1.1
|
|
unsigned SSL : 1; // HTTP server supports SSL
|
|
unsigned PCT : 1; // HTTP server supports PCT
|
|
unsigned IIS : 1; // HTTP server is MS IIS (could be running others?)
|
|
unsigned BadNS : 1; // HTTP server is BAD NS Enterprise server
|
|
} Bits;
|
|
unsigned Word;
|
|
} m_HttpSupport;
|
|
|
|
//
|
|
// m_Flags - collection of boolean flags
|
|
//
|
|
|
|
union {
|
|
struct {
|
|
unsigned KA_Init : 1; // KeepAliveListInitialized
|
|
unsigned Unreachable: 1; // host (currently) unreachable
|
|
unsigned ProxyByPassSet: 1; // has the next bit been set.
|
|
unsigned ProxyByPassed: 1; // did we bypass the proxy talking to this server.
|
|
unsigned ProxyScriptCached: 1; // did/are we using this entry to cache the result of JS proxy resolution
|
|
} Bits;
|
|
unsigned Word;
|
|
} m_Flags;
|
|
|
|
//
|
|
// m_KeepAliveList - if the server supports keep-alive, a list of the
|
|
// keep-alive connections
|
|
//
|
|
|
|
SERIALIZED_LIST m_KeepAliveList;
|
|
|
|
//
|
|
// m_Waiters - list of sync/async waiters for connections
|
|
//
|
|
|
|
CPriorityList m_Waiters;
|
|
|
|
//
|
|
// CConnectionWaiter - private class identifying waiters in m_Waiters list
|
|
//
|
|
|
|
class CConnectionWaiter : public CPriorityListEntry {
|
|
|
|
private:
|
|
|
|
DWORD m_Sync : 1;
|
|
DWORD m_KeepAlive : 1;
|
|
DWORD_PTR m_dwId;
|
|
HANDLE m_hEvent;
|
|
|
|
public:
|
|
|
|
CConnectionWaiter(
|
|
IN CPriorityList *pList,
|
|
IN BOOL bSync,
|
|
IN BOOL bKeepAlive,
|
|
IN DWORD_PTR dwId,
|
|
IN HANDLE hEvent,
|
|
IN LONG lPriority,
|
|
OUT LPDWORD lpdwStatus) : CPriorityListEntry(lPriority) {
|
|
|
|
m_Sync = bSync ? 1 : 0;
|
|
m_KeepAlive = bKeepAlive ? 1 : 0;
|
|
m_dwId = dwId;
|
|
m_hEvent = hEvent;
|
|
*lpdwStatus = pList->Insert(this);
|
|
}
|
|
|
|
~CConnectionWaiter() {
|
|
}
|
|
|
|
BOOL IsSync(VOID) {
|
|
return (m_Sync == 1) ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL IsKeepAlive(VOID) {
|
|
return (m_KeepAlive == 1) ? TRUE : FALSE;
|
|
}
|
|
|
|
DWORD_PTR Id(VOID) {
|
|
return m_dwId;
|
|
}
|
|
|
|
VOID Signal(VOID) {
|
|
SetEvent(m_hEvent);
|
|
}
|
|
};
|
|
|
|
//
|
|
// m_ConnectionLimit - number of simultaneous connections allowed to this
|
|
// server
|
|
//
|
|
|
|
LONG m_ConnectionLimit;
|
|
|
|
//
|
|
// m_NewLimit - set when we need to change limit
|
|
//
|
|
|
|
LONG m_NewLimit;
|
|
|
|
//
|
|
// m_ConnectionsAvailable - number of connections available to this server.
|
|
// If <= 0 (and not unlimited connections) then we have to wait until a
|
|
// connection is freed
|
|
//
|
|
|
|
LONG m_ConnectionsAvailable;
|
|
|
|
//
|
|
// m_ActiveConnections - number of connections that are active. An active
|
|
// connection is connected and sending or receiving data. This value can be
|
|
// greater than m_ConnectionLimit if we are in the situation of being run
|
|
// out of connections
|
|
//
|
|
|
|
//LONG m_ActiveConnections;
|
|
|
|
//
|
|
// m_LastActiveTime - timestamp (tick count) of last operation was made on
|
|
// any connection to this server
|
|
//
|
|
|
|
DWORD m_LastActiveTime;
|
|
|
|
//
|
|
// m_ConnectTime - the average time to connect in milliseconds
|
|
//
|
|
|
|
DWORD m_ConnectTime;
|
|
|
|
//
|
|
// m_RTT - average Round Trip Time
|
|
//
|
|
|
|
DWORD m_RTT;
|
|
|
|
//
|
|
// m_AddressList - list of resolved addresses for this server
|
|
//
|
|
|
|
CAddressList m_AddressList;
|
|
|
|
//
|
|
// m_dwError - error code (mainly for constructor)
|
|
//
|
|
|
|
DWORD m_dwError;
|
|
|
|
#if INET_DEBUG
|
|
|
|
DWORD m_Signature;
|
|
|
|
#define INIT_SERVER_INFO() m_Signature = SERVER_INFO_SIGNATURE
|
|
#define CHECK_SERVER_INFO() INET_ASSERT(m_Signature == SERVER_INFO_SIGNATURE)
|
|
|
|
#else
|
|
|
|
#define INIT_SERVER_INFO() /* NOTHING */
|
|
#define CHECK_SERVER_INFO() /* NOTHING */
|
|
|
|
#endif
|
|
|
|
//
|
|
// private methods
|
|
//
|
|
|
|
ICSocket *
|
|
FindKeepAliveConnection(
|
|
IN DWORD dwSocketFlags,
|
|
IN INTERNET_PORT nPort,
|
|
IN LPSTR pszTunnelServer
|
|
);
|
|
|
|
BOOL
|
|
KeepAliveWaiters(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
RunOutOfConnections(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
UpdateConnectionLimit(
|
|
VOID
|
|
);
|
|
|
|
public:
|
|
|
|
CServerInfo(
|
|
IN SERIALIZED_LIST * ServerInfoList,
|
|
IN LPSTR lpszHostName,
|
|
OUT DWORD* pdwError,
|
|
IN DWORD dwService = INTERNET_SERVICE_HTTP,
|
|
IN DWORD dwMaxConnections = WINHTTP_CONNS_PER_SERVER_UNLIMITED
|
|
);
|
|
|
|
~CServerInfo();
|
|
|
|
CServerInfo * Next(VOID) {
|
|
return (CServerInfo *)m_List.Flink;
|
|
}
|
|
|
|
CServerInfo * Prev(VOID) {
|
|
return (CServerInfo *)m_List.Blink;
|
|
}
|
|
|
|
// This code needs to handle system time roll over.
|
|
// SetExpiryTime is passed the duration, and we calculate the ultimate time
|
|
// However, this may result in a rollover -- e.g. if the current time is
|
|
// 0xffffff00, the ultimate time could be 0x000000fd
|
|
|
|
// Expired is passed the current tick count, however, and in the past
|
|
// would return TRUE immediately.
|
|
// Thus we set a flag is we need to wait for system time rollover to happen,
|
|
|
|
VOID SetExpiryTime(DWORD dwMilliseconds = GlobalServerInfoTimeout) {
|
|
DWORD dw = GetTickCountWrap();
|
|
m_Expires = dw + dwMilliseconds;
|
|
m_Wrap = (dw > (DWORD)m_Expires);
|
|
}
|
|
|
|
VOID ResetExpiryTime(VOID) {
|
|
m_Expires = 0;
|
|
m_Wrap = 0;
|
|
}
|
|
|
|
BOOL Expired(LONG dwTime = (LONG)GetTickCountWrap()) {
|
|
if (m_Wrap)
|
|
{
|
|
m_Wrap = ((LONG)dwTime < 0);
|
|
}
|
|
return (!m_Wrap && (dwTime > m_Expires)) ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID
|
|
Reference(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
Dereference(
|
|
VOID
|
|
);
|
|
|
|
LONG ReferenceCount(VOID) const {
|
|
return m_ReferenceCount;
|
|
}
|
|
|
|
LPSTR GetHostName(VOID) const {
|
|
return m_HostName.StringAddress();
|
|
}
|
|
|
|
DWORD
|
|
SetCachedProxyServerInfo(
|
|
IN CServerInfo * pProxyServer,
|
|
IN DWORD dwProxyVersion,
|
|
IN BOOL fUseProxy,
|
|
IN INTERNET_SCHEME HostScheme,
|
|
IN INTERNET_PORT HostPort,
|
|
IN INTERNET_SCHEME ProxyScheme,
|
|
IN INTERNET_PORT ProxyPort
|
|
);
|
|
|
|
CServerInfo *
|
|
GetCachedProxyServerInfo(
|
|
IN INTERNET_SCHEME HostScheme,
|
|
IN INTERNET_PORT HostPort,
|
|
OUT BOOL *pfCachedEntry
|
|
);
|
|
|
|
BOOL
|
|
CopyCachedProxyInfoToProxyMsg(
|
|
IN OUT AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo
|
|
);
|
|
|
|
BOOL Match(IN DWORD dwHash, IN LPSTR lpszHostName) {
|
|
return (dwHash == m_Hash) ? m_HostName.Strcmp(lpszHostName) : FALSE;
|
|
}
|
|
|
|
VOID SetHTTP(VOID) {
|
|
m_Services.Bits.HTTP = 1;
|
|
}
|
|
|
|
BOOL IsHTTP(VOID) {
|
|
return m_Services.Bits.HTTP ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetFTP(VOID) {
|
|
m_Services.Bits.FTP = 1;
|
|
}
|
|
|
|
BOOL IsFTP(VOID) {
|
|
return m_Services.Bits.FTP ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetGopher(VOID) {
|
|
m_Services.Bits.Gopher = 1;
|
|
}
|
|
|
|
BOOL IsGopher(VOID) {
|
|
return m_Services.Bits.Gopher ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetSocksGateway(VOID) {
|
|
m_Services.Bits.Socks_Proxy = 1;
|
|
}
|
|
|
|
BOOL IsSocksGateway(VOID) {
|
|
return m_Services.Bits.Socks_Proxy ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetCernProxy(VOID) {
|
|
m_Services.Bits.CERN_Proxy = 1;
|
|
}
|
|
|
|
VOID SetFTPProxy(VOID) {
|
|
m_Services.Bits.FTP_Proxy = 1;
|
|
}
|
|
|
|
BOOL IsCernProxy(VOID) {
|
|
return m_Services.Bits.CERN_Proxy ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetHttp1_1(VOID) {
|
|
m_HttpSupport.Bits.Http1_1 = 1;
|
|
}
|
|
|
|
BOOL IsHttp1_1(VOID) {
|
|
return m_HttpSupport.Bits.Http1_1 ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetHttp1_0(VOID) {
|
|
m_HttpSupport.Bits.Http1_0 = 1;
|
|
}
|
|
|
|
VOID SetBadNSServer(VOID) {
|
|
m_HttpSupport.Bits.BadNS = 1;
|
|
}
|
|
|
|
BOOL IsBadNSServer(VOID) {
|
|
return m_HttpSupport.Bits.BadNS ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL IsHttp1_0(VOID) {
|
|
return m_HttpSupport.Bits.Http1_0 ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetKeepAlive(VOID) {
|
|
m_HttpSupport.Bits.KeepAlive = 1;
|
|
}
|
|
|
|
BOOL IsKeepAlive(VOID) {
|
|
return m_HttpSupport.Bits.KeepAlive ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetProxyScriptCached(BOOL fSetCached) {
|
|
m_Flags.Bits.ProxyScriptCached = (fSetCached) ? 1 : 0;
|
|
}
|
|
|
|
BOOL IsProxyScriptCached(VOID) {
|
|
return m_Flags.Bits.ProxyScriptCached ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
VOID SetKeepAliveListInitialized(VOID) {
|
|
m_Flags.Bits.KA_Init = 1;
|
|
}
|
|
|
|
BOOL IsKeepAliveListInitialized(VOID) {
|
|
return m_Flags.Bits.KA_Init ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID SetUnreachable(VOID) {
|
|
m_Flags.Bits.Unreachable = 1;
|
|
}
|
|
|
|
VOID SetReachable(VOID) {
|
|
m_Flags.Bits.Unreachable = 0;
|
|
}
|
|
|
|
BOOL IsUnreachable(VOID) {
|
|
return m_Flags.Bits.Unreachable ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
VOID SetProxyByPassed(BOOL fProxyByPassed) {
|
|
m_Flags.Bits.ProxyByPassed = fProxyByPassed ? TRUE: FALSE;
|
|
m_Flags.Bits.ProxyByPassSet = TRUE;
|
|
}
|
|
|
|
BOOL IsProxyByPassSet(VOID)
|
|
{
|
|
return m_Flags.Bits.ProxyByPassSet ? TRUE : FALSE;
|
|
}
|
|
|
|
BOOL WasProxyByPassed(VOID) {
|
|
return m_Flags.Bits.ProxyByPassed ? TRUE : FALSE;
|
|
}
|
|
|
|
LONG ConnectionLimit(VOID) const {
|
|
return m_ConnectionLimit;
|
|
}
|
|
|
|
VOID SetConnectionLimit(LONG Limit) {
|
|
m_ConnectionLimit = Limit;
|
|
}
|
|
|
|
BOOL UnlimitedConnections(VOID) {
|
|
return (ConnectionLimit() == WINHTTP_CONNS_PER_SERVER_UNLIMITED) ? TRUE : FALSE;
|
|
}
|
|
|
|
LONG KeepAliveConnections(VOID) {
|
|
return ElementsOnSerializedList(&m_KeepAliveList);
|
|
}
|
|
|
|
LONG AvailableConnections(VOID) const {
|
|
return m_ConnectionsAvailable;
|
|
}
|
|
|
|
LONG TotalAvailableConnections(VOID) {
|
|
return KeepAliveConnections() + AvailableConnections();
|
|
}
|
|
|
|
LONG GetNewLimit(VOID) const {
|
|
return m_NewLimit;
|
|
}
|
|
|
|
VOID SetNewLimit(LONG Limit) {
|
|
m_NewLimit = Limit;
|
|
}
|
|
|
|
BOOL IsNewLimit(VOID) {
|
|
return (m_ConnectionLimit != m_NewLimit) ? TRUE : FALSE;
|
|
}
|
|
|
|
VOID
|
|
UpdateConnectTime(
|
|
IN DWORD dwConnectTime
|
|
);
|
|
|
|
DWORD GetConnectTime(VOID) const {
|
|
return (m_ConnectTime == (DWORD)-1) ? 0 : m_ConnectTime;
|
|
}
|
|
|
|
VOID
|
|
UpdateRTT(
|
|
IN DWORD dwTime
|
|
);
|
|
|
|
DWORD GetRTT(VOID) const {
|
|
return m_RTT;
|
|
}
|
|
|
|
DWORD
|
|
GetConnection_Fsm(
|
|
IN CFsm_GetConnection * Fsm
|
|
);
|
|
|
|
DWORD
|
|
ReleaseConnection(
|
|
IN ICSocket * lpSocket OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
RemoveWaiter(
|
|
IN DWORD_PTR dwId
|
|
);
|
|
|
|
VOID
|
|
PurgeKeepAlives(
|
|
IN DWORD dwForce = PKA_NO_FORCE
|
|
);
|
|
|
|
BOOL
|
|
GetNextAddress(
|
|
IN OUT LPDWORD lpdwResolutionId,
|
|
IN OUT LPDWORD lpdwIndex,
|
|
IN INTERNET_PORT nPort,
|
|
OUT LPCSADDR_INFO lpAddress
|
|
) {
|
|
return m_AddressList.GetNextAddress(lpdwResolutionId,
|
|
lpdwIndex,
|
|
nPort,
|
|
lpAddress
|
|
);
|
|
}
|
|
|
|
VOID
|
|
InvalidateAddress(
|
|
IN DWORD dwResolutionId,
|
|
IN DWORD dwAddressIndex
|
|
) {
|
|
m_AddressList.InvalidateAddress(dwResolutionId, dwAddressIndex);
|
|
}
|
|
|
|
DWORD
|
|
ResolveHost(
|
|
IN OUT LPDWORD lpdwResolutionId,
|
|
IN DWORD dwFlags
|
|
) {
|
|
return m_AddressList.ResolveHost(GetHostName(),
|
|
lpdwResolutionId,
|
|
dwFlags
|
|
);
|
|
}
|
|
|
|
DWORD GetError(VOID) const {
|
|
return m_dwError;
|
|
}
|
|
|
|
VOID SetError(DWORD dwError = GetLastError()) {
|
|
m_dwError = dwError;
|
|
}
|
|
|
|
//
|
|
// connection activity methods
|
|
//
|
|
|
|
VOID SetLastActiveTime(VOID) {
|
|
m_LastActiveTime = GetTickCountWrap();
|
|
}
|
|
|
|
VOID ResetLastActiveTime(VOID) {
|
|
m_LastActiveTime = 0;
|
|
}
|
|
|
|
DWORD GetLastActiveTime(VOID) const {
|
|
return m_LastActiveTime;
|
|
}
|
|
|
|
BOOL ConnectionActivity(VOID) {
|
|
|
|
DWORD lastActiveTime = GetLastActiveTime();
|
|
|
|
return (lastActiveTime != 0)
|
|
? (((GetTickCountWrap() - lastActiveTime)
|
|
<= GlobalConnectionInactiveTimeout) ? TRUE : FALSE)
|
|
: FALSE;
|
|
}
|
|
|
|
BOOL AllConnectionsInactive(VOID) {
|
|
//return ((ActiveConnectionCount() >= ConnectionLimit())
|
|
// && !ConnectionActivity())
|
|
// ? TRUE
|
|
// : FALSE;
|
|
return !ConnectionActivity();
|
|
}
|
|
|
|
//
|
|
// friend functions
|
|
//
|
|
|
|
friend
|
|
CServerInfo *
|
|
ContainingServerInfo(
|
|
IN LPVOID lpAddress
|
|
);
|
|
};
|
|
|
|
//
|
|
// prototypes
|
|
//
|
|
|
|
VOID
|
|
ReleaseServerInfo(
|
|
IN CServerInfo * lpServerInfo
|
|
);
|
|
|
|
CServerInfo *
|
|
ContainingServerInfo(
|
|
IN LPVOID lpAddress
|
|
);
|