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.
 
 
 
 
 
 

2988 lines
62 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
fsm.hxx
Abstract:
Contains Finite State Machine class definition
Author:
Richard L Firth (rfirth) 11-Apr-1997
Revision History:
11-Apr-1997 rfirth
Created
--*/
//
// types
//
//
// FSM_STATE - states FSMs can be in. We have some states defined for all FSMs,
// e.g. FSM_STATE_INIT, and other states that are used internally by the FSMs,
// e.g. FSM_STATE_1 through FSM_STATE_10
//
typedef enum {
FSM_STATE_BAD = -1,
FSM_STATE_INIT,
FSM_STATE_WAIT,
FSM_STATE_DONE,
FSM_STATE_ERROR,
FSM_STATE_CONTINUE,
FSM_STATE_FINISH,
FSM_STATE_1,
FSM_STATE_2,
FSM_STATE_3,
FSM_STATE_4,
FSM_STATE_5,
FSM_STATE_6,
FSM_STATE_7,
FSM_STATE_8,
FSM_STATE_9,
FSM_STATE_10
} FSM_STATE;
//
// FSM_HINT - QUICK if next operation is expected to complete quickly
//
typedef enum {
FSM_HINT_SLOW, // default
FSM_HINT_QUICK
} FSM_HINT;
//
// FSM_ACTION - type of (socket) action an FSM is waiting on
//
typedef enum {
FSM_ACTION_NONE = 0,
FSM_ACTION_CONNECT = 1,
FSM_ACTION_SEND,
FSM_ACTION_RECEIVE
} FSM_ACTION;
//
// FSM_TYPE - for debugging purposes
//
typedef enum {
FSM_TYPE_NONE,
FSM_TYPE_WAIT_FOR_COMPLETION,
FSM_TYPE_RESOLVE_HOST,
FSM_TYPE_SOCKET_CONNECT,
FSM_TYPE_SOCKET_SEND,
FSM_TYPE_SOCKET_RECEIVE,
FSM_TYPE_SOCKET_QUERY_AVAILABLE,
FSM_TYPE_SECURE_CONNECT,
FSM_TYPE_SECURE_HANDSHAKE,
FSM_TYPE_SECURE_NEGOTIATE,
FSM_TYPE_NEGOTIATE_LOOP,
FSM_TYPE_SECURE_SEND,
FSM_TYPE_SECURE_RECEIVE,
FSM_TYPE_GET_CONNECTION,
FSM_TYPE_HTTP_SEND_REQUEST,
FSM_TYPE_MAKE_CONNECTION,
FSM_TYPE_OPEN_CONNECTION,
FSM_TYPE_OPEN_PROXY_TUNNEL,
FSM_TYPE_SEND_REQUEST,
FSM_TYPE_RECEIVE_RESPONSE,
FSM_TYPE_HTTP_READ,
FSM_TYPE_HTTP_WRITE,
FSM_TYPE_READ_DATA,
FSM_TYPE_HTTP_QUERY_AVAILABLE,
FSM_TYPE_DRAIN_RESPONSE,
FSM_TYPE_REDIRECT,
FSM_TYPE_READ_LOOP,
FSM_TYPE_PARSE_HTTP_URL,
FSM_TYPE_PARSE_URL_FOR_HTTP,
FSM_TYPE_READ_FILE,
FSM_TYPE_READ_FILE_EX,
FSM_TYPE_WRITE_FILE,
FSM_TYPE_QUERY_DATA_AVAILABLE,
FSM_TYPE_FTP_CONNECT,
FSM_TYPE_FTP_FIND_FIRST_FILE,
FSM_TYPE_FTP_GET_FILE,
FSM_TYPE_FTP_PUT_FILE,
FSM_TYPE_FTP_DELETE_FILE,
FSM_TYPE_FTP_RENAME_FILE,
FSM_TYPE_FTP_GET_FILE_SIZE,
FSM_TYPE_FTP_OPEN_FILE,
FSM_TYPE_FTP_COMMAND,
FSM_TYPE_FTP_CREATE_DIRECTORY,
FSM_TYPE_FTP_REMOVE_DIRECTORY,
FSM_TYPE_FTP_SET_CURRENT_DIRECTORY,
FSM_TYPE_FTP_GET_CURRENT_DIRECTORY,
FSM_TYPE_GOPHER_FIND_FIRST_FILE,
FSM_TYPE_GOPHER_OPEN_FILE,
FSM_TYPE_GOPHER_GET_ATTRIBUTE,
FSM_TYPE_INTERNET_PARSE_URL,
FSM_TYPE_INTERNET_FIND_NEXT_FILE,
FSM_TYPE_INTERNET_QUERY_DATA_AVAILABLE,
FSM_TYPE_INTERNET_WRITE_FILE,
FSM_TYPE_INTERNET_READ_FILE,
FSM_TYPE_BACKGROUND_TASK
} FSM_TYPE;
//
// API_TYPE - what type of parameter API returns. Used in conjunction with
// SetApi()
//
typedef enum {
ApiType_None,
ApiType_Handle,
ApiType_Bool
} API_TYPE;
//
// macros
//
#define COPY_MANDATORY_PARAM(y,x) \
if (x) { \
y = NewString(x); \
if ( y == NULL) { \
SetError(ERROR_NOT_ENOUGH_MEMORY); \
} \
} \
else { \
y = NULL; \
INET_ASSERT(FALSE); \
}
#define COPY_MANDATORY_PARAMW(y,x) \
if (x) { \
y = NewStringW(x); \
if ( y == NULL) { \
SetError(ERROR_NOT_ENOUGH_MEMORY); \
} \
} \
else { \
y = NULL; \
INET_ASSERT(FALSE); \
}
#define COPY_OPTIONAL_PARAM(y,x) \
if (x) { \
y = NewString(x); \
if ( y == NULL) { \
SetError(ERROR_NOT_ENOUGH_MEMORY); \
} \
} \
else { \
y = NULL; \
}
#define DELETE_MANDATORY_PARAM(x) \
if (x) { \
x=(LPSTR)FREE_MEMORY(x); \
} \
else { \
INET_ASSERT(FALSE); \
}
#define DELETE_MANDATORY_PARAMW(x) \
if (x) { \
x=(LPWSTR)FREE_MEMORY(x); \
} \
else { \
INET_ASSERT(FALSE); \
}
#define DELETE_OPTIONAL_PARAM(x) \
if (x) { \
x=(LPSTR)FREE_MEMORY(x); \
}
//
// functions
//
BOOL
wInternetQueryDataAvailable(
IN LPVOID hFileMapped,
OUT LPDWORD lpdwNumberOfBytesAvailable,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
);
//
// classes
//
//
// CFsm - the finite state machine class. Describes the basic work unit,
// assumable by any available thread.
//
// State machines are chainable on a stack: the head of the stack is always the
// currently executing state machine
//
// For non-blocking socket operations, state machines are associated with the
// socket handle blocking the state machine
//
// State machines have a priority which is used in deciding which runnable state
// machine is executed next
//
class CFsm : public CPriorityListEntry {
private:
CFsm * m_Link; // 0x10
DWORD m_dwError; // 0x14
LPINTERNET_THREAD_INFO m_lpThreadInfo; // 0x18
DWORD_PTR m_dwContext; // 0x1C
HINTERNET m_hObject; // 0x20
INTERNET_HANDLE_OBJECT * m_hObjectMapped; // 0x24
DWORD m_dwMappedErrorCode; // 0x28
FSM_STATE m_State; // 0x2C
FSM_STATE m_NextState; // 0x30
FSM_STATE m_FunctionState; // 0x34
DWORD (*m_lpfnHandler)(CFsm *); // 0x38
LPVOID m_lpvContext; // 0x3C
FSM_HINT m_Hint; // 0x40
SOCKET m_Socket; // 0x44
FSM_ACTION m_Action; // 0x48
DWORD_PTR m_dwBlockId; // 0x4C
DWORD m_dwTimeout; // 0x50
BOOL m_fTimeoutWraps;
DWORD m_dwTimer; // 0x54
BOOL m_bTimerStarted; // 0x58
BOOL m_bIsApi; // 0x5C
// indicates a non-yielding fsm, that blocks a full thread while it executes
BOOL m_bIsBlockingFsm; // 0x60
API_TYPE m_ApiType; // 0x64
union {
BOOL Bool;
HINTERNET Handle;
} m_ApiResult; // 0x68
DWORD m_dwApiData; // 0x6C
BOOL m_bHasTimeout;
BOOL m_bOnAsyncList;
BOOL m_bPushPop;
//#if INET_DEBUG
#ifdef STRESS_BUG_DEBUG
DWORD m_Signature; // 0x70
public:
DWORD m_ThreadId; // 0x74
#define INET_ASSERT_X(x) if ( !(x) ) { OutputDebugString("WinHttp5.DLL: FSM still in use, contact venkatk, x54275 \r\n"); \
DebugBreak(); }
#define FSM_SIGNATURE 0x5f4d5346 // "FSM_"
#define INIT_FSM() m_Signature = FSM_SIGNATURE; \
m_Type = FSM_TYPE_NONE; \
m_ThreadId = 0
#define CHECK_FSM() INET_ASSERT_X(m_Signature == FSM_SIGNATURE)
#define SET_OWNED() m_ThreadId = GetCurrentThreadId()
#define RESET_OWNED() m_ThreadId = 0
#define CHECK_OWNED() INET_ASSERT_X(m_ThreadId == GetCurrentThreadId())
#define CHECK_UNOWNED() INET_ASSERT_X(m_ThreadId == 0)
#define SET_FSM_OWNED(p) if (p) p->m_ThreadId = GetCurrentThreadId()
#define RESET_FSM_OWNED(p) if (p) p->m_ThreadId = 0
#define CHECK_FSM_OWNED(p) if (p) INET_ASSERT_X(p->m_ThreadId == GetCurrentThreadId())
#define CHECK_FSM_UNOWNED(p) if (p) INET_ASSERT_X(p->m_ThreadId == 0)
#else
#define INIT_FSM() /* NOTHING */
#define CHECK_FSM() /* NOTHING */
#define SET_OWNED() /* NOTHING */
#define RESET_OWNED() /* NOTHING */
#define CHECK_OWNED() /* NOTHING */
#define CHECK_UNOWNED() /* NOTHING */
#define SET_FSM_OWNED(p) /* NOTHING */
#define RESET_FSM_OWNED(p) /* NOTHING */
#define CHECK_FSM_OWNED(p) /* NOTHING */
#define CHECK_FSM_UNOWNED(p) /* NOTHING */
#endif
protected:
FSM_TYPE m_Type; // 0x78
#define SET_FSM_TYPE(type) m_Type = FSM_TYPE_ ## type
public:
CFsm(DWORD (* lpfnHandler)(CFsm *), LPVOID lpvContext, BOOL fPushPop = TRUE);
virtual ~CFsm();
VOID
Push(
VOID
);
VOID
Pop(
VOID
);
VOID
SetPushPop(BOOL fPushPop) {
m_bPushPop = fPushPop;
}
DWORD GetError(VOID) const {
return m_dwError;
}
VOID SetError(DWORD Error) {
m_dwError = Error;
}
BOOL IsInvalid(VOID) {
INET_ASSERT(m_hObjectMapped != NULL);
return (m_hObjectMapped != NULL)
? m_hObjectMapped->IsInvalidated()
: FALSE;
}
DWORD GetMappedError(VOID) const {
return m_dwMappedErrorCode;
}
VOID SetMappedError(DWORD dwError) {
m_dwMappedErrorCode = dwError;
}
LPINTERNET_THREAD_INFO GetThreadInfo(VOID) const {
return m_lpThreadInfo;
}
VOID SetThreadInfo(LPINTERNET_THREAD_INFO lpThreadInfo) {
m_lpThreadInfo = lpThreadInfo;
}
DWORD_PTR GetAppContext(VOID) const {
return m_dwContext;
}
HINTERNET GetAppHandle(VOID) const {
return m_hObject;
}
HINTERNET GetMappedHandle(VOID) const {
return m_hObjectMapped;
}
INTERNET_HANDLE_OBJECT * GetMappedHandleObject(VOID) const {
return (INTERNET_HANDLE_OBJECT *)m_hObjectMapped;
}
FSM_STATE GetState(VOID) const {
return m_State;
}
VOID SetState(FSM_STATE State) {
m_State = State;
}
FSM_STATE GetNextState(VOID) const {
return m_NextState;
}
VOID SetNextState(FSM_STATE State) {
m_NextState = State;
}
FSM_STATE GetFunctionState(VOID) const {
//
// We should never enter into this state, cause the FSMs
// themselves must be correct enough to always set the
// next function state before exiting their state.
//
//INET_ASSERT(m_FunctionState != FSM_STATE_BAD);
return m_FunctionState;
}
VOID SetFunctionState(FSM_STATE State) {
m_FunctionState = State;
}
VOID SetWait(VOID) {
SetState(FSM_STATE_WAIT);
}
BOOL IsWait(VOID) {
return (m_State == FSM_STATE_WAIT) ? TRUE : FALSE;
}
VOID SetErrorState(DWORD Error) {
SetError(Error);
SetState(FSM_STATE_ERROR);
}
VOID SetDone(VOID) {
SetState(FSM_STATE_DONE);
}
VOID SetDone(DWORD Error) {
SetError(Error);
SetState(FSM_STATE_DONE);
}
BOOL IsDone(VOID) {
return (m_State == FSM_STATE_DONE) ? TRUE : FALSE;
}
LPVOID GetContext(VOID) const {
return m_lpvContext;
}
VOID SetContext(LPVOID lpvContext) {
m_lpvContext = lpvContext;
}
LPVOID GetHandler(VOID) const {
return (LPVOID)m_lpfnHandler;
}
VOID SetHandler(LPVOID lpfnHandler) {
m_lpfnHandler = (DWORD (*)(CFsm *))lpfnHandler;
}
VOID SetHandler2(DWORD (* lpfnHandler)(CFsm *)) {
m_lpfnHandler = lpfnHandler;
}
SOCKET GetSocket(VOID) const {
return m_Socket;
}
VOID SetSocket(SOCKET Socket) {
INET_ASSERT(m_Socket == INVALID_SOCKET);
m_Socket = Socket;
}
VOID ResetSocket(VOID) {
m_Socket = INVALID_SOCKET;
}
BOOL IsActive(VOID) {
return (m_Socket == INVALID_SOCKET) ? FALSE : TRUE;
}
FSM_ACTION GetAction(VOID) const {
return m_Action;
}
VOID SetAction(FSM_ACTION Action) {
m_Action = Action;
}
DWORD_PTR GetBlockId(VOID) const {
return m_dwBlockId;
}
VOID SetBlockId(DWORD_PTR dwBlockId) {
m_dwBlockId = dwBlockId;
}
BOOL IsBlockedOn(DWORD_PTR dwBlockId) {
return (m_dwBlockId == dwBlockId) ? TRUE : FALSE;
}
DWORD GetTimeout(VOID) const {
return m_dwTimeout;
}
// This code needs to handle system time roll over.
// SetTimeout 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
// IsTimedOut 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 SetTimeout(DWORD dwTimeout) {
if (dwTimeout != INFINITE)
m_bHasTimeout = TRUE;
else
m_bHasTimeout = FALSE;
DWORD dw = GetTickCountWrap();
m_dwTimeout = (dwTimeout == INFINITE)
? dwTimeout
: (dw + dwTimeout);
m_fTimeoutWraps = dw > m_dwTimeout;
}
BOOL HasTimeout()
{
return m_bHasTimeout;
}
VOID SetOnAsyncList(BOOL bOnAsyncList)
{
m_bOnAsyncList = bOnAsyncList;
}
BOOL IsOnAsyncList()
{
return m_bOnAsyncList;
}
BOOL IsTimedOut(DWORD dwTime) {
if (m_fTimeoutWraps)
{
m_fTimeoutWraps = ((LONG)dwTime < 0);
}
return ((m_dwTimeout == INFINITE) || m_fTimeoutWraps)
? FALSE
: (dwTime > m_dwTimeout);
}
VOID StartTimer(VOID) {
m_dwTimer = GetTickCountWrap();
m_bTimerStarted = TRUE;
}
DWORD StopTimer(VOID) {
if (m_bTimerStarted) {
m_dwTimer = GetTickCountWrap() - m_dwTimer;
m_bTimerStarted = FALSE;
}
return m_dwTimer;
}
DWORD GetElapsedTime(VOID) {
return (GetTickCountWrap() - m_dwTimer);
}
DWORD StopAndStartTimer(VOID) {
DWORD tNow = GetTickCountWrap();
DWORD tElapsed = (tNow - m_dwTimer);
m_dwTimer = tNow;
m_bTimerStarted = TRUE;
return tElapsed;
}
DWORD ReadTimer(VOID) {
return m_bTimerStarted ? GetElapsedTime() : m_dwTimer;
}
VOID SetBlocking(BOOL fBlocking = TRUE) {
m_bIsBlockingFsm = fBlocking;
}
BOOL IsBlocking(VOID) const {
return m_bIsBlockingFsm;
}
VOID SetApi(API_TYPE ApiType) {
m_bIsApi = TRUE;
m_ApiType = ApiType;
}
BOOL IsApi(VOID) const {
return m_bIsApi;
}
API_TYPE GetApiType(VOID) const {
return m_ApiType;
}
VOID SetApiResult(BOOL bResult) {
m_ApiResult.Bool = bResult;
}
VOID SetApiResult(HINTERNET hResult) {
m_ApiResult.Handle = hResult;
}
DWORD GetApiResult(VOID) {
// SUNDOWN: typecast problem
return (m_ApiType == ApiType_Handle)
? PtrToUlong(GetHandleResult())
: (m_ApiType == ApiType_Bool)
? (DWORD) GetBoolResult()
: 0;
}
BOOL GetBoolResult(VOID) const {
return m_ApiResult.Bool;
}
HINTERNET GetHandleResult(VOID) const {
return m_ApiResult.Handle;
}
DWORD GetApiData(VOID) const {
return m_dwApiData;
}
VOID SetApiData(DWORD dwApiData) {
m_dwApiData = dwApiData;
}
DWORD
QueueWorkItem(
VOID
);
static
DWORD
RunWorkItem(
IN CFsm * pFsm
);
DWORD
Run(
IN LPINTERNET_THREAD_INFO lpThreadInfo,
OUT DWORD *lpdwApiResult OPTIONAL,
OUT DWORD *lpdwApiData OPTIONAL
);
FSM_TYPE GetType(VOID) const {
return m_Type;
}
#if INET_DEBUG
DEBUG_FUNCTION
LPSTR
MapType(
VOID
);
DEBUG_FUNCTION
LPSTR
StateName(
IN DWORD State
);
DEBUG_FUNCTION
LPSTR MapState(VOID) {
return StateName(m_State);
}
DEBUG_FUNCTION
LPSTR MapFunctionState(VOID) {
return StateName(m_FunctionState);
}
#else
LPSTR MapType(VOID) {
return "";
}
LPSTR MapState(VOID) {
return "";
}
LPSTR MapFunctionState(VOID) {
return "";
}
#endif
};
/*DWORD
RunSM_Wrapper(
IN*/
//
// Derived State Machines
//
// The following state machines contain the parameters and variables that are
// maintained across machine states and thread switches
//
// In order to make the code more readable, the state machine is friends with
// the object class for which it operates (e.g. ICSocket or ICHttpRequest)
//
//
// CAddressList FSMs
//
class CFsm_ResolveHost : public CFsm {
friend class CAddressList;
private:
//
// parameters
//
LPSTR m_lpszHostName;
LPDWORD m_lpdwResolutionId;
DWORD m_dwFlags;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ResolveHost(
IN LPSTR lpszHostName,
IN LPDWORD lpdwResolutionId,
IN DWORD dwFlags,
IN CAddressList * pAddressList
) : CFsm(RunSM, (LPVOID)pAddressList) {
SET_FSM_TYPE(RESOLVE_HOST);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpszHostName = lpszHostName;
m_lpdwResolutionId = lpdwResolutionId;
m_dwFlags = dwFlags;
}
};
//
// Internet API FSMs
//
class CFsm_InternetParseUrl : public CFsm {
private:
//
// parameters
//
HINTERNET m_hConnectHandle;
DWORD_PTR m_dwContext;
LPCSTR m_lpszUrl;
LPCSTR m_lpszHeaders;
DWORD m_dwHeadersLength;
DWORD m_dwFlags;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
)
{
CFsm_InternetParseUrl *pFsm = (CFsm_InternetParseUrl *)Fsm;
INET_ASSERT(Fsm->GetState() == FSM_STATE_INIT);
pFsm->SetApiResult(InternetOpenUrlA(
pFsm->m_hConnectHandle,
pFsm->m_lpszUrl,
pFsm->m_lpszHeaders,
pFsm->m_dwHeadersLength,
pFsm->m_dwFlags,
pFsm->m_dwContext
));
pFsm->SetDone();
return ((pFsm->GetHandleResult()) ? ERROR_SUCCESS : GetLastError());
}
CFsm_InternetParseUrl(
IN HINTERNET hConnectHandle,
IN DWORD_PTR dwContext,
IN LPCSTR lpszUrl,
IN LPCSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwFlags
) : CFsm(RunSM, (LPVOID)hConnectHandle) {
SET_FSM_TYPE(INTERNET_PARSE_URL);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Handle);
SetBlocking();
m_hConnectHandle = hConnectHandle;
m_dwContext = dwContext;
m_lpszUrl = lpszUrl;
m_lpszHeaders = lpszHeaders;
m_dwHeadersLength = dwHeadersLength;
m_dwFlags = dwFlags;
}
};
class CFsm_InternetQueryDataAvailable : public CFsm {
private:
//
// parameters
//
HINTERNET m_hSessionHandle;
LPDWORD m_lpdwNumberOfBytesAvailable;
DWORD m_dwNumberOfBytesAvailable;
DWORD m_dwFlags;
DWORD_PTR m_dwContext;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
)
{
CFsm_InternetQueryDataAvailable *pFsm = (CFsm_InternetQueryDataAvailable *)Fsm;
INET_ASSERT(Fsm->GetState() == FSM_STATE_INIT);
pFsm->SetApiResult(wInternetQueryDataAvailable(
pFsm->m_hSessionHandle,
pFsm->m_lpdwNumberOfBytesAvailable,
pFsm->m_dwFlags,
pFsm->m_dwContext
));
pFsm->SetApiData(*pFsm->m_lpdwNumberOfBytesAvailable);
pFsm->SetDone();
return ((pFsm->GetBoolResult()) ? ERROR_SUCCESS : GetLastError());
}
CFsm_InternetQueryDataAvailable(
IN HINTERNET hSessionHandle,
OUT LPDWORD lpdwNumberOfBytesAvailable,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
) : CFsm(RunSM, (LPVOID)hSessionHandle) {
SET_FSM_TYPE(INTERNET_QUERY_DATA_AVAILABLE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
SetBlocking();
m_hSessionHandle = hSessionHandle;
m_lpdwNumberOfBytesAvailable = &m_dwNumberOfBytesAvailable;
m_dwNumberOfBytesAvailable = *lpdwNumberOfBytesAvailable;
m_dwFlags = dwFlags;
m_dwContext = dwContext;
}
};
class CFsm_InternetWriteFile : public CFsm {
private:
//
// parameters
//
HINTERNET m_hSessionHandle;
LPCVOID m_lpBuffer;
DWORD m_dwNumberOfBytesToWrite;
LPDWORD m_lpdwNumberOfBytesWritten;
DWORD m_dwNumberOfBytesWritten;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
)
{
CFsm_InternetWriteFile *pFsm = (CFsm_InternetWriteFile *)Fsm;
INET_ASSERT(Fsm->GetState() == FSM_STATE_INIT);
pFsm->SetApiResult(WinHttpWriteData(
pFsm->m_hSessionHandle,
pFsm->m_lpBuffer,
pFsm->m_dwNumberOfBytesToWrite,
pFsm->m_lpdwNumberOfBytesWritten
));
pFsm->SetApiData(*(pFsm->m_lpdwNumberOfBytesWritten));
pFsm->SetDone();
return ((pFsm->GetBoolResult()) ? ERROR_SUCCESS : GetLastError());
}
CFsm_InternetWriteFile(
IN HINTERNET hSessionHandle,
IN LPCVOID lpBuffer,
IN DWORD dwNumberOfBytesToWrite,
OUT LPDWORD lpdwNumberOfBytesWritten
) : CFsm(RunSM, (LPVOID)hSessionHandle) {
SET_FSM_TYPE(INTERNET_WRITE_FILE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
SetBlocking();
m_hSessionHandle = hSessionHandle;
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToWrite = dwNumberOfBytesToWrite;
m_dwNumberOfBytesWritten = *lpdwNumberOfBytesWritten;
m_lpdwNumberOfBytesWritten = &m_dwNumberOfBytesWritten;
}
};
class CFsm_InternetReadFile : public CFsm {
private:
//
// parameters
//
HINTERNET m_hSessionHandle;
LPVOID m_lpBuffer;
DWORD m_dwNumberOfBytesToRead;
LPDWORD m_lpdwNumberOfBytesRead;
DWORD m_dwNumberOfBytesRead;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
)
{
CFsm_InternetReadFile *pFsm = (CFsm_InternetReadFile *)Fsm;
INET_ASSERT(Fsm->GetState() == FSM_STATE_INIT);
pFsm->SetApiResult(WinHttpReadData(
pFsm->m_hSessionHandle,
pFsm->m_lpBuffer,
pFsm->m_dwNumberOfBytesToRead,
pFsm->m_lpdwNumberOfBytesRead
));
pFsm->SetApiData(*(pFsm->m_lpdwNumberOfBytesRead));
pFsm->SetDone();
return ((pFsm->GetBoolResult()) ? ERROR_SUCCESS : GetLastError());
}
CFsm_InternetReadFile(
IN HINTERNET hSessionHandle,
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToRead,
OUT LPDWORD lpdwNumberOfBytesRead
) : CFsm(RunSM, (LPVOID)hSessionHandle) {
SET_FSM_TYPE(INTERNET_READ_FILE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
SetBlocking();
m_hSessionHandle = hSessionHandle;
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToRead = dwNumberOfBytesToRead;
m_dwNumberOfBytesRead = *lpdwNumberOfBytesRead;
m_lpdwNumberOfBytesRead = &m_dwNumberOfBytesRead;
}
};
//
// ICSocket FSMs
//
//
// CFsm_SocketConnect -
//
class CFsm_SocketConnect : public CFsm {
friend class ICSocket;
private:
//
// parameters
//
LONG m_Timeout;
INT m_Retries;
DWORD m_dwFlags;
//
// local variables
//
BOOL m_bStopOfflineTimer;
LONG m_lPreviousTime;
BOOL m_bResolved;
DWORD m_dwResolutionId;
DWORD m_dwAddressIndex;
char m_AddressBuffer[CSADDR_BUFFER_LENGTH];
LPCSADDR_INFO m_pAddress;
CServerInfo * m_pServerInfo;
CServerInfo * m_pOriginServer;
BOOL m_fTimeout;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SocketConnect(
IN LONG Timeout,
IN INT Retries,
IN DWORD dwFlags,
IN ICSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SOCKET_CONNECT);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_Timeout = Timeout;
m_fTimeout = Timeout ? TRUE : FALSE;
m_Retries = Retries;
m_dwFlags = dwFlags;
m_bStopOfflineTimer = FALSE;
m_lPreviousTime = (LONG)GetTickCountWrap();
m_bResolved = FALSE;
m_dwResolutionId = (DWORD)-1;
m_dwAddressIndex = (DWORD)-1;
m_pAddress = (LPCSADDR_INFO)m_AddressBuffer;
m_pServerInfo = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetServerInfo();
m_pOriginServer = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetOriginServer();
}
VOID SetServerInfo(CServerInfo * pServerInfo) {
m_pServerInfo = pServerInfo;
}
BOOL IsCountedOut(VOID) {
return (--m_Retries <= 0) ? TRUE : FALSE;
}
BOOL IsTimedOut(VOID) {
return (m_fTimeout != INFINITE) ? (((m_Timeout -= (LONG)ReadTimer()) <= 0) ? TRUE : FALSE) : FALSE;
}
LONG GetTimeout(VOID) const
{
return m_Timeout;
}
};
//
// CFsm_SocketSend -
//
class CFsm_SocketIOCP : public CFsm
{
public:
BOOL bIOCPSuccess;
DWORD dwBytesTransferred;
DWORD dwIOCPError;
BOOL bIOCPInited;
CFsm_SocketIOCP(DWORD (* lpfnHandler)(CFsm *), LPVOID lpvContext):CFsm(lpfnHandler, lpvContext)
{
bIOCPSuccess = FALSE;
dwBytesTransferred = 0;
dwIOCPError = 0;
bIOCPInited = FALSE;
}
};
class CFsm_SocketSend : public CFsm_SocketIOCP
{
friend class ICSocket;
private:
//
// parameters
//
LPVOID m_lpBuffer;
DWORD m_dwBufferLength;
DWORD m_dwFlags;
//
// local variables
//
INT m_iTotalSent;
BOOL m_bStopOfflineTimer;
CServerInfo * m_pServerInfo;
CServerInfo * m_pOriginServer;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SocketSend(
IN LPVOID lpBuffer,
IN DWORD dwBufferLength,
IN DWORD dwFlags,
IN ICSocket * pSocket
) : CFsm_SocketIOCP(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SOCKET_SEND);
if (GetError() != ERROR_SUCCESS) {
return;
}
INET_ASSERT(lpBuffer != NULL);
INET_ASSERT((int)dwBufferLength > 0);
m_lpBuffer = lpBuffer;
m_dwBufferLength = dwBufferLength;
m_dwFlags = dwFlags;
m_iTotalSent = 0;
m_bStopOfflineTimer = FALSE;
m_pServerInfo = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetServerInfo();
m_pOriginServer = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetOriginServer();
}
};
//
// CFsm_SocketReceive -
//
class CFsm_SocketReceive : public CFsm_SocketIOCP
{
friend class ICSocket;
private:
//
// parameters
//
LPVOID * m_lplpBuffer;
LPDWORD m_lpdwBufferLength;
LPDWORD m_lpdwBufferRemaining;
LPDWORD m_lpdwBytesReceived;
DWORD m_dwExtraSpace;
DWORD m_dwFlags;
LPBOOL m_lpbEof;
//
// local variables
//
HLOCAL m_hBuffer;
LPBYTE m_lpBuffer;
DWORD m_dwBufferLength;
DWORD m_dwBufferLeft;
DWORD m_dwBytesReceived;
DWORD m_dwBytesRead;
BOOL m_bEof;
BOOL m_bAllocated;
CServerInfo * m_pServerInfo;
CServerInfo * m_pOriginServer;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SocketReceive(
IN OUT LPVOID * lplpBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPDWORD lpdwBufferRemaining,
IN OUT LPDWORD lpdwBytesReceived,
IN DWORD dwExtraSpace,
IN DWORD dwFlags,
OUT LPBOOL lpbEof,
IN ICSocket * pSocket
) : CFsm_SocketIOCP(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SOCKET_RECEIVE);
if (GetError() != ERROR_SUCCESS) {
return;
}
//
// sanity check
//
INET_ASSERT(lplpBuffer != NULL);
INET_ASSERT(lpdwBufferLength != NULL);
INET_ASSERT((*lpdwBufferLength == 0) ? (dwFlags & SF_EXPAND) : TRUE);
m_lplpBuffer = lplpBuffer;
m_lpdwBufferLength = lpdwBufferLength;
m_lpdwBufferRemaining = lpdwBufferRemaining;
m_lpdwBytesReceived = lpdwBytesReceived;
m_dwExtraSpace = dwExtraSpace;
m_dwFlags = dwFlags;
m_lpbEof = lpbEof;
m_hBuffer = *lplpBuffer;
m_lpBuffer = (LPBYTE)m_hBuffer;
m_dwBufferLength = *lpdwBufferLength;
m_dwBufferLeft = *lpdwBufferRemaining;
m_dwBytesReceived = *lpdwBytesReceived;
m_dwBytesRead = 0;
m_bEof = FALSE;
m_bAllocated = FALSE;
m_pServerInfo = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetServerInfo();
m_pOriginServer = ((HTTP_REQUEST_HANDLE_OBJECT *)
GetThreadInfo()->hObjectMapped)->GetOriginServer();
}
};
//
// ICSecureSocket FSMs
//
//
// CFsm_SecureConnect -
//
class CFsm_SecureConnect : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
LONG m_Timeout;
INT m_Retries;
DWORD m_dwFlags;
//
// locals
//
BOOL m_bAttemptReconnect;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SecureConnect(
IN LONG Timeout,
IN INT Retries,
IN DWORD dwFlags,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SECURE_CONNECT);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_Timeout = Timeout;
m_Retries = Retries;
m_dwFlags = dwFlags;
m_bAttemptReconnect = FALSE;
}
};
//
// CFsm_SecureHandshake -
//
class CFsm_SecureHandshake : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
DWORD m_dwFlags;
LPBOOL m_lpbAttemptReconnect;
//
// locals
//
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SecureHandshake(
IN DWORD dwFlags,
OUT LPBOOL lpbAttemptReconnect,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SECURE_HANDSHAKE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_dwFlags = dwFlags;
m_lpbAttemptReconnect = lpbAttemptReconnect;
}
};
//
// CFsm_SecureNegotiate -
//
class CFsm_SecureNegotiate : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
DWORD m_dwFlags;
LPBOOL m_lpbAttemptReconnect;
//
// locals
//
SecBufferDesc m_OutBuffer;
SecBuffer m_OutBuffers[1];
CredHandle m_hCreds;
BOOL m_bDoingClientAuth;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SecureNegotiate(
IN DWORD dwFlags,
OUT LPBOOL lpbAttemptReconnect,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SECURE_NEGOTIATE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_dwFlags = dwFlags;
m_lpbAttemptReconnect = lpbAttemptReconnect;
ClearCreds(m_hCreds);
m_bDoingClientAuth = FALSE;
}
~CFsm_SecureNegotiate() {
//INET_ASSERT(IsCredClear(m_hCreds));
INET_ASSERT(!m_bDoingClientAuth);
if ( m_bDoingClientAuth &&
!IsCredClear(m_hCreds))
{
// Look at comments before CliAuthSelectCredentials
// g_FreeCredentialsHandle(&m_hCreds);
m_bDoingClientAuth = FALSE;
}
}
};
//
// CFsm_NegotiateLoop -
//
class CFsm_NegotiateLoop : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
DBLBUFFER * m_pdblbufBuffer;
DWORD m_dwFlags;
BOOL m_bDoInitialRead;
//
// locals
//
SECURITY_STATUS m_scRet;
DWORD m_dwProviderIndex;
LPSTR m_lpszBuffer;
DWORD m_dwBufferLength;
DWORD m_dwBufferLeft;
DWORD m_dwBytesReceived;
BOOL m_bEofReceive;
BOOL m_bDoingClientAuth;
BOOL m_bDoRead;
SecBuffer m_InBuffers[2];
SecBuffer m_OutBuffers[1];
SecBufferDesc m_OutBuffer;
CredHandle m_hCreds;
DWORD m_dwSSPIFlags;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_NegotiateLoop(
IN DBLBUFFER * pdblbufBuffer,
IN DWORD dwFlags,
IN BOOL bDoInitialRead,
IN BOOL bDoingClientAuth,
IN CredHandle hCreds,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(NEGOTIATE_LOOP);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_pdblbufBuffer = pdblbufBuffer;
m_dwFlags = dwFlags;
m_bDoInitialRead = bDoInitialRead;
m_scRet = SEC_E_SECPKG_NOT_FOUND;
m_lpszBuffer = NULL;
m_dwBufferLength = 0;
m_dwBufferLeft = 0;
m_dwBytesReceived = 0;
m_bEofReceive = FALSE;
m_bDoingClientAuth = bDoingClientAuth;
m_bDoRead = m_bDoInitialRead;
if (bDoingClientAuth)
m_hCreds = hCreds;
else
ClearCreds(m_hCreds);
}
~CFsm_NegotiateLoop() {
if (m_bDoingClientAuth)
{
INET_ASSERT(!IsCredClear(m_hCreds));
// Look at comments before CliAuthSelectCredentials
// g_FreeCredentialsHandle(&m_hCreds);
m_bDoingClientAuth = FALSE;
}
}
};
//
// CFsm_SecureSend -
//
class CFsm_SecureSend : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
LPVOID m_lpBuffer;
DWORD m_dwBufferLength;
DWORD m_dwFlags;
//
// locals
//
LPVOID m_lpCryptBuffer;
DWORD m_dwCryptBufferLength;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SecureSend(
IN LPVOID lpBuffer,
IN DWORD dwBufferLength,
IN DWORD dwFlags,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SECURE_SEND);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpBuffer = lpBuffer;
m_dwBufferLength = dwBufferLength;
m_dwFlags = dwFlags;
m_lpCryptBuffer = NULL;
m_dwCryptBufferLength = 0;
}
};
//
// CFsm_SecureReceive -
//
class CFsm_SecureReceive : public CFsm {
friend class ICSecureSocket;
private:
//
// parameters
//
LPVOID * m_lplpBuffer;
LPDWORD m_lpdwBufferLength;
LPDWORD m_lpdwBufferRemaining;
LPDWORD m_lpdwBytesReceived;
DWORD m_dwExtraSpace;
DWORD m_dwFlags;
LPBOOL m_lpbEof;
//
// locals
//
HLOCAL m_hBuffer;
DWORD m_dwBufferLength;
DWORD m_dwBufferLeft;
DWORD m_dwBytesReceived;
DWORD m_dwBytesRead;
LPBYTE m_lpBuffer;
BOOL m_bEof;
BOOL m_bAllocated;
DWORD m_dwDecryptError;
DWORD m_dwReadFlags;
LPBYTE m_lpBufferDummy;
DWORD m_dwBufferLengthDummy;
DWORD m_dwBufferReceivedDummy;
DWORD m_dwBufferLeftDummy;
DWORD m_dwBufferReceivedPre;
DWORD m_dwInputBytesLeft;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SecureReceive(
IN OUT LPVOID* lplpBuffer,
IN OUT LPDWORD lpdwBufferLength,
IN OUT LPDWORD lpdwBufferRemaining,
IN OUT LPDWORD lpdwBytesReceived,
IN DWORD dwExtraSpace,
IN DWORD dwFlags,
OUT LPBOOL lpbEof,
IN ICSecureSocket * pSocket
) : CFsm(RunSM, (LPVOID)pSocket) {
SET_FSM_TYPE(SECURE_RECEIVE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lplpBuffer = lplpBuffer;
m_lpdwBufferLength = lpdwBufferLength;
m_lpdwBufferRemaining = lpdwBufferRemaining;
m_lpdwBytesReceived = lpdwBytesReceived;
m_dwExtraSpace = dwExtraSpace;
m_dwFlags = dwFlags;
m_lpbEof = lpbEof;
m_hBuffer = (HLOCAL)*lplpBuffer;
m_dwBufferLength = *lpdwBufferLength;
m_dwBufferLeft = *lpdwBufferRemaining;
m_dwBytesReceived = *lpdwBytesReceived;
m_dwBytesRead = 0;
m_bEof = FALSE;
m_bAllocated = FALSE;
m_dwDecryptError = ERROR_SUCCESS;
}
};
//
// CServerInfo FSMs
//
//
// CFsm_GetConnection -
//
class CFsm_GetConnection : public CFsm {
friend class CServerInfo;
private:
//
// parameters
//
DWORD m_dwSocketFlags;
INTERNET_PORT m_nPort;
DWORD m_dwTimeout;
BOOL m_fTimeoutWraps;
DWORD m_dwLimitTimeout;
ICSocket * * m_lplpSocket;
LPSTR m_lpszSecureTunnelHost;
//
// locals
//
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_GetConnection(
IN DWORD dwSocketFlags,
IN INTERNET_PORT nPort,
IN DWORD dwTimeout,
IN DWORD dwLimitTimeout,
OUT ICSocket * * lplpSocket,
IN CServerInfo * lpServerInfo,
IN LPSTR lpszSecureTunnelHost = NULL
) : CFsm(RunSM, (LPVOID)lpServerInfo) {
SET_FSM_TYPE(GET_CONNECTION);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_dwSocketFlags = dwSocketFlags;
m_nPort = nPort;
m_dwTimeout = dwTimeout;
m_fTimeoutWraps = GetTickCount() > dwTimeout;
m_dwLimitTimeout = dwLimitTimeout; // This is unused
m_lplpSocket = lplpSocket;
if (lpszSecureTunnelHost)
{
int ccSecureTunnelHost = strlen(lpszSecureTunnelHost) + 1;
m_lpszSecureTunnelHost = (LPSTR) ALLOCATE_FIXED_MEMORY(ccSecureTunnelHost);
if (m_lpszSecureTunnelHost)
memcpy(m_lpszSecureTunnelHost, lpszSecureTunnelHost, ccSecureTunnelHost);
}
else
{
m_lpszSecureTunnelHost = NULL;
}
}
~CFsm_GetConnection() {
if (m_lpszSecureTunnelHost)
FREE_MEMORY(m_lpszSecureTunnelHost);
}
};
//
// HTTP_REQUEST_HANDLE_OBJECT FSMs
//
//
// CFsm_HttpSendRequest -
//
class CFsm_HttpSendRequest : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
public:
AR_TYPE m_arRequest;
private:
//
// parameters
//
LPVOID m_lpOptional;
DWORD m_dwOptionalLength;
//
// local variables
//
HINTERNET m_hRequestMapped;
HTTP_REQUEST_HANDLE_OBJECT * m_pRequest;
BOOL m_bFinished;
BOOL m_bAuthNotFinished;
BOOL m_bRedirectCountedOut;
BOOL m_bCancelRedoOfProxy;
BOOL m_bRedirected;
BOOL m_bSink;
DWORD m_dwRedirectCount;
AUTO_PROXY_ASYNC_MSG *m_pProxyInfoQuery;
BOOL m_fOwnsProxyInfoQueryObj;
INTERNET_HANDLE_OBJECT * m_pInternet;
LPVOID m_pBuffer;
DWORD m_dwBytesDrained;
DWORD m_iRetries;
BOOL m_bWasKeepAlive;
HTTP_METHOD_TYPE m_tMethodRedirect;
DWORD m_dwCookieIndex;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_HttpSendRequest(
IN LPVOID lpOptional OPTIONAL,
IN DWORD dwOptionalLength,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest,
IN AR_TYPE arRequest
) : CFsm(RunSM, (LPVOID)pRequest, FALSE) {
SET_FSM_TYPE(HTTP_SEND_REQUEST);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
m_hRequestMapped = (HINTERNET)pRequest;
m_lpOptional = lpOptional;
m_dwOptionalLength = dwOptionalLength;
m_pRequest = pRequest;
m_bFinished = FALSE;
m_bAuthNotFinished = FALSE;
m_bRedirectCountedOut = FALSE;
m_bCancelRedoOfProxy = FALSE;
m_bRedirected = FALSE;
m_bSink = FALSE;
m_dwRedirectCount = GlobalMaxHttpRedirects;
m_pProxyInfoQuery = NULL;
m_arRequest = arRequest;
m_fOwnsProxyInfoQueryObj = TRUE;
m_dwCookieIndex = 0;
m_pInternet = GetRootHandle(pRequest);
INET_ASSERT(m_pInternet != NULL);
INET_ASSERT(m_pInternet->IsValid(TypeInternetHandle) == ERROR_SUCCESS);
m_pBuffer = NULL;
m_iRetries = 2;
m_tMethodRedirect = HTTP_METHOD_TYPE_UNKNOWN;
}
~CFsm_HttpSendRequest(
VOID
)
{
if ( m_fOwnsProxyInfoQueryObj && m_pProxyInfoQuery && m_pProxyInfoQuery->IsAlloced())
{
delete m_pProxyInfoQuery;
}
if (m_pBuffer != NULL)
{
m_pBuffer = (LPVOID)FREE_MEMORY(m_pBuffer);
}
}
};
//
// CFsm_MakeConnection -
//
class CFsm_MakeConnection : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
//
// local variables
//
HTTP_REQUEST_HANDLE_OBJECT * m_pRequest;
BOOL m_bAttemptReconnect;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_MakeConnection(
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(MAKE_CONNECTION);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_pRequest = pRequest;
}
};
//
// CFsm_OpenConnection -
//
class CFsm_OpenConnection : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
BOOL m_bNewConnection;
//
// local variables
//
BOOL m_bCreatedSocket;
BOOL m_fNoCreate;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_OpenConnection(
IN BOOL bNewConnection,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest,
IN BOOL fNoCreate = FALSE
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(OPEN_CONNECTION);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_bNewConnection = bNewConnection;
m_bCreatedSocket = FALSE;
m_fNoCreate = fNoCreate;
}
};
//
// CFsm_OpenProxyTunnel -
//
class CFsm_OpenProxyTunnel : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
//
// local variables
//
HINTERNET m_hConnect;
HINTERNET m_hRequest;
HINTERNET m_hRequestMapped;
HTTP_REQUEST_HANDLE_OBJECT * m_pRequest;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_OpenProxyTunnel(
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(OPEN_PROXY_TUNNEL);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_hConnect = NULL;
m_hRequest = NULL;
m_hRequestMapped = NULL;
}
};
//
// CFsm_SendRequest -
//
class CFsm_SendRequest : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPVOID m_lpOptional;
DWORD m_dwOptionalLength;
//
// local variables
//
LPSTR m_pRequestBuffer;
DWORD m_dwRequestLength;
BOOL m_bExtraCrLf;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_SendRequest(
IN LPVOID lpOptional,
IN DWORD dwOptionalLength,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(SEND_REQUEST);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpOptional = lpOptional;
m_dwOptionalLength = dwOptionalLength;
m_pRequestBuffer = NULL;
m_bExtraCrLf = FALSE;
}
~CFsm_SendRequest() {
if (m_pRequestBuffer != NULL) {
m_pRequestBuffer = (LPSTR)FREE_MEMORY(m_pRequestBuffer);
INET_ASSERT(m_pRequestBuffer == NULL);
}
}
};
//
// CFsm_ReceiveResponse -
//
class CFsm_ReceiveResponse : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
//
// local variables
//
HTTP_REQUEST_HANDLE_OBJECT * m_pRequest;
DWORD m_dwResponseLeft;
BOOL m_bEofResponseHeaders;
BOOL m_bDrained;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ReceiveResponse(
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(RECEIVE_RESPONSE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_pRequest = pRequest;
m_bDrained = FALSE;
}
};
//
// CFsm_HttpReadData -
//
class CFsm_HttpReadData : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPVOID m_lpBuffer;
DWORD m_dwNumberOfBytesToRead;
LPDWORD m_lpdwNumberOfBytesRead;
DWORD m_dwSocketFlags;
//
// local variables
//
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_HttpReadData(
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToRead,
OUT LPDWORD lpdwNumberOfBytesRead,
IN DWORD dwSocketFlags,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(HTTP_READ);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToRead = dwNumberOfBytesToRead;
m_lpdwNumberOfBytesRead = lpdwNumberOfBytesRead;
m_dwSocketFlags = dwSocketFlags;
}
};
//
// CFsm_HttpWriteData -
//
class CFsm_HttpWriteData : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPVOID m_lpBuffer;
DWORD m_dwNumberOfBytesToWrite;
LPDWORD m_lpdwNumberOfBytesWritten;
DWORD m_dwSocketFlags;
//
// local variables
//
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_HttpWriteData(
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToWrite,
OUT LPDWORD lpdwNumberOfBytesWritten,
IN DWORD dwSocketFlags,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest, FALSE) {
SET_FSM_TYPE(HTTP_WRITE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToWrite = dwNumberOfBytesToWrite;
m_lpdwNumberOfBytesWritten = lpdwNumberOfBytesWritten;
m_dwSocketFlags = dwSocketFlags;
SetApi(ApiType_Bool);
}
};
//
// CFsm_ReadData -
//
class CFsm_ReadData : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPVOID m_lpBuffer;
DWORD m_dwNumberOfBytesToRead;
LPDWORD m_lpdwNumberOfBytesRead;
BOOL m_fNoAsync;
DWORD m_dwSocketFlags;
//
// local variables
//
DWORD m_nBytes;
DWORD m_nBytesCopied;
DWORD m_dwBufferLeft;
DWORD m_dwBytesRead;
BOOL m_bEof;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ReadData(
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToRead,
OUT LPDWORD lpdwNumberOfBytesRead,
IN BOOL fNoAsync,
IN DWORD dwSocketFlags,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(READ_DATA);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToRead = dwNumberOfBytesToRead;
m_lpdwNumberOfBytesRead = lpdwNumberOfBytesRead;
m_fNoAsync = fNoAsync;
m_dwSocketFlags = dwSocketFlags;
m_nBytesCopied = 0;
}
};
//
// CFsm_HttpQueryAvailable -
//
class CFsm_HttpQueryAvailable : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPDWORD m_lpdwNumberOfBytesAvailable;
//
// local variables
//
LPVOID m_lpBuffer;
DWORD m_dwBufferLength;
DWORD m_dwBufferLeft;
BOOL m_bEof;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_HttpQueryAvailable(
IN LPDWORD lpdwNumberOfBytesAvailable,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(HTTP_QUERY_AVAILABLE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpdwNumberOfBytesAvailable = lpdwNumberOfBytesAvailable;
}
};
//
// CFsm_DrainResponse -
//
class CFsm_DrainResponse : CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
LPBOOL m_lpbDrained;
//
// local variables
//
DWORD m_dwAmountToRead;
DWORD m_dwBufferLeft;
DWORD m_dwPreviousBytesReceived;
DWORD m_dwAsyncFlags;
DWORD m_dwBytesReceived;
BOOL m_bEof;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_DrainResponse(
IN LPBOOL lpbDrained,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(DRAIN_RESPONSE);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_lpbDrained = lpbDrained;
m_bEof = FALSE;
m_dwBytesReceived = 0;
}
};
//
// CFsm_Redirect -
//
class CFsm_Redirect : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
HTTP_METHOD_TYPE m_tMethod;
//
// local variables
//
BOOL m_bDrained;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_Redirect(
IN HTTP_METHOD_TYPE tMethod,
IN BOOL fRedirectToProxy,
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(REDIRECT);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_tMethod = tMethod;
}
};
//
// CFsm_ReadLoop -
//
class CFsm_ReadLoop : public CFsm {
friend class HTTP_REQUEST_HANDLE_OBJECT;
private:
//
// parameters
//
DWORD m_dwSocketFlags;
PBYTE m_pRead;
DWORD m_cbReadIn;
DWORD* m_pcbReadOut;
//
// local variables
//
LPVOID m_pBuf; // read buffer
DWORD m_cbBuf; // size of read buffer
DWORD m_dwReadEnd; // read offset goal
DWORD m_cbRead; // bytes to read
DWORD m_cbRecv; // bytes received
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ReadLoop(
IN HTTP_REQUEST_HANDLE_OBJECT * pRequest,
IN DWORD dwSocketFlags,
IN PBYTE pRead,
IN DWORD cbReadIn,
OUT DWORD* pcbReadOut
) : CFsm(RunSM, (LPVOID)pRequest) {
SET_FSM_TYPE(READ_LOOP);
m_dwSocketFlags = dwSocketFlags;
m_pRead = pRead;
m_cbReadIn = cbReadIn;
m_pcbReadOut = pcbReadOut;
if (GetError() != ERROR_SUCCESS) {
return;
}
}
};
//
// CFsm_ParseHttpUrl -
//
class CFsm_ParseHttpUrl : public CFsm {
friend
DWORD
ParseHttpUrl_Fsm(
IN CFsm_ParseHttpUrl * Fsm
);
private:
//
// parameters
//
LPHINTERNET m_phInternet;
LPSTR m_lpszUrl;
DWORD m_dwSchemeLength;
LPSTR m_lpszHeaders;
DWORD m_dwHeadersLength;
DWORD m_dwFlags;
DWORD_PTR m_dwContext;
//
// locals
//
HINTERNET m_hConnect;
HINTERNET m_hRequest;
public:
CFsm_ParseHttpUrl(
IN OUT LPHINTERNET phInternet,
IN LPSTR lpszUrl,
IN DWORD dwSchemeLength,
IN LPSTR lpszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
) : CFsm((DWORD (*)(CFsm *))ParseHttpUrl_Fsm, NULL) {
SET_FSM_TYPE(PARSE_HTTP_URL);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_phInternet = phInternet;
m_lpszUrl = lpszUrl;
m_dwSchemeLength = dwSchemeLength;
m_lpszHeaders = lpszHeaders;
m_dwHeadersLength = dwHeadersLength;
m_dwFlags = dwFlags;
m_dwContext = dwContext;
}
};
//
// CFsm_OpenUrl -
//
class CFsm_OpenUrl : public CFsm {
private:
//
// parameters
//
//
// locals
//
public:
CFsm_OpenUrl();
};
//
// CFsm_ParseUrlForHttp -
//
class CFsm_ParseUrlForHttp : public CFsm {
friend
DWORD
ParseUrlForHttp_Fsm(
IN CFsm_ParseUrlForHttp * Fsm
);
private:
//
// parameters
//
LPHINTERNET m_lphInternet; // 0x7C
HINTERNET m_hInternet; // 0x80
LPVOID m_hInternetMapped; // 0x84
LPSTR m_lpcszUrl; // 0x88
LPSTR m_lpcszHeaders; // 0x8C
DWORD m_dwHeadersLength; // 0x90
DWORD m_dwFlags; // 0x94
DWORD_PTR m_dwContext; // 0x98
//
// locals
//
PROXY_STATE * m_pProxyState; // 0x9C
LPSTR m_lpszUrlCopy; // 0xA0
LPFN_URL_PARSER m_pUrlParser; // 0xA4
INTERNET_SCHEME m_SchemeType; // 0xA8
DWORD m_dwSchemeLength; // 0xAC
AUTO_PROXY_ASYNC_MSG *m_pProxyInfoQuery;// 0xB0
BOOL m_fFirstCall; // 0xB4
HINTERNET m_hInternetCopy; // 0xB8
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ParseUrlForHttp(
IN OUT LPHINTERNET lphInternet,
IN LPVOID hMapped,
IN LPCSTR lpcszUrl,
IN LPCSTR lpcszHeaders,
IN DWORD dwHeadersLength,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
) : CFsm(RunSM, NULL) {
SET_FSM_TYPE(PARSE_URL_FOR_HTTP);
if (GetError() != ERROR_SUCCESS) {
return;
}
//
// ParseUrlForHttp() is the function that returns the API result for
// InternetOpenUrl() in the new scheme. Make this FSM return the API
// result
//
SetApi(ApiType_Handle);
m_lphInternet = lphInternet;
m_hInternet = *lphInternet;
m_hInternetMapped = hMapped;
m_hInternetCopy = *lphInternet;
m_dwHeadersLength = dwHeadersLength;
m_dwFlags = dwFlags;
m_dwContext = dwContext;
m_pProxyState = NULL;
m_pUrlParser = NULL;
m_SchemeType = INTERNET_SCHEME_DEFAULT;
m_dwSchemeLength = 0;
m_pProxyInfoQuery = NULL;
m_fFirstCall = TRUE;
COPY_MANDATORY_PARAM(m_lpcszUrl, lpcszUrl);
if (lpcszHeaders)
{
m_lpcszHeaders = NewString(lpcszHeaders, dwHeadersLength);
if (!m_lpcszHeaders)
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
}
else
m_lpcszHeaders = NULL;
}
~CFsm_ParseUrlForHttp() {
DELETE_MANDATORY_PARAM(m_lpcszUrl);
DELETE_OPTIONAL_PARAM(m_lpcszHeaders);
}
BOOL IsOnApiCall(VOID) {
return m_fFirstCall;
}
VOID ClearOnApiCall(VOID) {
m_fFirstCall = FALSE;
}
DWORD
QueryProxySettings(
IN CFsm_ParseUrlForHttp * Fsm,
IN BOOL fCallback
);
DWORD
BuildProxyMessage(
IN CFsm_ParseUrlForHttp * Fsm
);
DWORD
ScanProxyUrl(
IN CFsm_ParseUrlForHttp * Fsm
);
DWORD
CompleteParseUrl(
IN CFsm_ParseUrlForHttp * Fsm,
IN LPINTERNET_THREAD_INFO lpThreadInfo,
IN DWORD error
);
};
//
// InternetReadFile API
//
class CFsm_ReadFile : public CFsm {
friend
DWORD
ReadFile_Fsm(
IN CFsm_ReadFile * Fsm
);
public:
LPVOID m_lpBuffer;
LPDWORD m_lpdwNumberOfBytesRead;
private:
//
// parameters
//
DWORD m_dwNumberOfBytesToRead;
//
// local variables
//
DWORD m_dwBytesRead;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ReadFile(
IN LPVOID lpBuffer,
IN DWORD dwNumberOfBytesToRead,
OUT LPDWORD lpdwNumberOfBytesRead
) : CFsm(RunSM, NULL, FALSE) {
SET_FSM_TYPE(READ_FILE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
m_lpBuffer = lpBuffer;
m_dwNumberOfBytesToRead = dwNumberOfBytesToRead;
m_lpdwNumberOfBytesRead = lpdwNumberOfBytesRead;
}
};
//
// InternetReadFileEx API
//
class CFsm_ReadFileEx : public CFsm {
friend
DWORD
ReadFileEx_Fsm(
IN CFsm_ReadFileEx * Fsm
);
private:
//
// parameters
//
LPINTERNET_BUFFERS m_lpBuffersOut;
DWORD m_dwFlags;
DWORD_PTR m_dwContext;
//
// local variables
//
DWORD m_dwNumberOfBytesToRead;
DWORD m_dwBytesRead;
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_ReadFileEx(
IN LPINTERNET_BUFFERS lpBuffersOut,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
) : CFsm(RunSM, NULL) {
SET_FSM_TYPE(READ_FILE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
m_lpBuffersOut = lpBuffersOut;
m_dwFlags = dwFlags;
m_dwContext = dwContext;
}
};
//
// InternetQueryDataAvailable API
//
class CFsm_QueryAvailable : public CFsm {
friend
DWORD
QueryAvailable_Fsm(
IN CFsm_QueryAvailable * Fsm
);
public:
LPDWORD m_lpdwNumberOfBytesAvailable;
private:
//
// parameters
//
DWORD m_dwFlags;
DWORD_PTR m_dwContext;
//
// local variables
//
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
CFsm_QueryAvailable(
IN LPDWORD lpdwNumberOfBytesAvailable,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
) : CFsm(RunSM, NULL, FALSE) {
SET_FSM_TYPE(QUERY_DATA_AVAILABLE);
if (GetError() != ERROR_SUCCESS) {
return;
}
SetApi(ApiType_Bool);
m_lpdwNumberOfBytesAvailable = lpdwNumberOfBytesAvailable;
m_dwFlags = dwFlags;
m_dwContext = dwContext;
}
};
//
// Fsm to Background tasks
//
class BackgroundTaskMgr; // defined in bgtask.hxx
class CFsm_BackgroundTask : public CFsm {
friend class BackgroundTaskMgr;
friend
DWORD
BackgroundTask_Fsm(
IN CFsm_BackgroundTask * Fsm
);
private:
//
// parameters
//
BackgroundTaskMgr* m_pMgr;
LPCSTR m_lpszUrl;
//
// local variables
//
//
// internal methods
DWORD DoSendReq();
//
// this private func can only
// be called from Mgr
//
CFsm_BackgroundTask(
IN BackgroundTaskMgr* pMgr,
IN LPCSTR lpszUrl
) : CFsm(RunSM, NULL) {
SET_FSM_TYPE(BACKGROUND_TASK);
if (GetError() != ERROR_SUCCESS) {
return;
}
m_pMgr = pMgr;
COPY_MANDATORY_PARAM(m_lpszUrl, lpszUrl);
}
public:
static
DWORD
RunSM(
IN CFsm * Fsm
);
~CFsm_BackgroundTask();
};
//
// prototypes
//
CFsm *
ContainingFsm(
IN LPVOID lpAddress
);
DWORD
RunAll(
VOID
);
DWORD
DoFsm(
IN CFsm * pFsm
);
DWORD
DoAsyncFsm(
IN CFsm * pFsm,
IN HTTP_REQUEST_HANDLE_OBJECT *pRequest
);