242 lines
8.7 KiB
C++
242 lines
8.7 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
Protocol.hxx
|
|
|
|
Abstract:
|
|
|
|
The Protocol object definitions
|
|
|
|
Author:
|
|
|
|
Kamen Moutafov [KamenM]
|
|
|
|
Revision History:
|
|
|
|
KamenM 12/22/1998 Creation
|
|
|
|
--*/
|
|
|
|
#if _MSC_VER >= 1200
|
|
#pragma once
|
|
#endif
|
|
|
|
#ifndef __PROTOCOL_HXX_
|
|
#define __PROTOCOL_HXX_
|
|
|
|
// uncomment this to turn on PNP debug spew
|
|
//#define MAJOR_PNP_DEBUG
|
|
|
|
enum TransportProtocolStates
|
|
{
|
|
ProtocolNotLoaded,
|
|
ProtocolLoadedWithoutAddress,
|
|
ProtocolWasLoadedOrNeedsActivation,
|
|
ProtocolLoaded,
|
|
ProtocolWasLoadedOrNeedsActivationWithoutAddress,
|
|
ProtocolLoadedAndMonitored
|
|
};
|
|
|
|
struct BASE_ASYNC_OBJECT; // forwards
|
|
extern RPC_ADDRESS_CHANGE_FN * AddressChangeFn;
|
|
void RPC_ENTRY NullAddressChangeFn( PVOID arg );
|
|
|
|
class TransportProtocol
|
|
/*
|
|
This object encapsulates a protocol on the transport level. Used primarily for PnP support.
|
|
*/
|
|
{
|
|
public:
|
|
TransportProtocol(void)
|
|
{
|
|
State = ProtocolNotLoaded;
|
|
RpcpInitializeListHead(&ObjectList);
|
|
addressChangeSocket = 0;
|
|
// provide arbitrary non-zero code, to indicate that this query has not succeeded
|
|
addressChangeOverlapped.Internal = (ULONG_PTR)-1;
|
|
}
|
|
|
|
// If a piece of code detects that a protocol is functional through means other
|
|
// than PnP, it may call this function to notify the PnP code that the protocol is functional
|
|
// The only effect will be speedier processing of a potential PnP notification
|
|
void DetectedAsFunctional(PROTOCOL_ID ProtocolId);
|
|
|
|
// Whenever a PnP notification arrives, this method needs to be called for each protocol.
|
|
// The method is idempotent - it saves the previous state and will no-op redundant calls
|
|
// However, this method should not be called before the runtime is ready to accept
|
|
// calls on transport addresses
|
|
void HandleProtocolChange(IN WSAPROTOCOL_INFO *lpProtocolBuffer, IN int ProtocolCount,
|
|
IN PROTOCOL_ID thisProtocolId);
|
|
|
|
// Adds an object to the list of objects for this protocol. The list is used to track down
|
|
// all instances of objects belonging to this protocol when a PnP notification arrives.
|
|
void AddObjectToList(IN OUT BASE_ASYNC_OBJECT *pObj);
|
|
|
|
// Removes an object from the list of objects on this protocol
|
|
void RemoveObjectFromList(IN OUT BASE_ASYNC_OBJECT *pObj);
|
|
|
|
// If a NewAddress query fails asynchronously, this function needs to be called which will
|
|
// retry submitting all failed query for this protocol. For non-failed, or non-submitted queries,
|
|
// this is a no-op
|
|
BOOL ResubmitQueriesIfNecessary(PROTOCOL_ID ProtocolId);
|
|
|
|
// Handle a PnP notification. Does all necessary processing
|
|
static BOOL HandlePnPStateChange(void);
|
|
|
|
// Calls ResubmitQueriesIfNecessary(PROTOCOL_ID ProtocolId) on all protocols.
|
|
static BOOL ResubmitQueriesIfNecessary(void);
|
|
|
|
// Same as the non-static FunctionalProtocolDetected, except that this one operates
|
|
// without this pointer - it will retrieve the appropriate object and will call
|
|
// FunctionalProtocolDetected on it.
|
|
static void FunctionalProtocolDetected(PROTOCOL_ID ProtocolId);
|
|
|
|
// Same as AddObjectToList except that it will call AddObjectToList on the appropriate
|
|
// protocol
|
|
static void AddObjectToProtocolList(IN OUT BASE_ASYNC_OBJECT *pObj);
|
|
|
|
// Same as RemoveObjectFromList except that it will call RemoveObjectFromList on the appropriate
|
|
// protocol
|
|
static void RemoveObjectFromProtocolList(IN OUT BASE_ASYNC_OBJECT *pObj);
|
|
|
|
#if defined(DBG) || defined(_DEBUG)
|
|
// will ASSERT that all protocols are in a consistent state
|
|
static void AssertTransportProtocolState(void);
|
|
|
|
// will ASSSERT that this protocol is in a consistent state
|
|
void AssertState(PROTOCOL_ID ProtocolId);
|
|
|
|
#endif
|
|
|
|
private:
|
|
// attempts to verify that a protocol is functional, and if found so, advances the state of
|
|
// the protocol
|
|
BOOL VerifyProtocolIsFunctional(PROTOCOL_ID ProtocolId);
|
|
|
|
// checks whether the given protocol has an address
|
|
BOOL DoesAddressSocketHaveAddress(void);
|
|
|
|
// If there is a pending address change request (WSAIoctl), it cancels it
|
|
// if fForceCancel is FALSE, monitored protocols don't have their
|
|
// address change requests canceled. If fForceCancel is TRUE,
|
|
// all protocols get their address change requests cancelled
|
|
void CancelAddressChangeRequestIfNecessary(IN BOOL fForceCancel, IN PROTOCOL_ID ProtocolId);
|
|
|
|
// Restarts a protocol that was unloaded. Currently not used.
|
|
void RestartProtocol(PROTOCOL_ID ProtocolId);
|
|
|
|
// Unloads a protocol that was loaded.
|
|
void UnloadProtocol(PROTOCOL_ID ProtocolId);
|
|
|
|
// Submits an address change query (WSAIoctl)
|
|
BOOL SubmitAddressChangeQuery(void);
|
|
|
|
// Sets the state of the given protocol. Other code should never directly set the State - it should
|
|
// always go through this function. This allows for derivative protocols (like HTTP) to mirror
|
|
// the state of their base protocols - TCP
|
|
void SetState(TransportProtocolStates newState, PROTOCOL_ID ProtocolId);
|
|
|
|
// will return whether address change monitoring is required for this protocol. Currently this
|
|
// is used only by RPCSS for SPX (in order to start sending updated SAP broadcasts)
|
|
BOOL IsAddressChangeMonitoringOn(PROTOCOL_ID ProtocolId)
|
|
{
|
|
// if this is TCP & SPX, and somebody actually cares about this (i.e. somebody has
|
|
// registered a notification callback), then turn on address monitoring
|
|
return (
|
|
(
|
|
#ifdef SPX_ON
|
|
(ProtocolId == SPX)
|
|
||
|
|
#endif
|
|
(ProtocolId == TCP)
|
|
)
|
|
&&
|
|
(AddressChangeFn != NullAddressChangeFn)
|
|
&&
|
|
(AddressChangeFn != NULL)
|
|
);
|
|
}
|
|
|
|
// Trailing protocols are protocols that don't have their own independent transport provider
|
|
// They use the transport provider of another protocol, but for some reason we present it
|
|
// to the upper layers as different protocols. We call them trailing, because their
|
|
// state trails the state of the protocol whose transport they use.
|
|
// Currently we have only one of those - HTTP which trails TCP
|
|
BOOL IsTrailingProtocol(PROTOCOL_ID ProtocolId)
|
|
{
|
|
return (ProtocolId == HTTP);
|
|
}
|
|
|
|
void SetStateToLoadedAndMonitorProtocolIfNecessary(PROTOCOL_ID ProtocolId);
|
|
|
|
// checks if there is an address change request pending, and if there isn't
|
|
// submits one. Will also open an address change socket if necessary
|
|
BOOL MonitorFunctionalProtocolForAddressChange(PROTOCOL_ID ProtocolId);
|
|
|
|
// checks if these's an address change request socket, and if there
|
|
// isn't it opens one
|
|
BOOL OpenAddressChangeRequestSocket(PROTOCOL_ID ProtocolId);
|
|
|
|
// if ThisProtocolsId is in ProtocolLoadedAndMonitored or ProtocolLoaded state
|
|
// move the Mirrored protocol to the corresponding state
|
|
void
|
|
MirrorProtocolState (
|
|
IN PROTOCOL_ID MirrorProtocolId
|
|
);
|
|
|
|
#ifdef MAJOR_PNP_DEBUG
|
|
// Dumps the protocol state on the debugger for the current protocol
|
|
void DumpProtocolState(PROTOCOL_ID ProtocolId);
|
|
// Dumps the protocol state on the debugger for all protocols
|
|
static void DumpProtocolState(void);
|
|
#endif
|
|
|
|
// the current state of this protocol
|
|
TransportProtocolStates State;
|
|
|
|
// the list of opened objects for this protocol
|
|
LIST_ENTRY ObjectList;
|
|
|
|
// iff there's address change request submitted on this socket, it will be non-null
|
|
SOCKET addressChangeSocket;
|
|
|
|
// the OVERLAPPED for the address change request (WSAIoctl). It's Internal member will be -1
|
|
// if no request has been submitted. Other data members are as normal.
|
|
OVERLAPPED addressChangeOverlapped;
|
|
|
|
// NOTE: A TransportProtocol object is not aware of its PROTOCOL_ID - it must be
|
|
// passed externally to it for all methods that require it. This is done to save memory.
|
|
};
|
|
|
|
extern TransportProtocol *TransportProtocolArray;
|
|
|
|
// returns the TransportProtocol object for the ProtocolId. Ownership of the object does not pass
|
|
// to the caller
|
|
inline TransportProtocol *GetTransportProtocol(IN PROTOCOL_ID ProtocolId)
|
|
{
|
|
ASSERT(ProtocolId >= 1);
|
|
ASSERT(ProtocolId < MAX_PROTOCOLS);
|
|
|
|
return &TransportProtocolArray[ProtocolId];
|
|
}
|
|
|
|
inline void TransportProtocol::FunctionalProtocolDetected(PROTOCOL_ID ProtocolId)
|
|
{
|
|
GetTransportProtocol(ProtocolId)->DetectedAsFunctional(ProtocolId);
|
|
}
|
|
|
|
RPC_STATUS InitTransportProtocols(void);
|
|
|
|
#if defined(DBG) || defined(_DEBUG)
|
|
#define ASSERT_ALL_TRANSPORT_PROTOCOL_STATE() TransportProtocol::AssertTransportProtocolState()
|
|
#define ASSERT_TRANSPORT_PROTOCOL_STATE(p) AssertState(p)
|
|
#else
|
|
#define ASSERT_ALL_TRANSPORT_PROTOCOL_STATE()
|
|
#define ASSERT_TRANSPORT_PROTOCOL_STATE(p)
|
|
#endif
|
|
|
|
#endif
|