/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    rtutils.h

Abstract:
     Public declarations for the Router process  utility functions.

--*/

#ifndef __ROUTING_RTUTILS_H__
#define __ROUTING_RTUTILS_H__

#if _MSC_VER > 1000
#pragma once
#endif

#ifdef __cplusplus
extern "C" {
#endif


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// TRACING FUNCTION PROTOTYPES                                              //
//                                                                          //
// See DOCUMENT for more information                                        //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Definitions for flags and constants                                      //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define TRACE_USE_FILE      0x00000001
#define TRACE_USE_CONSOLE   0x00000002
#define TRACE_NO_SYNCH      0x00000004

#define TRACE_NO_STDINFO    0x00000001
#define TRACE_USE_MASK      0x00000002
#define TRACE_USE_MSEC      0x00000004
#define TRACE_USE_DATE      0x00000008

#define INVALID_TRACEID     0xFFFFFFFF


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// ANSI entry-points                                                        //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

DWORD
APIENTRY
TraceRegisterExA(
    IN  LPCSTR      lpszCallerName,
    IN  DWORD       dwFlags
    );

DWORD
APIENTRY
TraceDeregisterA(
    IN  DWORD       dwTraceID
    );

DWORD
APIENTRY
TraceDeregisterExA(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags
    );

DWORD
APIENTRY
TraceGetConsoleA(
    IN  DWORD       dwTraceID,
    OUT LPHANDLE    lphConsole
    );

DWORD
__cdecl
TracePrintfA(
    IN  DWORD       dwTraceID,
    IN  LPCSTR      lpszFormat,
    IN  ...         OPTIONAL
    );

DWORD
__cdecl
TracePrintfExA(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCSTR      lpszFormat,
    IN  ...         OPTIONAL
    );

DWORD
APIENTRY
TraceVprintfExA(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCSTR      lpszFormat,
    IN  va_list     arglist
    );

DWORD
APIENTRY
TracePutsExA(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCSTR      lpszString
    );

DWORD
APIENTRY
TraceDumpExA(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPBYTE      lpbBytes,
    IN  DWORD       dwByteCount,
    IN  DWORD       dwGroupSize,
    IN  BOOL        bAddressPrefix,
    IN  LPCSTR      lpszPrefix
    );


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// ANSI entry-points macros                                                 //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define TraceRegisterA(a)               TraceRegisterExA(a,0)
#define TraceVprintfA(a,b,c)            TraceVprintfExA(a,0,b,c)
#define TracePutsA(a,b)                 TracePutsExA(a,0,b)
#define TraceDumpA(a,b,c,d,e,f)         TraceDumpExA(a,0,b,c,d,e,f)



//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Unicode entry-points                                                     //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

DWORD
APIENTRY
TraceRegisterExW(
    IN  LPCWSTR     lpszCallerName,
    IN  DWORD       dwFlags
    );

DWORD
APIENTRY
TraceDeregisterW(
    IN  DWORD       dwTraceID
    );

DWORD
APIENTRY
TraceDeregisterExW(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags
    );

DWORD
APIENTRY
TraceGetConsoleW(
    IN  DWORD       dwTraceID,
    OUT LPHANDLE    lphConsole
    );

DWORD
__cdecl
TracePrintfW(
    IN  DWORD       dwTraceID,
    IN  LPCWSTR     lpszFormat,
    IN  ...         OPTIONAL
    );

DWORD
__cdecl
TracePrintfExW(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCWSTR     lpszFormat,
    IN  ...         OPTIONAL
    );

DWORD
APIENTRY
TraceVprintfExW(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCWSTR     lpszFormat,
    IN  va_list     arglist
    );

DWORD
APIENTRY
TracePutsExW(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPCWSTR     lpszString
    );

DWORD
APIENTRY
TraceDumpExW(
    IN  DWORD       dwTraceID,
    IN  DWORD       dwFlags,
    IN  LPBYTE      lpbBytes,
    IN  DWORD       dwByteCount,
    IN  DWORD       dwGroupSize,
    IN  BOOL        bAddressPrefix,
    IN  LPCWSTR     lpszPrefix
    );


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Unicode entry-points macros                                              //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define TraceRegisterW(a)               TraceRegisterExW(a,0)
#define TraceVprintfW(a,b,c)            TraceVprintfExW(a,0,b,c)
#define TracePutsW(a,b)                 TracePutsExW(a,0,b)
#define TraceDumpW(a,b,c,d,e,f)         TraceDumpExW(a,0,b,c,d,e,f)



//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Code-page dependent entry-point macros                                   //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#ifdef UNICODE
#define TraceRegister           TraceRegisterW
#define TraceDeregister         TraceDeregisterW
#define TraceDeregisterEx       TraceDeregisterExW
#define TraceGetConsole         TraceGetConsoleW
#define TracePrintf             TracePrintfW
#define TraceVprintf            TraceVprintfW
#define TracePuts               TracePutsW
#define TraceDump               TraceDumpW
#define TraceRegisterEx         TraceRegisterExW
#define TracePrintfEx           TracePrintfExW
#define TraceVprintfEx          TraceVprintfExW
#define TracePutsEx             TracePutsExW
#define TraceDumpEx             TraceDumpExW
#else
#define TraceRegister           TraceRegisterA
#define TraceDeregister         TraceDeregisterA
#define TraceDeregisterEx       TraceDeregisterExA
#define TraceGetConsole         TraceGetConsoleA
#define TracePrintf             TracePrintfA
#define TraceVprintf            TraceVprintfA
#define TracePuts               TracePutsA
#define TraceDump               TraceDumpA
#define TraceRegisterEx         TraceRegisterExA
#define TracePrintfEx           TracePrintfExA
#define TraceVprintfEx          TraceVprintfExA
#define TracePutsEx             TracePutsExA
#define TraceDumpEx             TraceDumpExA
#endif



//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// EVENT LOGGING FUNCTION PROTOTYPES                                        //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// ANSI prototypes                                                          //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////


VOID
APIENTRY
LogErrorA(
    IN DWORD    dwMessageId,
    IN DWORD    cNumberOfSubStrings,
    IN LPSTR   *plpwsSubStrings,
    IN DWORD    dwErrorCode
);

VOID
APIENTRY
LogEventA(
    IN DWORD   wEventType,
    IN DWORD   dwMessageId,
    IN DWORD   cNumberOfSubStrings,
    IN LPSTR  *plpwsSubStrings
);


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Unicode prototypes                                                       //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

VOID
LogErrorW(
    IN DWORD    dwMessageId,
    IN DWORD    cNumberOfSubStrings,
    IN LPWSTR  *plpwsSubStrings,
    IN DWORD    dwErrorCode
);

VOID
LogEventW(
    IN DWORD   wEventType,
    IN DWORD   dwMessageId,
    IN DWORD   cNumberOfSubStrings,
    IN LPWSTR *plpwsSubStrings
);


#ifdef UNICODE
#define LogError                LogErrorW
#define LogEvent                LogEventW
#else
#define LogError                LogErrorA
#define LogEvent                LogEventA
#endif


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// The following functions allow the caller to specify the event source.    //
//                                                                          //
// Call RouterLogRegister with the strings which would be passed to         //
// RegisterEventSource; this returns a handle which can be passed           //
// to the functions RouterLogEvent and RouterLogEventData.                  //
//                                                                          //
// Call RouterLogDeregister to close the handle.                            //
//                                                                          //
// Macros are provided for the different kinds of event log entrys:         //
//  RouterLogError          logs an error (EVENTLOG_ERROR_TYPE)             //
//  RouterLogWarning        logs a warning (EVENTLOG_WARNING_TYPE)          //
//  RouterLogInformation    logs information (EVENTLOG_INFORMATION_TYPE)    //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// ANSI prototypes                                                          //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

HANDLE
RouterLogRegisterA(
    LPCSTR lpszSource
    );

VOID
RouterLogDeregisterA(
    HANDLE hLogHandle
    );

VOID
RouterLogEventA(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPSTR *plpszSubStringArray,
    IN DWORD dwErrorCode
    );

VOID
RouterLogEventDataA(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPSTR *plpszSubStringArray,
    IN DWORD dwDataBytes,
    IN LPBYTE lpDataBytes
    );

VOID
RouterLogEventStringA(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPSTR *plpszSubStringArray,
    IN DWORD dwErrorCode,
    IN DWORD dwErrorIndex
    );

VOID
__cdecl
RouterLogEventExA(
    IN HANDLE   hLogHandle,
    IN DWORD    dwEventType,
    IN DWORD    dwErrorCode,
    IN DWORD    dwMessageId,
    IN LPCSTR   ptszFormat,
    ...
    );

VOID
RouterLogEventValistExA(
    IN HANDLE   hLogHandle,
    IN DWORD    dwEventType,
    IN DWORD    dwErrorCode,
    IN DWORD    dwMessageId,
    IN LPCSTR   ptszFormat,
    IN va_list  arglist
    );

DWORD
RouterGetErrorStringA(
    IN  DWORD   dwErrorCode,
    OUT LPSTR * lplpszErrorString
    );

#define RouterLogErrorA(h,msg,count,array,err) \
        RouterLogEventA(h,EVENTLOG_ERROR_TYPE,msg,count,array,err)
#define RouterLogWarningA(h,msg,count,array,err) \
        RouterLogEventA(h,EVENTLOG_WARNING_TYPE,msg,count,array,err)
#define RouterLogInformationA(h,msg,count,array,err) \
        RouterLogEventA(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,err)

#define RouterLogErrorDataA(h,msg,count,array,c,buf) \
        RouterLogEventDataA(h,EVENTLOG_ERROR_TYPE,msg,count,array,c,buf)
#define RouterLogWarningDataA(h,msg,count,array,c,buf) \
        RouterLogEventDataA(h,EVENTLOG_WARNING_TYPE,msg,count,array,c,buf)
#define RouterLogInformationDataA(h,msg,count,array,c,buf) \
        RouterLogEventDataA(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,c,buf)

#define RouterLogErrorStringA(h,msg,count,array,err,index) \
        RouterLogEventStringA(h,EVENTLOG_ERROR_TYPE,msg,count,array, err,index)
#define RouterLogWarningStringA(h,msg,count,array,err,index) \
        RouterLogEventStringA(h,EVENTLOG_WARNING_TYPE,msg,count,array,err,index)
#define RouterLogInformationStringA(h,msg,count,array, err,index) \
        RouterLogEventStringA(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,err,\
                              index)


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Unicode prototypes                                                       //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

HANDLE
RouterLogRegisterW(
    LPCWSTR lpszSource
    );

VOID
RouterLogDeregisterW(
    HANDLE hLogHandle
    );

VOID
RouterLogEventW(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPWSTR *plpszSubStringArray,
    IN DWORD dwErrorCode
    );

VOID
RouterLogEventDataW(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPWSTR *plpszSubStringArray,
    IN DWORD dwDataBytes,
    IN LPBYTE lpDataBytes
    );

VOID
RouterLogEventStringW(
    IN HANDLE hLogHandle,
    IN DWORD dwEventType,
    IN DWORD dwMessageId,
    IN DWORD dwSubStringCount,
    IN LPWSTR *plpszSubStringArray,
    IN DWORD dwErrorCode,
    IN DWORD dwErrorIndex
    );

VOID
__cdecl
RouterLogEventExW(
    IN HANDLE   hLogHandle,
    IN DWORD    dwEventType,
    IN DWORD    dwErrorCode,
    IN DWORD    dwMessageId,
    IN LPCWSTR  ptszFormat,
    ...
    );

VOID
RouterLogEventValistExW(
    IN HANDLE   hLogHandle,
    IN DWORD    dwEventType,
    IN DWORD    dwErrorCode,
    IN DWORD    dwMessageId,
    IN LPCWSTR  ptszFormat,
    IN va_list  arglist
    );

DWORD
RouterGetErrorStringW(
    IN  DWORD    dwErrorCode,
    OUT LPWSTR * lplpwszErrorString
    );


#define RouterLogErrorW(h,msg,count,array,err) \
        RouterLogEventW(h,EVENTLOG_ERROR_TYPE,msg,count,array,err)
#define RouterLogWarningW(h,msg,count,array,err) \
        RouterLogEventW(h,EVENTLOG_WARNING_TYPE,msg,count,array,err)
#define RouterLogInformationW(h,msg,count,array,err) \
        RouterLogEventW(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,err)

#define RouterLogErrorDataW(h,msg,count,array,c,buf) \
        RouterLogEventDataW(h,EVENTLOG_ERROR_TYPE,msg,count,array,c,buf)
#define RouterLogWarningDataW(h,msg,count,array,c,buf) \
        RouterLogEventDataW(h,EVENTLOG_WARNING_TYPE,msg,count,array,c,buf)
#define RouterLogInformationDataW(h,msg,count,array,c,buf) \
        RouterLogEventDataW(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,c,buf)

#define RouterLogErrorStringW(h,msg,count,array,err,index) \
        RouterLogEventStringW(h,EVENTLOG_ERROR_TYPE,msg,count,array,err,index)
#define RouterLogWarningStringW(h,msg,count,array,err,index) \
        RouterLogEventStringW(h,EVENTLOG_WARNING_TYPE,msg,count,array,err,index)
#define RouterLogInformationStringW(h,msg,count,array,err,index) \
        RouterLogEventStringW(h,EVENTLOG_INFORMATION_TYPE,msg,count,array,err,\
                              index)


#ifdef UNICODE
#define RouterLogRegister           RouterLogRegisterW
#define RouterLogDeregister         RouterLogDeregisterW
#define RouterLogEvent              RouterLogEventW
#define RouterLogError              RouterLogErrorW
#define RouterLogWarning            RouterLogWarningW
#define RouterLogInformation        RouterLogInformationW
#define RouterLogEventData          RouterLogEventDataW
#define RouterLogErrorData          RouterLogErrorDataW
#define RouterLogWarningData        RouterLogWarningDataW
#define RouterLogInformationData    RouterLogInformationDataW
#define RouterLogEventString        RouterLogEventStringW
#define RouterLogEventEx            RouterLogEventExW
#define RouterLogEventValistEx      RouterLogEventValistExW
#define RouterLogErrorString        RouterLogErrorStringW
#define RouterLogWarningString      RouterLogWarningStringW
#define RouterLogInformationString  RouterLogInformationStringW
#define RouterGetErrorString        RouterGetErrorStringW
#
#else
#define RouterLogRegister           RouterLogRegisterA
#define RouterLogDeregister         RouterLogDeregisterA
#define RouterLogEvent              RouterLogEventA
#define RouterLogError              RouterLogErrorA
#define RouterLogWarning            RouterLogWarningA
#define RouterLogInformation        RouterLogInformationA
#define RouterLogEventData          RouterLogEventDataA
#define RouterLogErrorData          RouterLogErrorDataA
#define RouterLogWarningData        RouterLogWarningDataA
#define RouterLogInformationData    RouterLogInformationDataA
#define RouterLogEventString        RouterLogEventStringA
#define RouterLogEventEx            RouterLogEventExA
#define RouterLogEventValistEx      RouterLogEventValistExA
#define RouterLogErrorString        RouterLogErrorStringA
#define RouterLogWarningString      RouterLogWarningStringA
#define RouterLogInformationString  RouterLogInformationStringA
#define RouterGetErrorString        RouterGetErrorStringA
#endif


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// WORKER THREAD POOL FUNCTIONS                                             //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// definition of worker function passed in QueueWorkItem API                //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

typedef VOID (APIENTRY * WORKERFUNCTION)(PVOID);


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//  Function: Queues the supplied work item in the work queue.              //
//                                                                          //
//  functionptr: function to be called must be of WORKERFUNCTION type       //
//  context:     opaque ptr                                                 //
//  serviceinalertablethread: if TRUE gets scheduled in                     //
//               a alertably waiting thread that never dies                 //
//  Returns:  0 (success)                                                   //
//            Win32 error codes for cases like out of memory                //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

DWORD
APIENTRY
QueueWorkItem(
    IN WORKERFUNCTION functionptr,
    IN PVOID context,
    IN BOOL serviceinalertablethread
    );


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Function:        Associates file handle with the completion port (all    //
//                  asynchronous i/o on this handle will be queued to       //
//			        the completion port)                                    //
//                                                                          //
// FileHandle:	    File handle to be associated with completion port       //
//                                                                          //
// CompletionProc:  Procedure to be called when io associated with the file //
//				    handle completes. This function will be executed in     //
//				    the context of non-alertable worker thread              //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

DWORD
APIENTRY
SetIoCompletionProc (
	IN HANDLE							FileHandle,
	IN LPOVERLAPPED_COMPLETION_ROUTINE	CompletionProc
	);



//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// The following defines are included here as a hint on how the worker      //
// thread pool is managed:                                                  //
//                                                                          //
// There are NUM_ALERTABLE_THREADS permanent threads that never quit and    //
// wait alertably on a alertable worker queue.  These threads should solely //
// be used for work items that intiate asyncronous operation (file io,      //
// waitable timer) that ABSOLUTELY require APCs to complete (preferable     //
// method for IO is the usage of completio port API)                        //
//                                                                          //
// There is a pool of the threads that wait on completion port              //
// that used both for processing of IO and non-IO related work items        //
//                                                                          //
// The minimum number of threads is Number of processors                    //
// The maximum number of threads is MAX_WORKER_THREADS                      //
//                                                                          //
// A new thread is created if worker queue has not been served for more     //
// that WORK_QUEUE_TIMEOUT                                                  //
// The existing thread will be shut down if it is not used for more than    //
// THREAD_IDLE_TIMEOUT                                                      //
//                                                                          //
// Note that worker threads age guaranteed to be alive for at least         //
// THREAD_IDLE_TIMEOUT after the last work item is executed.  This timeout  //
// is chosen such that bulk of IO request could be completed before it      //
// expires.  If it is not enough for your case, use alertable thread with   //
// APC, or create your own thread.                                          //
//                                                                          //
// Note: changing these flags will not change anything.                     //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Number of alertable threads                                              //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define NUM_ALERTABLE_THREADS		2

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Max number of threads at any time                                        //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define MAX_WORKER_THREADS          10

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Time that the worker queue is not served before starting new thread      //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define WORK_QUEUE_TIMEOUT			1 //sec

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Time that thread has to be idle before exiting                           //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define THREAD_IDLE_TIMEOUT			10 //sec


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// ROUTER ASSERT DECLARATION                                                //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

VOID
RouterAssert(
    IN PSTR pszFailedAssertion,
    IN PSTR pszFileName,
    IN DWORD dwLineNumber,
    IN PSTR pszMessage OPTIONAL
    );


#if DBG
#define RTASSERT(exp) \
        if (!(exp)) \
            RouterAssert(#exp, __FILE__, __LINE__, NULL)
#define RTASSERTMSG(msg, exp) \
        if (!(exp)) \
            RouterAssert(#exp, __FILE__, __LINE__, msg)
#else
#define RTASSERT(exp)
#define RTASSERTMSG(msg, exp)
#endif

//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// REGISTRY CONFIGURATION FUNCTIONS                                         //
//                                                                          //
// The following definitions are used to read configuration information     //
// about installed protocols.                                               //
//                                                                          //
// Call 'MprSetupProtocolEnum' to enumerate the routing-protocols           //
// for transport 'dwTransportId'. This fills an array with entries          //
// of type 'MPR_PROTOCOL_0'.                                                //
//                                                                          //
// The array loaded can be destroyed by calling 'MprSetupProtocolFree'.     //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////

#define RTUTILS_MAX_PROTOCOL_NAME_LEN	                40
#define RTUTILS_MAX_PROTOCOL_DLL_LEN                    48

//
// the below two names should not be used
//

#ifndef MAX_PROTOCOL_NAME_LEN
#define MAX_PROTOCOL_NAME_LEN RTUTILS_MAX_PROTOCOL_NAME_LEN
#else
#undef MAX_PROTOCOL_NAME_LEN
#endif
#define MAX_PROTOCOL_DLL_LEN  RTUTILS_MAX_PROTOCOL_DLL_LEN



typedef struct _MPR_PROTOCOL_0 {

    DWORD       dwProtocolId;                           // e.g. IP_RIP
    WCHAR       wszProtocol[RTUTILS_MAX_PROTOCOL_NAME_LEN+1];   // e.g. "IPRIP"
    WCHAR       wszDLLName[RTUTILS_MAX_PROTOCOL_DLL_LEN+1];     // e.g. "iprip2.dll"

} MPR_PROTOCOL_0;


DWORD APIENTRY
MprSetupProtocolEnum(
    IN      DWORD                   dwTransportId,
    OUT     LPBYTE*                 lplpBuffer,         // MPR_PROTOCOL_0
    OUT     LPDWORD                 lpdwEntriesRead
    );


DWORD APIENTRY
MprSetupProtocolFree(
    IN      LPVOID                  lpBuffer
    );


//////////////////////////////////////////////////////////////////////////////
// Extensions to Rtutils to improve worker thread utilization.				//
// 																			//
//////////////////////////////////////////////////////////////////////////////

#define ROUTING_RESERVED
#define OPT1_1
#define OPT1_2
#define OPT2_1
#define OPT2_2
#define OPT3_1
#define OPT3_2


//
// When everyone is migrated to using Winsock2
//

#if 0


//==========================================================================================================//
//==========================================================================================================//

// ASYNC_SOCKET_DATA structure is used to pass / receive back data from an    	//
// asynchronous wait recv from call												//

typedef struct _ASYNC_SOCKET_DATA {
			OVERLAPPED		Overlapped;			// reserved. not to be used
	IN		WSABUF			WsaBuf;				// WsaBuf.buf to be initialized to point to buffer
												// WsaBuf.len set to the length of the buffer
	OUT		SOCKADDR_IN		SrcAddress;			// AsyncWsaRecvFrom fills this with the source address of the packet
	OUT		DWORD			NumBytesReceived;	// AsyncWsaRecvFrom fills this with the number of bytes returned in the packet
	IN OUT	DWORD			Flags;				// Used to set flags for WSARecvFrom, and returns the flags set by WSARecvFrom
	OUT		DWORD			Status;				// status returned by IO Completion Port

	IN		WORKERFUNCTION	pFunction;			// Function to be executed on receiving packet
	IN		PVOID			pContext;			// context for the above function
} ASYNC_SOCKET_DATA, *PASYNC_SOCKET_DATA;



// AsyncSocketInit() binds the socket to the IOCompletionPort. This should be called//
// after the socket is created and before AsyncWsaRecvFrom() call is made			//
DWORD
APIENTRY
AsyncSocketInit (
	SOCKET	sock
	);


// This should be called only after the appropriate fields in SockData are initialized	//
// This sets up an asynchronous WSARecvFrom(), and on its return dispatches the 		//
// function to a worker thread. It should be remembered that the function will run in 	//
// a worker thread which might later on be deleted. So SetWaitableTimer() and 			//
// asynchronous receive calls should be avoided unless you are sure that it would not be//
// a problem. It is adviced that if you want the function to run in an alertable thread,//
// then have the callback function queue a work item to alertable thread. Queue work 	//
// items to alertable worker threads for SetWaitableTimer() and async receives. 		//
// One must not make many AsyncWSArecvFrom() calls, as the buffer are non-paged			//
DWORD
APIENTRY
AsyncWSARecvFrom (
	SOCKET		sock,
	PASYNC_SOCKET_DATA	pSockData
	);

#endif // all winsock2 functions

//==========================================================================================================//
//==========================================================================================================//


// forward declarations
struct _WAIT_THREAD_ENTRY;
struct _WT_EVENT_ENTRY;


typedef struct _WT_TIMER_ENTRY {
	LONGLONG		    te_Timeout;

	WORKERFUNCTION	    te_Function;
	PVOID			    te_Context;
	DWORD			    te_ContextSz;
	BOOL			    te_RunInServer;
	
	DWORD			    te_Status;

	#define 		TIMER_INACTIVE  3
	#define 		TIMER_ACTIVE	4

	DWORD			    te_ServerId;
	struct _WAIT_THREAD_ENTRY *teP_wte;	
	LIST_ENTRY		    te_ServerLinks;
	
	LIST_ENTRY		    te_Links;

	BOOL			    te_Flag;		//todo: not used
	DWORD			    te_TimerId;
} WT_TIMER_ENTRY, *PWT_TIMER_ENTRY;

	
typedef struct _WT_WORK_ITEM {
    WORKERFUNCTION      wi_Function;    			// function to call
    PVOID               wi_Context;    				// context passed into function call
	DWORD			    wi_ContextSz;				// size of context, used for allocating
	BOOL			    wi_RunInServer;				// run in wait server thread or get queued to some worker thread

	struct _WT_EVENT_ENTRY	*wiP_ee;
	LIST_ENTRY		wi_ServerLinks;
    LIST_ENTRY      wi_Links;  					//todo not req    // link to next and prev element
} WT_WORK_ITEM, *PWT_WORK_ITEM;

#define WT_EVENT_BINDING 	WT_WORK_ITEM
#define PWT_EVENT_BINDING 	PWT_WORK_ITEM


//
// WT_EVENT_ENTRY
//
typedef struct _WT_EVENT_ENTRY {
	HANDLE			ee_Event;
	BOOL			ee_bManualReset;							// is the event manually reset
	BOOL			ee_bInitialState;						// is the initial state of the event active
	BOOL			ee_bDeleteEvent;						// was the event created as part of createWaitEvent
	
	DWORD			ee_Status;								// current status of the event entry
	BOOL			ee_bHighPriority;
	
	LIST_ENTRY		eeL_wi;
	
	BOOL			ee_bSignalSingle;						// signal single function or multiple functions						// how many functions to activate when event signalled (default:1)
	BOOL			ee_bOwnerSelf;							// the owner if the client which create this event

	INT				ee_ArrayIndex;							// index in the events array if active
	
	DWORD			ee_ServerId;							// Id of server: used while deleting
	struct _WAIT_THREAD_ENTRY *eeP_wte;						// pointer to wait thread entry
	LIST_ENTRY		ee_ServerLinks;							// used by wait server thread
	LIST_ENTRY		ee_Links;								// used by client

	DWORD			ee_RefCount;
	BOOL			ee_bFlag;		//todo: notused								// reserved for use during deletion
	DWORD			ee_EventId;		//todo: remove it, being used only for testing/debugging	

} WT_EVENT_ENTRY, *PWT_EVENT_ENTRY;




// PROTOTYPES OF FUNCTIONS USED IN THIS FILE ONLY
//


// used by client to create a wait event
// context size should be 0 if you are passing a dword instead of a pointer
// if pEvent field is set, then lpName and security attributes are ignored
// if pFunction is NULL, then pContext, dwContextSz, and bRunInServerContext are ignored
PWT_EVENT_ENTRY
APIENTRY
CreateWaitEvent (
	//IN	PWT_EVENT_ENTRY	pEventEntry,					// handle to event entry if initialized by others
	IN	HANDLE			pEvent 				OPT1_1,			// handle to event if already created

	IN	LPSECURITY_ATTRIBUTES lpEventAttributes OPT1_2, 	// pointer to security attributes
	IN	BOOL			bManualReset,
	IN	BOOL			bInitialState,
	IN	LPCTSTR 		lpName 				OPT1_2, 		// pointer to event-object name

	IN  BOOL			bHighPriority,						// create high priority event

	IN	WORKERFUNCTION 	pFunction 			OPT2_1,			// if null, means will be set by other clients
	IN	PVOID 			pContext  			OPT2_1,			// can be null
	IN  DWORD			dwContextSz			OPT2_1,			// size of context: used for allocating context to functions
	IN 	BOOL			bRunInServerContext	OPT2_1			// run in server thread or get dispatched to worker thread
	);



//dwContextSz should be 0 if a dword is being passed. >0 only if pointer to block of that size is being passed.
PWT_EVENT_BINDING
APIENTRY
CreateWaitEventBinding (
	IN	PWT_EVENT_ENTRY	pee,
	IN 	WORKERFUNCTION 	pFunction,
	IN 	PVOID			pContext,
	IN	DWORD			dwContextSz,
	IN	BOOL			bRunInServerContext
	);

	
PWT_TIMER_ENTRY
APIENTRY
CreateWaitTimer (
	IN	WORKERFUNCTION	pFunction,
	IN	PVOID			pContext,
	IN	DWORD			dwContextSz,
	IN	BOOL			bRunInServerContext
	);

DWORD
APIENTRY
DeRegisterWaitEventBindingSelf (
	IN	PWT_EVENT_BINDING	pwiWorkItem
	);

	
DWORD
APIENTRY
DeRegisterWaitEventBinding (
	IN	PWT_EVENT_BINDING	pwiWorkItem
	);


//all the events and timers should be registered with one waitThread server
//todo: change the above requirement
DWORD
APIENTRY
DeRegisterWaitEventsTimers (
	PLIST_ENTRY	pLEvents,	// list of events linked by ee_Links field
	PLIST_ENTRY pLTimers	// list of timers linked by te_Links field:
	//these lists can be a single list entry, or a multiple entry list with a list header entry.
	);

// this should be used only when called within a server thread
DWORD
APIENTRY
DeRegisterWaitEventsTimersSelf (
	IN	PLIST_ENTRY pLEvents,
	IN	PLIST_ENTRY	pLTimers
	);

	
DWORD
APIENTRY
RegisterWaitEventBinding (
	IN	PWT_EVENT_BINDING	pwiWorkItem
	);
	
// Register the client with the wait thread
DWORD
APIENTRY
RegisterWaitEventsTimers (
	IN	PLIST_ENTRY pLEventsToAdd,
	IN	PLIST_ENTRY	pLTimersToAdd
	);

DWORD
APIENTRY
UpdateWaitTimer (
	IN	PWT_TIMER_ENTRY	pte,
	IN	LONGLONG 		*time
	);

VOID
APIENTRY
WTFree (
	PVOID ptr
	);


//used to free wait-event. Should be deallocated using DeRegisterWaitEventsTimers
//This function is to be used only when the events have not been registered
VOID
APIENTRY
WTFreeEvent (
	IN	PWT_EVENT_ENTRY	peeEvent
	);


//used to free wait-timer. Should be deallocated using DeRegisterWaitEventsTimers
//This function is to be used only when the timers have not been registered
VOID
APIENTRY
WTFreeTimer (
	IN PWT_TIMER_ENTRY pteTimer
	);

	
VOID
APIENTRY
DebugPrintWaitWorkerThreads (
	DWORD	dwDebugLevel
	);

#define DEBUGPRINT_FILTER_NONCLIENT_EVENTS	0x2
#define DEBUGPRINT_FILTER_EVENTS			0x4
#define DEBUGPRINT_FILTER_TIMERS			0x8


//
//ERROR VALUES
//
#define ERROR_WAIT_THREAD_UNAVAILABLE 	1

#define ERROR_WT_EVENT_ALREADY_DELETED 	2




#define TIMER_HIGH(time) \
	(((LARGE_INTEGER*)&time)->HighPart)

#define TIMER_LOW(time) \
	(((LARGE_INTEGER*)&time)->LowPart)


#ifdef __cplusplus
}
#endif

#endif // ___ROUTING_RTUTILS_H__