//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: ISAPI.H
Abstract: ISAPI Exten & Filter handling classes
--*/


typedef enum {
	SCRIPT_TYPE_NONE = 0,
	SCRIPT_TYPE_EXTENSION,
	SCRIPT_TYPE_ASP,
	SCRIPT_TYPE_FILTER
}
SCRIPT_TYPE;

typedef DWORD (WINAPI *PFN_HTTPFILTERPROC)(HTTP_FILTER_CONTEXT* pfc, DWORD NotificationType, VOID* pvNotification);
typedef BOOL  (WINAPI *PFN_GETFILTERVERSION)(HTTP_FILTER_VERSION* pVer);
typedef BOOL  (WINAPI *PFN_TERMINATEFILTER)(DWORD dwFlags);
typedef void  (WINAPI *PFN_TERMINATEASP)();
typedef DWORD (WINAPI *PFN_EXECUTEASP)(PASP_CONTROL_BLOCK pASPBlock);

class CISAPICache; 
BOOL InitExtensions(CReg *pWebsite);
int RecvToBuf(SOCKET socket,PVOID pv, DWORD dw,DWORD dwTimeout);

class CISAPI {
friend CISAPICache;

// ISAPI extension & filter handling data members
	SCRIPT_TYPE  m_scriptType;   // Extension, Filter, or ASP?
	HINSTANCE  m_hinst;
	FARPROC m_pfnGetVersion;
	FARPROC m_pfnHttpProc;
	FARPROC m_pfnTerminate;
	DWORD dwFilterFlags;  	// Flags negotiated on GetFilterVersion	

	// Used by the caching class 
	PWSTR   m_wszDLLName;	// full path of ISAPI Dll
	DWORD   m_cRef;			// Reference Count
	__int64 m_ftLastUsed;	// Last used, treat as FILETIME struct
	BOOL    m_fCanTimeout;  // If ISAPI is to permanently stay in cache.

public:
	CISAPI(SCRIPT_TYPE st) { 
		ZEROMEM(this); 
		m_scriptType = st; 
	}

	~CISAPI() 	{ 
		MyFree(m_wszDLLName);
		MyFreeLib(m_hinst);
	}

	void Unload(PWSTR wszDLLName=NULL);
	BOOL Load(PWSTR wszPath);
	void CoFreeUnusedLibrariesIfASP() {
		// Calls into ASP exported function, which calls CoFreeUnusedLibraries
		// but does nothing else.  We don't call CoFreeUnusedLibraries from the web 
		// server directly because we don't want to have to link it to COM.
		// Does not free asp.dll, because we have a reference to it in the server.

		// Do nothing because services.exe spun up thread does this already.
		// ((PFN_TERMINATEASP)m_pfnTerminate)();
		;
	}

	BOOL LoadExports(HINSTANCE hInst, BOOL fVerifyOnly);
	
	DWORD CallExtension(EXTENSION_CONTROL_BLOCK * pECB)	{ return ((PFN_HTTPEXTENSIONPROC)m_pfnHttpProc)(pECB); }
	DWORD CallFilter(HTTP_FILTER_CONTEXT* pfc, DWORD n, VOID* pv) { return ((PFN_HTTPFILTERPROC)m_pfnHttpProc)(pfc, n, pv); }
	DWORD CallASP(PASP_CONTROL_BLOCK pACB)  { return ((PFN_EXECUTEASP) m_pfnHttpProc)(pACB); }
	DWORD GetFilterFlags()  { return dwFilterFlags; }
};


typedef struct _isapi_node {
	CISAPI *m_pISAPI;		// class has library and entry point functions
	struct _isapi_node *m_pNext;
} ISAPINODE, *PISAPINODE;

typedef struct _SCRIPT_MAP_NODE {
	WCHAR *wszFileExtension;
	WCHAR *wszISAPIPath;
	BOOL  fASP;
} SCRIPT_MAP_NODE, *PSCRIPT_MAP_NODE;

typedef struct _SCRIPT_MAP {
	PSCRIPT_MAP_NODE pScriptNodes;
	DWORD            dwEntries;
} SCRIPT_MAP, *PSCRIPT_MAP;


typedef struct _SCRIPT_NOUNLOAD {
	WCHAR**               ppszNoUnloadEntry;
	DWORD                 dwEntries;
} SCRIPT_NOUNLOAD, *PSCRIPT_NOUNLOAD;

void InitScriptMapping(PSCRIPT_MAP pTable);
void InitScriptNoUnloadList(PSCRIPT_NOUNLOAD pNoUnloadList);
BOOL MapScriptExtension(WCHAR *wszFileExt, WCHAR **pwszISAPIPath, BOOL *pfIsASP);

class CISAPICache {
private:
	PISAPINODE m_pHead;
	CRITICAL_SECTION m_CritSec;

public:
	CISAPICache() 	{ 
		ZEROMEM(this);  	
		InitializeCriticalSection(&m_CritSec);
	}
	~CISAPICache() {
		DeleteCriticalSection(&m_CritSec);
	}

	
	HINSTANCE Load(PWSTR wszDLLName, CISAPI **ppISAPI, SCRIPT_TYPE st=SCRIPT_TYPE_EXTENSION);
	void Unload(CISAPI *pISAPI) {
		SYSTEMTIME st;
		if (NULL == pISAPI)
			return;
			
		EnterCriticalSection(&m_CritSec);
		
		GetSystemTime(&st);
		SystemTimeToFileTime(&st,(FILETIME *) &pISAPI->m_ftLastUsed);
		pISAPI->m_cRef--;

		LeaveCriticalSection(&m_CritSec);
	}

	void RemoveUnusedISAPIs(BOOL fRemoveAll);
	friend DWORD WINAPI RemoveUnusedISAPIs(LPVOID lpv);
};
