/*++ 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 );