Leaked source code of windows server 2003
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.
 
 
 
 
 
 

846 lines
19 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'
#define UNLIMITED_CONNECTIONS 0xffffffff
//
// 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 SERIALIZED_LIST GlobalServerInfoList;
extern 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_List - CServerInfo's are kept in a list
//
LIST_ENTRY m_List;
//
// 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;
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_PipelinedList - list of HTTP 1.1 pipelined connections
//
SERIALIZED_LIST m_PipelinedList;
//
// 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) : CPriorityListEntry(lPriority) {
m_Sync = bSync ? 1 : 0;
m_KeepAlive = bKeepAlive ? 1 : 0;
m_dwId = dwId;
m_hEvent = hEvent;
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_DownloadRate - the average download rate in bytes per second
//
DWORD m_DownloadRate;
//
// m_UploadRate - the average upload rate in bytes per second. Will be
// different from m_DownloadRate if using ADSL e.g.
//
DWORD m_UploadRate;
//
// 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 LPSTR lpszHostName,
OUT LPDWORD pdwError,
IN DWORD dwService = INTERNET_SERVICE_HTTP,
IN DWORD dwMaxConnections = GlobalMaxConnectionsPerServer
);
~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() == UNLIMITED_CONNECTIONS) ? 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;
}
VOID
UpdateDownloadRate(
IN DWORD dwBytesPerSecond
);
DWORD GetDownloadRate(VOID) const {
return m_DownloadRate;
}
VOID
UpdateUploadRate(
IN DWORD dwBytesPerSecond
);
DWORD GetUploadRate(VOID) const {
return m_UploadRate;
}
//DWORD
//GetConnection(
// IN DWORD dwSocketFlags,
// IN INTERNET_PORT nPort,
// IN DWORD dwTimeout,
// OUT ICSocket * * lplpSocket
// );
DWORD
GetConnection_Fsm(
IN CFsm_GetConnection * Fsm
);
DWORD
ReleaseConnection(
IN ICSocket * lpSocket OPTIONAL,
IN BOOL fExemptConnLimit
);
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 AddActiveConnection(VOID) {
// LockSerializedList(&m_Waiters);
//
// INET_ASSERT(m_ActiveConnections >= 0);
//
// ++m_ActiveConnections;
// UnlockSerializedList(&m_Waiters);
//}
//
//VOID RemoveActiveConnection(VOID) {
// LockSerializedList(&m_Waiters);
// --m_ActiveConnections;
//
// INET_ASSERT(m_ActiveConnections >= 0);
//
// UnlockSerializedList(&m_Waiters);
//}
//
//LONG ActiveConnectionCount(VOID) const {
//
// INET_ASSERT(m_ActiveConnections >= 0);
//
// return m_ActiveConnections;
//}
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
//
DWORD
GetServerInfo(
IN LPSTR lpszHostName,
IN DWORD dwServiceType,
IN BOOL bDoResolution,
OUT CServerInfo * * lplpServerInfo
);
CServerInfo *
FindServerInfo(
IN LPSTR lpszHostName
);
CServerInfo *
FindNearestServer(
VOID
);
VOID
ReleaseServerInfo(
IN CServerInfo * lpServerInfo
);
VOID
PurgeServerInfoList(
IN BOOL bForce
);
VOID
PurgeKeepAlives(
IN DWORD dwForce = PKA_NO_FORCE
);
DWORD
PingServerInfoList(
OUT LPBOOL lpbUnreachable
);
DWORD
LoadServerInfoDatabase(
VOID
);
DWORD
SaveServerInfoDatabase(
VOID
);
CServerInfo *
ContainingServerInfo(
IN LPVOID lpAddress
);